From 435eb49b5841ddbfe84394f8047cdc2bd048f12e Mon Sep 17 00:00:00 2001 From: emerald000 Date: Fri, 2 Oct 2015 23:38:11 -0400 Subject: [PATCH 001/268] Added missing Licids + tests (including 2 failing tests). --- .../src/mage/sets/exodus/DominatingLicid.java | 71 +++++++++++ .../sets/exodus/TransmogrifyingLicid.java | 78 ++++++++++++ .../mage/sets/stronghold/CalmingLicid.java | 71 +++++++++++ .../mage/sets/stronghold/ConvulsingLicid.java | 71 +++++++++++ .../mage/sets/stronghold/CorruptingLicid.java | 72 +++++++++++ .../mage/sets/stronghold/GlidingLicid.java | 72 +++++++++++ .../mage/sets/stronghold/TemptingLicid.java | 71 +++++++++++ .../src/mage/sets/tempest/LeechingLicid.java | 74 +++++++++++ .../src/mage/sets/tempest/NurturingLicid.java | 71 +++++++++++ .../mage/sets/tempest/QuickeningLicid.java | 73 +++++++++++ .../src/mage/sets/tempest/StingingLicid.java | 70 +++++++++++ .../abilities/activated/LicidAbilityTest.java | 118 ++++++++++++++++++ 12 files changed, 912 insertions(+) create mode 100644 Mage.Sets/src/mage/sets/exodus/DominatingLicid.java create mode 100644 Mage.Sets/src/mage/sets/exodus/TransmogrifyingLicid.java create mode 100644 Mage.Sets/src/mage/sets/stronghold/CalmingLicid.java create mode 100644 Mage.Sets/src/mage/sets/stronghold/ConvulsingLicid.java create mode 100644 Mage.Sets/src/mage/sets/stronghold/CorruptingLicid.java create mode 100644 Mage.Sets/src/mage/sets/stronghold/GlidingLicid.java create mode 100644 Mage.Sets/src/mage/sets/stronghold/TemptingLicid.java create mode 100644 Mage.Sets/src/mage/sets/tempest/LeechingLicid.java create mode 100644 Mage.Sets/src/mage/sets/tempest/NurturingLicid.java create mode 100644 Mage.Sets/src/mage/sets/tempest/QuickeningLicid.java create mode 100644 Mage.Sets/src/mage/sets/tempest/StingingLicid.java create mode 100644 Mage.Tests/src/test/java/org/mage/test/cards/abilities/activated/LicidAbilityTest.java diff --git a/Mage.Sets/src/mage/sets/exodus/DominatingLicid.java b/Mage.Sets/src/mage/sets/exodus/DominatingLicid.java new file mode 100644 index 00000000000..3dc6bcb736b --- /dev/null +++ b/Mage.Sets/src/mage/sets/exodus/DominatingLicid.java @@ -0,0 +1,71 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.sets.exodus; + +import java.util.UUID; +import mage.MageInt; +import mage.abilities.common.LicidAbility; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.costs.mana.ColoredManaCost; +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.effects.common.continuous.ControlEnchantedEffect; +import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.ColoredManaSymbol; +import mage.constants.Rarity; +import mage.constants.Zone; + +/** + * + * @author emerald000 + */ +public class DominatingLicid extends CardImpl { + + public DominatingLicid(UUID ownerId) { + super(ownerId, 30, "Dominating Licid", Rarity.RARE, new CardType[]{CardType.CREATURE}, "{1}{U}{U}"); + this.expansionSetCode = "EXO"; + this.subtype.add("Licid"); + this.power = new MageInt(1); + this.toughness = new MageInt(1); + + // {1}{U}{U}, {tap}: Dominating Licid loses this ability and becomes an Aura enchantment with enchant creature. Attach it to target creature. You may pay {U} to end this effect. + this.addAbility(new LicidAbility(new ManaCostsImpl<>("{1}{U}{U}"), new ColoredManaCost(ColoredManaSymbol.U))); + + // You control enchanted creature. + this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new ControlEnchantedEffect())); + } + + public DominatingLicid(final DominatingLicid card) { + super(card); + } + + @Override + public DominatingLicid copy() { + return new DominatingLicid(this); + } +} diff --git a/Mage.Sets/src/mage/sets/exodus/TransmogrifyingLicid.java b/Mage.Sets/src/mage/sets/exodus/TransmogrifyingLicid.java new file mode 100644 index 00000000000..c98e0f48e4c --- /dev/null +++ b/Mage.Sets/src/mage/sets/exodus/TransmogrifyingLicid.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.exodus; + +import java.util.UUID; +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.LicidAbility; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.costs.mana.GenericManaCost; +import mage.abilities.effects.Effect; +import mage.abilities.effects.common.continuous.AddCardTypeAttachedEffect; +import mage.abilities.effects.common.continuous.BoostEnchantedEffect; +import mage.cards.CardImpl; +import mage.constants.AttachmentType; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.Rarity; +import mage.constants.Zone; + +/** + * + * @author emerald000 + */ +public class TransmogrifyingLicid extends CardImpl { + + public TransmogrifyingLicid(UUID ownerId) { + super(ownerId, 141, "Transmogrifying Licid", Rarity.UNCOMMON, new CardType[]{CardType.ARTIFACT, CardType.CREATURE}, "{3}"); + this.expansionSetCode = "EXO"; + this.subtype.add("Licid"); + this.power = new MageInt(2); + this.toughness = new MageInt(2); + + // {1}, {tap}: Transmogrifying Licid loses this ability and becomes an Aura enchantment with enchant creature. Attach it to target creature. You may pay {1} to end this effect. + this.addAbility(new LicidAbility(new GenericManaCost(1), new GenericManaCost(1))); + + // Enchanted creature gets +1/+1 and is an artifact in addition to its other types. + Ability ability = new SimpleStaticAbility(Zone.BATTLEFIELD, new BoostEnchantedEffect(1, 1)); + Effect effect = new AddCardTypeAttachedEffect(CardType.ARTIFACT, Duration.WhileOnBattlefield, AttachmentType.AURA); + effect.setText("and is an artifact in addition to its other types"); + ability.addEffect(effect); + this.addAbility(ability); + } + + public TransmogrifyingLicid(final TransmogrifyingLicid card) { + super(card); + } + + @Override + public TransmogrifyingLicid copy() { + return new TransmogrifyingLicid(this); + } +} diff --git a/Mage.Sets/src/mage/sets/stronghold/CalmingLicid.java b/Mage.Sets/src/mage/sets/stronghold/CalmingLicid.java new file mode 100644 index 00000000000..2f3b09634eb --- /dev/null +++ b/Mage.Sets/src/mage/sets/stronghold/CalmingLicid.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.stronghold; + +import java.util.UUID; +import mage.MageInt; +import mage.abilities.common.LicidAbility; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.costs.mana.ColoredManaCost; +import mage.abilities.effects.common.combat.CantAttackAttachedEffect; +import mage.cards.CardImpl; +import mage.constants.AttachmentType; +import mage.constants.CardType; +import mage.constants.ColoredManaSymbol; +import mage.constants.Rarity; +import mage.constants.Zone; + +/** + * + * @author emerald000 + */ +public class CalmingLicid extends CardImpl { + + public CalmingLicid(UUID ownerId) { + super(ownerId, 102, "Calming Licid", Rarity.UNCOMMON, new CardType[]{CardType.CREATURE}, "{2}{W}"); + this.expansionSetCode = "STH"; + this.subtype.add("Licid"); + this.power = new MageInt(2); + this.toughness = new MageInt(2); + + // {W}, {tap}: Calming Licid loses this ability and becomes an Aura enchantment with enchant creature. Attach it to target creature. You may pay {W} to end this effect. + this.addAbility(new LicidAbility(new ColoredManaCost(ColoredManaSymbol.W), new ColoredManaCost(ColoredManaSymbol.W))); + + // Enchanted creature can't attack. + this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new CantAttackAttachedEffect(AttachmentType.AURA))); + } + + public CalmingLicid(final CalmingLicid card) { + super(card); + } + + @Override + public CalmingLicid copy() { + return new CalmingLicid(this); + } +} diff --git a/Mage.Sets/src/mage/sets/stronghold/ConvulsingLicid.java b/Mage.Sets/src/mage/sets/stronghold/ConvulsingLicid.java new file mode 100644 index 00000000000..ebb349d1880 --- /dev/null +++ b/Mage.Sets/src/mage/sets/stronghold/ConvulsingLicid.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.stronghold; + +import java.util.UUID; +import mage.MageInt; +import mage.abilities.common.LicidAbility; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.costs.mana.ColoredManaCost; +import mage.abilities.effects.common.combat.CantBlockAttachedEffect; +import mage.cards.CardImpl; +import mage.constants.AttachmentType; +import mage.constants.CardType; +import mage.constants.ColoredManaSymbol; +import mage.constants.Rarity; +import mage.constants.Zone; + +/** + * + * @author emerald000 + */ +public class ConvulsingLicid extends CardImpl { + + public ConvulsingLicid(UUID ownerId) { + super(ownerId, 77, "Convulsing Licid", Rarity.UNCOMMON, new CardType[]{CardType.CREATURE}, "{2}{R}"); + this.expansionSetCode = "STH"; + this.subtype.add("Licid"); + this.power = new MageInt(2); + this.toughness = new MageInt(2); + + // {R}, {tap}: Convulsing Licid loses this ability and becomes an Aura enchantment with enchant creature. Attach it to target creature. You may pay {R} to end this effect. + this.addAbility(new LicidAbility(new ColoredManaCost(ColoredManaSymbol.R), new ColoredManaCost(ColoredManaSymbol.R))); + + // Enchanted creature can't block. + this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new CantBlockAttachedEffect(AttachmentType.AURA))); + } + + public ConvulsingLicid(final ConvulsingLicid card) { + super(card); + } + + @Override + public ConvulsingLicid copy() { + return new ConvulsingLicid(this); + } +} diff --git a/Mage.Sets/src/mage/sets/stronghold/CorruptingLicid.java b/Mage.Sets/src/mage/sets/stronghold/CorruptingLicid.java new file mode 100644 index 00000000000..081b7a3a61f --- /dev/null +++ b/Mage.Sets/src/mage/sets/stronghold/CorruptingLicid.java @@ -0,0 +1,72 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.sets.stronghold; + +import java.util.UUID; +import mage.MageInt; +import mage.abilities.common.LicidAbility; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.costs.mana.ColoredManaCost; +import mage.abilities.effects.common.continuous.GainAbilityAttachedEffect; +import mage.abilities.keyword.FearAbility; +import mage.cards.CardImpl; +import mage.constants.AttachmentType; +import mage.constants.CardType; +import mage.constants.ColoredManaSymbol; +import mage.constants.Rarity; +import mage.constants.Zone; + +/** + * + * @author emerald000 + */ +public class CorruptingLicid extends CardImpl { + + public CorruptingLicid(UUID ownerId) { + super(ownerId, 4, "Corrupting Licid", Rarity.UNCOMMON, new CardType[]{CardType.CREATURE}, "{2}{B}"); + this.expansionSetCode = "STH"; + this.subtype.add("Licid"); + this.power = new MageInt(2); + this.toughness = new MageInt(2); + + // {B}, {tap}: Corrupting Licid loses this ability and becomes an Aura enchantment with enchant creature. Attach it to target creature. You may pay {B} to end this effect. + this.addAbility(new LicidAbility(new ColoredManaCost(ColoredManaSymbol.B), new ColoredManaCost(ColoredManaSymbol.B))); + + // Enchanted creature has fear. + this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new GainAbilityAttachedEffect(FearAbility.getInstance(), AttachmentType.AURA))); + } + + public CorruptingLicid(final CorruptingLicid card) { + super(card); + } + + @Override + public CorruptingLicid copy() { + return new CorruptingLicid(this); + } +} diff --git a/Mage.Sets/src/mage/sets/stronghold/GlidingLicid.java b/Mage.Sets/src/mage/sets/stronghold/GlidingLicid.java new file mode 100644 index 00000000000..6f9a8feffb3 --- /dev/null +++ b/Mage.Sets/src/mage/sets/stronghold/GlidingLicid.java @@ -0,0 +1,72 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.sets.stronghold; + +import java.util.UUID; +import mage.MageInt; +import mage.abilities.common.LicidAbility; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.costs.mana.ColoredManaCost; +import mage.abilities.effects.common.continuous.GainAbilityAttachedEffect; +import mage.abilities.keyword.FlyingAbility; +import mage.cards.CardImpl; +import mage.constants.AttachmentType; +import mage.constants.CardType; +import mage.constants.ColoredManaSymbol; +import mage.constants.Rarity; +import mage.constants.Zone; + +/** + * + * @author emerald000 + */ +public class GlidingLicid extends CardImpl { + + public GlidingLicid(UUID ownerId) { + super(ownerId, 31, "Gliding Licid", Rarity.UNCOMMON, new CardType[]{CardType.CREATURE}, "{2}{U}"); + this.expansionSetCode = "STH"; + this.subtype.add("Licid"); + this.power = new MageInt(2); + this.toughness = new MageInt(2); + + // {U}, {tap}: Gliding Licid loses this ability and becomes an Aura enchantment with enchant creature. Attach it to target creature. You may pay {U} to end this effect. + this.addAbility(new LicidAbility(new ColoredManaCost(ColoredManaSymbol.U), new ColoredManaCost(ColoredManaSymbol.U))); + + // Enchanted creature has flying. + this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new GainAbilityAttachedEffect(FlyingAbility.getInstance(), AttachmentType.AURA))); + } + + public GlidingLicid(final GlidingLicid card) { + super(card); + } + + @Override + public GlidingLicid copy() { + return new GlidingLicid(this); + } +} diff --git a/Mage.Sets/src/mage/sets/stronghold/TemptingLicid.java b/Mage.Sets/src/mage/sets/stronghold/TemptingLicid.java new file mode 100644 index 00000000000..7666b868b92 --- /dev/null +++ b/Mage.Sets/src/mage/sets/stronghold/TemptingLicid.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.stronghold; + +import java.util.UUID; +import mage.MageInt; +import mage.abilities.common.LicidAbility; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.costs.mana.ColoredManaCost; +import mage.abilities.effects.common.combat.MustBeBlockedByAllAttachedEffect; +import mage.cards.CardImpl; +import mage.constants.AttachmentType; +import mage.constants.CardType; +import mage.constants.ColoredManaSymbol; +import mage.constants.Rarity; +import mage.constants.Zone; + +/** + * + * @author emerald000 + */ +public class TemptingLicid extends CardImpl { + + public TemptingLicid(UUID ownerId) { + super(ownerId, 72, "Tempting Licid", Rarity.UNCOMMON, new CardType[]{CardType.CREATURE}, "{2}{G}"); + this.expansionSetCode = "STH"; + this.subtype.add("Licid"); + this.power = new MageInt(2); + this.toughness = new MageInt(2); + + // {G}, {tap}: Tempting Licid loses this ability and becomes an Aura enchantment with enchant creature. Attach it to target creature. You may pay {G} to end this effect. + this.addAbility(new LicidAbility(new ColoredManaCost(ColoredManaSymbol.G), new ColoredManaCost(ColoredManaSymbol.G))); + + // All creatures able to block enchanted creature do so. + this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new MustBeBlockedByAllAttachedEffect(AttachmentType.AURA))); + } + + public TemptingLicid(final TemptingLicid card) { + super(card); + } + + @Override + public TemptingLicid copy() { + return new TemptingLicid(this); + } +} diff --git a/Mage.Sets/src/mage/sets/tempest/LeechingLicid.java b/Mage.Sets/src/mage/sets/tempest/LeechingLicid.java new file mode 100644 index 00000000000..cdd9dc5ce26 --- /dev/null +++ b/Mage.Sets/src/mage/sets/tempest/LeechingLicid.java @@ -0,0 +1,74 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.sets.tempest; + +import java.util.UUID; +import mage.MageInt; +import mage.abilities.common.BeginningOfUpkeepTriggeredAbility; +import mage.abilities.common.LicidAbility; +import mage.abilities.costs.mana.ColoredManaCost; +import mage.abilities.effects.Effect; +import mage.abilities.effects.common.DamageTargetEffect; +import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.ColoredManaSymbol; +import mage.constants.Rarity; +import mage.constants.TargetController; +import mage.constants.Zone; + +/** + * + * @author emerald000 + */ +public class LeechingLicid extends CardImpl { + + public LeechingLicid(UUID ownerId) { + super(ownerId, 35, "Leeching Licid", Rarity.UNCOMMON, new CardType[]{CardType.CREATURE}, "{1}{B}"); + this.expansionSetCode = "TMP"; + this.subtype.add("Licid"); + this.power = new MageInt(1); + this.toughness = new MageInt(1); + + // {B}, {tap}: Leeching Licid loses this ability and becomes an Aura enchantment with enchant creature. Attach it to target creature. You may pay {B} to end this effect. + this.addAbility(new LicidAbility(new ColoredManaCost(ColoredManaSymbol.B), new ColoredManaCost(ColoredManaSymbol.B))); + + // At the beginning of the upkeep of enchanted creature's controller, Leeching Licid deals 1 damage to that player. + Effect effect = new DamageTargetEffect(1); + effect.setText("{this} deals 1 damage to that player"); + this.addAbility(new BeginningOfUpkeepTriggeredAbility(Zone.BATTLEFIELD, effect, TargetController.CONTROLLER_ATTACHED_TO, false, true)); + } + + public LeechingLicid(final LeechingLicid card) { + super(card); + } + + @Override + public LeechingLicid copy() { + return new LeechingLicid(this); + } +} diff --git a/Mage.Sets/src/mage/sets/tempest/NurturingLicid.java b/Mage.Sets/src/mage/sets/tempest/NurturingLicid.java new file mode 100644 index 00000000000..e2dafd29a94 --- /dev/null +++ b/Mage.Sets/src/mage/sets/tempest/NurturingLicid.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.tempest; + +import java.util.UUID; +import mage.MageInt; +import mage.abilities.common.LicidAbility; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.costs.mana.ColoredManaCost; +import mage.abilities.effects.common.RegenerateAttachedEffect; +import mage.cards.CardImpl; +import mage.constants.AttachmentType; +import mage.constants.CardType; +import mage.constants.ColoredManaSymbol; +import mage.constants.Rarity; +import mage.constants.Zone; + +/** + * + * @author emerald000 + */ +public class NurturingLicid extends CardImpl { + + public NurturingLicid(UUID ownerId) { + super(ownerId, 136, "Nurturing Licid", Rarity.UNCOMMON, new CardType[]{CardType.CREATURE}, "{1}{G}"); + this.expansionSetCode = "TMP"; + this.subtype.add("Licid"); + this.power = new MageInt(1); + this.toughness = new MageInt(1); + + // {G}, {tap}: Nurturing Licid loses this ability and becomes an Aura enchantment with enchant creature. Attach it to target creature. You may pay {G} to end this effect. + this.addAbility(new LicidAbility(new ColoredManaCost(ColoredManaSymbol.G), new ColoredManaCost(ColoredManaSymbol.G))); + + // {G}: Regenerate enchanted creature. + this.addAbility(new SimpleActivatedAbility(Zone.BATTLEFIELD, new RegenerateAttachedEffect(AttachmentType.AURA), new ColoredManaCost(ColoredManaSymbol.G))); + } + + public NurturingLicid(final NurturingLicid card) { + super(card); + } + + @Override + public NurturingLicid copy() { + return new NurturingLicid(this); + } +} diff --git a/Mage.Sets/src/mage/sets/tempest/QuickeningLicid.java b/Mage.Sets/src/mage/sets/tempest/QuickeningLicid.java new file mode 100644 index 00000000000..1fa9cc30c09 --- /dev/null +++ b/Mage.Sets/src/mage/sets/tempest/QuickeningLicid.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.tempest; + +import java.util.UUID; +import mage.MageInt; +import mage.abilities.common.LicidAbility; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.costs.mana.ColoredManaCost; +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.effects.common.continuous.GainAbilityAttachedEffect; +import mage.abilities.keyword.FirstStrikeAbility; +import mage.cards.CardImpl; +import mage.constants.AttachmentType; +import mage.constants.CardType; +import mage.constants.ColoredManaSymbol; +import mage.constants.Rarity; +import mage.constants.Zone; + +/** + * + * @author emerald000 + */ +public class QuickeningLicid extends CardImpl { + + public QuickeningLicid(UUID ownerId) { + super(ownerId, 248, "Quickening Licid", Rarity.UNCOMMON, new CardType[]{CardType.CREATURE}, "{1}{W}"); + this.expansionSetCode = "TMP"; + this.subtype.add("Licid"); + this.power = new MageInt(1); + this.toughness = new MageInt(1); + + // {1}{W}, {tap}: Quickening Licid loses this ability and becomes an Aura enchantment with enchant creature. Attach it to target creature. You may pay {W} to end this effect. + this.addAbility(new LicidAbility(new ManaCostsImpl<>("{1}{W}"), new ColoredManaCost(ColoredManaSymbol.W))); + + // Enchanted creature has first strike. + this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new GainAbilityAttachedEffect(FirstStrikeAbility.getInstance(), AttachmentType.AURA))); + } + + public QuickeningLicid(final QuickeningLicid card) { + super(card); + } + + @Override + public QuickeningLicid copy() { + return new QuickeningLicid(this); + } +} diff --git a/Mage.Sets/src/mage/sets/tempest/StingingLicid.java b/Mage.Sets/src/mage/sets/tempest/StingingLicid.java new file mode 100644 index 00000000000..7703fd35bb4 --- /dev/null +++ b/Mage.Sets/src/mage/sets/tempest/StingingLicid.java @@ -0,0 +1,70 @@ +/* + * 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.BecomesTappedAttachedTriggeredAbility; +import mage.abilities.common.LicidAbility; +import mage.abilities.costs.mana.ColoredManaCost; +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.effects.common.DamageAttachedControllerEffect; +import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.ColoredManaSymbol; +import mage.constants.Rarity; + +/** + * + * @author emerald000 + */ +public class StingingLicid extends CardImpl { + + public StingingLicid(UUID ownerId) { + super(ownerId, 91, "Stinging Licid", Rarity.UNCOMMON, new CardType[]{CardType.CREATURE}, "{1}{U}"); + this.expansionSetCode = "TMP"; + this.subtype.add("Licid"); + this.power = new MageInt(1); + this.toughness = new MageInt(1); + + // {1}{U}, {tap}: Stinging Licid loses this ability and becomes an Aura enchantment with enchant creature. Attach it to target creature. You may pay {U} to end this effect. + this.addAbility(new LicidAbility(new ManaCostsImpl<>("{1}{U}"), new ColoredManaCost(ColoredManaSymbol.U))); + + // Whenever enchanted creature becomes tapped, Stinging Licid deals 2 damage to that creature's controller. + this.addAbility(new BecomesTappedAttachedTriggeredAbility(new DamageAttachedControllerEffect(2), "enchanted creature")); + } + + public StingingLicid(final StingingLicid card) { + super(card); + } + + @Override + public StingingLicid copy() { + return new StingingLicid(this); + } +} diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/abilities/activated/LicidAbilityTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/abilities/activated/LicidAbilityTest.java new file mode 100644 index 00000000000..27907d2fed5 --- /dev/null +++ b/Mage.Tests/src/test/java/org/mage/test/cards/abilities/activated/LicidAbilityTest.java @@ -0,0 +1,118 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package org.mage.test.cards.abilities.activated; + +import mage.abilities.common.LicidAbility; +import mage.abilities.costs.mana.ColoredManaCost; +import mage.abilities.keyword.HasteAbility; +import mage.constants.CardType; +import mage.constants.ColoredManaSymbol; +import mage.constants.PhaseStep; +import mage.constants.Zone; +import org.junit.Ignore; +import org.junit.Test; +import org.mage.test.serverside.base.CardTestPlayerBase; + +/** + * + * @author emerald0000 + */ + +public class LicidAbilityTest extends CardTestPlayerBase { + + /** + * Activate on another creature + */ + @Test + public void BasicUsageTest() { + addCard(Zone.BATTLEFIELD, playerA, "Pillarfield Ox"); + // {R}, {T}: Enraging Licid loses this ability and becomes an Aura enchantment with enchant creature. Attach it to target creature. You may pay {R} to end this effect. + // Enchanted creature has haste. + addCard(Zone.BATTLEFIELD, playerA, "Enraging Licid"); + addCard(Zone.BATTLEFIELD, playerA, "Mountain"); + + activateAbility(1, PhaseStep.UPKEEP, playerA, "{R},", "Pillarfield Ox"); + setStopAt(1, PhaseStep.PRECOMBAT_MAIN); + + execute(); + + assertAbility(playerA, "Pillarfield Ox", HasteAbility.getInstance(), true); + assertAbility(playerA, "Enraging Licid", new LicidAbility(new ColoredManaCost(ColoredManaSymbol.R), new ColoredManaCost(ColoredManaSymbol.R)), false); + assertType("Enraging Licid", CardType.ENCHANTMENT, true); + assertType("Enraging Licid", CardType.CREATURE, false); + } + + /** + * Use special action to remove the continuous effect + */ + @Test + @Ignore("Test player can't activate special actions yet") + public void SpecialActionTest() { + addCard(Zone.BATTLEFIELD, playerA, "Pillarfield Ox"); + // {R}, {T}: Enraging Licid loses this ability and becomes an Aura enchantment with enchant creature. Attach it to target creature. You may pay {R} to end this effect. + // Enchanted creature has haste. + addCard(Zone.BATTLEFIELD, playerA, "Enraging Licid"); + addCard(Zone.BATTLEFIELD, playerA, "Mountain", 2); + + activateAbility(1, PhaseStep.UPKEEP, playerA, "{R},", "Pillarfield Ox"); + activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "{R}: End"); + setStopAt(1, PhaseStep.BEGIN_COMBAT); + + execute(); + + assertActionCount(playerA, 0); + assertAbility(playerA, "Pillarfield Ox", HasteAbility.getInstance(), false); + assertAbility(playerA, "Enraging Licid", new LicidAbility(new ColoredManaCost(ColoredManaSymbol.R), new ColoredManaCost(ColoredManaSymbol.R)), true); + assertType("Enraging Licid", CardType.ENCHANTMENT, false); + assertType("Enraging Licid", CardType.CREATURE, true); + } + + /** + * Licid should die if enchanted creature dies + */ + @Test + @Ignore("Enraging Licid doesn't die when its enchanted creature dies due to similarity to Bestow") + public void EnchantedCreatureDiesTest() { + addCard(Zone.BATTLEFIELD, playerA, "Pillarfield Ox"); + // {R}, {T}: Enraging Licid loses this ability and becomes an Aura enchantment with enchant creature. Attach it to target creature. You may pay {R} to end this effect. + // Enchanted creature has haste. + addCard(Zone.BATTLEFIELD, playerA, "Enraging Licid"); + // Destroy target nonblack creature. + addCard(Zone.HAND, playerB, "Doom Blade"); + addCard(Zone.BATTLEFIELD, playerA, "Mountain", 1); + addCard(Zone.BATTLEFIELD, playerB, "Swamp", 2); + + activateAbility(1, PhaseStep.UPKEEP, playerA, "{R},", "Pillarfield Ox"); + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerB, "Doom Blade", "Pillarfield Ox"); + setStopAt(1, PhaseStep.BEGIN_COMBAT); + + execute(); + + assertGraveyardCount(playerA, 2); // Pillarfield Ox + Enraging Licid + } +} From a1fb65858c88e1ad097f78fa76373a6df1350e65 Mon Sep 17 00:00:00 2001 From: LevelX2 Date: Sat, 3 Oct 2015 08:56:56 +0200 Subject: [PATCH 002/268] * Fixed some minor bugs of the split cards Supply // Demand and Pure // Simple. --- .../src/mage/sets/dissension/PureSimple.java | 28 ++++++++----------- .../mage/sets/dissension/SupplyDemand.java | 13 ++++----- 2 files changed, 18 insertions(+), 23 deletions(-) diff --git a/Mage.Sets/src/mage/sets/dissension/PureSimple.java b/Mage.Sets/src/mage/sets/dissension/PureSimple.java index 9a2b77b35f2..ec456b064da 100644 --- a/Mage.Sets/src/mage/sets/dissension/PureSimple.java +++ b/Mage.Sets/src/mage/sets/dissension/PureSimple.java @@ -25,18 +25,18 @@ * authors and should not be interpreted as representing official policies, either expressed * or implied, of BetaSteward_at_googlemail.com. */ - package mage.sets.dissension; import java.util.UUID; import mage.abilities.effects.common.DestroyAllEffect; import mage.abilities.effects.common.DestroyTargetEffect; +import mage.cards.SplitCard; import mage.constants.CardType; import mage.constants.Rarity; -import mage.cards.SplitCard; import mage.filter.FilterPermanent; -import mage.filter.predicate.mageobject.SubtypePredicate; +import mage.filter.predicate.Predicates; import mage.filter.predicate.mageobject.MulticoloredPredicate; +import mage.filter.predicate.mageobject.SubtypePredicate; import mage.target.TargetPermanent; /** @@ -45,30 +45,26 @@ import mage.target.TargetPermanent; */ public class PureSimple extends SplitCard { - private static final FilterPermanent filterAura = new FilterPermanent("aura"); - private static final FilterPermanent filterEquipment = new FilterPermanent("equipment"); + private static final FilterPermanent filterDestroy = new FilterPermanent("Auras and Equipment"); private static final FilterPermanent filterMulticolor = new FilterPermanent("multicolor permanent"); - + static { - filterAura.add(new SubtypePredicate("Aura")); - filterEquipment.add(new SubtypePredicate("Equipment")); + filterDestroy.add(Predicates.or(new SubtypePredicate("Aura"), new SubtypePredicate("Equipment"))); filterMulticolor.add(new MulticoloredPredicate()); } - + public PureSimple(UUID ownerId) { super(ownerId, 154, "Pure", "Simple", Rarity.UNCOMMON, new CardType[]{CardType.SORCERY}, "{1}{R}{G}", "{1}{G}{W}", true); this.expansionSetCode = "DIS"; // Pure - // Destroy all Auras - getLeftHalfCard().getSpellAbility().addEffect(new DestroyAllEffect(filterAura)); - // and Equipment. - getLeftHalfCard().getSpellAbility().addEffect(new DestroyAllEffect(filterEquipment)); + // Destroy target multicolored permanent. + getLeftHalfCard().getSpellAbility().addEffect(new DestroyTargetEffect()); + getLeftHalfCard().getSpellAbility().addTarget(new TargetPermanent(filterMulticolor)); // Simple - // Destroy target multicolored permanent. - getRightHalfCard().getSpellAbility().addEffect(new DestroyTargetEffect()); - getRightHalfCard().getSpellAbility().addTarget(new TargetPermanent(filterMulticolor)); + // Destroy all Auras and Equipment. + getRightHalfCard().getSpellAbility().addEffect(new DestroyAllEffect(filterDestroy)); } public PureSimple(final PureSimple card) { diff --git a/Mage.Sets/src/mage/sets/dissension/SupplyDemand.java b/Mage.Sets/src/mage/sets/dissension/SupplyDemand.java index 8eae6bf7da0..9f57c434cba 100644 --- a/Mage.Sets/src/mage/sets/dissension/SupplyDemand.java +++ b/Mage.Sets/src/mage/sets/dissension/SupplyDemand.java @@ -39,7 +39,6 @@ import mage.filter.predicate.mageobject.MulticoloredPredicate; import mage.game.permanent.token.SaprolingToken; import mage.target.common.TargetCardInLibrary; - /** * * @author LevelX2 @@ -53,16 +52,16 @@ public class SupplyDemand extends SplitCard { } public SupplyDemand(UUID ownerId) { - super(ownerId, 157, "Supply", "Demand", Rarity.UNCOMMON, new CardType[]{CardType.SORCERY}, "{1}{W}{U}", "{X}{G}{W}", false); + super(ownerId, 157, "Supply", "Demand", Rarity.UNCOMMON, new CardType[]{CardType.SORCERY}, "{X}{G}{W}", "{1}{W}{U}", false); this.expansionSetCode = "DIS"; - // Demand - // Search your library for a multicolored card, reveal it, and put it into your hand. Then shuffle your library. - getLeftHalfCard().getSpellAbility().addEffect(new SearchLibraryPutInHandEffect(new TargetCardInLibrary(1, filter), true)); - // Supply // Put X 1/1 green Saproling creature tokens onto the battlefield. - getRightHalfCard().getSpellAbility().addEffect(new CreateTokenEffect(new SaprolingToken(), new ManacostVariableValue())); + getLeftHalfCard().getSpellAbility().addEffect(new CreateTokenEffect(new SaprolingToken(), new ManacostVariableValue())); + + // Demand + // Search your library for a multicolored card, reveal it, and put it into your hand. Then shuffle your library. + getRightHalfCard().getSpellAbility().addEffect(new SearchLibraryPutInHandEffect(new TargetCardInLibrary(1, filter), true)); } From 8e50c18d8c53486e29b51b5a99ab06ae2139fa64 Mon Sep 17 00:00:00 2001 From: LevelX2 Date: Sat, 3 Oct 2015 08:57:32 +0200 Subject: [PATCH 003/268] * Added Hit//Run, Trial//Error and Bound//Determined. --- .../mage/sets/dissension/BoundDetermined.java | 179 ++++++++++++++++++ .../src/mage/sets/dissension/HitRun.java | 156 +++++++++++++++ .../src/mage/sets/dissension/TrialError.java | 133 +++++++++++++ .../effects/common/ExileSourceEffect.java | 26 +-- .../effects/common/ExileSpellEffect.java | 57 +++--- 5 files changed, 509 insertions(+), 42 deletions(-) create mode 100644 Mage.Sets/src/mage/sets/dissension/BoundDetermined.java create mode 100644 Mage.Sets/src/mage/sets/dissension/HitRun.java create mode 100644 Mage.Sets/src/mage/sets/dissension/TrialError.java diff --git a/Mage.Sets/src/mage/sets/dissension/BoundDetermined.java b/Mage.Sets/src/mage/sets/dissension/BoundDetermined.java new file mode 100644 index 00000000000..5fb91193ccc --- /dev/null +++ b/Mage.Sets/src/mage/sets/dissension/BoundDetermined.java @@ -0,0 +1,179 @@ +/* + * 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.dissension; + +import java.util.UUID; +import mage.MageObject; +import mage.abilities.Ability; +import mage.abilities.effects.ContinuousRuleModifyingEffectImpl; +import mage.abilities.effects.Effect; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.DrawCardSourceControllerEffect; +import mage.abilities.effects.common.ExileSourceEffect; +import mage.cards.CardsImpl; +import mage.cards.SplitCard; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.Outcome; +import mage.constants.Rarity; +import mage.constants.Zone; +import mage.filter.FilterCard; +import mage.filter.FilterSpell; +import mage.filter.common.FilterControlledCreaturePermanent; +import mage.filter.predicate.mageobject.MulticoloredPredicate; +import mage.game.Game; +import mage.game.events.GameEvent; +import mage.game.permanent.Permanent; +import mage.game.stack.Spell; +import mage.players.Player; +import mage.target.common.TargetCardInYourGraveyard; +import mage.target.common.TargetControlledPermanent; + +/** + * + * @author LevelX2 + */ +public class BoundDetermined extends SplitCard { + + private static final FilterSpell filter = new FilterSpell("multicolored spell"); + + static { + filter.add(new MulticoloredPredicate()); + } + + public BoundDetermined(UUID ownerId) { + super(ownerId, 149, "Bound", "Determined", Rarity.RARE, new CardType[]{CardType.INSTANT}, "{3}{B}{G}", "{G}{U}", false); + this.expansionSetCode = "DIS"; + + // Bound + // Sacrifice a creature. Return up to X cards from your graveyard to your hand, where X is the number of colors that creature was. Exile this card. + getLeftHalfCard().getSpellAbility().addEffect(new BoundEffect()); + Effect effect = new ExileSourceEffect(); + effect.setText("Exile this card"); + getLeftHalfCard().getSpellAbility().addEffect(effect); + // Determined + // Other spells you control can't be countered by spells or abilities this turn. + // Draw a card. + getRightHalfCard().getSpellAbility().addEffect(new DeterminedEffect()); + getRightHalfCard().getSpellAbility().addEffect(new DrawCardSourceControllerEffect(1)); + + } + + public BoundDetermined(final BoundDetermined card) { + super(card); + } + + @Override + public BoundDetermined copy() { + return new BoundDetermined(this); + } +} + +class BoundEffect extends OneShotEffect { + + public BoundEffect() { + super(Outcome.ReturnToHand); + this.staticText = "Sacrifice a creature. Return up to X cards from your graveyard to your hand, where X is the number of colors that creature was"; + } + + public BoundEffect(final BoundEffect effect) { + super(effect); + } + + @Override + public BoundEffect copy() { + return new BoundEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player controller = game.getPlayer(source.getControllerId()); + if (controller != null) { + TargetControlledPermanent target = new TargetControlledPermanent(1, 1, new FilterControlledCreaturePermanent("a creature (to sacrifice)"), true); + if (target.canChoose(source.getSourceId(), controller.getId(), game)) { + if (controller.chooseTarget(outcome, target, source, game)) { + Permanent toSacrifice = game.getPermanent(target.getFirstTarget()); + if (toSacrifice != null) { + toSacrifice.sacrifice(source.getSourceId(), game); + int colors = toSacrifice.getColor(game).getColorCount(); + if (colors > 0) { + TargetCardInYourGraveyard targetCard = new TargetCardInYourGraveyard(0, colors, + new FilterCard("up to " + colors + " card" + (colors > 1 ? "s" : "") + " from your graveyard")); + controller.chooseTarget(outcome, targetCard, source, game); + controller.moveCards(new CardsImpl(targetCard.getTargets()), null, Zone.HAND, source, game); + } + } + } + } + return true; + } + return false; + } +} + +class DeterminedEffect extends ContinuousRuleModifyingEffectImpl { + + DeterminedEffect() { + super(Duration.EndOfTurn, Outcome.Benefit); + staticText = "Other spells you control can't be countered by spells or abilities this turn"; + } + + DeterminedEffect(final DeterminedEffect effect) { + super(effect); + } + + @Override + public DeterminedEffect copy() { + return new DeterminedEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + return true; + } + + @Override + public String getInfoMessage(Ability source, GameEvent event, Game game) { + MageObject sourceObject = game.getObject(source.getSourceId()); + if (sourceObject != null) { + return "This spell can't be countered (" + sourceObject.getIdName() + ")."; + } + return null; + } + + @Override + public boolean checksEventType(GameEvent event, Game game) { + return event.getType() == GameEvent.EventType.COUNTER; + } + + @Override + public boolean applies(GameEvent event, Ability source, Game game) { + Spell spell = game.getStack().getSpell(event.getTargetId()); + return spell != null && !spell.getSourceId().equals(source.getSourceId()) && spell.getControllerId().equals(source.getControllerId()); + } +} diff --git a/Mage.Sets/src/mage/sets/dissension/HitRun.java b/Mage.Sets/src/mage/sets/dissension/HitRun.java new file mode 100644 index 00000000000..a7452d77914 --- /dev/null +++ b/Mage.Sets/src/mage/sets/dissension/HitRun.java @@ -0,0 +1,156 @@ +/* + * 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.dissension; + +import java.util.UUID; +import mage.abilities.Ability; +import mage.abilities.effects.ContinuousEffect; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.continuous.BoostTargetEffect; +import mage.cards.SplitCard; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.Outcome; +import mage.constants.Rarity; +import mage.filter.common.FilterAttackingCreature; +import mage.filter.common.FilterControlledPermanent; +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.TargetPlayer; +import mage.target.common.TargetControlledPermanent; +import mage.target.targetpointer.FixedTarget; + +/** + * + * @author LevelX2 + */ +public class HitRun extends SplitCard { + + public HitRun(UUID ownerId) { + super(ownerId, 152, "Hit", "Run", Rarity.UNCOMMON, new CardType[]{CardType.INSTANT}, "{1}{B}{R}", "{3}{R}{G}", false); + this.expansionSetCode = "DIS"; + + // Hit + // Target player sacrifices an artifact or creature. Hit deals damage to that player equal to that permanent's converted mana cost. + getLeftHalfCard().getSpellAbility().addEffect(new HitEffect()); + getLeftHalfCard().getSpellAbility().addTarget(new TargetPlayer()); + + // Run + // Attacking creatures you control get +1/+0 until end of turn for each other attacking creature. + getRightHalfCard().getSpellAbility().addEffect(new RunEffect()); + + } + + public HitRun(final HitRun card) { + super(card); + } + + @Override + public HitRun copy() { + return new HitRun(this); + } +} + +class HitEffect extends OneShotEffect { + + public HitEffect() { + super(Outcome.DestroyPermanent); + this.staticText = "Target player sacrifices an artifact or creature. Hit deals damage to that player equal to that permanent's converted mana cost"; + } + + public HitEffect(final HitEffect effect) { + super(effect); + } + + @Override + public HitEffect copy() { + return new HitEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player targetPlayer = game.getPlayer(source.getTargets().getFirstTarget()); + if (targetPlayer != null) { + FilterControlledPermanent filter = new FilterControlledPermanent("artifact or creature"); + filter.add(Predicates.or( + new CardTypePredicate(CardType.ARTIFACT), + new CardTypePredicate(CardType.CREATURE))); + TargetControlledPermanent target = new TargetControlledPermanent(1, 1, filter, true); + + if (target.canChoose(targetPlayer.getId(), game)) { + targetPlayer.choose(Outcome.Sacrifice, target, source.getSourceId(), game); + Permanent permanent = game.getPermanent(target.getFirstTarget()); + if (permanent != null) { + permanent.sacrifice(source.getSourceId(), game); + int damage = permanent.getManaCost().convertedManaCost(); + if (damage > 0) { + targetPlayer.damage(damage, source.getSourceId(), game, false, true); + } + } + } + } + return true; + } +} + +class RunEffect extends OneShotEffect { + + public RunEffect() { + super(Outcome.BoostCreature); + this.staticText = "Attacking creatures you control get +1/+0 until end of turn for each other attacking creature"; + } + + public RunEffect(final RunEffect effect) { + super(effect); + } + + @Override + public RunEffect copy() { + return new RunEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player controller = game.getPlayer(source.getControllerId()); + if (controller != null) { + int attackingCreatures = game.getBattlefield().count(new FilterAttackingCreature(), controller.getId(), controller.getId(), game); + if (attackingCreatures > 1) { + for (Permanent permanent : game.getBattlefield().getAllActivePermanents(new FilterAttackingCreature(), controller.getId(), game)) { + ContinuousEffect effect = new BoostTargetEffect(attackingCreatures - 1, 0, Duration.EndOfTurn); + effect.setTargetPointer(new FixedTarget(permanent, game)); + game.addEffect(effect, source); + } + } + return true; + } + return false; + } +} diff --git a/Mage.Sets/src/mage/sets/dissension/TrialError.java b/Mage.Sets/src/mage/sets/dissension/TrialError.java new file mode 100644 index 00000000000..46877c7937c --- /dev/null +++ b/Mage.Sets/src/mage/sets/dissension/TrialError.java @@ -0,0 +1,133 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.sets.dissension; + +import java.util.HashSet; +import java.util.Set; +import java.util.UUID; +import mage.abilities.Ability; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.CounterTargetEffect; +import mage.cards.Card; +import mage.cards.SplitCard; +import mage.constants.CardType; +import mage.constants.Outcome; +import mage.constants.Rarity; +import mage.constants.Zone; +import mage.filter.FilterSpell; +import mage.filter.predicate.mageobject.MulticoloredPredicate; +import mage.game.Game; +import mage.game.combat.CombatGroup; +import mage.game.permanent.Permanent; +import mage.players.Player; +import mage.target.TargetSpell; +import mage.target.common.TargetCreaturePermanent; + +/** + * + * @author LevelX2 + */ +public class TrialError extends SplitCard { + + private static final FilterSpell filter = new FilterSpell("multicolored spell"); + + static { + filter.add(new MulticoloredPredicate()); + } + + public TrialError(UUID ownerId) { + super(ownerId, 158, "Trial", "Error", Rarity.UNCOMMON, new CardType[]{CardType.INSTANT}, "{W}{U}", "{U}{B}", false); + this.expansionSetCode = "DIS"; + + // Trial + // Return all creatures blocking or blocked by target creature to their owner's hand. + getLeftHalfCard().getSpellAbility().addEffect(new TrialEffect()); + getLeftHalfCard().getSpellAbility().addTarget(new TargetCreaturePermanent()); + + // Error + // Counter target multicolored spell. + getRightHalfCard().getSpellAbility().addEffect(new CounterTargetEffect()); + getRightHalfCard().getSpellAbility().addTarget(new TargetSpell(filter)); + + } + + public TrialError(final TrialError card) { + super(card); + } + + @Override + public TrialError copy() { + return new TrialError(this); + } +} + +class TrialEffect extends OneShotEffect { + + public TrialEffect() { + super(Outcome.ReturnToHand); + this.staticText = "Return all creatures blocking or blocked by target creature to their owner's hand"; + } + + public TrialEffect(final TrialEffect effect) { + super(effect); + } + + @Override + public TrialEffect copy() { + return new TrialEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player controller = game.getPlayer(source.getControllerId()); + Permanent creature = game.getPermanent(getTargetPointer().getFirst(game, source)); + if (controller != null && creature != null) { + Set toHand = new HashSet<>(); + for (CombatGroup combatGroup : game.getCombat().getGroups()) { + if (combatGroup.getBlockers().contains(creature.getId())) { + for (UUID attackerId : combatGroup.getAttackers()) { + Permanent attacker = game.getPermanent(attackerId); + if (attacker != null) { + toHand.add(attacker); + } + } + } else if (combatGroup.getAttackers().contains(creature.getId())) { + for (UUID blockerId : combatGroup.getBlockers()) { + Permanent blocker = game.getPermanent(blockerId); + if (blocker != null) { + toHand.add(blocker); + } + } + } + } + controller.moveCards(toHand, null, Zone.HAND, source, game); + return true; + } + return false; + } +} diff --git a/Mage/src/mage/abilities/effects/common/ExileSourceEffect.java b/Mage/src/mage/abilities/effects/common/ExileSourceEffect.java index f60cf67ba16..60efb497e97 100644 --- a/Mage/src/mage/abilities/effects/common/ExileSourceEffect.java +++ b/Mage/src/mage/abilities/effects/common/ExileSourceEffect.java @@ -1,16 +1,16 @@ /* * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. - * + * * Redistribution and use in source and binary forms, with or without modification, are * permitted provided that the following conditions are met: - * + * * 1. Redistributions of source code must retain the above copyright notice, this list of * conditions and the following disclaimer. - * + * * 2. Redistributions in binary form must reproduce the above copyright notice, this list * of conditions and the following disclaimer in the documentation and/or other materials * provided with the distribution. - * + * * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR @@ -20,12 +20,11 @@ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * + * * The views and conclusions contained in the software and documentation are those of the * authors and should not be interpreted as representing official policies, either expressed * or implied, of BetaSteward_at_googlemail.com. */ - package mage.abilities.effects.common; import java.util.UUID; @@ -49,11 +48,12 @@ public class ExileSourceEffect extends OneShotEffect { public ExileSourceEffect() { this(false); } - + /** - * - * @param toUniqueExileZone moves the card to a source object dependant unique exile zone, so another - * effect of the same source object (e.g. Deadeye Navigator) can identify the card + * + * @param toUniqueExileZone moves the card to a source object dependant + * unique exile zone, so another effect of the same source object (e.g. + * Deadeye Navigator) can identify the card */ public ExileSourceEffect(boolean toUniqueExileZone) { super(Outcome.Exile); @@ -72,10 +72,10 @@ public class ExileSourceEffect extends OneShotEffect { } @Override - public boolean apply(Game game, Ability source) { + public boolean apply(Game game, Ability source) { Player controller = game.getPlayer(source.getControllerId()); if (controller != null) { - MageObject sourceObject = source.getSourceObjectIfItStillExists(game); + MageObject sourceObject = source.getSourceObjectIfItStillExists(game); if (sourceObject instanceof Card) { UUID exileZoneId = null; String exileZoneName = ""; @@ -84,7 +84,7 @@ public class ExileSourceEffect extends OneShotEffect { exileZoneName = sourceObject.getName(); } Card sourceCard = (Card) sourceObject; - return controller.moveCardToExileWithInfo(sourceCard, exileZoneId, exileZoneName, source.getSourceId(), game, game.getState().getZone(sourceCard.getId()), true); + return controller.moveCardsToExile(sourceCard, source, game, true, exileZoneId, exileZoneName); } return true; } diff --git a/Mage/src/mage/abilities/effects/common/ExileSpellEffect.java b/Mage/src/mage/abilities/effects/common/ExileSpellEffect.java index df19c8af57e..2725630dc30 100644 --- a/Mage/src/mage/abilities/effects/common/ExileSpellEffect.java +++ b/Mage/src/mage/abilities/effects/common/ExileSpellEffect.java @@ -1,31 +1,30 @@ /* -* Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. -* -* Redistribution and use in source and binary forms, with or without modification, are -* permitted provided that the following conditions are met: -* -* 1. Redistributions of source code must retain the above copyright notice, this list of -* conditions and the following disclaimer. -* -* 2. Redistributions in binary form must reproduce the above copyright notice, this list -* of conditions and the following disclaimer in the documentation and/or other materials -* provided with the distribution. -* -* THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED -* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND -* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR -* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR -* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON -* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING -* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF -* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -* -* The views and conclusions contained in the software and documentation are those of the -* authors and should not be interpreted as representing official policies, either expressed -* or implied, of BetaSteward_at_googlemail.com. -*/ - + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ package mage.abilities.effects.common; import mage.abilities.Ability; @@ -58,14 +57,14 @@ public class ExileSpellEffect extends OneShotEffect implements MageSingleton { public ExileSpellEffect copy() { return fINSTANCE; } - + @Override public boolean apply(Game game, Ability source) { Player controller = game.getPlayer(source.getControllerId()); if (controller != null) { Card spellCard = game.getStack().getSpell(source.getSourceId()).getCard(); if (spellCard != null) { - controller.moveCardToExileWithInfo(spellCard, null, "", source.getSourceId(), game, Zone.STACK, true); + controller.moveCards(spellCard, null, Zone.EXILED, source, game); } return true; } From 7b6860447122bc7111f90339859b3a399eaecb95 Mon Sep 17 00:00:00 2001 From: LevelX2 Date: Sat, 3 Oct 2015 13:33:22 +0200 Subject: [PATCH 004/268] Some changes/fixes to conspire ability. --- .../src/mage/sets/shadowmoor/AEthertow.java | 2 +- .../sets/shadowmoor/BarkshellBlessing.java | 8 +- .../src/mage/sets/shadowmoor/BurnTrail.java | 4 +- .../mage/sets/shadowmoor/DisturbingPlot.java | 2 +- .../sets/shadowmoor/GhastlyDiscovery.java | 2 +- .../mage/sets/shadowmoor/Giantbaiting.java | 2 +- .../mage/sets/shadowmoor/GleefulSabotage.java | 4 +- .../mage/sets/shadowmoor/MemorySluice.java | 6 +- .../mage/sets/shadowmoor/MineExcavation.java | 8 +- .../mage/sets/shadowmoor/TraitorsRoar.java | 2 +- .../abilities/keywords/ConspireTest.java | 95 ++++++--- Mage/src/mage/abilities/AbilityImpl.java | 32 +-- .../abilities/keyword/ConspireAbility.java | 191 +++++++++++------- Mage/src/mage/game/stack/StackObjImpl.java | 4 +- 14 files changed, 234 insertions(+), 128 deletions(-) diff --git a/Mage.Sets/src/mage/sets/shadowmoor/AEthertow.java b/Mage.Sets/src/mage/sets/shadowmoor/AEthertow.java index 2e384acbeb9..14e313f4a57 100644 --- a/Mage.Sets/src/mage/sets/shadowmoor/AEthertow.java +++ b/Mage.Sets/src/mage/sets/shadowmoor/AEthertow.java @@ -58,7 +58,7 @@ public class AEthertow extends CardImpl { this.getSpellAbility().addTarget(new TargetCreaturePermanent(filter)); // Conspire - this.addAbility(new ConspireAbility(this)); + this.addAbility(new ConspireAbility(getId(), ConspireAbility.ConspireTargets.ONE)); } public AEthertow(final AEthertow card) { diff --git a/Mage.Sets/src/mage/sets/shadowmoor/BarkshellBlessing.java b/Mage.Sets/src/mage/sets/shadowmoor/BarkshellBlessing.java index 7916a18bfec..db328a78993 100644 --- a/Mage.Sets/src/mage/sets/shadowmoor/BarkshellBlessing.java +++ b/Mage.Sets/src/mage/sets/shadowmoor/BarkshellBlessing.java @@ -41,7 +41,7 @@ import mage.target.common.TargetCreaturePermanent; * @author jeffwadsworth */ public class BarkshellBlessing extends CardImpl { - + public BarkshellBlessing(UUID ownerId) { super(ownerId, 224, "Barkshell Blessing", Rarity.COMMON, new CardType[]{CardType.INSTANT}, "{G/W}"); this.expansionSetCode = "SHM"; @@ -51,13 +51,13 @@ public class BarkshellBlessing extends CardImpl { this.getSpellAbility().addEffect(new BoostTargetEffect(2, 2, Duration.EndOfTurn)); // Conspire - this.addAbility(new ConspireAbility(this)); + this.addAbility(new ConspireAbility(getId(), ConspireAbility.ConspireTargets.ONE)); } - + public BarkshellBlessing(final BarkshellBlessing card) { super(card); } - + @Override public BarkshellBlessing copy() { return new BarkshellBlessing(this); diff --git a/Mage.Sets/src/mage/sets/shadowmoor/BurnTrail.java b/Mage.Sets/src/mage/sets/shadowmoor/BurnTrail.java index 0e4a193204d..1a0e264ca32 100644 --- a/Mage.Sets/src/mage/sets/shadowmoor/BurnTrail.java +++ b/Mage.Sets/src/mage/sets/shadowmoor/BurnTrail.java @@ -48,9 +48,9 @@ public class BurnTrail extends CardImpl { // Burn Trail deals 3 damage to target creature or player. this.getSpellAbility().addEffect(new DamageTargetEffect(3)); this.getSpellAbility().addTarget(new TargetCreatureOrPlayer()); - + // Conspire - this.addAbility(new ConspireAbility(this)); + this.addAbility(new ConspireAbility(getId(), ConspireAbility.ConspireTargets.ONE)); } public BurnTrail(final BurnTrail card) { diff --git a/Mage.Sets/src/mage/sets/shadowmoor/DisturbingPlot.java b/Mage.Sets/src/mage/sets/shadowmoor/DisturbingPlot.java index 5e22bf9f40f..9d7cf445939 100644 --- a/Mage.Sets/src/mage/sets/shadowmoor/DisturbingPlot.java +++ b/Mage.Sets/src/mage/sets/shadowmoor/DisturbingPlot.java @@ -51,7 +51,7 @@ public class DisturbingPlot extends CardImpl { this.getSpellAbility().addTarget(new TargetCardInGraveyard(new FilterCreatureCard("creature card in a graveyard"))); // Conspire - this.addAbility(new ConspireAbility(this)); + this.addAbility(new ConspireAbility(getId(), ConspireAbility.ConspireTargets.ONE)); } diff --git a/Mage.Sets/src/mage/sets/shadowmoor/GhastlyDiscovery.java b/Mage.Sets/src/mage/sets/shadowmoor/GhastlyDiscovery.java index 2b317197e3b..2ba3dd8d915 100644 --- a/Mage.Sets/src/mage/sets/shadowmoor/GhastlyDiscovery.java +++ b/Mage.Sets/src/mage/sets/shadowmoor/GhastlyDiscovery.java @@ -52,7 +52,7 @@ public class GhastlyDiscovery extends CardImpl { this.getSpellAbility().addEffect(new GhastlyDiscoveryEffect()); // Conspire - this.addAbility(new ConspireAbility(this)); + this.addAbility(new ConspireAbility(getId(), ConspireAbility.ConspireTargets.NONE)); } public GhastlyDiscovery(final GhastlyDiscovery card) { diff --git a/Mage.Sets/src/mage/sets/shadowmoor/Giantbaiting.java b/Mage.Sets/src/mage/sets/shadowmoor/Giantbaiting.java index 43ca95f1ffa..146c80a3a34 100644 --- a/Mage.Sets/src/mage/sets/shadowmoor/Giantbaiting.java +++ b/Mage.Sets/src/mage/sets/shadowmoor/Giantbaiting.java @@ -58,7 +58,7 @@ public class Giantbaiting extends CardImpl { this.getSpellAbility().addEffect(new GiantbaitingEffect()); // Conspire - this.addAbility(new ConspireAbility(this)); + this.addAbility(new ConspireAbility(getId(), ConspireAbility.ConspireTargets.NONE)); } diff --git a/Mage.Sets/src/mage/sets/shadowmoor/GleefulSabotage.java b/Mage.Sets/src/mage/sets/shadowmoor/GleefulSabotage.java index 16869be8383..faf02584055 100644 --- a/Mage.Sets/src/mage/sets/shadowmoor/GleefulSabotage.java +++ b/Mage.Sets/src/mage/sets/shadowmoor/GleefulSabotage.java @@ -49,9 +49,9 @@ public class GleefulSabotage extends CardImpl { // Destroy target artifact or enchantment. this.getSpellAbility().addEffect(new DestroyTargetEffect()); this.getSpellAbility().addTarget(new TargetPermanent(new FilterArtifactOrEnchantmentPermanent())); - + // Conspire - this.addAbility(new ConspireAbility(this)); + this.addAbility(new ConspireAbility(getId(), ConspireAbility.ConspireTargets.ONE)); } public GleefulSabotage(final GleefulSabotage card) { diff --git a/Mage.Sets/src/mage/sets/shadowmoor/MemorySluice.java b/Mage.Sets/src/mage/sets/shadowmoor/MemorySluice.java index 61329fd77ad..80c47736dd1 100644 --- a/Mage.Sets/src/mage/sets/shadowmoor/MemorySluice.java +++ b/Mage.Sets/src/mage/sets/shadowmoor/MemorySluice.java @@ -48,10 +48,10 @@ public class MemorySluice extends CardImpl { // Target player puts the top four cards of his or her library into his or her graveyard. this.getSpellAbility().addEffect(new PutLibraryIntoGraveTargetEffect(4)); this.getSpellAbility().addTarget(new TargetPlayer()); - + // Conspire - this.addAbility(new ConspireAbility(this)); - + this.addAbility(new ConspireAbility(getId(), ConspireAbility.ConspireTargets.ONE)); + } public MemorySluice(final MemorySluice card) { diff --git a/Mage.Sets/src/mage/sets/shadowmoor/MineExcavation.java b/Mage.Sets/src/mage/sets/shadowmoor/MineExcavation.java index b26e24c4b13..4b5484404e1 100644 --- a/Mage.Sets/src/mage/sets/shadowmoor/MineExcavation.java +++ b/Mage.Sets/src/mage/sets/shadowmoor/MineExcavation.java @@ -43,9 +43,9 @@ import mage.target.common.TargetCardInGraveyard; * @author jeffwadsworth */ public class MineExcavation extends CardImpl { - + private static final FilterCard filter = new FilterCard("artifact or enchantment card in a graveyard"); - + static { filter.add(Predicates.or(new CardTypePredicate(CardType.ARTIFACT), new CardTypePredicate(CardType.ENCHANTMENT))); @@ -58,9 +58,9 @@ public class MineExcavation extends CardImpl { // Return target artifact or enchantment card from a graveyard to its owner's hand. this.getSpellAbility().addEffect(new ReturnFromGraveyardToHandTargetEffect()); this.getSpellAbility().addTarget(new TargetCardInGraveyard(filter)); - + // Conspire - this.addAbility(new ConspireAbility(this)); + this.addAbility(new ConspireAbility(getId(), ConspireAbility.ConspireTargets.ONE)); } public MineExcavation(final MineExcavation card) { diff --git a/Mage.Sets/src/mage/sets/shadowmoor/TraitorsRoar.java b/Mage.Sets/src/mage/sets/shadowmoor/TraitorsRoar.java index 90021a3dbbf..df7145b391c 100644 --- a/Mage.Sets/src/mage/sets/shadowmoor/TraitorsRoar.java +++ b/Mage.Sets/src/mage/sets/shadowmoor/TraitorsRoar.java @@ -64,7 +64,7 @@ public class TraitorsRoar extends CardImpl { this.getSpellAbility().addEffect(new TraitorsRoarEffect()); // Conspire - this.addAbility(new ConspireAbility(this)); + this.addAbility(new ConspireAbility(getId(), ConspireAbility.ConspireTargets.ONE)); } diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/abilities/keywords/ConspireTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/abilities/keywords/ConspireTest.java index eda72663473..a9ef3d1e769 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/abilities/keywords/ConspireTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/abilities/keywords/ConspireTest.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.abilities.keywords; import mage.constants.PhaseStep; @@ -40,31 +39,31 @@ import org.mage.test.serverside.base.CardTestPlayerBase; public class ConspireTest extends CardTestPlayerBase { /** - * 702.77. Conspire - * 702.77a Conspire is a keyword that represents two abilities. The first is a static ability that functions - * while the spell with conspire is on the stack. The second is a triggered ability that functions - * while the spell with conspire is on the stack. “Conspire” means “As an additional cost to cast - * this spell, you may tap two untapped creatures you control that each share a color with it” and - * “When you cast this spell, if its conspire cost was paid, copy it. If the spell has any targets, you - * may choose new targets for the copy.” Paying a spell’s conspire cost follows the rules for - * paying additional costs in rules 601.2b and 601.2e–g. - * - * 702.77b If a spell has multiple instances of conspire, each is paid separately and triggers based on - * its own payment, not any other instance of conspire - * - */ - - /** - * Burn Trail - * Sorcery, 3R (4) - * Burn Trail deals 3 damage to target creature or player. - * - * Conspire (As you cast this spell, you may tap two untapped creatures you - * control that share a color with it. When you do, copy it and you may - * choose a new target for the copy.) + * 702.77. Conspire 702.77a Conspire is a keyword that represents two + * abilities. The first is a static ability that functions while the spell + * with conspire is on the stack. The second is a triggered ability that + * functions while the spell with conspire is on the stack. “Conspire” means + * “As an additional cost to cast this spell, you may tap two untapped + * creatures you control that each share a color with it” and “When you cast + * this spell, if its conspire cost was paid, copy it. If the spell has any + * targets, you may choose new targets for the copy.” Paying a spell’s + * conspire cost follows the rules for paying additional costs in rules + * 601.2b and 601.2e–g. + * + * 702.77b If a spell has multiple instances of conspire, each is paid + * separately and triggers based on its own payment, not any other instance + * of conspire + * + */ + /** + * Burn Trail Sorcery, 3R (4) Burn Trail deals 3 damage to target creature + * or player. + * + * Conspire (As you cast this spell, you may tap two untapped creatures you + * control that share a color with it. When you do, copy it and you may + * choose a new target for the copy.) * */ - @Test public void testConspire() { addCard(Zone.BATTLEFIELD, playerA, "Mountain", 4); @@ -72,7 +71,6 @@ public class ConspireTest extends CardTestPlayerBase { addCard(Zone.BATTLEFIELD, playerA, "Raging Goblin"); addCard(Zone.HAND, playerA, "Burn Trail"); - castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Burn Trail", playerB); setChoice(playerA, "Yes"); @@ -93,7 +91,6 @@ public class ConspireTest extends CardTestPlayerBase { addCard(Zone.BATTLEFIELD, playerA, "Raging Goblin"); addCard(Zone.HAND, playerA, "Burn Trail"); - castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Burn Trail", playerB); setChoice(playerA, "No"); @@ -107,4 +104,50 @@ public class ConspireTest extends CardTestPlayerBase { } + @Test + public void testWortTheRaidmother() { + addCard(Zone.BATTLEFIELD, playerA, "Mountain", 7); + // When Wort, the Raidmother enters the battlefield, put two 1/1 red and green Goblin Warrior creature tokens onto the battlefield. + // Each red or green instant or sorcery spell you cast has conspire. + // (As you cast the spell, you may tap two untapped creatures you control that share a color with it. When you do, copy it and you may choose new targets for the copy.) + addCard(Zone.HAND, playerA, "Wort, the Raidmother"); + addCard(Zone.HAND, playerA, "Lightning Bolt"); + + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Wort, the Raidmother");// {4}{R/G}{R/G} + + castSpell(1, PhaseStep.POSTCOMBAT_MAIN, playerA, "Lightning Bolt", playerB); + setChoice(playerA, "Yes"); + + setStopAt(1, PhaseStep.END_TURN); + execute(); + assertPermanentCount(playerA, "Wort, the Raidmother", 1); + assertGraveyardCount(playerA, "Lightning Bolt", 1); + assertLife(playerB, 14); + + } + + @Test + public void testWortTheRaidmotherWithConspireSpell() { + addCard(Zone.BATTLEFIELD, playerA, "Mountain", 10); + addCard(Zone.BATTLEFIELD, playerA, "Raging Goblin", 2); + // When Wort, the Raidmother enters the battlefield, put two 1/1 red and green Goblin Warrior creature tokens onto the battlefield. + // Each red or green instant or sorcery spell you cast has conspire. + // (As you cast the spell, you may tap two untapped creatures you control that share a color with it. When you do, copy it and you may choose new targets for the copy.) + addCard(Zone.HAND, playerA, "Wort, the Raidmother"); + addCard(Zone.HAND, playerA, "Burn Trail"); + + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Wort, the Raidmother"); // {4}{R/G}{R/G} + + castSpell(1, PhaseStep.POSTCOMBAT_MAIN, playerA, "Burn Trail", playerB); + setChoice(playerA, "Yes"); // use Conspire from Burn Trail itself + setChoice(playerA, "Yes"); // use Conspire gained from Wort, the Raidmother + + setStopAt(1, PhaseStep.END_TURN); + execute(); + assertPermanentCount(playerA, "Wort, the Raidmother", 1); + assertLife(playerB, 11); + assertLife(playerA, 20); + assertGraveyardCount(playerA, "Burn Trail", 1); + + } } diff --git a/Mage/src/mage/abilities/AbilityImpl.java b/Mage/src/mage/abilities/AbilityImpl.java index 50746636057..150ddd0747f 100644 --- a/Mage/src/mage/abilities/AbilityImpl.java +++ b/Mage/src/mage/abilities/AbilityImpl.java @@ -445,20 +445,28 @@ public abstract class AbilityImpl implements Ability { public boolean activateAlternateOrAdditionalCosts(MageObject sourceObject, boolean noMana, Player controller, Game game) { boolean alternativeCostisUsed = false; if (sourceObject != null && !(sourceObject instanceof Permanent) && !(this instanceof FlashbackAbility)) { - for (Ability ability : sourceObject.getAbilities()) { - // if cast for noMana no Alternative costs are allowed - if (!noMana && ability instanceof AlternativeSourceCosts) { - AlternativeSourceCosts alternativeSpellCosts = (AlternativeSourceCosts) ability; - if (alternativeSpellCosts.isAvailable(this, game)) { - if (alternativeSpellCosts.askToActivateAlternativeCosts(this, game)) { - // only one alternative costs may be activated - alternativeCostisUsed = true; - break; + Abilities abilities = null; + if (sourceObject instanceof Card) { + abilities = ((Card) sourceObject).getAbilities(game); + } else { + sourceObject.getAbilities(); + } + if (abilities != null) { + for (Ability ability : abilities) { + // if cast for noMana no Alternative costs are allowed + if (!noMana && ability instanceof AlternativeSourceCosts) { + AlternativeSourceCosts alternativeSpellCosts = (AlternativeSourceCosts) ability; + if (alternativeSpellCosts.isAvailable(this, game)) { + if (alternativeSpellCosts.askToActivateAlternativeCosts(this, game)) { + // only one alternative costs may be activated + alternativeCostisUsed = true; + break; + } } } - } - if (ability instanceof OptionalAdditionalSourceCosts) { - ((OptionalAdditionalSourceCosts) ability).addOptionalAdditionalCosts(this, game); + if (ability instanceof OptionalAdditionalSourceCosts) { + ((OptionalAdditionalSourceCosts) ability).addOptionalAdditionalCosts(this, game); + } } } // controller specific alternate spell costs diff --git a/Mage/src/mage/abilities/keyword/ConspireAbility.java b/Mage/src/mage/abilities/keyword/ConspireAbility.java index fe470c425fd..7d48fe50e04 100644 --- a/Mage/src/mage/abilities/keyword/ConspireAbility.java +++ b/Mage/src/mage/abilities/keyword/ConspireAbility.java @@ -27,14 +27,16 @@ */ package mage.abilities.keyword; +import java.util.HashSet; import java.util.Iterator; +import java.util.Set; +import java.util.UUID; import mage.abilities.Ability; import mage.abilities.SpellAbility; import mage.abilities.StaticAbility; import mage.abilities.TriggeredAbilityImpl; import mage.abilities.costs.Cost; import mage.abilities.costs.Costs; -import mage.abilities.costs.OptionalAdditionalCost; import mage.abilities.costs.OptionalAdditionalCostImpl; import mage.abilities.costs.OptionalAdditionalSourceCosts; import mage.abilities.costs.common.TapTargetCost; @@ -50,48 +52,77 @@ import mage.filter.predicate.permanent.TappedPredicate; import mage.game.Game; import mage.game.events.GameEvent; import mage.game.stack.Spell; -import mage.game.stack.StackObject; import mage.players.Player; import mage.target.common.TargetControlledPermanent; -/** - * 702.77. Conspire 702.77a Conspire is a keyword that represents two abilities. - * The first is a static ability that functions while the spell with conspire is - * on the stack. The second is a triggered ability that functions while the - * spell with conspire is on the stack. "Conspire" means "As an additional cost - * to cast this spell, you may tap two untapped creatures you control that each - * share a color with it" and "When you cast this spell, if its conspire cost - * was paid, copy it. If the spell has any targets, you may choose new targets - * for the copy." Paying a spell’s conspire cost follows the rules for paying - * additional costs in rules 601.2b and 601.2e–g. 702.77b If a spell has - * multiple instances of conspire, each is paid separately and triggers based on - * its own payment, not any other instance of conspire. * +/* + * 702.77. Conspire + * 702.77a Conspire is a keyword that represents two abilities. + * The first is a static ability that functions while the spell with conspire is on the stack. + * The second is a triggered ability that functions while the spell with conspire is on the stack. + * "Conspire" means "As an additional cost to cast this spell, + * you may tap two untapped creatures you control that each share a color with it" + * and "When you cast this spell, if its conspire cost was paid, copy it. + * If the spell has any targets, you may choose new targets for the copy." + * Paying a spell’s conspire cost follows the rules for paying additional costs in rules 601.2b and 601.2e–g. + * 702.77b If a spell has multiple instances of conspire, each is paid separately and triggers + * based on its own payment, not any other instance of conspire. * * * @author jeffwadsworth heavily based off the replicate keyword by LevelX */ public class ConspireAbility extends StaticAbility implements OptionalAdditionalSourceCosts { private static final String keywordText = "Conspire"; - private static final String reminderTextCost = "As you cast this spell, you may tap two untapped creatures you control that share a color with it. When you do, copy it and you may choose a new target for the copy.)"; - private static final FilterControlledCreaturePermanent filter = new FilterControlledCreaturePermanent("two untapped creatures you control that share a color with it"); + private static final FilterControlledCreaturePermanent filter = new FilterControlledCreaturePermanent("untapped creatures you control that share a color with it"); + protected static final String CONSPIRE_ACTIVATION_KEY = "ConspireActivation"; static { filter.add(Predicates.not(new TappedPredicate())); filter.add(new SharesColorWithSourcePredicate()); } - Cost costConspire = new TapTargetCost(new TargetControlledPermanent(2, 2, filter, true)); - OptionalAdditionalCost conspireCost = new OptionalAdditionalCostImpl(keywordText, "-", reminderTextCost, costConspire); + public enum ConspireTargets { - public ConspireAbility(Card card) { + NONE, + ONE, + MORE + } + + private UUID conspireId; + private String reminderText; + private OptionalAdditionalCostImpl conspireCost; + + /** + * Unique Id for a ConspireAbility but may not change while a continuous + * effect gives Conspire + * + * @param conspireId + * @param conspireTargets controls the content of the reminder text + */ + public ConspireAbility(UUID conspireId, ConspireTargets conspireTargets) { super(Zone.STACK, null); - setRuleAtTheTop(false); - addSubAbility(new ConspireTriggeredAbility()); + this.conspireId = conspireId; + switch (conspireTargets) { + case NONE: + reminderText = "As you cast this spell, you may tap two untapped creatures you control that share a color with it. When you do, copy it.)"; + break; + case ONE: + reminderText = "As you cast this spell, you may tap two untapped creatures you control that share a color with it. When you do, copy it and you may choose a new target for the copy.)"; + break; + case MORE: + reminderText = "As you cast this spell, you may tap two untapped creatures you control that share a color with it. When you do, copy it and you may choose a new targets for the copy.)"; + break; + } + conspireCost = new OptionalAdditionalCostImpl(keywordText, "-", reminderText, + new TapTargetCost(new TargetControlledPermanent(2, 2, filter, true))); + addSubAbility(new ConspireTriggeredAbility(conspireId)); } public ConspireAbility(final ConspireAbility ability) { super(ability); - conspireCost = ability.conspireCost; + this.conspireId = ability.conspireId; + this.conspireCost = ability.conspireCost.copy(); + this.reminderText = ability.reminderText; } @Override @@ -106,18 +137,21 @@ public class ConspireAbility extends StaticAbility implements OptionalAdditional } } - @Override - public boolean isActivated() { - if (conspireCost != null) { - return conspireCost.isActivated(); - } - return false; + public UUID getConspireId() { + return conspireId; } - public void resetConspire() { - if (conspireCost != null) { - conspireCost.reset(); + @Override + public boolean isActivated() { + throw new UnsupportedOperationException("Use ConspireAbility.isActivated(Ability ability, Game game) method instead!"); + } + + public boolean isActivated(Ability ability, Game game) { + Set activations = (Set) game.getState().getValue(CONSPIRE_ACTIVATION_KEY + ability.getId()); + if (activations != null) { + return activations.contains(getConspireId()); } + return false; } @Override @@ -125,9 +159,9 @@ public class ConspireAbility extends StaticAbility implements OptionalAdditional if (ability instanceof SpellAbility) { Player player = game.getPlayer(controllerId); if (player != null) { - this.resetConspire(); - if (player.chooseUse(Outcome.Benefit, new StringBuilder("Pay ").append(conspireCost.getText(false)).append(" ?").toString(), ability, game)) { - conspireCost.activate(); + resetConspire(ability, game); + if (player.chooseUse(Outcome.Benefit, "Pay " + conspireCost.getText(false) + " ?", ability, game)) { + activateConspire(ability, game); for (Iterator it = ((Costs) conspireCost).iterator(); it.hasNext();) { Cost cost = (Cost) it.next(); ability.getCosts().add(cost.copy()); @@ -137,6 +171,22 @@ public class ConspireAbility extends StaticAbility implements OptionalAdditional } } + private void activateConspire(Ability ability, Game game) { + Set activations = (Set) game.getState().getValue(CONSPIRE_ACTIVATION_KEY + ability.getId()); + if (activations == null) { + activations = new HashSet<>(); + game.getState().setValue(CONSPIRE_ACTIVATION_KEY + ability.getId(), activations); + } + activations.add(getConspireId()); + } + + private void resetConspire(Ability ability, Game game) { + Set activations = (Set) game.getState().getValue(CONSPIRE_ACTIVATION_KEY + ability.getId()); + if (activations != null) { + activations.remove(getConspireId()); + } + } + @Override public String getRule() { StringBuilder sb = new StringBuilder(); @@ -167,13 +217,17 @@ public class ConspireAbility extends StaticAbility implements OptionalAdditional class ConspireTriggeredAbility extends TriggeredAbilityImpl { - public ConspireTriggeredAbility() { + private UUID conspireId; + + public ConspireTriggeredAbility(UUID conspireId) { super(Zone.STACK, new ConspireEffect()); + this.conspireId = conspireId; this.setRuleVisible(false); } private ConspireTriggeredAbility(final ConspireTriggeredAbility ability) { super(ability); + this.conspireId = ability.conspireId; } @Override @@ -188,20 +242,18 @@ class ConspireTriggeredAbility extends TriggeredAbilityImpl { @Override public boolean checkTrigger(GameEvent event, Game game) { - if (event.getSourceId().equals(this.sourceId)) { - StackObject spell = game.getStack().getStackObject(this.sourceId); - if (spell instanceof Spell) { - Card card = game.getCard(spell.getSourceId()); - if (card != null) { - for (Ability ability : card.getAbilities()) { - if (ability instanceof ConspireAbility) { - if (((ConspireAbility) ability).isActivated()) { - for (Effect effect : this.getEffects()) { - effect.setValue("ConspireSpell", spell); - } - return true; + if (event.getSourceId().equals(getSourceId())) { + Spell spell = game.getStack().getSpell(event.getSourceId()); + for (Ability ability : spell.getAbilities(game)) { + if (ability instanceof ConspireAbility + && ((ConspireAbility) ability).getConspireId().equals(getConspireId())) { + if (((ConspireAbility) ability).isActivated(spell.getSpellAbility(), game)) { + for (Effect effect : this.getEffects()) { + if (effect instanceof ConspireEffect) { + ((ConspireEffect) effect).setConspiredSpell(spell); } } + return true; } } } @@ -209,52 +261,53 @@ class ConspireTriggeredAbility extends TriggeredAbilityImpl { return false; } + public UUID getConspireId() { + return conspireId; + } + @Override public String getRule() { - return "Conspire: As you cast this spell, you may tap two untapped creatures you control that share a color with it. When you do, copy it and you may choose a new target for the copy.)"; + return "When you pay the conspire costs, copy it and you may choose a new target for the copy."; } } class ConspireEffect extends OneShotEffect { + private Spell conspiredSpell; + public ConspireEffect() { super(Outcome.Copy); } public ConspireEffect(final ConspireEffect effect) { super(effect); + this.conspiredSpell = effect.conspiredSpell; } @Override public boolean apply(Game game, Ability source) { Player controller = game.getPlayer(source.getControllerId()); - if (controller != null) { - Spell spell = (Spell) this.getValue("ConspireSpell"); - if (spell != null) { - Card card = game.getCard(spell.getSourceId()); - if (card != null) { - for (Ability ability : card.getAbilities()) { - if (ability instanceof ConspireAbility) { - if (((ConspireAbility) ability).isActivated()) { - ((ConspireAbility) ability).resetConspire(); - } - } - } - Spell copy = spell.copySpell(); - copy.setControllerId(source.getControllerId()); - copy.setCopiedSpell(true); - game.getStack().push(copy); - copy.chooseNewTargets(game, source.getControllerId()); - if (!game.isSimulation()) { - game.informPlayers(new StringBuilder(controller.getLogName()).append(copy.getActivatedMessage(game)).toString()); - } - return true; + if (controller != null && conspiredSpell != null) { + Card card = game.getCard(conspiredSpell.getSourceId()); + if (card != null) { + Spell copy = conspiredSpell.copySpell(); + copy.setControllerId(source.getControllerId()); + copy.setCopiedSpell(true); + game.getStack().push(copy); + copy.chooseNewTargets(game, source.getControllerId()); + if (!game.isSimulation()) { + game.informPlayers(controller.getLogName() + copy.getActivatedMessage(game)); } + return true; } } return false; } + public void setConspiredSpell(Spell conspiredSpell) { + this.conspiredSpell = conspiredSpell; + } + @Override public ConspireEffect copy() { return new ConspireEffect(this); diff --git a/Mage/src/mage/game/stack/StackObjImpl.java b/Mage/src/mage/game/stack/StackObjImpl.java index 8ca3c7a6be5..6cf33e65ea5 100644 --- a/Mage/src/mage/game/stack/StackObjImpl.java +++ b/Mage/src/mage/game/stack/StackObjImpl.java @@ -106,6 +106,7 @@ public abstract class StackObjImpl implements StackObject { public boolean chooseNewTargets(Game game, UUID targetControllerId, boolean forceChange, boolean onlyOneTarget, FilterPermanent filterNewTarget) { Player targetController = game.getPlayer(targetControllerId); if (targetController != null) { + StringBuilder oldTargetDescription = new StringBuilder(); StringBuilder newTargetDescription = new StringBuilder(); // Fused split spells or spells where "Splice on Arcane" was used can have more than one ability Abilities objectAbilities = new AbilitiesImpl<>(); @@ -118,6 +119,7 @@ public abstract class StackObjImpl implements StackObject { // Some spells can have more than one mode for (UUID modeId : ability.getModes().getSelectedModes()) { Mode mode = ability.getModes().get(modeId); + oldTargetDescription.append(ability.getTargetDescription(mode.getTargets(), game)); for (Target target : mode.getTargets()) { Target newTarget = chooseNewTarget(targetController, ability, mode, target, forceChange, filterNewTarget, game); // clear the old target and copy all targets from new target @@ -131,7 +133,7 @@ public abstract class StackObjImpl implements StackObject { } } - if (newTargetDescription.length() > 0 && !game.isSimulation()) { + if (!newTargetDescription.toString().equals(oldTargetDescription.toString()) && !game.isSimulation()) { game.informPlayers(this.getLogName() + " is now " + newTargetDescription.toString()); } return true; From d10e63bea4e2078398a5bcf634dca5f86d766755 Mon Sep 17 00:00:00 2001 From: LevelX2 Date: Sat, 3 Oct 2015 13:33:40 +0200 Subject: [PATCH 005/268] Added Wort, the Raidmother. --- .../sets/shadowmoor/WortTheRaidmother.java | 139 ++++++++++++++++++ 1 file changed, 139 insertions(+) create mode 100644 Mage.Sets/src/mage/sets/shadowmoor/WortTheRaidmother.java diff --git a/Mage.Sets/src/mage/sets/shadowmoor/WortTheRaidmother.java b/Mage.Sets/src/mage/sets/shadowmoor/WortTheRaidmother.java new file mode 100644 index 00000000000..d44ba058135 --- /dev/null +++ b/Mage.Sets/src/mage/sets/shadowmoor/WortTheRaidmother.java @@ -0,0 +1,139 @@ +/* + * 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.shadowmoor; + +import java.util.UUID; +import mage.MageInt; +import mage.ObjectColor; +import mage.abilities.Ability; +import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.effects.ContinuousEffectImpl; +import mage.abilities.effects.common.CreateTokenEffect; +import mage.abilities.keyword.ConspireAbility; +import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.Layer; +import mage.constants.Outcome; +import mage.constants.Rarity; +import mage.constants.SubLayer; +import mage.constants.Zone; +import mage.filter.common.FilterInstantOrSorcerySpell; +import mage.filter.predicate.Predicates; +import mage.filter.predicate.mageobject.ColorPredicate; +import mage.game.Game; +import mage.game.permanent.token.Token; +import mage.game.stack.Spell; +import mage.game.stack.StackObject; + +/** + * + * @author LevelX2 + */ +public class WortTheRaidmother extends CardImpl { + + public WortTheRaidmother(UUID ownerId) { + super(ownerId, 223, "Wort, the Raidmother", Rarity.RARE, new CardType[]{CardType.CREATURE}, "{4}{R/G}{R/G}"); + this.expansionSetCode = "SHM"; + this.supertype.add("Legendary"); + this.subtype.add("Goblin"); + this.subtype.add("Shaman"); + this.power = new MageInt(3); + this.toughness = new MageInt(3); + + // When Wort, the Raidmother enters the battlefield, put two 1/1 red and green Goblin Warrior creature tokens onto the battlefield. + this.addAbility(new EntersBattlefieldTriggeredAbility(new CreateTokenEffect(new WortTheRaidmotherToken(), 2), false)); + + // Each red or green instant or sorcery spell you cast has conspire. + this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new WortGainConspireEffect())); + } + + public WortTheRaidmother(final WortTheRaidmother card) { + super(card); + } + + @Override + public WortTheRaidmother copy() { + return new WortTheRaidmother(this); + } +} + +class WortGainConspireEffect extends ContinuousEffectImpl { + + private final static FilterInstantOrSorcerySpell filter = new FilterInstantOrSorcerySpell(); + + static { + filter.add(Predicates.or(new ColorPredicate(ObjectColor.RED), new ColorPredicate(ObjectColor.GREEN))); + } + private final ConspireAbility conspireAbility; + + public WortGainConspireEffect() { + super(Duration.WhileOnBattlefield, Layer.AbilityAddingRemovingEffects_6, SubLayer.NA, Outcome.AddAbility); + staticText = "Each red or green instant or sorcery spell you cast has conspire. (As you cast the spell, you may tap two untapped creatures you control that share a color with it. When you do, copy it and you may choose new targets for the copy.)"; + conspireAbility = new ConspireAbility(getId(), ConspireAbility.ConspireTargets.MORE); + } + + public WortGainConspireEffect(final WortGainConspireEffect effect) { + super(effect); + this.conspireAbility = new ConspireAbility(getId(), ConspireAbility.ConspireTargets.MORE); + } + + @Override + public WortGainConspireEffect copy() { + return new WortGainConspireEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + for (StackObject stackObject : game.getStack()) { + // only spells cast, so no copies of spells + if ((stackObject instanceof Spell) && !stackObject.isCopy() && stackObject.getControllerId().equals(source.getControllerId())) { + Spell spell = (Spell) stackObject; + if (filter.match(stackObject, game)) { + game.getState().addOtherAbility(spell.getCard(), conspireAbility); + } + } + } + return true; + } +} + +class WortTheRaidmotherToken extends Token { + + public WortTheRaidmotherToken() { + super("Goblin Warrior", "1/1 red and green Goblin Warrior creature token"); + cardType.add(CardType.CREATURE); + color.setRed(true); + color.setGreen(true); + subtype.add("Goblin"); + subtype.add("Warrior"); + power = new MageInt(1); + toughness = new MageInt(1); + } +} From f6ec543b1b8f1d342a57d404a75352c2d10d2911 Mon Sep 17 00:00:00 2001 From: LevelX2 Date: Sat, 3 Oct 2015 18:20:59 +0200 Subject: [PATCH 006/268] TestPlayer fixed that target events created by RestPlayer are reset back if ability activation failed. --- .../test/java/org/mage/test/player/TestPlayer.java | 11 ++++++++--- Mage/src/mage/players/PlayerImpl.java | 2 +- 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/Mage.Tests/src/test/java/org/mage/test/player/TestPlayer.java b/Mage.Tests/src/test/java/org/mage/test/player/TestPlayer.java index 3abe238a3b0..f168cd1c3dd 100644 --- a/Mage.Tests/src/test/java/org/mage/test/player/TestPlayer.java +++ b/Mage.Tests/src/test/java/org/mage/test/player/TestPlayer.java @@ -370,6 +370,7 @@ public class TestPlayer implements Player { } for (Ability ability : computerPlayer.getPlayable(game, true)) { if (ability.toString().startsWith(groups[0])) { + int bookmark = game.bookmarkState(); Ability newAbility = ability.copy(); if (groups.length > 1 && !groups[1].equals("target=NO_TARGET")) { if (!addTargets(newAbility, groups, game)) { @@ -377,9 +378,13 @@ public class TestPlayer implements Player { break; } } - computerPlayer.activateAbility((ActivatedAbility) newAbility, game); - actions.remove(action); - return true; + if (computerPlayer.activateAbility((ActivatedAbility) newAbility, game)) { + actions.remove(action); + return true; + } else { + game.restoreState(bookmark, ability.getRule()); + } + } } } else if (action.getAction().startsWith("manaActivate:")) { diff --git a/Mage/src/mage/players/PlayerImpl.java b/Mage/src/mage/players/PlayerImpl.java index 3ce3070c96e..b6d6cb24050 100644 --- a/Mage/src/mage/players/PlayerImpl.java +++ b/Mage/src/mage/players/PlayerImpl.java @@ -1105,7 +1105,7 @@ public abstract class PlayerImpl implements Player, Serializable { return false; } - private void restoreState(int bookmark, String text, Game game) { + protected void restoreState(int bookmark, String text, Game game) { game.restoreState(bookmark, text); if (storedBookmark >= bookmark) { resetStoredBookmark(game); From 85f0cc6bb3e42da4e57ca26760773a0a01196fc0 Mon Sep 17 00:00:00 2001 From: LevelX2 Date: Sat, 3 Oct 2015 18:22:14 +0200 Subject: [PATCH 007/268] Fixed variable remove counter costs to work also correctly if X=0 (e.g. Retribution of the Ancients and Willbreaker). --- .../test/cards/control/ItThatBetraysTest.java | 15 ++-- .../test/cards/control/WillbreakerTest.java | 73 +++++++++++++++++++ .../abilities/costs/VariableCostImpl.java | 3 +- .../costs/common/RemoveCounterCost.java | 3 + 4 files changed, 84 insertions(+), 10 deletions(-) create mode 100644 Mage.Tests/src/test/java/org/mage/test/cards/control/WillbreakerTest.java diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/control/ItThatBetraysTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/control/ItThatBetraysTest.java index e48bd054ec9..3dd7735cd8e 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/control/ItThatBetraysTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/control/ItThatBetraysTest.java @@ -27,7 +27,6 @@ */ package org.mage.test.cards.control; -import mage.abilities.keyword.HasteAbility; import mage.constants.PhaseStep; import mage.constants.Zone; import org.junit.Test; @@ -37,15 +36,15 @@ import org.mage.test.serverside.base.CardTestPlayerBase; * * @author LevelX2 */ - public class ItThatBetraysTest extends CardTestPlayerBase { /** * https://github.com/magefree/mage/issues/796 * - * When an opponent sacrifices a fetchland and you have an It That Betrays in play, - * sacrificing the fetchland that comes under your control from its ability returns - * it to play under your control, allowing you to fetch infinite lands. + * When an opponent sacrifices a fetchland and you have an It That Betrays + * in play, sacrificing the fetchland that comes under your control from its + * ability returns it to play under your control, allowing you to fetch + * infinite lands. * */ @Test @@ -62,7 +61,7 @@ public class ItThatBetraysTest extends CardTestPlayerBase { assertLife(playerA, 19); assertLife(playerB, 19); - + // Going to graveyard if player B sacrifices it assertGraveyardCount(playerA, "Flooded Strand", 1); } @@ -71,7 +70,7 @@ public class ItThatBetraysTest extends CardTestPlayerBase { @Test public void testExileItThatBetraysEffect() { addCard(Zone.BATTLEFIELD, playerA, "Flooded Strand", 1); - + addCard(Zone.BATTLEFIELD, playerA, "Rest in Peace", 1); addCard(Zone.BATTLEFIELD, playerB, "It That Betrays"); @@ -83,7 +82,7 @@ public class ItThatBetraysTest extends CardTestPlayerBase { assertLife(playerA, 19); assertLife(playerB, 20); - + // Player B now controls a Flooded Strand, even though it went to exile assertPermanentCount(playerB, "Flooded Strand", 1); } diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/control/WillbreakerTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/control/WillbreakerTest.java new file mode 100644 index 00000000000..92b78b12a08 --- /dev/null +++ b/Mage.Tests/src/test/java/org/mage/test/cards/control/WillbreakerTest.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 org.mage.test.cards.control; + +import mage.constants.PhaseStep; +import mage.constants.Zone; +import org.junit.Test; +import org.mage.test.serverside.base.CardTestPlayerBase; + +/** + * + * @author LevelX2 + */ +public class WillbreakerTest extends CardTestPlayerBase { + + /** + * http://www.slightlymagic.net/forum/viewtopic.php?f=70&t=17664&start=120#p186736 + * + * I tried to activate Retribution of the Ancients while I only controlled + * Nantuko Husk and Willbreaker without +1/+1 counters on them. The program + * didn't let me activate the RotA, even though the creature you choose + * doesn't need to have any counters on it (X can be 0, doesn't say + * otherwise on the card and it isn't a target requirement). It asked me to + * pay B, then choose a creature I controlled, which I did... and then + * nothing happened. + * + */ + @Test + public void testRetributionOfTheAncientsZeroCounter() { + addCard(Zone.BATTLEFIELD, playerA, "Swamp", 1); + // {B}, Remove X +1/+1 counters from among creatures you control: Target creature gets -X/-X until end of turn. + addCard(Zone.BATTLEFIELD, playerA, "Retribution of the Ancients", 1); // Enchantment {B} + // Whenever a creature an opponent controls becomes the target of a spell or ability you control, gain control of that creature for as long as you control Willbreaker. + addCard(Zone.BATTLEFIELD, playerA, "Willbreaker", 1); + + addCard(Zone.BATTLEFIELD, playerB, "Silvercoat Lion"); + + activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "{B},Remove", "Silvercoat Lion"); + setChoice(playerA, "X=0"); + + setStopAt(1, PhaseStep.BEGIN_COMBAT); + execute(); + + assertPermanentCount(playerA, "Willbreaker", 1); + assertPermanentCount(playerA, "Silvercoat Lion", 1); + } + +} diff --git a/Mage/src/mage/abilities/costs/VariableCostImpl.java b/Mage/src/mage/abilities/costs/VariableCostImpl.java index c020d7922ba..68557546df2 100644 --- a/Mage/src/mage/abilities/costs/VariableCostImpl.java +++ b/Mage/src/mage/abilities/costs/VariableCostImpl.java @@ -157,8 +157,7 @@ public abstract class VariableCostImpl implements Cost, VariableCost { Player controller = game.getPlayer(source.getControllerId()); if (controller != null) { xValue = controller.announceXCost(getMinValue(source, game), getMaxValue(source, game), - new StringBuilder("Announce the number of ").append(actionText).toString(), - game, source, this); + "Announce the number of " + actionText, game, source, this); } return xValue; } diff --git a/Mage/src/mage/abilities/costs/common/RemoveCounterCost.java b/Mage/src/mage/abilities/costs/common/RemoveCounterCost.java index 85f7676eb46..0167f67807f 100644 --- a/Mage/src/mage/abilities/costs/common/RemoveCounterCost.java +++ b/Mage/src/mage/abilities/costs/common/RemoveCounterCost.java @@ -84,6 +84,9 @@ public class RemoveCounterCost extends CostImpl { int countersRemoved = 0; Player controller = game.getPlayer(controllerId); if (controller != null) { + if (countersToRemove == 0) { // Can happen when used for X costs where X = 0; + return paid = true; + } target.clearChosen(); if (target.choose(Outcome.UnboostCreature, controllerId, sourceId, game)) { for (UUID targetId : target.getTargets()) { From f24a1b38986fe846c6de10134fd0dc0c8bcd6aa7 Mon Sep 17 00:00:00 2001 From: LevelX2 Date: Sat, 3 Oct 2015 19:23:58 +0200 Subject: [PATCH 008/268] * Fixed check of dies attched triggered abilities not always triggering if attachment and attached object went to graveyard at the same time. --- .../cards/enchantments/SkullclampTest.java | 88 +++++++++++++++++++ .../common/DiesAttachedTriggeredAbility.java | 23 +++-- Mage/src/mage/game/permanent/Permanent.java | 2 + .../mage/game/permanent/PermanentImpl.java | 8 ++ 4 files changed, 116 insertions(+), 5 deletions(-) create mode 100644 Mage.Tests/src/test/java/org/mage/test/cards/enchantments/SkullclampTest.java diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/enchantments/SkullclampTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/enchantments/SkullclampTest.java new file mode 100644 index 00000000000..8f4e7415e6b --- /dev/null +++ b/Mage.Tests/src/test/java/org/mage/test/cards/enchantments/SkullclampTest.java @@ -0,0 +1,88 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package org.mage.test.cards.enchantments; + +import mage.constants.PhaseStep; +import mage.constants.Zone; +import org.junit.Test; +import org.mage.test.serverside.base.CardTestPlayerBase; + +/** + * + * @author LevelX2 + */ +public class SkullclampTest extends CardTestPlayerBase { + + /** + * Skullclamp and the creature it's attached to are destroyed by same + * Pernicious Deed activation. AFAIK Skullclamp should trigger, but it + * doesn't. + * + * 400.7e Abilities of Auras that trigger when the enchanted permanent + * leaves the battlefield can find the new object that Aura became in its + * owners graveyard if it was put into that graveyard at the same time the + * enchanted permanent left the battlefield. It can also find the new object + * that Aura became in its owners graveyard as a result of being put there + * as a state-based action for not being attached to a permanent. (See rule + * 704.5n.) + * + */ + @Test + public void testPerniciousDeed() { + // Equipped creature gets +1/-1. + // Whenever equipped creature dies, draw two cards. + // Equip {1} + addCard(Zone.BATTLEFIELD, playerA, "Skullclamp", 1); + addCard(Zone.BATTLEFIELD, playerA, "Silvercoat Lion", 1); + addCard(Zone.BATTLEFIELD, playerA, "Pillarfield Ox", 1); + + addCard(Zone.BATTLEFIELD, playerA, "Island", 1); + + addCard(Zone.BATTLEFIELD, playerB, "Swamp", 2); + // {X}, Sacrifice Pernicious Deed: Destroy each artifact, creature, and enchantment with converted mana cost X or less. + addCard(Zone.BATTLEFIELD, playerB, "Pernicious Deed"); // Enchantment + + activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Equip", "Silvercoat Lion"); + + activateAbility(1, PhaseStep.POSTCOMBAT_MAIN, playerB, "{X},Sacrifice"); + setChoice(playerB, "X=2"); + + setStopAt(1, PhaseStep.END_TURN); + execute(); + + assertGraveyardCount(playerA, "Skullclamp", 1); + assertGraveyardCount(playerA, "Silvercoat Lion", 1); + + assertGraveyardCount(playerB, "Pernicious Deed", 1); + + assertPermanentCount(playerA, "Pillarfield Ox", 1); + + assertHandCount(playerA, 2); + } + +} diff --git a/Mage/src/mage/abilities/common/DiesAttachedTriggeredAbility.java b/Mage/src/mage/abilities/common/DiesAttachedTriggeredAbility.java index 78fc74d57c1..83adbea699a 100644 --- a/Mage/src/mage/abilities/common/DiesAttachedTriggeredAbility.java +++ b/Mage/src/mage/abilities/common/DiesAttachedTriggeredAbility.java @@ -1,21 +1,23 @@ package mage.abilities.common; -import mage.constants.Zone; import mage.abilities.TriggeredAbilityImpl; import mage.abilities.effects.Effect; +import mage.constants.Zone; import mage.game.Game; import mage.game.events.GameEvent; import mage.game.events.ZoneChangeEvent; +import mage.game.permanent.Permanent; /** * "When enchanted/equipped creature dies" triggered ability + * * @author Loki */ public class DiesAttachedTriggeredAbility extends TriggeredAbilityImpl { - + private String attachedDescription; private boolean diesRuleText; - + public DiesAttachedTriggeredAbility(Effect effect, String attachedDescription) { this(effect, attachedDescription, false); } @@ -30,7 +32,6 @@ public class DiesAttachedTriggeredAbility extends TriggeredAbilityImpl { this.diesRuleText = diesRuleText; } - public DiesAttachedTriggeredAbility(final DiesAttachedTriggeredAbility ability) { super(ability); this.attachedDescription = ability.attachedDescription; @@ -49,9 +50,21 @@ public class DiesAttachedTriggeredAbility extends TriggeredAbilityImpl { @Override public boolean checkTrigger(GameEvent event, Game game) { - if (((ZoneChangeEvent)event).isDiesEvent()) { + if (((ZoneChangeEvent) event).isDiesEvent()) { ZoneChangeEvent zEvent = (ZoneChangeEvent) event; + boolean triggered = false; if (zEvent.getTarget().getAttachments().contains(this.getSourceId())) { + triggered = true; + } else { + // If both (attachment and attached went to graveyard at the same time, the attachemnets can be already removed from the attached object.) + // So check here with the LKI of the enchantment + Permanent attachment = game.getPermanentOrLKIBattlefield(getSourceId()); + if (attachment != null && attachment.getAttachedTo().equals(zEvent.getTargetId()) + && attachment.getAttachedToZoneChangeCounter() == zEvent.getTarget().getZoneChangeCounter(game)) { + triggered = true; + } + } + if (triggered) { for (Effect effect : getEffects()) { effect.setValue("attachedTo", zEvent.getTarget()); } diff --git a/Mage/src/mage/game/permanent/Permanent.java b/Mage/src/mage/game/permanent/Permanent.java index 84ae5f3986f..b7e8178a815 100644 --- a/Mage/src/mage/game/permanent/Permanent.java +++ b/Mage/src/mage/game/permanent/Permanent.java @@ -109,6 +109,8 @@ public interface Permanent extends Card, Controllable { UUID getAttachedTo(); + int getAttachedToZoneChangeCounter(); + void attachTo(UUID permanentId, Game game); boolean addAttachment(UUID permanentId, Game game); diff --git a/Mage/src/mage/game/permanent/PermanentImpl.java b/Mage/src/mage/game/permanent/PermanentImpl.java index 93b2f355be7..f5be69ff35f 100644 --- a/Mage/src/mage/game/permanent/PermanentImpl.java +++ b/Mage/src/mage/game/permanent/PermanentImpl.java @@ -115,6 +115,7 @@ public abstract class PermanentImpl extends CardImpl implements Permanent { protected Map> connectedCards = new HashMap<>(); protected HashSet dealtDamageByThisTurn; protected UUID attachedTo; + protected int attachedToZoneChangeCounter; protected UUID pairedCard; protected Counters counters; protected List markedDamage; @@ -172,6 +173,7 @@ public abstract class PermanentImpl extends CardImpl implements Permanent { } this.counters = permanent.counters.copy(); this.attachedTo = permanent.attachedTo; + this.attachedToZoneChangeCounter = permanent.attachedToZoneChangeCounter; this.minBlockedBy = permanent.minBlockedBy; this.maxBlockedBy = permanent.maxBlockedBy; this.transformed = permanent.transformed; @@ -676,6 +678,11 @@ public abstract class PermanentImpl extends CardImpl implements Permanent { return attachedTo; } + @Override + public int getAttachedToZoneChangeCounter() { + return attachedToZoneChangeCounter; + } + @Override public void addConnectedCard(String key, UUID connectedCard) { if (this.connectedCards.containsKey(key)) { @@ -712,6 +719,7 @@ public abstract class PermanentImpl extends CardImpl implements Permanent { } } this.attachedTo = permanentId; + this.attachedToZoneChangeCounter = game.getState().getZoneChangeCounter(permanentId); for (Ability ability : this.getAbilities()) { for (Iterator ite = ability.getEffects(game, EffectType.CONTINUOUS).iterator(); ite.hasNext();) { ContinuousEffect effect = (ContinuousEffect) ite.next(); From 208a890d1d244855eb5225f35c41942cc61f0d0d Mon Sep 17 00:00:00 2001 From: emerald000 Date: Sun, 4 Oct 2015 01:57:37 -0400 Subject: [PATCH 009/268] Added Chainer, Dementia Master; Concerted Effort; Spellweaver Helix; Thought Lash and Tithe. Fixed OpponentControlsMoreCondition spelling. --- .../src/mage/sets/alliances/ThoughtLash.java | 52 ++++ .../sets/commander2014/GiftOfEstates.java | 4 +- Mage.Sets/src/mage/sets/legends/LandTax.java | 4 +- .../sets/masterseditionii/ThoughtLash.java | 182 ++++++++++++++ .../mage/sets/mirrodin/SpellweaverHelix.java | 231 ++++++++++++++++++ .../sets/onslaught/WeatheredWayfarer.java | 4 +- .../mage/sets/ravnica/ConcertedEffort.java | 164 +++++++++++++ .../shardsofalara/KnightOfTheWhiteOrchid.java | 4 +- .../sets/torment/ChainerDementiaMaster.java | 144 +++++++++++ Mage.Sets/src/mage/sets/visions/Tithe.java | 98 ++++++++ ...ava => OpponentControlsMoreCondition.java} | 4 +- .../keyword/CumulativeUpkeepAbility.java | 46 ++-- Mage/src/mage/game/events/GameEvent.java | 2 +- 13 files changed, 903 insertions(+), 36 deletions(-) create mode 100644 Mage.Sets/src/mage/sets/alliances/ThoughtLash.java create mode 100644 Mage.Sets/src/mage/sets/masterseditionii/ThoughtLash.java create mode 100644 Mage.Sets/src/mage/sets/mirrodin/SpellweaverHelix.java create mode 100644 Mage.Sets/src/mage/sets/ravnica/ConcertedEffort.java create mode 100644 Mage.Sets/src/mage/sets/torment/ChainerDementiaMaster.java create mode 100644 Mage.Sets/src/mage/sets/visions/Tithe.java rename Mage/src/mage/abilities/condition/common/{OpponentControllsMoreCondition.java => OpponentControlsMoreCondition.java} (92%) diff --git a/Mage.Sets/src/mage/sets/alliances/ThoughtLash.java b/Mage.Sets/src/mage/sets/alliances/ThoughtLash.java new file mode 100644 index 00000000000..6f9c9f2720c --- /dev/null +++ b/Mage.Sets/src/mage/sets/alliances/ThoughtLash.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.alliances; + +import java.util.UUID; + +/** + * + * @author emerald000 + */ +public class ThoughtLash extends mage.sets.masterseditionii.ThoughtLash { + + public ThoughtLash(UUID ownerId) { + super(ownerId); + this.cardNumber = 58; + this.expansionSetCode = "ALL"; + } + + public ThoughtLash(final ThoughtLash card) { + super(card); + } + + @Override + public ThoughtLash copy() { + return new ThoughtLash(this); + } +} diff --git a/Mage.Sets/src/mage/sets/commander2014/GiftOfEstates.java b/Mage.Sets/src/mage/sets/commander2014/GiftOfEstates.java index c87bb2c1f4f..e4c6731a64d 100644 --- a/Mage.Sets/src/mage/sets/commander2014/GiftOfEstates.java +++ b/Mage.Sets/src/mage/sets/commander2014/GiftOfEstates.java @@ -28,7 +28,7 @@ package mage.sets.commander2014; import java.util.UUID; -import mage.abilities.condition.common.OpponentControllsMoreCondition; +import mage.abilities.condition.common.OpponentControlsMoreCondition; import mage.abilities.decorator.ConditionalOneShotEffect; import mage.abilities.effects.common.search.SearchLibraryPutInHandEffect; import mage.cards.CardImpl; @@ -60,7 +60,7 @@ public class GiftOfEstates extends CardImpl { // If an opponent controls more lands than you, search your library for up to three Plains cards, reveal them, and put them into your hand. Then shuffle your library. this.getSpellAbility().addEffect(new ConditionalOneShotEffect( new SearchLibraryPutInHandEffect(new TargetCardInLibrary(0, 3, filter), true), - new OpponentControllsMoreCondition(new FilterLandPermanent("lands")))); + new OpponentControlsMoreCondition(new FilterLandPermanent("lands")))); } public GiftOfEstates(final GiftOfEstates card) { diff --git a/Mage.Sets/src/mage/sets/legends/LandTax.java b/Mage.Sets/src/mage/sets/legends/LandTax.java index ffd80349b0c..823758648df 100644 --- a/Mage.Sets/src/mage/sets/legends/LandTax.java +++ b/Mage.Sets/src/mage/sets/legends/LandTax.java @@ -29,7 +29,7 @@ package mage.sets.legends; import java.util.UUID; import mage.abilities.common.BeginningOfUpkeepTriggeredAbility; -import mage.abilities.condition.common.OpponentControllsMoreCondition; +import mage.abilities.condition.common.OpponentControlsMoreCondition; import mage.abilities.decorator.ConditionalTriggeredAbility; import mage.abilities.effects.common.search.SearchLibraryPutInHandEffect; import mage.cards.CardImpl; @@ -53,7 +53,7 @@ public class LandTax extends CardImpl { // At the beginning of your upkeep, if an opponent controls more lands than you, you may search your library for up to three basic land cards, reveal them, and put them into your hand. If you do, shuffle your library. this.addAbility(new ConditionalTriggeredAbility( new BeginningOfUpkeepTriggeredAbility(new SearchLibraryPutInHandEffect(new TargetCardInLibrary(0, 3, new FilterBasicLandCard()), true), TargetController.YOU, true), - new OpponentControllsMoreCondition(new FilterLandPermanent("lands")), + new OpponentControlsMoreCondition(new FilterLandPermanent("lands")), "At the beginning of your upkeep, if an opponent controls more lands than you, you may search your library for up to three basic land cards, reveal them, and put them into your hand. If you do, shuffle your library" )); diff --git a/Mage.Sets/src/mage/sets/masterseditionii/ThoughtLash.java b/Mage.Sets/src/mage/sets/masterseditionii/ThoughtLash.java new file mode 100644 index 00000000000..e8a28e8196f --- /dev/null +++ b/Mage.Sets/src/mage/sets/masterseditionii/ThoughtLash.java @@ -0,0 +1,182 @@ +/* + * 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.masterseditionii; + +import java.util.UUID; +import mage.abilities.Ability; +import mage.abilities.TriggeredAbilityImpl; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.costs.common.ExileFromTopOfLibraryCost; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.PreventionEffectImpl; +import mage.abilities.keyword.CumulativeUpkeepAbility; +import mage.cards.CardImpl; +import mage.cards.Cards; +import mage.cards.CardsImpl; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.Outcome; +import mage.constants.Rarity; +import mage.constants.Zone; +import mage.game.Game; +import mage.game.events.GameEvent; +import mage.game.events.GameEvent.EventType; +import mage.players.Player; + +/** + * + * @author emerald000 + */ +public class ThoughtLash extends CardImpl { + + public ThoughtLash(UUID ownerId) { + super(ownerId, 70, "Thought Lash", Rarity.RARE, new CardType[]{CardType.ENCHANTMENT}, "{2}{U}{U}"); + this.expansionSetCode = "ME2"; + + // Cumulative upkeep - Exile the top card of your library. + this.addAbility(new CumulativeUpkeepAbility(new ExileFromTopOfLibraryCost(1))); + + // When a player doesn't pay Thought Lash's cumulative upkeep, that player exiles all cards from his or her library. + this.addAbility(new ThoughtLashTriggeredAbility()); + + // Exile the top card of your library: Prevent the next 1 damage that would be dealt to you this turn. + this.addAbility(new SimpleActivatedAbility(Zone.BATTLEFIELD, new ThoughtLashPreventionEffect(), new ExileFromTopOfLibraryCost(1))); + } + + public ThoughtLash(final ThoughtLash card) { + super(card); + } + + @Override + public ThoughtLash copy() { + return new ThoughtLash(this); + } +} + +class ThoughtLashTriggeredAbility extends TriggeredAbilityImpl { + + ThoughtLashTriggeredAbility() { + super(Zone.BATTLEFIELD, new ThoughtLashExileLibraryEffect(), false); + } + + ThoughtLashTriggeredAbility(final ThoughtLashTriggeredAbility ability) { + super(ability); + } + + @Override + public ThoughtLashTriggeredAbility copy() { + return new ThoughtLashTriggeredAbility(this); + } + + @Override + public boolean checkEventType(GameEvent event, Game game) { + return event.getType() == EventType.DIDNT_PAY_CUMULATIVE_UPKEEP; + } + + @Override + public boolean checkTrigger(GameEvent event, Game game) { + return event.getSourceId() == this.getSourceId(); + } + + @Override + public String getRule() { + return "When a player doesn't pay {this}'s cumulative upkeep, that player exiles all cards from his or her library."; + } +} + +class ThoughtLashExileLibraryEffect extends OneShotEffect { + + ThoughtLashExileLibraryEffect() { + super(Outcome.Detriment); + this.staticText = "that player exiles all cards from his or her library"; + } + + ThoughtLashExileLibraryEffect(final ThoughtLashExileLibraryEffect effect) { + super(effect); + } + + @Override + public ThoughtLashExileLibraryEffect copy() { + return new ThoughtLashExileLibraryEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player controller = game.getPlayer(source.getControllerId()); + if (controller != null) { + Cards cards = new CardsImpl(); + cards.addAll(controller.getLibrary().getTopCards(game, controller.getLibrary().size())); + controller.moveCards(cards, Zone.LIBRARY, Zone.EXILED, source, game); + return true; + } + return false; + } +} + +class ThoughtLashPreventionEffect extends PreventionEffectImpl { + + ThoughtLashPreventionEffect() { + super(Duration.EndOfTurn); + this.staticText = "Prevent the next 1 damage that would be dealt to you this turn"; + } + + ThoughtLashPreventionEffect(final ThoughtLashPreventionEffect effect) { + super(effect); + } + + @Override + public ThoughtLashPreventionEffect copy() { + return new ThoughtLashPreventionEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + return true; + } + + @Override + public boolean replaceEvent(GameEvent event, Ability source, Game game) { + GameEvent preventEvent = new GameEvent(GameEvent.EventType.PREVENT_DAMAGE, + source.getControllerId(), source.getSourceId(), source.getControllerId(), event.getAmount(), false); + if (!game.replaceEvent(preventEvent)) { + int damage = event.getAmount(); + if (damage > 0) { + event.setAmount(damage - 1); + this.used = true; + game.fireEvent(GameEvent.getEvent(GameEvent.EventType.PREVENTED_DAMAGE, + source.getControllerId(), source.getSourceId(), source.getControllerId(), 1)); + } + } + return false; + } + + @Override + public boolean applies(GameEvent event, Ability source, Game game) { + return !this.used && super.applies(event, source, game) && event.getTargetId().equals(source.getControllerId()); + } +} diff --git a/Mage.Sets/src/mage/sets/mirrodin/SpellweaverHelix.java b/Mage.Sets/src/mage/sets/mirrodin/SpellweaverHelix.java new file mode 100644 index 00000000000..e83b0afe794 --- /dev/null +++ b/Mage.Sets/src/mage/sets/mirrodin/SpellweaverHelix.java @@ -0,0 +1,231 @@ +/* + * 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.mirrodin; + +import java.util.UUID; +import mage.abilities.Ability; +import mage.abilities.TriggeredAbilityImpl; +import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.effects.Effect; +import mage.abilities.effects.OneShotEffect; +import mage.cards.Card; +import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.Outcome; +import mage.constants.Rarity; +import mage.constants.Zone; +import mage.filter.FilterCard; +import mage.filter.predicate.mageobject.CardTypePredicate; +import mage.game.Game; +import mage.game.events.GameEvent; +import mage.game.permanent.Permanent; +import mage.game.stack.Spell; +import mage.players.Player; +import mage.target.common.TargetCardInASingleGraveyard; +import mage.target.targetpointer.FixedTarget; +import mage.util.CardUtil; + +/** + * + * @author emerald000 + */ +public class SpellweaverHelix extends CardImpl { + + private static final FilterCard filter = new FilterCard("sorcery cards from a single graveyard"); + static { + filter.add(new CardTypePredicate(CardType.SORCERY)); + } + + public SpellweaverHelix(UUID ownerId) { + super(ownerId, 247, "Spellweaver Helix", Rarity.RARE, new CardType[]{CardType.ARTIFACT}, "{3}"); + this.expansionSetCode = "MRD"; + + // Imprint - When Spellweaver Helix enters the battlefield, you may exile two target sorcery cards from a single graveyard. + Ability ability = new EntersBattlefieldTriggeredAbility(new SpellweaverHelixImprintEffect(), true, "Imprint — "); + ability.addTarget(new TargetCardInASingleGraveyard(2, 2, filter)); + this.addAbility(ability); + + // Whenever a player casts a card, if it has the same name as one of the cards exiled with Spellweaver Helix, you may copy the other. If you do, you may cast the copy without paying its mana cost. + this.addAbility(new SpellweaverHelixTriggeredAbility()); + } + + public SpellweaverHelix(final SpellweaverHelix card) { + super(card); + } + + @java.lang.Override + public SpellweaverHelix copy() { + return new SpellweaverHelix(this); + } +} + +class SpellweaverHelixImprintEffect extends OneShotEffect { + + SpellweaverHelixImprintEffect() { + super(Outcome.Exile); + this.staticText = "you may exile two target sorcery cards from a single graveyard"; + } + + SpellweaverHelixImprintEffect(final SpellweaverHelixImprintEffect effect) { + super(effect); + } + + @java.lang.Override + public SpellweaverHelixImprintEffect copy() { + return new SpellweaverHelixImprintEffect(this); + } + + @java.lang.Override + public boolean apply(Game game, Ability source) { + Player controller = game.getPlayer(source.getControllerId()); + if (controller != null) { + Permanent sourcePermanent = game.getPermanent(source.getSourceId()); + for (UUID targetId : this.getTargetPointer().getTargets(game, source)) { + Card card = game.getCard(targetId); + if (card != null) { + controller.moveCardsToExile(card, source, game, true, CardUtil.getExileZoneId(game, source.getSourceId(), source.getSourceObjectZoneChangeCounter()), source.getSourceObject(game).getIdName()); + if (sourcePermanent != null) { + sourcePermanent.imprint(targetId, game); + } + } + } + return true; + } + return false; + } +} + +class SpellweaverHelixTriggeredAbility extends TriggeredAbilityImpl { + + SpellweaverHelixTriggeredAbility() { + super(Zone.BATTLEFIELD, new SpellweaverHelixCastEffect(), false); + } + + SpellweaverHelixTriggeredAbility(final SpellweaverHelixTriggeredAbility ability) { + super(ability); + } + + @java.lang.Override + public SpellweaverHelixTriggeredAbility copy() { + return new SpellweaverHelixTriggeredAbility(this); + } + + @java.lang.Override + public boolean checkEventType(GameEvent event, Game game) { + return event.getType() == GameEvent.EventType.SPELL_CAST; + } + + @java.lang.Override + public boolean checkTrigger(GameEvent event, Game game) { + Spell spell = game.getStack().getSpell(event.getTargetId()); + if (spell != null && spell.getCard() != null && !spell.getCard().isCopy()) { + for (Effect effect : this.getEffects()) { + effect.setTargetPointer(new FixedTarget(spell.getId())); + } + return true; + } + return false; + } + + @java.lang.Override + public boolean checkInterveningIfClause(Game game) { + Spell spell = game.getStack().getSpell(this.getEffects().get(0).getTargetPointer().getFirst(game, this)); + if (spell != null) { + String spellName = spell.getName(); + Permanent sourcePermanent = game.getPermanent(this.getSourceId()); + if (sourcePermanent != null) { + for (UUID imprintId : sourcePermanent.getImprinted()) { + Card card = game.getCard(imprintId); + if (card != null && card.getName().equals(spellName)) { + ((SpellweaverHelixCastEffect) this.getEffects().get(0)).setSpellName(spellName); + return true; + } + } + } + } + return false; + } + + @java.lang.Override + public String getRule() { + return "Whenever a player casts a card, if it has the same name as one of the cards exiled with Spellweaver Helix, you may copy the other. If you do, you may cast the copy without paying its mana cost."; + } +} + +class SpellweaverHelixCastEffect extends OneShotEffect { + + private String spellName = ""; + + SpellweaverHelixCastEffect() { + super(Outcome.Benefit); + this.staticText = "you may copy the other. If you do, you may cast the copy without paying its mana cost"; + } + + SpellweaverHelixCastEffect(final SpellweaverHelixCastEffect effect) { + super(effect); + this.spellName = effect.spellName; + } + + @java.lang.Override + public SpellweaverHelixCastEffect copy() { + return new SpellweaverHelixCastEffect(this); + } + + public void setSpellName(String spellName) { + this.spellName = spellName; + } + + @java.lang.Override + public boolean apply(Game game, Ability source) { + Player controller = game.getPlayer(source.getControllerId()); + if (controller != null) { + Permanent sourcePermanent = game.getPermanentOrLKIBattlefield(source.getSourceId()); + if (sourcePermanent != null) { + boolean foundSpellWithSameName = false; + for (UUID imprintId : sourcePermanent.getImprinted()) { + Card card = game.getCard(imprintId); + if (card != null) { + if (!foundSpellWithSameName && card.getName().equals(spellName)) { + foundSpellWithSameName = true; + } + else { + if (controller.chooseUse(Outcome.Copy, "Copy " + card.getIdName(), source, game)) { + Card copy = game.copyCard(card, source, source.getControllerId()); + if (controller.chooseUse(Outcome.PlayForFree, "Cast " + copy.getIdName() + " without paying its mana cost?", source, game)) { + controller.cast(copy.getSpellAbility(), game, true); + } + } + } + } + } + } + return true; + } + return false; + } +} diff --git a/Mage.Sets/src/mage/sets/onslaught/WeatheredWayfarer.java b/Mage.Sets/src/mage/sets/onslaught/WeatheredWayfarer.java index 74c9474f8ea..738cd6a0d18 100644 --- a/Mage.Sets/src/mage/sets/onslaught/WeatheredWayfarer.java +++ b/Mage.Sets/src/mage/sets/onslaught/WeatheredWayfarer.java @@ -35,7 +35,7 @@ import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.ActivateIfConditionActivatedAbility; import mage.abilities.condition.Condition; -import mage.abilities.condition.common.OpponentControllsMoreCondition; +import mage.abilities.condition.common.OpponentControlsMoreCondition; import mage.abilities.costs.common.TapSourceCost; import mage.abilities.costs.mana.ManaCostsImpl; import mage.abilities.effects.common.search.SearchLibraryPutInHandEffect; @@ -67,7 +67,7 @@ public class WeatheredWayfarer extends CardImpl { Zone.BATTLEFIELD, new SearchLibraryPutInHandEffect(new TargetCardInLibrary(new FilterLandCard()), true, true), new ManaCostsImpl("{W}"), - new OpponentControllsMoreCondition(new FilterLandPermanent("lands"))); + new OpponentControlsMoreCondition(new FilterLandPermanent("lands"))); ability.addCost(new TapSourceCost()); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/sets/ravnica/ConcertedEffort.java b/Mage.Sets/src/mage/sets/ravnica/ConcertedEffort.java new file mode 100644 index 00000000000..672cfe903ef --- /dev/null +++ b/Mage.Sets/src/mage/sets/ravnica/ConcertedEffort.java @@ -0,0 +1,164 @@ +/* + * 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.ravnica; + +import java.util.UUID; +import mage.abilities.Ability; +import mage.abilities.common.BeginningOfUpkeepTriggeredAbility; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.continuous.GainAbilityAllEffect; +import mage.abilities.keyword.DoubleStrikeAbility; +import mage.abilities.keyword.FearAbility; +import mage.abilities.keyword.FirstStrikeAbility; +import mage.abilities.keyword.FlyingAbility; +import mage.abilities.keyword.LandwalkAbility; +import mage.abilities.keyword.ProtectionAbility; +import mage.abilities.keyword.TrampleAbility; +import mage.abilities.keyword.VigilanceAbility; +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.FilterCreaturePermanent; +import mage.filter.predicate.mageobject.AbilityPredicate; +import mage.game.Game; +import mage.game.permanent.Permanent; + +/** + * + * @author emerald000 + */ +public class ConcertedEffort extends CardImpl { + + public ConcertedEffort(UUID ownerId) { + super(ownerId, 8, "Concerted Effort", Rarity.RARE, new CardType[]{CardType.ENCHANTMENT}, "{2}{W}{W}"); + this.expansionSetCode = "RAV"; + + // At the beginning of each upkeep, creatures you control gain flying until end of turn if a creature you control has flying. The same is true for fear, first strike, double strike, landwalk, protection, trample, and vigilance. + this.addAbility(new BeginningOfUpkeepTriggeredAbility(new ConcertedEffortEffect(), TargetController.ANY, false)); + } + + public ConcertedEffort(final ConcertedEffort card) { + super(card); + } + + @Override + public ConcertedEffort copy() { + return new ConcertedEffort(this); + } +} + +class ConcertedEffortEffect extends OneShotEffect { + + private static final FilterCreaturePermanent filterFlying = new FilterCreaturePermanent(); + private static final FilterCreaturePermanent filterFear = new FilterCreaturePermanent(); + private static final FilterCreaturePermanent filterFirstStrike = new FilterCreaturePermanent(); + private static final FilterCreaturePermanent filterDoubleStrike = new FilterCreaturePermanent(); + private static final FilterCreaturePermanent filterLandwalk = new FilterCreaturePermanent(); + private static final FilterCreaturePermanent filterProtection = new FilterCreaturePermanent(); + private static final FilterCreaturePermanent filterTrample = new FilterCreaturePermanent(); + private static final FilterCreaturePermanent filterVigilance = new FilterCreaturePermanent(); + static { + filterFlying.add(new AbilityPredicate(FlyingAbility.class)); + filterFear.add(new AbilityPredicate(FearAbility.class)); + filterFirstStrike.add(new AbilityPredicate(FirstStrikeAbility.class)); + filterDoubleStrike.add(new AbilityPredicate(DoubleStrikeAbility.class)); + filterLandwalk.add(new AbilityPredicate(LandwalkAbility.class)); + filterProtection.add(new AbilityPredicate(ProtectionAbility.class)); + filterTrample.add(new AbilityPredicate(TrampleAbility.class)); + filterVigilance.add(new AbilityPredicate(VigilanceAbility.class)); + } + + ConcertedEffortEffect() { + super(Outcome.BoostCreature); + this.staticText = "creatures you control gain flying until end of turn if a creature you control has flying. The same is true for fear, first strike, double strike, landwalk, protection, trample, and vigilance"; + } + + ConcertedEffortEffect(final ConcertedEffortEffect effect) { + super(effect); + } + + @Override + public ConcertedEffortEffect copy() { + return new ConcertedEffortEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + // Flying + if (game.getBattlefield().contains(filterFlying, source.getControllerId(), 1, game)) { + game.addEffect(new GainAbilityAllEffect(FlyingAbility.getInstance(), Duration.EndOfTurn), source); + } + + // Fear + if (game.getBattlefield().contains(filterFear, source.getControllerId(), 1, game)) { + game.addEffect(new GainAbilityAllEffect(FearAbility.getInstance(), Duration.EndOfTurn), source); + } + + // First strike + if (game.getBattlefield().contains(filterFirstStrike, source.getControllerId(), 1, game)) { + game.addEffect(new GainAbilityAllEffect(FirstStrikeAbility.getInstance(), Duration.EndOfTurn), source); + } + + // Double strike + if (game.getBattlefield().contains(filterDoubleStrike, source.getControllerId(), 1, game)) { + game.addEffect(new GainAbilityAllEffect(DoubleStrikeAbility.getInstance(), Duration.EndOfTurn), source); + } + + // Landwalk + for (Permanent permanent : game.getBattlefield().getAllActivePermanents(filterLandwalk, source.getControllerId(), game)) { + for (Ability ability : permanent.getAbilities(game)) { + if (ability instanceof LandwalkAbility) { + game.addEffect(new GainAbilityAllEffect(ability, Duration.EndOfTurn), source); + } + } + } + + // Protection + for (Permanent permanent : game.getBattlefield().getAllActivePermanents(filterProtection, source.getControllerId(), game)) { + for (Ability ability : permanent.getAbilities(game)) { + if (ability instanceof ProtectionAbility) { + game.addEffect(new GainAbilityAllEffect(ability, Duration.EndOfTurn), source); + } + } + } + + // Trample + if (game.getBattlefield().contains(filterTrample, source.getControllerId(), 1, game)) { + game.addEffect(new GainAbilityAllEffect(TrampleAbility.getInstance(), Duration.EndOfTurn), source); + } + + // Vigilance + if (game.getBattlefield().contains(filterVigilance, source.getControllerId(), 1, game)) { + game.addEffect(new GainAbilityAllEffect(VigilanceAbility.getInstance(), Duration.EndOfTurn), source); + } + return true; + } +} diff --git a/Mage.Sets/src/mage/sets/shardsofalara/KnightOfTheWhiteOrchid.java b/Mage.Sets/src/mage/sets/shardsofalara/KnightOfTheWhiteOrchid.java index 92a3e4ead30..7cd19df83b1 100644 --- a/Mage.Sets/src/mage/sets/shardsofalara/KnightOfTheWhiteOrchid.java +++ b/Mage.Sets/src/mage/sets/shardsofalara/KnightOfTheWhiteOrchid.java @@ -33,7 +33,7 @@ import mage.constants.CardType; import mage.constants.Rarity; import mage.MageInt; import mage.abilities.common.EntersBattlefieldTriggeredAbility; -import mage.abilities.condition.common.OpponentControllsMoreCondition; +import mage.abilities.condition.common.OpponentControlsMoreCondition; import mage.abilities.decorator.ConditionalTriggeredAbility; import mage.abilities.effects.common.search.SearchLibraryPutInPlayEffect; import mage.abilities.keyword.FirstStrikeAbility; @@ -63,7 +63,7 @@ public class KnightOfTheWhiteOrchid extends CardImpl { // When Knight of the White Orchid enters the battlefield, if an opponent controls more lands than you, you may search your library for a Plains card, put it onto the battlefield, then shuffle your library. this.addAbility(new ConditionalTriggeredAbility( new EntersBattlefieldTriggeredAbility(new SearchLibraryPutInPlayEffect(new TargetCardInLibrary(0, 1, new FilterBySubtypeCard("Plains")), false), true), - new OpponentControllsMoreCondition(new FilterLandPermanent("lands")), + new OpponentControlsMoreCondition(new FilterLandPermanent("lands")), "When {this} enters the battlefield, if an opponent controls more lands than you, you may search your library for a Plains card, put it onto the battlefield, then shuffle your library")); } diff --git a/Mage.Sets/src/mage/sets/torment/ChainerDementiaMaster.java b/Mage.Sets/src/mage/sets/torment/ChainerDementiaMaster.java new file mode 100644 index 00000000000..88929b04b28 --- /dev/null +++ b/Mage.Sets/src/mage/sets/torment/ChainerDementiaMaster.java @@ -0,0 +1,144 @@ +/* + * 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.torment; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.UUID; +import mage.MageInt; +import mage.ObjectColor; +import mage.abilities.Ability; +import mage.abilities.common.LeavesBattlefieldTriggeredAbility; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.costs.common.PayLifeCost; +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.effects.ContinuousEffectImpl; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.ExileAllEffect; +import mage.abilities.effects.common.ReturnFromGraveyardToBattlefieldTargetEffect; +import mage.abilities.effects.common.continuous.BecomesColorTargetEffect; +import mage.abilities.effects.common.continuous.BecomesSubtypeTargetEffect; +import mage.abilities.effects.common.continuous.BoostAllEffect; +import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.Outcome; +import mage.constants.Rarity; +import mage.constants.Zone; +import mage.filter.FilterPermanent; +import mage.filter.common.FilterCreatureCard; +import mage.filter.common.FilterCreaturePermanent; +import mage.filter.predicate.mageobject.SubtypePredicate; +import mage.game.Game; +import mage.game.permanent.Permanent; +import mage.players.Player; +import mage.target.common.TargetCardInGraveyard; +import mage.target.targetpointer.FixedTarget; + +/** + * + * @author emerald000 + */ +public class ChainerDementiaMaster extends CardImpl { + + private static final FilterCreaturePermanent filterCreature = new FilterCreaturePermanent("Nightmare creatures"); + private static final FilterPermanent filterPermanent = new FilterPermanent("Nightmares"); + static { + filterCreature.add(new SubtypePredicate("Nightmare")); + filterPermanent.add(new SubtypePredicate("Nightmare")); + } + + public ChainerDementiaMaster(UUID ownerId) { + super(ownerId, 56, "Chainer, Dementia Master", Rarity.RARE, new CardType[]{CardType.CREATURE}, "{3}{B}{B}"); + this.expansionSetCode = "TOR"; + this.supertype.add("Legendary"); + this.subtype.add("Human"); + this.subtype.add("Minion"); + this.power = new MageInt(3); + this.toughness = new MageInt(3); + + // Nightmare creatures get +1/+1. + this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new BoostAllEffect(1, 1, Duration.WhileOnBattlefield, filterCreature, false))); + + // {B}{B}{B}, Pay 3 life: Put target creature card from a graveyard onto the battlefield under your control. That creature is black and is a Nightmare in addition to its other creature types. + Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new ChainerDementiaMasterEffect(), new ManaCostsImpl<>("{B}{B}{B}")); + ability.addCost(new PayLifeCost(3)); + ability.addTarget(new TargetCardInGraveyard(new FilterCreatureCard("creature card from a graveyard"))); + this.addAbility(ability); + + // When Chainer, Dementia Master leaves the battlefield, exile all Nightmares. + this.addAbility(new LeavesBattlefieldTriggeredAbility(new ExileAllEffect(filterPermanent), false)); + } + + public ChainerDementiaMaster(final ChainerDementiaMaster card) { + super(card); + } + + @Override + public ChainerDementiaMaster copy() { + return new ChainerDementiaMaster(this); + } +} + +class ChainerDementiaMasterEffect extends OneShotEffect { + + ChainerDementiaMasterEffect() { + super(Outcome.PutCreatureInPlay); + this.staticText = "Put target creature card from a graveyard onto the battlefield under your control. That creature is black and is a Nightmare in addition to its other creature types"; + } + + ChainerDementiaMasterEffect(final ChainerDementiaMasterEffect effect) { + super(effect); + } + + @Override + public ChainerDementiaMasterEffect copy() { + return new ChainerDementiaMasterEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player controller = game.getPlayer(source.getControllerId()); + if (controller != null) { + UUID cardId = this.getTargetPointer().getFirst(game, source); + new ReturnFromGraveyardToBattlefieldTargetEffect().apply(game, source); + Permanent permanent = game.getPermanent(cardId); + if (permanent != null) { + ContinuousEffectImpl effect = new BecomesColorTargetEffect(ObjectColor.BLACK, Duration.WhileOnBattlefield); + effect.setTargetPointer(new FixedTarget(permanent, game)); + game.addEffect(effect, source); + effect = new BecomesSubtypeTargetEffect(Duration.WhileOnBattlefield, new ArrayList<>(Arrays.asList("Nightmare")), false); + effect.setTargetPointer(new FixedTarget(permanent, game)); + game.addEffect(effect, source); + } + return true; + } + return false; + } +} diff --git a/Mage.Sets/src/mage/sets/visions/Tithe.java b/Mage.Sets/src/mage/sets/visions/Tithe.java new file mode 100644 index 00000000000..dd0563cc515 --- /dev/null +++ b/Mage.Sets/src/mage/sets/visions/Tithe.java @@ -0,0 +1,98 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.sets.visions; + +import java.util.UUID; +import mage.abilities.Ability; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.search.SearchLibraryPutInHandEffect; +import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.Outcome; +import mage.constants.Rarity; +import mage.filter.FilterCard; +import mage.filter.common.FilterLandPermanent; +import mage.filter.predicate.mageobject.SubtypePredicate; +import mage.game.Game; +import mage.target.common.TargetCardInLibrary; +import mage.target.common.TargetOpponent; + +/** + * + * @author emerald000 + */ +public class Tithe extends CardImpl { + + public Tithe(UUID ownerId) { + super(ownerId, 84, "Tithe", Rarity.RARE, new CardType[]{CardType.INSTANT}, "{W}"); + this.expansionSetCode = "VIS"; + + // Search your library for a Plains card. If target opponent controls more lands than you, you may search your library for an additional Plains card. Reveal those cards and put them into your hand. Then shuffle your library. + this.getSpellAbility().addEffect(new TitheEffect()); + this.getSpellAbility().addTarget(new TargetOpponent()); + } + + public Tithe(final Tithe card) { + super(card); + } + + @Override + public Tithe copy() { + return new Tithe(this); + } +} + +class TitheEffect extends OneShotEffect { + + private static final FilterCard filter = new FilterCard("Plains"); + static { + filter.add(new SubtypePredicate("Plains")); + } + + TitheEffect() { + super(Outcome.Benefit); + this.staticText = "Search your library for a Plains card. If target opponent controls more lands than you, you may search your library for an additional Plains card. Reveal those cards and put them into your hand. Then shuffle your library"; + } + + TitheEffect(final TitheEffect effect) { + super(effect); + } + + @Override + public TitheEffect copy() { + return new TitheEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + int numYourLands = game.getBattlefield().countAll(new FilterLandPermanent(), source.getControllerId(), game); + int numOpponentLands = game.getBattlefield().countAll(new FilterLandPermanent(), this.getTargetPointer().getFirst(game, source), game); + new SearchLibraryPutInHandEffect(new TargetCardInLibrary(0, (numOpponentLands > numYourLands ? 2 : 1), filter), true).apply(game, source); + return true; + } +} diff --git a/Mage/src/mage/abilities/condition/common/OpponentControllsMoreCondition.java b/Mage/src/mage/abilities/condition/common/OpponentControlsMoreCondition.java similarity index 92% rename from Mage/src/mage/abilities/condition/common/OpponentControllsMoreCondition.java rename to Mage/src/mage/abilities/condition/common/OpponentControlsMoreCondition.java index 8a8183af340..f4a0ccc106e 100644 --- a/Mage/src/mage/abilities/condition/common/OpponentControllsMoreCondition.java +++ b/Mage/src/mage/abilities/condition/common/OpponentControlsMoreCondition.java @@ -39,11 +39,11 @@ import mage.game.Game; * @author LevelX2 */ -public class OpponentControllsMoreCondition implements Condition { +public class OpponentControlsMoreCondition implements Condition { private final FilterPermanent filter; - public OpponentControllsMoreCondition(FilterPermanent filter) { + public OpponentControlsMoreCondition(FilterPermanent filter) { this.filter = filter; } diff --git a/Mage/src/mage/abilities/keyword/CumulativeUpkeepAbility.java b/Mage/src/mage/abilities/keyword/CumulativeUpkeepAbility.java index 199c8536108..4077074fa77 100644 --- a/Mage/src/mage/abilities/keyword/CumulativeUpkeepAbility.java +++ b/Mage/src/mage/abilities/keyword/CumulativeUpkeepAbility.java @@ -25,8 +25,6 @@ * authors and should not be interpreted as representing official policies, either expressed * or implied, of BetaSteward_at_googlemail.com. */ - - package mage.abilities.keyword; import mage.abilities.Ability; @@ -41,6 +39,8 @@ import mage.constants.Outcome; import mage.constants.TargetController; import mage.counters.CounterType; import mage.game.Game; +import mage.game.events.GameEvent; +import mage.game.events.GameEvent.EventType; import mage.game.permanent.Permanent; import mage.players.Player; @@ -48,12 +48,10 @@ import mage.players.Player; * * @author Plopman */ - - public class CumulativeUpkeepAbility extends BeginningOfUpkeepTriggeredAbility { - + private Cost cumulativeCost; - + public CumulativeUpkeepAbility(Cost cumulativeCost) { super(new AddCountersSourceEffect(CounterType.AGE.createInstance()), TargetController.YOU, false); this.addEffect(new CumulativeUpkeepEffect(cumulativeCost)); @@ -82,9 +80,9 @@ public class CumulativeUpkeepAbility extends BeginningOfUpkeepTriggeredAbility { } class CumulativeUpkeepEffect extends OneShotEffect { - - private Cost cumulativeCost; - + + private final Cost cumulativeCost; + CumulativeUpkeepEffect(Cost cumulativeCost) { super(Outcome.Sacrifice); this.cumulativeCost = cumulativeCost; @@ -95,46 +93,44 @@ class CumulativeUpkeepEffect extends OneShotEffect { this.cumulativeCost = effect.cumulativeCost.copy(); } - @Override public boolean apply(Game game, Ability source) { Player player = game.getPlayer(source.getControllerId()); Permanent permanent = game.getPermanent(source.getSourceId()); - if (player != null && permanent != null) { + if (player != null && permanent != null) { int ageCounter = permanent.getCounters().getCount(CounterType.AGE); - if(cumulativeCost instanceof ManaCost){ - ManaCostsImpl totalCost = new ManaCostsImpl(); - for(int i = 0 ; i < ageCounter; i++){ + if (cumulativeCost instanceof ManaCost) { + ManaCostsImpl totalCost = new ManaCostsImpl<>(); + for (int i = 0; i < ageCounter; i++) { totalCost.add((ManaCost) cumulativeCost.copy()); } if (player.chooseUse(Outcome.Benefit, "Pay " + totalCost.getText() + "?", source, game)) { totalCost.clearPaid(); - if (totalCost.payOrRollback(source, game, source.getSourceId(), source.getControllerId())){ + if (totalCost.payOrRollback(source, game, source.getSourceId(), source.getControllerId())) { return true; } } + game.fireEvent(new GameEvent(EventType.DIDNT_PAY_CUMULATIVE_UPKEEP, permanent.getId(), permanent.getId(), player.getId(), ageCounter, false)); permanent.sacrifice(source.getSourceId(), game); - return true; - } - else{ - CostsImpl totalCost = new CostsImpl(); - for(int i = 0 ; i < ageCounter; i++){ + return true; + } else { + CostsImpl totalCost = new CostsImpl<>(); + for (int i = 0; i < ageCounter; i++) { totalCost.add(cumulativeCost.copy()); } if (player.chooseUse(Outcome.Benefit, totalCost.getText() + "?", source, game)) { totalCost.clearPaid(); int bookmark = game.bookmarkState(); - if (totalCost.pay(source, game, source.getSourceId(), source.getControllerId(), false)){ + if (totalCost.pay(source, game, source.getSourceId(), source.getControllerId(), false)) { return true; - } - else{ + } else { game.restoreState(bookmark, source.getRule()); } } + game.fireEvent(new GameEvent(EventType.DIDNT_PAY_CUMULATIVE_UPKEEP, permanent.getId(), permanent.getId(), player.getId(), ageCounter, false)); permanent.sacrifice(source.getSourceId(), game); - return true; + return true; } - } return false; } diff --git a/Mage/src/mage/game/events/GameEvent.java b/Mage/src/mage/game/events/GameEvent.java index 93d4cef0249..a6909fe7293 100644 --- a/Mage/src/mage/game/events/GameEvent.java +++ b/Mage/src/mage/game/events/GameEvent.java @@ -185,6 +185,7 @@ public class GameEvent implements Serializable { ENCHANT_PLAYER, ENCHANTED_PLAYER, CAN_TAKE_MULLIGAN, FLIP_COIN, COIN_FLIPPED, SCRY, FATESEAL, + DIDNT_PAY_CUMULATIVE_UPKEEP, //permanent events ENTERS_THE_BATTLEFIELD, TAP, TAPPED, TAPPED_FOR_MANA, @@ -241,7 +242,6 @@ public class GameEvent implements Serializable { //combat events COMBAT_DAMAGE_APPLIED, SELECTED_ATTACKER, SELECTED_BLOCKER; - } public GameEvent(EventType type, UUID targetId, UUID sourceId, UUID playerId) { From 87078057e0bf025c078818950adf17ca18c482fe Mon Sep 17 00:00:00 2001 From: LevelX2 Date: Sun, 4 Oct 2015 09:45:22 +0200 Subject: [PATCH 010/268] * Some fixed to cards submitted by BursegSardaukar. --- .../mage/sets/archenemy/SkirkCommando.java | 55 ++++++++---------- .../src/mage/sets/guildpact/RabbleRouser.java | 14 ++--- .../src/mage/sets/iceage/GoblinSnowman.java | 24 +++++--- .../src/mage/sets/iceage/TinderWall.java | 36 +----------- .../mage/sets/lorwyn/BoggartSpriteChaser.java | 22 ++++---- .../src/mage/sets/lorwyn/FodderLaunch.java | 56 ++----------------- .../mage/sets/lorwyn/QuillSlingerBoggart.java | 2 +- .../mage/sets/planarchaos/FirefrightMage.java | 17 +++--- .../mage/sets/ravnica/GoblinFireFiend.java | 13 ++--- .../src/mage/sets/tempest/MoggSquad.java | 8 +-- .../CantBeBlockedByAllTargetEffect.java | 51 +++++++++++++++++ 11 files changed, 131 insertions(+), 167 deletions(-) create mode 100644 Mage/src/mage/abilities/effects/common/combat/CantBeBlockedByAllTargetEffect.java diff --git a/Mage.Sets/src/mage/sets/archenemy/SkirkCommando.java b/Mage.Sets/src/mage/sets/archenemy/SkirkCommando.java index d995faa763d..a97f8981cb5 100644 --- a/Mage.Sets/src/mage/sets/archenemy/SkirkCommando.java +++ b/Mage.Sets/src/mage/sets/archenemy/SkirkCommando.java @@ -28,21 +28,18 @@ package mage.sets.archenemy; import java.util.UUID; - -import mage.constants.CardType; -import mage.constants.Rarity; import mage.MageInt; -import mage.abilities.Ability; import mage.abilities.common.DealsCombatDamageToAPlayerTriggeredAbility; import mage.abilities.costs.mana.ManaCostsImpl; -import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.DamageTargetEffect; import mage.abilities.keyword.MorphAbility; import mage.cards.CardImpl; -import mage.constants.Outcome; +import mage.constants.CardType; +import mage.constants.Rarity; import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.permanent.ControllerIdPredicate; import mage.game.Game; -import mage.players.Player; +import mage.game.events.GameEvent; import mage.target.common.TargetCreaturePermanent; /** @@ -50,7 +47,7 @@ import mage.target.common.TargetCreaturePermanent; * @author BursegSardaukar */ public class SkirkCommando extends CardImpl { - + public SkirkCommando(UUID ownerId) { super(ownerId, 47, "Skirk Commando", Rarity.COMMON, new CardType[]{CardType.CREATURE}, "{1}{R}{R}"); this.expansionSetCode = "ARC"; @@ -59,13 +56,13 @@ public class SkirkCommando extends CardImpl { this.power = new MageInt(2); this.toughness = new MageInt(1); - + //Whenever Skirk Commando deals combat damage to a player, you may have it deal 2 damage to target creature that player controls. - this.addAbility(new DealsCombatDamageToAPlayerTriggeredAbility(new SkirkCommandoEffect(), true, true)); - + this.addAbility(new SkirkCommandoTriggeredAbility()); + //Morph {2}{R} (You may cast this card face down as a 2/2 creature for 3. Turn it face up any time for its morph cost.) this.addAbility(new MorphAbility(this, new ManaCostsImpl("{2}{R}"))); - + } public SkirkCommando(final SkirkCommando card) { @@ -78,37 +75,29 @@ public class SkirkCommando extends CardImpl { } } -class SkirkCommandoEffect extends OneShotEffect { +class SkirkCommandoTriggeredAbility extends DealsCombatDamageToAPlayerTriggeredAbility { + + public SkirkCommandoTriggeredAbility() { + super(new DamageTargetEffect(2), true, false); - public SkirkCommandoEffect() { - super(Outcome.Damage); - staticText = "have it deal 2 damage to target creature that player controls"; } - public SkirkCommandoEffect(final SkirkCommandoEffect effect) { - super(effect); + public SkirkCommandoTriggeredAbility(SkirkCommandoTriggeredAbility ability) { + super(ability); } @Override - public boolean apply(Game game, Ability source) { - Player player = game.getPlayer(targetPointer.getFirst(game, source)); - if (player != null) { - FilterCreaturePermanent filter = new FilterCreaturePermanent("creature " + player.getLogName() + " controls"); - filter.add(new ControllerIdPredicate(player.getId())); - TargetCreaturePermanent target = new TargetCreaturePermanent(filter); - if (target.canChoose(source.getControllerId(), game) && target.choose(Outcome.Damage, source.getControllerId(), source.getSourceId(), game)) { - UUID creature = target.getFirstTarget(); - if (creature != null) { - game.getPermanent(creature).damage(2, source.getSourceId(), game, false, true); - return true; - } - } + public boolean checkTrigger(GameEvent event, Game game) { + if (super.checkTrigger(event, game)) { + FilterCreaturePermanent filter = new FilterCreaturePermanent("creature that player controls"); + filter.add(new ControllerIdPredicate(event.getPlayerId())); + addTarget(new TargetCreaturePermanent(filter)); } return false; } @Override - public SkirkCommandoEffect copy() { - return new SkirkCommandoEffect(this); + public SkirkCommandoTriggeredAbility copy() { + return new SkirkCommandoTriggeredAbility(this); } } diff --git a/Mage.Sets/src/mage/sets/guildpact/RabbleRouser.java b/Mage.Sets/src/mage/sets/guildpact/RabbleRouser.java index aafc1493d0e..fc935905f7c 100644 --- a/Mage.Sets/src/mage/sets/guildpact/RabbleRouser.java +++ b/Mage.Sets/src/mage/sets/guildpact/RabbleRouser.java @@ -28,9 +28,6 @@ package mage.sets.guildpact; import java.util.UUID; - -import mage.constants.CardType; -import mage.constants.Rarity; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.SimpleActivatedAbility; @@ -42,7 +39,9 @@ import mage.abilities.dynamicvalue.common.StaticValue; import mage.abilities.effects.common.continuous.BoostAllEffect; import mage.abilities.keyword.BloodthirstAbility; import mage.cards.CardImpl; +import mage.constants.CardType; import mage.constants.Duration; +import mage.constants.Rarity; import mage.constants.Zone; import mage.filter.common.FilterAttackingCreature; @@ -51,9 +50,7 @@ import mage.filter.common.FilterAttackingCreature; * @author BursegSardaukar */ public class RabbleRouser extends CardImpl { - - final static private String rule = "Attacking creatures get +X/+0 until end of turn, where X is Rabble-Rouser's power."; - + public RabbleRouser(UUID ownerId) { super(ownerId, 73, "Rabble-Rouser", Rarity.UNCOMMON, new CardType[]{CardType.CREATURE}, "{3}{R}"); this.expansionSetCode = "GPT"; @@ -68,7 +65,10 @@ public class RabbleRouser extends CardImpl { //{R}, {T}: Attacking creatures get +X/+0 until end of turn, where X is Rabble-Rouser's power. DynamicValue amount = new SourcePermanentPowerCount(); - Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new BoostAllEffect(amount, new StaticValue(0), Duration.EndOfTurn, new FilterAttackingCreature(), false, rule), new ManaCostsImpl("{R}")); + Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, + new BoostAllEffect(amount, new StaticValue(0), Duration.EndOfTurn, new FilterAttackingCreature(), false, + "Attacking creatures get +X/+0 until end of turn, where X is {this}'s power"), + new ManaCostsImpl("{R}")); ability.addCost(new TapSourceCost()); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/sets/iceage/GoblinSnowman.java b/Mage.Sets/src/mage/sets/iceage/GoblinSnowman.java index 9fb3b18c09d..775512bd9a4 100644 --- a/Mage.Sets/src/mage/sets/iceage/GoblinSnowman.java +++ b/Mage.Sets/src/mage/sets/iceage/GoblinSnowman.java @@ -28,21 +28,22 @@ package mage.sets.iceage; import java.util.UUID; - -import mage.constants.CardType; -import mage.constants.Rarity; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.BlocksTriggeredAbility; import mage.abilities.common.SimpleActivatedAbility; import mage.abilities.costs.common.TapSourceCost; +import mage.abilities.effects.Effect; import mage.abilities.effects.common.DamageTargetEffect; import mage.abilities.effects.common.PreventCombatDamageBySourceEffect; import mage.abilities.effects.common.PreventCombatDamageToSourceEffect; import mage.cards.CardImpl; +import mage.constants.CardType; import mage.constants.Duration; +import mage.constants.Rarity; import mage.constants.Zone; import mage.filter.common.FilterAttackingCreature; +import mage.filter.predicate.permanent.BlockedByIdPredicate; import mage.target.common.TargetCreaturePermanent; /** @@ -60,15 +61,20 @@ public class GoblinSnowman extends CardImpl { this.toughness = new MageInt(1); //Whenever Goblin Snowman blocks, prevent all combat damage that would be dealt to and dealt by it this turn. - this.addAbility(new BlocksTriggeredAbility(new PreventCombatDamageBySourceEffect(Duration.EndOfTurn), false)); - this.addAbility(new BlocksTriggeredAbility(new PreventCombatDamageToSourceEffect(Duration.EndOfTurn), false)); - + Effect effect = new PreventCombatDamageBySourceEffect(Duration.EndOfTurn); + effect.setText("prevent all combat damage that would be dealt to"); + Ability ability = new BlocksTriggeredAbility(effect, false); + effect = new PreventCombatDamageToSourceEffect(Duration.EndOfTurn); + effect.setText("and dealt by it this turn"); + ability.addEffect(effect); + this.addAbility(ability); + //{T}: Goblin Snowman deals 1 damage to target creature it's blocking. FilterAttackingCreature filter = new FilterAttackingCreature("creature it's blocking"); - filter.add(new BlockingByPredicate(this.getId())); - Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new DamageTargetEffect(1), new TapSourceCost()); + filter.add(new BlockedByIdPredicate(this.getId())); + ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new DamageTargetEffect(1), new TapSourceCost()); ability.addTarget(new TargetCreaturePermanent(filter)); - this.addAbility(ability, new BlockedByWatcher()); + this.addAbility(ability); } public GoblinSnowman(final GoblinSnowman card) { diff --git a/Mage.Sets/src/mage/sets/iceage/TinderWall.java b/Mage.Sets/src/mage/sets/iceage/TinderWall.java index 5ee8dc535c8..048387e2942 100644 --- a/Mage.Sets/src/mage/sets/iceage/TinderWall.java +++ b/Mage.Sets/src/mage/sets/iceage/TinderWall.java @@ -43,16 +43,15 @@ import mage.cards.CardImpl; import mage.constants.WatcherScope; import mage.constants.Zone; import mage.filter.common.FilterAttackingCreature; -import mage.filter.predicate.Predicate; import mage.game.Game; import mage.game.events.GameEvent; -import mage.game.permanent.Permanent; import mage.target.common.TargetCreaturePermanent; import mage.watchers.Watcher; import java.util.ArrayList; import java.util.List; import java.util.UUID; +import mage.filter.predicate.permanent.BlockedByIdPredicate; /** * @@ -75,7 +74,7 @@ public class TinderWall extends CardImpl { this.addAbility(new SimpleManaAbility(Zone.BATTLEFIELD, new BasicManaEffect(Mana.RedMana(2)), new SacrificeSourceCost())); // {R}, Sacrifice Tinder Wall: Tinder Wall deals 2 damage to target creature it's blocking. FilterAttackingCreature filter = new FilterAttackingCreature("creature it's blocking"); - filter.add(new BlockingByPredicate(this.getId())); + filter.add(new BlockedByIdPredicate(this.getId())); Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new DamageTargetEffect(2), new ManaCostsImpl("{R}")); ability.addTarget(new TargetCreaturePermanent(filter)); ability.addCost(new SacrificeSourceCost()); @@ -92,10 +91,9 @@ public class TinderWall extends CardImpl { } } - class BlockedByWatcher extends Watcher { - public List blockedByWatcher = new ArrayList(); + public List blockedByWatcher = new ArrayList<>(); public BlockedByWatcher() { super("BlockedByWatcher", WatcherScope.CARD); @@ -127,31 +125,3 @@ class BlockedByWatcher extends Watcher { } } - -class BlockingByPredicate implements Predicate { - - private UUID source; - - public BlockingByPredicate(UUID source) { - this.source = source; - } - - @Override - public boolean apply(Permanent input, Game game) { - BlockedByWatcher watcher = (BlockedByWatcher) game.getState().getWatchers().get("BlockedByWatcher", source); - - for(UUID uuid :watcher.blockedByWatcher){ - Permanent creature = game.getPermanent(uuid); - if(creature != null && creature.getId().equals(input.getId())){ - return true; - } - } - return false; - - } - - @Override - public String toString() { - return "creature it's blocking"; - } -} \ No newline at end of file diff --git a/Mage.Sets/src/mage/sets/lorwyn/BoggartSpriteChaser.java b/Mage.Sets/src/mage/sets/lorwyn/BoggartSpriteChaser.java index 9d6b6e441b8..22c0d5a9e62 100644 --- a/Mage.Sets/src/mage/sets/lorwyn/BoggartSpriteChaser.java +++ b/Mage.Sets/src/mage/sets/lorwyn/BoggartSpriteChaser.java @@ -29,9 +29,11 @@ package mage.sets.lorwyn; import java.util.UUID; import mage.MageInt; +import mage.abilities.Ability; import mage.abilities.common.SimpleStaticAbility; import mage.abilities.condition.common.PermanentsOnTheBattlefieldCondition; import mage.abilities.decorator.ConditionalContinuousEffect; +import mage.abilities.effects.Effect; import mage.abilities.effects.common.continuous.BoostSourceWhileControlsEffect; import mage.abilities.effects.common.continuous.GainAbilitySourceEffect; import mage.abilities.keyword.FlyingAbility; @@ -41,7 +43,6 @@ import mage.constants.Duration; import mage.constants.Rarity; import mage.constants.Zone; import mage.filter.FilterPermanent; -import mage.filter.predicate.mageobject.SubtypePredicate; /** * @@ -49,14 +50,6 @@ import mage.filter.predicate.mageobject.SubtypePredicate; */ public class BoggartSpriteChaser extends CardImpl { - final static private String rule = "{this} has flying as long as you control a Faerie"; - - private static final FilterPermanent filter = new FilterPermanent("Faerie"); - - static { - filter.add(new SubtypePredicate("Faerie")); - } - public BoggartSpriteChaser(UUID ownerId) { super(ownerId, 156, "Boggart Sprite-Chaser", Rarity.COMMON, new CardType[]{CardType.CREATURE}, "{1}{R}"); this.expansionSetCode = "LRW"; @@ -67,8 +60,15 @@ public class BoggartSpriteChaser extends CardImpl { this.toughness = new MageInt(2); // As long as you control a Faerie, Boggart Sprite-Chaser gets +1/+1 and has flying. - this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new BoostSourceWhileControlsEffect(filter, 1, 1))); - this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new ConditionalContinuousEffect(new GainAbilitySourceEffect(FlyingAbility.getInstance(), Duration.WhileOnBattlefield), new PermanentsOnTheBattlefieldCondition(filter), rule))); + FilterPermanent filter = new FilterPermanent("Faerie", "Faerie"); + Effect effect = new BoostSourceWhileControlsEffect(filter, 1, 1); + effect.setText("As long as you control a Faerie, {this} gets +1/+1"); + Ability ability = new SimpleStaticAbility(Zone.BATTLEFIELD, effect); + ability.addEffect(new ConditionalContinuousEffect( + new GainAbilitySourceEffect(FlyingAbility.getInstance(), Duration.WhileOnBattlefield), + new PermanentsOnTheBattlefieldCondition(filter), "and has flying")); + this.addAbility(ability); + } public BoggartSpriteChaser(final BoggartSpriteChaser card) { diff --git a/Mage.Sets/src/mage/sets/lorwyn/FodderLaunch.java b/Mage.Sets/src/mage/sets/lorwyn/FodderLaunch.java index d8d8cbebbcb..5fbf233ad1c 100644 --- a/Mage.Sets/src/mage/sets/lorwyn/FodderLaunch.java +++ b/Mage.Sets/src/mage/sets/lorwyn/FodderLaunch.java @@ -25,26 +25,18 @@ * authors and should not be interpreted as representing official policies, either expressed * or implied, of BetaSteward_at_googlemail.com. */ - package mage.sets.lorwyn; import java.util.UUID; -import mage.MageObject; -import mage.abilities.Ability; import mage.constants.CardType; import mage.constants.Rarity; import mage.abilities.costs.common.SacrificeTargetCost; -import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.DamageTargetControllerEffect; import mage.abilities.effects.common.continuous.BoostTargetEffect; import mage.cards.CardImpl; import mage.constants.Duration; -import mage.constants.Outcome; import mage.filter.common.FilterControlledCreaturePermanent; -import mage.filter.predicate.mageobject.SubtypePredicate; -import mage.game.Game; -import mage.game.permanent.Permanent; -import mage.players.Player; import mage.target.common.TargetControlledCreaturePermanent; import mage.target.common.TargetCreaturePermanent; @@ -53,24 +45,18 @@ import mage.target.common.TargetCreaturePermanent; */ public class FodderLaunch extends CardImpl { - private static final FilterControlledCreaturePermanent filter = new FilterControlledCreaturePermanent("a Goblin"); - - static { - filter.add(new SubtypePredicate("Goblin")); - } - public FodderLaunch(UUID ownerId) { super(ownerId, 114, "Fodder Launch", Rarity.UNCOMMON, new CardType[]{CardType.SORCERY}, "{3}{B}"); this.expansionSetCode = "LRW"; this.subtype.add("Goblin"); - + //As an additional cost to cast Fodder Launch, sacrifice a Goblin. - this.getSpellAbility().addCost(new SacrificeTargetCost(new TargetControlledCreaturePermanent(1, 1, filter, false))); - + this.getSpellAbility().addCost(new SacrificeTargetCost(new TargetControlledCreaturePermanent(1, 1, new FilterControlledCreaturePermanent("Goblin", "a Goblin"), true))); + //Target creature gets -5/-5 until end of turn. Fodder Launch deals 5 damage to that creature's controller. this.getSpellAbility().addEffect(new BoostTargetEffect(-5, -5, Duration.EndOfTurn)); this.getSpellAbility().addTarget(new TargetCreaturePermanent()); - this.getSpellAbility().addEffect(new FodderLaunchEffect()); + this.getSpellAbility().addEffect(new DamageTargetControllerEffect(5)); } public FodderLaunch(final FodderLaunch card) { @@ -83,35 +69,3 @@ public class FodderLaunch extends CardImpl { } } - -class FodderLaunchEffect extends OneShotEffect { - - public FodderLaunchEffect() { - super(Outcome.Damage); - this.staticText = "Target creature gets -5/-5 until end of turn. Fodder Launch deals 5 damage to that creature's controller."; - } - - public FodderLaunchEffect(final FodderLaunchEffect effect) { - super(effect); - } - - @Override - public FodderLaunchEffect copy() { - return new FodderLaunchEffect(this); - } - - @Override - public boolean apply(Game game, Ability source) { - Player controller = game.getPlayer(source.getControllerId()); - MageObject sourceObject = game.getObject(source.getSourceId()); - if (controller != null && sourceObject != null) { - Permanent targetCreature = game.getPermanent(getTargetPointer().getFirst(game, source)); - if (targetCreature != null) { - Player controllerOfTargetCreature = game.getPlayer(targetCreature.getControllerId()); - controllerOfTargetCreature.damage(5, source.getSourceId(), game, false, true); - return true; - } - } - return false; - } -} \ No newline at end of file diff --git a/Mage.Sets/src/mage/sets/lorwyn/QuillSlingerBoggart.java b/Mage.Sets/src/mage/sets/lorwyn/QuillSlingerBoggart.java index 513bf353a4a..cdb736215b6 100644 --- a/Mage.Sets/src/mage/sets/lorwyn/QuillSlingerBoggart.java +++ b/Mage.Sets/src/mage/sets/lorwyn/QuillSlingerBoggart.java @@ -61,7 +61,7 @@ public class QuillSlingerBoggart extends CardImpl { this.toughness = new MageInt(2); // Whenever a player casts a Kithkin spell, you may have target player lose 1 life. - Ability ability = new SpellCastAllTriggeredAbility(new LoseLifeTargetEffect(2), filter, true); + Ability ability = new SpellCastAllTriggeredAbility(new LoseLifeTargetEffect(1), filter, true); ability.addTarget(new TargetPlayer()); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/sets/planarchaos/FirefrightMage.java b/Mage.Sets/src/mage/sets/planarchaos/FirefrightMage.java index 741bfabb0a8..729e237799c 100644 --- a/Mage.Sets/src/mage/sets/planarchaos/FirefrightMage.java +++ b/Mage.Sets/src/mage/sets/planarchaos/FirefrightMage.java @@ -28,21 +28,18 @@ package mage.sets.planarchaos; import java.util.UUID; - -import mage.constants.CardType; -import mage.constants.Rarity; import mage.MageInt; import mage.ObjectColor; import mage.abilities.Ability; import mage.abilities.common.SimpleActivatedAbility; -import mage.abilities.common.SimpleEvasionAbility; import mage.abilities.costs.common.DiscardCardCost; import mage.abilities.costs.common.TapSourceCost; import mage.abilities.costs.mana.ManaCostsImpl; -import mage.abilities.effects.common.combat.CantBeBlockedByCreaturesSourceEffect; -import mage.abilities.effects.common.continuous.GainAbilityTargetEffect; +import mage.abilities.effects.common.combat.CantBeBlockedByAllTargetEffect; 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; @@ -55,7 +52,7 @@ import mage.target.common.TargetCreaturePermanent; * @author BursegSardaukar */ public class FirefrightMage extends CardImpl { - + private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("except by artifact creatures and/or red creatures"); static { @@ -65,7 +62,7 @@ public class FirefrightMage extends CardImpl { Predicates.and(new CardTypePredicate(CardType.CREATURE), new ColorPredicate(ObjectColor.RED) )))); } - + public FirefrightMage(UUID ownerId) { super(ownerId, 99, "Firefright Mage", Rarity.COMMON, new CardType[]{CardType.CREATURE}, "{R}"); this.expansionSetCode = "PLC"; @@ -75,8 +72,8 @@ public class FirefrightMage extends CardImpl { this.power = new MageInt(1); this.toughness = new MageInt(1); - //{1} {R}, {T}, Discard a card: Target creature can't be blocked this turn except by artifact creatures and/or red creatures. - Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new GainAbilityTargetEffect(new SimpleEvasionAbility(new CantBeBlockedByCreaturesSourceEffect(filter, Duration.EndOfTurn)), Duration.EndOfTurn),new ManaCostsImpl("{1}{R}")); + //{1}{R}, {T}, Discard a card: Target creature can't be blocked this turn except by artifact creatures and/or red creatures. + Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new CantBeBlockedByAllTargetEffect(filter, Duration.EndOfTurn), new ManaCostsImpl("{1}{R}")); ability.addCost(new TapSourceCost()); ability.addCost(new DiscardCardCost()); ability.addTarget(new TargetCreaturePermanent()); diff --git a/Mage.Sets/src/mage/sets/ravnica/GoblinFireFiend.java b/Mage.Sets/src/mage/sets/ravnica/GoblinFireFiend.java index 053454589d6..1c7d12327e0 100644 --- a/Mage.Sets/src/mage/sets/ravnica/GoblinFireFiend.java +++ b/Mage.Sets/src/mage/sets/ravnica/GoblinFireFiend.java @@ -32,11 +32,9 @@ import java.util.UUID; import mage.constants.CardType; import mage.constants.Rarity; import mage.MageInt; -import mage.abilities.Ability; import mage.abilities.common.SimpleActivatedAbility; import mage.abilities.common.SimpleStaticAbility; import mage.abilities.costs.mana.ManaCostsImpl; -import mage.abilities.dynamicvalue.common.StaticValue; import mage.abilities.effects.common.combat.MustBeBlockedByAtLeastOneSourceEffect; import mage.abilities.effects.common.continuous.BoostSourceEffect; import mage.abilities.keyword.HasteAbility; @@ -49,7 +47,7 @@ import mage.constants.Zone; * @author BursegSardaukar */ public class GoblinFireFiend extends CardImpl { - + public GoblinFireFiend(UUID ownerId) { super(ownerId, 127, "Goblin Fire Fiend", Rarity.COMMON, new CardType[]{CardType.CREATURE}, "{3}{R}"); this.expansionSetCode = "RAV"; @@ -58,16 +56,15 @@ public class GoblinFireFiend extends CardImpl { this.power = new MageInt(1); this.toughness = new MageInt(1); - + //Haste this.addAbility(HasteAbility.getInstance()); - + //Goblin Fire Fiend must be blocked if able. this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new MustBeBlockedByAtLeastOneSourceEffect())); - + //{R}: Goblin Fire Fiend gets +1/+0 until end of turn. - Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new BoostSourceEffect(new StaticValue(1), new StaticValue(0), Duration.EndOfTurn), new ManaCostsImpl("{R}")); - this.addAbility(ability); + this.addAbility(new SimpleActivatedAbility(Zone.BATTLEFIELD, new BoostSourceEffect(1, 0, Duration.EndOfTurn), new ManaCostsImpl("{R}"))); } public GoblinFireFiend(final GoblinFireFiend card) { diff --git a/Mage.Sets/src/mage/sets/tempest/MoggSquad.java b/Mage.Sets/src/mage/sets/tempest/MoggSquad.java index 6188bc20831..1bc3a474e7e 100644 --- a/Mage.Sets/src/mage/sets/tempest/MoggSquad.java +++ b/Mage.Sets/src/mage/sets/tempest/MoggSquad.java @@ -28,9 +28,6 @@ package mage.sets.tempest; import java.util.UUID; - -import mage.constants.CardType; -import mage.constants.Rarity; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.SimpleStaticAbility; @@ -39,7 +36,9 @@ import mage.abilities.dynamicvalue.common.PermanentsOnBattlefieldCount; import mage.abilities.dynamicvalue.common.SignInversionDynamicValue; 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; import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.permanent.AnotherPredicate; @@ -63,7 +62,8 @@ public class MoggSquad extends CardImpl { this.power = new MageInt(3); this.toughness = new MageInt(3); - + + // Mogg Squad gets -1/-1 for each other creature on the battlefield. DynamicValue amount = new SignInversionDynamicValue(new PermanentsOnBattlefieldCount(filter)); Ability ability = new SimpleStaticAbility(Zone.BATTLEFIELD, new BoostSourceEffect(amount, amount, Duration.WhileOnBattlefield)); this.addAbility(ability); diff --git a/Mage/src/mage/abilities/effects/common/combat/CantBeBlockedByAllTargetEffect.java b/Mage/src/mage/abilities/effects/common/combat/CantBeBlockedByAllTargetEffect.java new file mode 100644 index 00000000000..ec697e3ba89 --- /dev/null +++ b/Mage/src/mage/abilities/effects/common/combat/CantBeBlockedByAllTargetEffect.java @@ -0,0 +1,51 @@ +/* + * To change this license header, choose License Headers in Project Properties. + * To change this template file, choose Tools | Templates + * and open the template in the editor. + */ +package mage.abilities.effects.common.combat; + +import mage.abilities.Ability; +import mage.abilities.effects.RestrictionEffect; +import mage.constants.Duration; +import mage.filter.common.FilterCreaturePermanent; +import mage.game.Game; +import mage.game.permanent.Permanent; + +/** + * + * @author LevelX2 + */ +public class CantBeBlockedByAllTargetEffect extends RestrictionEffect { + + private final FilterCreaturePermanent filterBlockedBy; + + public CantBeBlockedByAllTargetEffect(FilterCreaturePermanent filterBlockedBy, Duration duration) { + super(Duration.WhileOnBattlefield); + this.filterBlockedBy = filterBlockedBy; + staticText = "Target creature" + + " can't be blocked " + + (filterBlockedBy.getMessage().startsWith("except by") ? "" : "by ") + + filterBlockedBy.getMessage(); + } + + public CantBeBlockedByAllTargetEffect(final CantBeBlockedByAllTargetEffect effect) { + super(effect); + this.filterBlockedBy = effect.filterBlockedBy; + } + + @Override + public boolean applies(Permanent permanent, Ability source, Game game) { + return getTargetPointer().getTargets(game, source).contains(permanent.getId()); + } + + @Override + public boolean canBeBlocked(Permanent attacker, Permanent blocker, Ability source, Game game) { + return !filterBlockedBy.match(blocker, source.getSourceId(), source.getControllerId(), game); + } + + @Override + public CantBeBlockedByAllTargetEffect copy() { + return new CantBeBlockedByAllTargetEffect(this); + } +} From 8c7dc7b2da3630b6dfec1390854fa2be11631c79 Mon Sep 17 00:00:00 2001 From: LevelX2 Date: Sun, 4 Oct 2015 09:56:47 +0200 Subject: [PATCH 011/268] * Fixed rule text problem of Skirk Commando. --- Mage.Sets/src/mage/sets/archenemy/SkirkCommando.java | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/Mage.Sets/src/mage/sets/archenemy/SkirkCommando.java b/Mage.Sets/src/mage/sets/archenemy/SkirkCommando.java index a97f8981cb5..3dd3c0fc6d5 100644 --- a/Mage.Sets/src/mage/sets/archenemy/SkirkCommando.java +++ b/Mage.Sets/src/mage/sets/archenemy/SkirkCommando.java @@ -79,7 +79,6 @@ class SkirkCommandoTriggeredAbility extends DealsCombatDamageToAPlayerTriggeredA public SkirkCommandoTriggeredAbility() { super(new DamageTargetEffect(2), true, false); - } public SkirkCommandoTriggeredAbility(SkirkCommandoTriggeredAbility ability) { @@ -100,4 +99,9 @@ class SkirkCommandoTriggeredAbility extends DealsCombatDamageToAPlayerTriggeredA public SkirkCommandoTriggeredAbility copy() { return new SkirkCommandoTriggeredAbility(this); } + + @Override + public String getRule() { + return "Whenever {this} deals combat damage to a player, you may have it deal 2 damage to target creature that player controls."; + } } From 3e27d07d0d1611620411706d05de18c744460a4e Mon Sep 17 00:00:00 2001 From: LevelX2 Date: Sun, 4 Oct 2015 10:33:33 +0200 Subject: [PATCH 012/268] Xmage 1.4.4v8 --- Mage.Common/src/mage/utils/MageVersion.java | 2 +- Mage/src/mage/cards/repository/CardRepository.java | 2 +- Utils/release/getting_implemented_cards.txt | 3 +++ 3 files changed, 5 insertions(+), 2 deletions(-) diff --git a/Mage.Common/src/mage/utils/MageVersion.java b/Mage.Common/src/mage/utils/MageVersion.java index c28ce7ebc7b..5e79ba1e3ed 100644 --- a/Mage.Common/src/mage/utils/MageVersion.java +++ b/Mage.Common/src/mage/utils/MageVersion.java @@ -41,7 +41,7 @@ public class MageVersion implements Serializable, Comparable { public final static int MAGE_VERSION_MAJOR = 1; public final static int MAGE_VERSION_MINOR = 4; public final static int MAGE_VERSION_PATCH = 4; - public final static String MAGE_VERSION_MINOR_PATCH = "v7"; + public final static String MAGE_VERSION_MINOR_PATCH = "v8"; public final static String MAGE_VERSION_INFO = ""; private final int major; diff --git a/Mage/src/mage/cards/repository/CardRepository.java b/Mage/src/mage/cards/repository/CardRepository.java index 8a709d93107..0605160f496 100644 --- a/Mage/src/mage/cards/repository/CardRepository.java +++ b/Mage/src/mage/cards/repository/CardRepository.java @@ -63,7 +63,7 @@ public enum CardRepository { // raise this if db structure was changed private static final long CARD_DB_VERSION = 41; // raise this if new cards were added to the server - private static final long CARD_CONTENT_VERSION = 39; + private static final long CARD_CONTENT_VERSION = 40; private final Random random = new Random(); private Dao cardDao; diff --git a/Utils/release/getting_implemented_cards.txt b/Utils/release/getting_implemented_cards.txt index 3a42aba4874..f922aab6fba 100644 --- a/Utils/release/getting_implemented_cards.txt +++ b/Utils/release/getting_implemented_cards.txt @@ -33,6 +33,9 @@ git log 513a574ae98aff3d7820e5411a8e5f2a6506e69c..head --diff-filter=A --name-st since 1.4.4.v6 git log 7650f53dee0b4d480d2a63befed72b6c8197e752..head --diff-filter=A --name-status | sed -ne "s/^A[^u]Mage.Sets\/src\/mage\/sets\///p" | sort > added_cards.txt +since 1.4.4.v8 +git log 8c7dc7b2da3630b6dfec1390854fa2be11631c79..head --diff-filter=A --name-status | sed -ne "s/^A[^u]Mage.Sets\/src\/mage\/sets\///p" | sort > added_cards.txt + 3. Copy added_cards.txt to trunk\Utils folder 4. Run script: > perl extract_in_wiki_format.perl From fca3582420bb80c5bd4a9efacac1cb0bf42ab31e Mon Sep 17 00:00:00 2001 From: LevelX2 Date: Sun, 4 Oct 2015 20:08:19 +0200 Subject: [PATCH 013/268] * Rattleblaze Scarecrow - Fixed that the haze ability was gained from controlled black instead of red creature. --- .../mage/sets/shadowmoor/RattleblazeScarecrow.java | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/Mage.Sets/src/mage/sets/shadowmoor/RattleblazeScarecrow.java b/Mage.Sets/src/mage/sets/shadowmoor/RattleblazeScarecrow.java index 41bcbcbe978..3bbba8d7fe0 100644 --- a/Mage.Sets/src/mage/sets/shadowmoor/RattleblazeScarecrow.java +++ b/Mage.Sets/src/mage/sets/shadowmoor/RattleblazeScarecrow.java @@ -50,9 +50,10 @@ import mage.filter.predicate.mageobject.ColorPredicate; * @author jeffwadsworth */ public class RattleblazeScarecrow extends CardImpl { - + private static final FilterControlledCreaturePermanent filter = new FilterControlledCreaturePermanent("a black creature"); private static final FilterControlledCreaturePermanent filter2 = new FilterControlledCreaturePermanent("a red creature"); + static { filter.add(new ColorPredicate(ObjectColor.BLACK)); filter2.add(new ColorPredicate(ObjectColor.RED)); @@ -60,7 +61,7 @@ public class RattleblazeScarecrow extends CardImpl { private static final String rule = "{this} has persist as long as you control a black creature"; private static final String rule2 = "{this} has haste as long as you control a red creature"; - + public RattleblazeScarecrow(UUID ownerId) { super(ownerId, 259, "Rattleblaze Scarecrow", Rarity.COMMON, new CardType[]{CardType.ARTIFACT, CardType.CREATURE}, "{6}"); this.expansionSetCode = "SHM"; @@ -71,11 +72,11 @@ public class RattleblazeScarecrow extends CardImpl { // Rattleblaze Scarecrow has persist as long as you control a black creature. ContinuousEffect effect = new GainAbilitySourceEffect(new PersistAbility(), Duration.WhileOnBattlefield); this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new ConditionalContinuousEffect(effect, new PermanentsOnTheBattlefieldCondition(filter), rule))); - + // Rattleblaze Scarecrow has haste as long as you control a red creature. ContinuousEffect effect2 = new GainAbilitySourceEffect(HasteAbility.getInstance(), Duration.WhileOnBattlefield); - this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new ConditionalContinuousEffect(effect2, new PermanentsOnTheBattlefieldCondition(filter), rule2))); - + this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new ConditionalContinuousEffect(effect2, new PermanentsOnTheBattlefieldCondition(filter2), rule2))); + } public RattleblazeScarecrow(final RattleblazeScarecrow card) { From 3bb7de006a6b3d4fed23c85d8e8946071df635bf Mon Sep 17 00:00:00 2001 From: LevelX2 Date: Sun, 4 Oct 2015 20:41:59 +0200 Subject: [PATCH 014/268] * Goblin Snowman - Fixed set code and source file location. --- .../mage/sets/{timespiral => timeshifted}/GoblinSnowman.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) rename Mage.Sets/src/mage/sets/{timespiral => timeshifted}/GoblinSnowman.java (94%) diff --git a/Mage.Sets/src/mage/sets/timespiral/GoblinSnowman.java b/Mage.Sets/src/mage/sets/timeshifted/GoblinSnowman.java similarity index 94% rename from Mage.Sets/src/mage/sets/timespiral/GoblinSnowman.java rename to Mage.Sets/src/mage/sets/timeshifted/GoblinSnowman.java index ef7ca062566..bb2b7516b7e 100644 --- a/Mage.Sets/src/mage/sets/timespiral/GoblinSnowman.java +++ b/Mage.Sets/src/mage/sets/timeshifted/GoblinSnowman.java @@ -25,7 +25,7 @@ * authors and should not be interpreted as representing official policies, either expressed * or implied, of BetaSteward_at_googlemail.com. */ -package mage.sets.timespiral; +package mage.sets.timeshifted; import java.util.UUID; @@ -38,7 +38,7 @@ public class GoblinSnowman extends mage.sets.iceage.GoblinSnowman { public GoblinSnowman(UUID ownerId) { super(ownerId); this.cardNumber = 64; - this.expansionSetCode = "ICE"; + this.expansionSetCode = "TSB"; } public GoblinSnowman(final GoblinSnowman card) { From b3cadac4eaca1c3206db3c0af046d32c9a9c211a Mon Sep 17 00:00:00 2001 From: LevelX2 Date: Sun, 4 Oct 2015 22:58:09 +0200 Subject: [PATCH 015/268] * Image download - Fixed a bug of mythicspoiler source, that preveneted download of EXP images. --- .../mage/plugins/card/dl/sources/MythicspoilerComSource.java | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/Mage.Client/src/main/java/org/mage/plugins/card/dl/sources/MythicspoilerComSource.java b/Mage.Client/src/main/java/org/mage/plugins/card/dl/sources/MythicspoilerComSource.java index ef80a0785ae..78995593cd7 100644 --- a/Mage.Client/src/main/java/org/mage/plugins/card/dl/sources/MythicspoilerComSource.java +++ b/Mage.Client/src/main/java/org/mage/plugins/card/dl/sources/MythicspoilerComSource.java @@ -100,7 +100,10 @@ public class MythicspoilerComSource implements CardImageSource { Map setLinks = new HashMap<>(); try { String setNames = setsAliases.get(cardSet.toLowerCase()); - Set aliasesStart = cardNameAliasesStart.get(cardSet); + Set aliasesStart = new HashSet<>(); + if (cardNameAliasesStart.containsKey(cardSet)) { + aliasesStart.addAll(cardNameAliasesStart.get(cardSet)); + } if (setNames == null) { setNames = cardSet.toLowerCase(); } From 6c2e2cad5f3978b681e65800d1786b95f8cdc218 Mon Sep 17 00:00:00 2001 From: emerald000 Date: Sun, 4 Oct 2015 17:48:51 -0400 Subject: [PATCH 016/268] Added Blatant Thievery, Drafna's Restoration and Naked Singularity. --- .../sets/antiquities/DrafnasRestoration.java | 166 +++++++++++++++++ .../mage/sets/iceage/NakedSingularity.java | 168 ++++++++++++++++++ .../masterseditioniv/NakedSingularity.java | 52 ++++++ .../mage/sets/onslaught/BlatantThievery.java | 84 +++++++++ 4 files changed, 470 insertions(+) create mode 100644 Mage.Sets/src/mage/sets/antiquities/DrafnasRestoration.java create mode 100644 Mage.Sets/src/mage/sets/iceage/NakedSingularity.java create mode 100644 Mage.Sets/src/mage/sets/masterseditioniv/NakedSingularity.java create mode 100644 Mage.Sets/src/mage/sets/onslaught/BlatantThievery.java diff --git a/Mage.Sets/src/mage/sets/antiquities/DrafnasRestoration.java b/Mage.Sets/src/mage/sets/antiquities/DrafnasRestoration.java new file mode 100644 index 00000000000..55f990e15dc --- /dev/null +++ b/Mage.Sets/src/mage/sets/antiquities/DrafnasRestoration.java @@ -0,0 +1,166 @@ +/* + * 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.antiquities; + +import java.util.HashSet; +import java.util.Set; +import java.util.UUID; +import mage.MageObject; +import mage.abilities.Ability; +import mage.abilities.effects.OneShotEffect; +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.FilterCard; +import mage.filter.common.FilterArtifactCard; +import mage.game.Game; +import mage.game.events.GameEvent; +import mage.game.stack.StackObject; +import mage.players.Player; +import mage.target.TargetCard; +import mage.target.TargetPlayer; +import mage.target.common.TargetCardInGraveyard; + +/** + * + * @author emerald000 + */ +public class DrafnasRestoration extends CardImpl { + + public DrafnasRestoration(UUID ownerId) { + super(ownerId, 52, "Drafna's Restoration", Rarity.COMMON, new CardType[]{CardType.SORCERY}, "{U}"); + this.expansionSetCode = "ATQ"; + + // Return any number of target artifact cards from target player's graveyard to the top of his or her library in any order. + this.getSpellAbility().addEffect(new DrafnasRestorationEffect()); + this.getSpellAbility().addTarget(new TargetPlayer()); + this.getSpellAbility().addTarget(new DrafnasRestorationTarget()); + } + + public DrafnasRestoration(final DrafnasRestoration card) { + super(card); + } + + @Override + public DrafnasRestoration copy() { + return new DrafnasRestoration(this); + } +} + +class DrafnasRestorationTarget extends TargetCardInGraveyard { + + DrafnasRestorationTarget() { + super(0, Integer.MAX_VALUE, new FilterArtifactCard("any number of artifact cards from that player's graveyard")); + } + + DrafnasRestorationTarget(final DrafnasRestorationTarget target) { + super(target); + } + + @Override + public boolean canTarget(UUID id, Ability source, Game game) { + Player targetPlayer = game.getPlayer(source.getFirstTarget()); + return targetPlayer != null && targetPlayer.getGraveyard().contains(id) && super.canTarget(id, source, game); + } + + @Override + public Set possibleTargets(UUID sourceId, UUID sourceControllerId, Game game) { + Set possibleTargets = new HashSet<>(); + MageObject object = game.getObject(sourceId); + if (object != null && object instanceof StackObject) { + Player targetPlayer = game.getPlayer(((StackObject) object).getStackAbility().getFirstTarget()); + if (targetPlayer != null) { + for (Card card : targetPlayer.getGraveyard().getCards(filter, sourceId, sourceControllerId, game)) { + if (!game.replaceEvent(GameEvent.getEvent(GameEvent.EventType.TARGET, card.getId(), sourceId, sourceControllerId))) { + possibleTargets.add(card.getId()); + } + } + } + } + return possibleTargets; + } + + @Override + public DrafnasRestorationTarget copy() { + return new DrafnasRestorationTarget(this); + } +} + +class DrafnasRestorationEffect extends OneShotEffect { + + DrafnasRestorationEffect() { + super(Outcome.Benefit); + this.staticText = "Return any number of target artifact cards from target player's graveyard to the top of his or her library in any order"; + } + + DrafnasRestorationEffect(final DrafnasRestorationEffect effect) { + super(effect); + } + + @Override + public DrafnasRestorationEffect copy() { + return new DrafnasRestorationEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player controller = game.getPlayer(source.getControllerId()); + Player targetPlayer = game.getPlayer(source.getFirstTarget()); + if (controller != null && targetPlayer != null) { + Cards cards = new CardsImpl(source.getTargets().get(1).getTargets()); // prevent possible ConcurrentModificationException + cards.addAll(source.getTargets().get(1).getTargets()); + if (!cards.isEmpty()) { + TargetCard target = new TargetCard(Zone.PICK, new FilterCard("card to put on the top of the library (last one chosen will be topmost)")); + target.setRequired(true); + while (controller.isInGame() && cards.size() > 1) { + controller.choose(Outcome.Neutral, cards, target, game); + UUID targetId = target.getFirstTarget(); + cards.remove(targetId); + target.clearChosen(); + Card card = targetPlayer.getGraveyard().get(targetId, game); + if (card != null) { + controller.moveCards(card, Zone.GRAVEYARD, Zone.LIBRARY, source, game); + } + } + if (cards.size() == 1) { + Card card = targetPlayer.getGraveyard().get(cards.iterator().next(), game); + if (card != null) { + controller.moveCards(card, Zone.GRAVEYARD, Zone.LIBRARY, source, game); + } + } + } + return true; + } + return false; + } +} diff --git a/Mage.Sets/src/mage/sets/iceage/NakedSingularity.java b/Mage.Sets/src/mage/sets/iceage/NakedSingularity.java new file mode 100644 index 00000000000..5ef0077ec27 --- /dev/null +++ b/Mage.Sets/src/mage/sets/iceage/NakedSingularity.java @@ -0,0 +1,168 @@ +/* + * 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.iceage; + +import java.util.UUID; +import mage.Mana; +import mage.abilities.Ability; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.costs.mana.GenericManaCost; +import mage.abilities.effects.ReplacementEffectImpl; +import mage.abilities.keyword.CumulativeUpkeepAbility; +import mage.cards.CardImpl; +import mage.choices.Choice; +import mage.choices.ChoiceImpl; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.Outcome; +import mage.constants.Rarity; +import mage.constants.Zone; +import mage.game.Game; +import mage.game.events.GameEvent; +import mage.game.events.ManaEvent; +import mage.game.permanent.Permanent; +import mage.players.Player; + +/** + * + * @author emerald000 + */ +public class NakedSingularity extends CardImpl { + + public NakedSingularity(UUID ownerId) { + super(ownerId, 305, "Naked Singularity", Rarity.RARE, new CardType[]{CardType.ARTIFACT}, "{5}"); + this.expansionSetCode = "ICE"; + + // Cumulative upkeep {3} + this.addAbility(new CumulativeUpkeepAbility(new GenericManaCost(3))); + + // If tapped for mana, Plains produce {R}, Islands produce {G}, Swamps produce {W}, Mountains produce {U}, and Forests produce {B} instead of any other type. + this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new NakedSingularityEffect())); + } + + public NakedSingularity(final NakedSingularity card) { + super(card); + } + + @Override + public NakedSingularity copy() { + return new NakedSingularity(this); + } +} + +class NakedSingularityEffect extends ReplacementEffectImpl { + + NakedSingularityEffect() { + super(Duration.WhileOnBattlefield, Outcome.Neutral); + staticText = "If tapped for mana, Plains produce {R}, Islands produce {G}, Swamps produce {W}, Mountains produce {U}, and Forests produce {B} instead of any other type"; + } + + NakedSingularityEffect(final NakedSingularityEffect effect) { + super(effect); + } + + @Override + public NakedSingularityEffect copy() { + return new NakedSingularityEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + return true; + } + + @Override + public boolean replaceEvent(GameEvent event, Ability source, Game game) { + Player controller = game.getPlayer(source.getControllerId()); + if (controller != null) { + Permanent permanent = game.getPermanent(event.getSourceId()); + Choice choice = new ChoiceImpl(true); + choice.setMessage("Pick a color to produce"); + if (permanent.hasSubtype("Plains")) { + choice.getChoices().add("Red"); + } + if (permanent.hasSubtype("Island")) { + choice.getChoices().add("Green"); + } + if (permanent.hasSubtype("Swamp")) { + choice.getChoices().add("White"); + } + if (permanent.hasSubtype("Mountain")) { + choice.getChoices().add("Blue"); + } + if (permanent.hasSubtype("Forest")) { + choice.getChoices().add("Black"); + } + String chosenColor; + if (choice.getChoices().size() == 1) { + chosenColor = choice.getChoices().iterator().next(); + } + else { + controller.choose(Outcome.PutManaInPool, choice, game); + chosenColor = choice.getChoice(); + } + ManaEvent manaEvent = (ManaEvent) event; + Mana mana = manaEvent.getMana(); + int amount = mana.count(); + switch (chosenColor) { + case "White": + mana.setToMana(Mana.WhiteMana(amount)); + break; + case "Blue": + mana.setToMana(Mana.BlueMana(amount)); + break; + case "Black": + mana.setToMana(Mana.BlackMana(amount)); + break; + case "Red": + mana.setToMana(Mana.RedMana(amount)); + break; + case "Green": + mana.setToMana(Mana.GreenMana(amount)); + break; + } + } + return false; + } + + @Override + public boolean checksEventType(GameEvent event, Game game) { + return event.getType() == GameEvent.EventType.TAPPED_FOR_MANA; + } + + @Override + public boolean applies(GameEvent event, Ability source, Game game) { + Permanent permanent = game.getPermanent(event.getSourceId()); + return permanent != null + && (permanent.hasSubtype("Plains") + || permanent.hasSubtype("Island") + || permanent.hasSubtype("Swamp") + || permanent.hasSubtype("Mountain") + || permanent.hasSubtype("Forest")); + } +} diff --git a/Mage.Sets/src/mage/sets/masterseditioniv/NakedSingularity.java b/Mage.Sets/src/mage/sets/masterseditioniv/NakedSingularity.java new file mode 100644 index 00000000000..355d9ad917f --- /dev/null +++ b/Mage.Sets/src/mage/sets/masterseditioniv/NakedSingularity.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.masterseditioniv; + +import java.util.UUID; + +/** + * + * @author emerald000 + */ +public class NakedSingularity extends mage.sets.iceage.NakedSingularity { + + public NakedSingularity(UUID ownerId) { + super(ownerId); + this.cardNumber = 216; + this.expansionSetCode = "ME4"; + } + + public NakedSingularity(final NakedSingularity card) { + super(card); + } + + @Override + public NakedSingularity copy() { + return new NakedSingularity(this); + } +} diff --git a/Mage.Sets/src/mage/sets/onslaught/BlatantThievery.java b/Mage.Sets/src/mage/sets/onslaught/BlatantThievery.java new file mode 100644 index 00000000000..512927844ec --- /dev/null +++ b/Mage.Sets/src/mage/sets/onslaught/BlatantThievery.java @@ -0,0 +1,84 @@ +/* + * 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.SpellAbility; +import mage.abilities.effects.Effect; +import mage.abilities.effects.common.continuous.GainControlTargetEffect; +import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.Rarity; +import mage.filter.FilterPermanent; +import mage.filter.predicate.permanent.ControllerIdPredicate; +import mage.game.Game; +import mage.players.Player; +import mage.target.TargetPermanent; + +/** + * + * @author emerald000 + */ +public class BlatantThievery extends CardImpl { + + public BlatantThievery(UUID ownerId) { + super(ownerId, 71, "Blatant Thievery", Rarity.RARE, new CardType[]{CardType.SORCERY}, "{4}{U}{U}{U}"); + this.expansionSetCode = "ONS"; + + // For each opponent, gain control of target permanent that player controls. + Effect effect = new GainControlTargetEffect(Duration.EndOfGame); + effect.setText("For each opponent, gain control of target permanent that player controls"); + this.getSpellAbility().addEffect(effect); + } + + public BlatantThievery(final BlatantThievery card) { + super(card); + } + + @Override + public void adjustTargets(Ability ability, Game game) { + if (ability instanceof SpellAbility) { + ability.getTargets().clear(); + for (UUID opponentId : game.getOpponents(ability.getControllerId())) { + Player opponent = game.getPlayer(opponentId); + if (opponent != null) { + FilterPermanent filter = new FilterPermanent("permanent controlled by " + opponent.getName()); + filter.add(new ControllerIdPredicate(opponentId)); + ability.addTarget(new TargetPermanent(filter)); + } + } + } + } + + @Override + public BlatantThievery copy() { + return new BlatantThievery(this); + } +} From 87f3054f5df854c5d8bef6cc900bc587484500e7 Mon Sep 17 00:00:00 2001 From: LoneFox Date: Mon, 5 Oct 2015 09:51:54 +0300 Subject: [PATCH 017/268] Fix Tithe's card number --- Mage.Sets/src/mage/sets/visions/Tithe.java | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/Mage.Sets/src/mage/sets/visions/Tithe.java b/Mage.Sets/src/mage/sets/visions/Tithe.java index dd0563cc515..d36db987a05 100644 --- a/Mage.Sets/src/mage/sets/visions/Tithe.java +++ b/Mage.Sets/src/mage/sets/visions/Tithe.java @@ -49,7 +49,7 @@ import mage.target.common.TargetOpponent; public class Tithe extends CardImpl { public Tithe(UUID ownerId) { - super(ownerId, 84, "Tithe", Rarity.RARE, new CardType[]{CardType.INSTANT}, "{W}"); + super(ownerId, 123, "Tithe", Rarity.RARE, new CardType[]{CardType.INSTANT}, "{W}"); this.expansionSetCode = "VIS"; // Search your library for a Plains card. If target opponent controls more lands than you, you may search your library for an additional Plains card. Reveal those cards and put them into your hand. Then shuffle your library. @@ -68,26 +68,26 @@ public class Tithe extends CardImpl { } class TitheEffect extends OneShotEffect { - + private static final FilterCard filter = new FilterCard("Plains"); static { filter.add(new SubtypePredicate("Plains")); } - + TitheEffect() { super(Outcome.Benefit); this.staticText = "Search your library for a Plains card. If target opponent controls more lands than you, you may search your library for an additional Plains card. Reveal those cards and put them into your hand. Then shuffle your library"; } - + TitheEffect(final TitheEffect effect) { super(effect); } - + @Override public TitheEffect copy() { return new TitheEffect(this); } - + @Override public boolean apply(Game game, Ability source) { int numYourLands = game.getBattlefield().countAll(new FilterLandPermanent(), source.getControllerId(), game); From b10c01f517090ecde750cb921c3243bd8bdfa208 Mon Sep 17 00:00:00 2001 From: LevelX2 Date: Mon, 5 Oct 2015 14:40:33 +0200 Subject: [PATCH 018/268] Some minor fixes to player class. --- Mage/src/mage/players/PlayerImpl.java | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/Mage/src/mage/players/PlayerImpl.java b/Mage/src/mage/players/PlayerImpl.java index 3ce3070c96e..c905d5a541d 100644 --- a/Mage/src/mage/players/PlayerImpl.java +++ b/Mage/src/mage/players/PlayerImpl.java @@ -875,16 +875,15 @@ public abstract class PlayerImpl implements Player, Serializable { */ @Override public boolean putCardsOnTopOfLibrary(Cards cardsToLibrary, Game game, Ability source, boolean anyOrder) { - Cards cards = new CardsImpl(cardsToLibrary); // prevent possible ConcurrentModificationException - cards.addAll(cardsToLibrary); - if (!cards.isEmpty()) { + if (!cardsToLibrary.isEmpty()) { + Cards cards = new CardsImpl(cardsToLibrary); // prevent possible ConcurrentModificationException UUID sourceId = (source == null ? null : source.getSourceId()); if (!anyOrder) { for (UUID cardId : cards) { moveObjectToLibrary(cardId, sourceId, game, true, false); } } else { - TargetCard target = new TargetCard(Zone.PICK, new FilterCard("card to put on the top of your library (last one chosen will be topmost)")); + TargetCard target = new TargetCard(Zone.LIBRARY, new FilterCard("card to put on the top of your library (last one chosen will be topmost)")); target.setRequired(true); while (isInGame() && cards.size() > 1) { this.choose(Outcome.Neutral, cards, target, game); From 65e7527b2f721df401c83611ad8eba5b6d4e0cc8 Mon Sep 17 00:00:00 2001 From: emerald000 Date: Mon, 5 Oct 2015 11:31:38 -0400 Subject: [PATCH 019/268] Fixed Blatant Thievery and Drafna's Restoration. --- .../sets/antiquities/DrafnasRestoration.java | 30 ++------------- .../mage/sets/onslaught/BlatantThievery.java | 37 +++++++++++++++++-- 2 files changed, 36 insertions(+), 31 deletions(-) diff --git a/Mage.Sets/src/mage/sets/antiquities/DrafnasRestoration.java b/Mage.Sets/src/mage/sets/antiquities/DrafnasRestoration.java index 55f990e15dc..fc24c4ffcbb 100644 --- a/Mage.Sets/src/mage/sets/antiquities/DrafnasRestoration.java +++ b/Mage.Sets/src/mage/sets/antiquities/DrafnasRestoration.java @@ -40,14 +40,11 @@ import mage.cards.CardsImpl; import mage.constants.CardType; import mage.constants.Outcome; import mage.constants.Rarity; -import mage.constants.Zone; -import mage.filter.FilterCard; import mage.filter.common.FilterArtifactCard; import mage.game.Game; import mage.game.events.GameEvent; import mage.game.stack.StackObject; import mage.players.Player; -import mage.target.TargetCard; import mage.target.TargetPlayer; import mage.target.common.TargetCardInGraveyard; @@ -135,30 +132,9 @@ class DrafnasRestorationEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { Player controller = game.getPlayer(source.getControllerId()); - Player targetPlayer = game.getPlayer(source.getFirstTarget()); - if (controller != null && targetPlayer != null) { - Cards cards = new CardsImpl(source.getTargets().get(1).getTargets()); // prevent possible ConcurrentModificationException - cards.addAll(source.getTargets().get(1).getTargets()); - if (!cards.isEmpty()) { - TargetCard target = new TargetCard(Zone.PICK, new FilterCard("card to put on the top of the library (last one chosen will be topmost)")); - target.setRequired(true); - while (controller.isInGame() && cards.size() > 1) { - controller.choose(Outcome.Neutral, cards, target, game); - UUID targetId = target.getFirstTarget(); - cards.remove(targetId); - target.clearChosen(); - Card card = targetPlayer.getGraveyard().get(targetId, game); - if (card != null) { - controller.moveCards(card, Zone.GRAVEYARD, Zone.LIBRARY, source, game); - } - } - if (cards.size() == 1) { - Card card = targetPlayer.getGraveyard().get(cards.iterator().next(), game); - if (card != null) { - controller.moveCards(card, Zone.GRAVEYARD, Zone.LIBRARY, source, game); - } - } - } + if (controller != null) { + Cards cards = new CardsImpl(source.getTargets().get(1).getTargets()); + controller.putCardsOnTopOfLibrary(cards, game, source, true); return true; } return false; diff --git a/Mage.Sets/src/mage/sets/onslaught/BlatantThievery.java b/Mage.Sets/src/mage/sets/onslaught/BlatantThievery.java index 512927844ec..09586f61089 100644 --- a/Mage.Sets/src/mage/sets/onslaught/BlatantThievery.java +++ b/Mage.Sets/src/mage/sets/onslaught/BlatantThievery.java @@ -30,17 +30,21 @@ package mage.sets.onslaught; import java.util.UUID; import mage.abilities.Ability; import mage.abilities.SpellAbility; -import mage.abilities.effects.Effect; +import mage.abilities.effects.ContinuousEffect; +import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.continuous.GainControlTargetEffect; import mage.cards.CardImpl; import mage.constants.CardType; import mage.constants.Duration; +import mage.constants.Outcome; import mage.constants.Rarity; import mage.filter.FilterPermanent; import mage.filter.predicate.permanent.ControllerIdPredicate; import mage.game.Game; import mage.players.Player; +import mage.target.Target; import mage.target.TargetPermanent; +import mage.target.targetpointer.FixedTarget; /** * @@ -53,9 +57,7 @@ public class BlatantThievery extends CardImpl { this.expansionSetCode = "ONS"; // For each opponent, gain control of target permanent that player controls. - Effect effect = new GainControlTargetEffect(Duration.EndOfGame); - effect.setText("For each opponent, gain control of target permanent that player controls"); - this.getSpellAbility().addEffect(effect); + this.getSpellAbility().addEffect(new BlatantThieveryEffect()); } public BlatantThievery(final BlatantThievery card) { @@ -82,3 +84,30 @@ public class BlatantThievery extends CardImpl { return new BlatantThievery(this); } } + +class BlatantThieveryEffect extends OneShotEffect { + + BlatantThieveryEffect() { + super(Outcome.GainControl); + this.staticText = "For each opponent, gain control of target permanent that player controls"; + } + + BlatantThieveryEffect(final BlatantThieveryEffect effect) { + super(effect); + } + + @Override + public BlatantThieveryEffect copy() { + return new BlatantThieveryEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + for (Target target : source.getTargets()) { + ContinuousEffect effect = new GainControlTargetEffect(Duration.EndOfGame); + effect.setTargetPointer(new FixedTarget(target.getFirstTarget())); + game.addEffect(effect, source); + } + return true; + } +} From f4a643437bf0e06e2b9788cf82d4875d815426fa Mon Sep 17 00:00:00 2001 From: LevelX2 Date: Mon, 5 Oct 2015 18:44:05 +0200 Subject: [PATCH 020/268] Added Celestial Dawn. --- .../classicsixthedition/CelestialDawn.java | 54 ++++ .../mage/sets/darksteel/MycosynthLattice.java | 23 +- .../src/mage/sets/mirage/CelestialDawn.java | 54 ++++ .../src/mage/sets/theros/DaxosOfMeletis.java | 7 + .../mage/sets/theros/PsychicIntrusion.java | 32 +- .../mage/sets/timeshifted/CelestialDawn.java | 284 ++++++++++++++++++ .../abilities/effects/AsThoughEffect.java | 19 +- .../abilities/effects/AsThoughEffectImpl.java | 20 +- .../abilities/effects/ContinuousEffects.java | 22 ++ .../mage/constants/AsThoughEffectType.java | 4 +- Mage/src/mage/players/ManaPool.java | 47 ++- 11 files changed, 513 insertions(+), 53 deletions(-) create mode 100644 Mage.Sets/src/mage/sets/classicsixthedition/CelestialDawn.java create mode 100644 Mage.Sets/src/mage/sets/mirage/CelestialDawn.java create mode 100644 Mage.Sets/src/mage/sets/timeshifted/CelestialDawn.java diff --git a/Mage.Sets/src/mage/sets/classicsixthedition/CelestialDawn.java b/Mage.Sets/src/mage/sets/classicsixthedition/CelestialDawn.java new file mode 100644 index 00000000000..8d4443648a9 --- /dev/null +++ b/Mage.Sets/src/mage/sets/classicsixthedition/CelestialDawn.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.classicsixthedition; + +import java.util.UUID; +import mage.constants.Rarity; + +/** + * + * @author LevelX2 + */ +public class CelestialDawn extends mage.sets.timeshifted.CelestialDawn { + + public CelestialDawn(UUID ownerId) { + super(ownerId); + this.cardNumber = 7; + this.expansionSetCode = "6ED"; + this.rarity = Rarity.RARE; + } + + public CelestialDawn(final CelestialDawn card) { + super(card); + } + + @Override + public CelestialDawn copy() { + return new CelestialDawn(this); + } +} diff --git a/Mage.Sets/src/mage/sets/darksteel/MycosynthLattice.java b/Mage.Sets/src/mage/sets/darksteel/MycosynthLattice.java index 1cd753fd6d0..fa2aa3f3c0b 100644 --- a/Mage.Sets/src/mage/sets/darksteel/MycosynthLattice.java +++ b/Mage.Sets/src/mage/sets/darksteel/MycosynthLattice.java @@ -38,17 +38,19 @@ import mage.abilities.effects.ContinuousEffectImpl; import mage.cards.Card; import mage.cards.CardImpl; import mage.constants.AsThoughEffectType; -import mage.constants.Rarity; import mage.constants.CardType; import mage.constants.Duration; import mage.constants.Layer; +import mage.constants.ManaType; import mage.constants.Outcome; +import mage.constants.Rarity; import mage.constants.SubLayer; import mage.constants.Zone; import mage.game.Game; import mage.game.command.CommandObject; import mage.game.permanent.Permanent; import mage.game.stack.Spell; +import mage.players.ManaPoolItem; import mage.players.Player; /** @@ -79,8 +81,8 @@ public class MycosynthLattice extends CardImpl { } class PermanentsAreArtifactsEffect extends ContinuousEffectImpl { - - public PermanentsAreArtifactsEffect(){ + + public PermanentsAreArtifactsEffect() { super(Duration.WhileOnBattlefield, Layer.TypeChangingEffects_4, SubLayer.NA, Outcome.Neutral); staticText = "All permanents are artifacts in addition to their other types"; } @@ -106,9 +108,8 @@ class PermanentsAreArtifactsEffect extends ContinuousEffectImpl { } } - class EverythingIsColorlessEffect extends ContinuousEffectImpl { - + public EverythingIsColorlessEffect() { super(Duration.WhileOnBattlefield, Layer.ColorChangingEffects_5, SubLayer.NA, Outcome.Neutral); staticText = "All cards that aren't on the battlefield, spells, and permanents are colorless"; @@ -141,7 +142,7 @@ class EverythingIsColorlessEffect extends ContinuousEffectImpl { Player player = game.getPlayer(playerId); if (player != null) { // hand - for (Card card: player.getHand().getCards(game)) { + for (Card card : player.getHand().getCards(game)) { game.getState().getCreateCardAttribute(card).getColor().setColor(colorless); } // library @@ -169,7 +170,6 @@ class EverythingIsColorlessEffect extends ContinuousEffectImpl { } } - class ManaCanBeSpentAsAnyColorEffect extends AsThoughEffectImpl { public ManaCanBeSpentAsAnyColorEffect() { @@ -183,7 +183,12 @@ class ManaCanBeSpentAsAnyColorEffect extends AsThoughEffectImpl { } @Override - public boolean applies(UUID sourceId, Ability source, UUID affectedControllerId, Game game) { + public boolean applies(UUID objectId, Ability source, UUID affectedControllerId, Game game) { + return true; // not used for mana thought as effects + } + + @Override + public boolean applies(UUID objectId, Ability source, UUID affectedControllerId, Game game, ManaType manaType, ManaPoolItem mana) { return true; } @@ -194,5 +199,5 @@ class ManaCanBeSpentAsAnyColorEffect extends AsThoughEffectImpl { private ManaCanBeSpentAsAnyColorEffect(ManaCanBeSpentAsAnyColorEffect effect) { super(effect); - } + } } diff --git a/Mage.Sets/src/mage/sets/mirage/CelestialDawn.java b/Mage.Sets/src/mage/sets/mirage/CelestialDawn.java new file mode 100644 index 00000000000..a0f4bf3c743 --- /dev/null +++ b/Mage.Sets/src/mage/sets/mirage/CelestialDawn.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.mirage; + +import java.util.UUID; +import mage.constants.Rarity; + +/** + * + * @author LevelX2 + */ +public class CelestialDawn extends mage.sets.timeshifted.CelestialDawn { + + public CelestialDawn(UUID ownerId) { + super(ownerId); + this.cardNumber = 210; + this.expansionSetCode = "MIR"; + this.rarity = Rarity.RARE; + } + + public CelestialDawn(final CelestialDawn card) { + super(card); + } + + @Override + public CelestialDawn copy() { + return new CelestialDawn(this); + } +} diff --git a/Mage.Sets/src/mage/sets/theros/DaxosOfMeletis.java b/Mage.Sets/src/mage/sets/theros/DaxosOfMeletis.java index 555da66687d..e0208b506f0 100644 --- a/Mage.Sets/src/mage/sets/theros/DaxosOfMeletis.java +++ b/Mage.Sets/src/mage/sets/theros/DaxosOfMeletis.java @@ -42,6 +42,7 @@ import mage.cards.CardImpl; import mage.constants.AsThoughEffectType; import mage.constants.CardType; import mage.constants.Duration; +import mage.constants.ManaType; import mage.constants.Outcome; import mage.constants.Rarity; import mage.constants.Zone; @@ -50,6 +51,7 @@ import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.mageobject.PowerPredicate; import mage.game.ExileZone; import mage.game.Game; +import mage.players.ManaPoolItem; import mage.players.Player; import mage.target.targetpointer.FixedTarget; import mage.util.CardUtil; @@ -204,6 +206,11 @@ class DaxosOfMeletisSpendAnyManaEffect extends AsThoughEffectImpl { @Override public boolean applies(UUID objectId, Ability source, UUID affectedControllerId, Game game) { + return true; // not used for mana thought as effects + } + + @Override + public boolean applies(UUID objectId, Ability source, UUID affectedControllerId, Game game, ManaType manaType, ManaPoolItem mana) { return source.getControllerId().equals(affectedControllerId) && objectId == ((FixedTarget) getTargetPointer()).getTarget() && ((FixedTarget) getTargetPointer()).getZoneChangeCounter() + 1 == game.getState().getZoneChangeCounter(objectId) diff --git a/Mage.Sets/src/mage/sets/theros/PsychicIntrusion.java b/Mage.Sets/src/mage/sets/theros/PsychicIntrusion.java index 31c62eccfc8..ed5d78e197c 100644 --- a/Mage.Sets/src/mage/sets/theros/PsychicIntrusion.java +++ b/Mage.Sets/src/mage/sets/theros/PsychicIntrusion.java @@ -38,11 +38,13 @@ import mage.cards.CardImpl; import mage.constants.AsThoughEffectType; import mage.constants.CardType; import mage.constants.Duration; +import mage.constants.ManaType; import mage.constants.Outcome; import mage.constants.Rarity; import mage.constants.Zone; import mage.filter.common.FilterNonlandCard; import mage.game.Game; +import mage.players.ManaPoolItem; import mage.players.Player; import mage.target.TargetCard; import mage.target.common.TargetOpponent; @@ -59,7 +61,6 @@ public class PsychicIntrusion extends CardImpl { super(ownerId, 200, "Psychic Intrusion", Rarity.RARE, new CardType[]{CardType.SORCERY}, "{3}{U}{B}"); this.expansionSetCode = "THS"; - // Target opponent reveals his or her hand. You choose a nonland card from that player's graveyard or hand and exile it. // You may cast that card for as long as it remains exiled, and you may spend mana as though it were mana of any color // to cast that spell. @@ -135,7 +136,7 @@ class PsychicIntrusionExileEffect extends OneShotEffect { if (card != null) { // move card to exile UUID exileId = CardUtil.getCardExileZoneId(game, source); - controller.moveCardToExileWithInfo(card, exileId, sourceObject.getIdName(), source.getSourceId(), game, fromHand ? Zone.HAND:Zone.GRAVEYARD, true); + controller.moveCardToExileWithInfo(card, exileId, sourceObject.getIdName(), source.getSourceId(), game, fromHand ? Zone.HAND : Zone.GRAVEYARD, true); // allow to cast the card ContinuousEffect effect = new PsychicIntrusionCastFromExileEffect(); effect.setTargetPointer(new FixedTarget(card.getId())); @@ -178,13 +179,13 @@ class PsychicIntrusionCastFromExileEffect extends AsThoughEffectImpl { if (objectId.equals(getTargetPointer().getFirst(game, source))) { if (affectedControllerId.equals(source.getControllerId())) { return true; - } + } } else { - if (((FixedTarget)getTargetPointer()).getTarget().equals(objectId)) { + if (((FixedTarget) getTargetPointer()).getTarget().equals(objectId)) { // object has moved zone so effect can be discarted this.discard(); } - } + } return false; } } @@ -212,18 +213,23 @@ class PsychicIntrusionSpendAnyManaEffect extends AsThoughEffectImpl { @Override public boolean applies(UUID objectId, Ability source, UUID affectedControllerId, Game game) { - if (objectId.equals(((FixedTarget)getTargetPointer()).getTarget()) - && game.getState().getZoneChangeCounter(objectId) <= ((FixedTarget)getTargetPointer()).getZoneChangeCounter() +1) { - - if (affectedControllerId.equals(source.getControllerId())) { + return true; // not used for mana thought as effects + } + + @Override + public boolean applies(UUID objectId, Ability source, UUID affectedControllerId, Game game, ManaType manaType, ManaPoolItem mana) { + if (objectId.equals(((FixedTarget) getTargetPointer()).getTarget()) + && game.getState().getZoneChangeCounter(objectId) <= ((FixedTarget) getTargetPointer()).getZoneChangeCounter() + 1) { + + if (affectedControllerId.equals(source.getControllerId())) { // if the card moved from exile to spell the zone change counter is increased by 1 - if (game.getState().getZoneChangeCounter(objectId) == ((FixedTarget)getTargetPointer()).getZoneChangeCounter() +1) { + if (game.getState().getZoneChangeCounter(objectId) == ((FixedTarget) getTargetPointer()).getZoneChangeCounter() + 1) { return true; } - } - + } + } else { - if (((FixedTarget)getTargetPointer()).getTarget().equals(objectId)) { + if (((FixedTarget) getTargetPointer()).getTarget().equals(objectId)) { // object has moved zone so effect can be discarted this.discard(); } diff --git a/Mage.Sets/src/mage/sets/timeshifted/CelestialDawn.java b/Mage.Sets/src/mage/sets/timeshifted/CelestialDawn.java new file mode 100644 index 00000000000..e899f506b68 --- /dev/null +++ b/Mage.Sets/src/mage/sets/timeshifted/CelestialDawn.java @@ -0,0 +1,284 @@ +/* + * 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.timeshifted; + +import java.util.UUID; +import mage.MageObject; +import mage.ObjectColor; +import mage.abilities.Ability; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.effects.AsThoughEffectImpl; +import mage.abilities.effects.ContinuousEffectImpl; +import mage.abilities.mana.WhiteManaAbility; +import mage.cards.Card; +import mage.cards.CardImpl; +import mage.constants.AsThoughEffectType; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.Layer; +import static mage.constants.Layer.AbilityAddingRemovingEffects_6; +import static mage.constants.Layer.TypeChangingEffects_4; +import mage.constants.ManaType; +import mage.constants.Outcome; +import mage.constants.Rarity; +import mage.constants.SubLayer; +import mage.constants.Zone; +import mage.filter.common.FilterLandPermanent; +import mage.filter.common.FilterNonlandPermanent; +import mage.game.Game; +import mage.game.command.CommandObject; +import mage.game.permanent.Permanent; +import mage.game.stack.Spell; +import mage.players.ManaPoolItem; +import mage.players.Player; +import mage.sets.Commander; + +/** + * + * @author LevelX2 + */ +public class CelestialDawn extends CardImpl { + + public CelestialDawn(UUID ownerId) { + super(ownerId, 3, "Celestial Dawn", Rarity.SPECIAL, new CardType[]{CardType.ENCHANTMENT}, "{1}{W}{W}"); + this.expansionSetCode = "TSB"; + + // Lands you control are Plains. + this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new CelestialDawnToPlainsEffect())); + + // Nonland cards you own that aren't on the battlefield, spells you control, and nonland permanents you control are white. + this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new CelestialDawnToWhiteEffect())); + + // You may spend white mana as though it were mana of any color. + // You may spend other mana only as though it were colorless mana. + Ability ability = new SimpleStaticAbility(Zone.BATTLEFIELD, new CelestialDawnSpendAnyManaEffect()); + ability.addEffect(new CelestialDawnSpendColorlessManaEffect()); + this.addAbility(ability); + + } + + public CelestialDawn(final CelestialDawn card) { + super(card); + } + + @Override + public CelestialDawn copy() { + return new CelestialDawn(this); + } +} + +class CelestialDawnToPlainsEffect extends ContinuousEffectImpl { + + private static final FilterLandPermanent filter = new FilterLandPermanent(); + + CelestialDawnToPlainsEffect() { + super(Duration.WhileOnBattlefield, Outcome.Detriment); + this.staticText = "Lands you control are Plains"; + } + + CelestialDawnToPlainsEffect(final CelestialDawnToPlainsEffect effect) { + super(effect); + } + + @Override + public boolean apply(Game game, Ability source) { + return false; + } + + @Override + public CelestialDawnToPlainsEffect copy() { + return new CelestialDawnToPlainsEffect(this); + } + + @Override + public boolean apply(Layer layer, SubLayer sublayer, Ability source, Game game) { + for (Permanent land : game.getBattlefield().getAllActivePermanents(filter, source.getControllerId(), game)) { + switch (layer) { + case AbilityAddingRemovingEffects_6: + land.removeAllAbilities(source.getSourceId(), game); + land.addAbility(new WhiteManaAbility(), source.getSourceId(), game); + break; + case TypeChangingEffects_4: + land.getSubtype().clear(); + land.getSubtype().add("Plains"); + break; + } + } + return true; + } + + @Override + public boolean hasLayer(Layer layer) { + return layer == Layer.AbilityAddingRemovingEffects_6 || layer == Layer.TypeChangingEffects_4; + } + +} + +class CelestialDawnToWhiteEffect extends ContinuousEffectImpl { + + private static final FilterNonlandPermanent filter = new FilterNonlandPermanent(); + + public CelestialDawnToWhiteEffect() { + super(Duration.WhileOnBattlefield, Layer.ColorChangingEffects_5, SubLayer.NA, Outcome.Benefit); + staticText = "Nonland cards you own that aren't on the battlefield, spells you control, and nonland permanents you control are white"; + staticText = "All cards that aren't on the battlefield, spells, and permanents are the chosen color in addition to their other colors"; + } + + @Override + public boolean apply(Game game, Ability source) { + Player controller = game.getPlayer(source.getControllerId()); + if (controller != null) { + for (Permanent perm : game.getBattlefield().getAllActivePermanents(filter, source.getControllerId(), game)) { + setColor(perm.getColor(game), game); + } + // Stack + for (MageObject object : game.getStack()) { + if (object instanceof Spell && ((Spell) object).getControllerId().equals(controller.getId())) { + setColor(object.getColor(game), game); + } + } + // Exile + for (Card card : game.getExile().getAllCards(game)) { + if (card.getOwnerId().equals(controller.getId())) { + setColor(card.getColor(game), game); + } + } + // Command + for (CommandObject commandObject : game.getState().getCommand()) { + if (commandObject instanceof Commander) { + if (commandObject.getControllerId().equals(controller.getId())) { + setColor(commandObject.getColor(game), game); + } + } + } + + // Hand + for (Card card : controller.getHand().getCards(game)) { + setColor(card.getColor(game), game); + } + // Library + for (Card card : controller.getLibrary().getCards(game)) { + setColor(card.getColor(game), game); + } + // Graveyard + for (Card card : controller.getGraveyard().getCards(game)) { + setColor(card.getColor(game), game); + } + return true; + } + return false; + } + + protected static void setColor(ObjectColor color, Game game) { + color.setWhite(true); + color.setGreen(false); + color.setBlue(false); + color.setBlack(false); + color.setRed(false); + } + + @Override + public CelestialDawnToWhiteEffect copy() { + return new CelestialDawnToWhiteEffect(this); + } + + private CelestialDawnToWhiteEffect(CelestialDawnToWhiteEffect effect) { + super(effect); + } + +} + +class CelestialDawnSpendAnyManaEffect extends AsThoughEffectImpl { + + public CelestialDawnSpendAnyManaEffect() { + super(AsThoughEffectType.SPEND_ANY_MANA, Duration.Custom, Outcome.Benefit); + staticText = "You may spend white mana as though it were mana of any color"; + } + + public CelestialDawnSpendAnyManaEffect(final CelestialDawnSpendAnyManaEffect effect) { + super(effect); + } + + @Override + public boolean apply(Game game, Ability source) { + return true; + } + + @Override + public CelestialDawnSpendAnyManaEffect copy() { + return new CelestialDawnSpendAnyManaEffect(this); + } + + @Override + public boolean applies(UUID objectId, Ability source, UUID affectedControllerId, Game game) { + return true; // not used for mana thought as effects + } + + @Override + public boolean applies(UUID objectId, Ability source, UUID affectedControllerId, Game game, ManaType manaType, ManaPoolItem mana) { + if (affectedControllerId.equals(source.getControllerId())) { + return mana.getWhite() > 0; + } + return false; + } +} + +class CelestialDawnSpendColorlessManaEffect extends AsThoughEffectImpl { + + public CelestialDawnSpendColorlessManaEffect() { + super(AsThoughEffectType.SPEND_COLORLESS_MANA, Duration.Custom, Outcome.Detriment); + staticText = "You may spend other mana only as though it were colorless mana"; + } + + public CelestialDawnSpendColorlessManaEffect(final CelestialDawnSpendColorlessManaEffect effect) { + super(effect); + } + + @Override + public boolean apply(Game game, Ability source) { + return true; + } + + @Override + public CelestialDawnSpendColorlessManaEffect copy() { + return new CelestialDawnSpendColorlessManaEffect(this); + } + + @Override + public boolean applies(UUID objectId, Ability source, UUID affectedControllerId, Game game) { + return true; // not used for mana thought as effects + } + + @Override + public boolean applies(UUID objectId, Ability source, UUID affectedControllerId, Game game, ManaType manaType, ManaPoolItem mana) { + if (affectedControllerId.equals(source.getControllerId())) { + return mana.getWhite() == 0; + } + return false; + } +} diff --git a/Mage/src/mage/abilities/effects/AsThoughEffect.java b/Mage/src/mage/abilities/effects/AsThoughEffect.java index c65b2638e78..21d77b1bfdc 100644 --- a/Mage/src/mage/abilities/effects/AsThoughEffect.java +++ b/Mage/src/mage/abilities/effects/AsThoughEffect.java @@ -1,16 +1,16 @@ /* * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. - * + * * Redistribution and use in source and binary forms, with or without modification, are * permitted provided that the following conditions are met: - * + * * 1. Redistributions of source code must retain the above copyright notice, this list of * conditions and the following disclaimer. - * + * * 2. Redistributions in binary form must reproduce the above copyright notice, this list * of conditions and the following disclaimer in the documentation and/or other materials * provided with the distribution. - * + * * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR @@ -20,18 +20,19 @@ * 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; import java.util.UUID; -import mage.constants.AsThoughEffectType; import mage.abilities.Ability; +import mage.constants.AsThoughEffectType; +import mage.constants.ManaType; import mage.game.Game; +import mage.players.ManaPoolItem; /** * @@ -40,7 +41,11 @@ import mage.game.Game; public interface AsThoughEffect extends ContinuousEffect { boolean applies(UUID sourceId, Ability affectedAbility, Ability source, Game game); + boolean applies(UUID sourceId, Ability source, UUID affectedControllerId, Game game); + + boolean applies(UUID sourceId, Ability source, UUID affectedControllerId, Game game, ManaType manaType, ManaPoolItem mana); + AsThoughEffectType getAsThoughEffectType(); @Override diff --git a/Mage/src/mage/abilities/effects/AsThoughEffectImpl.java b/Mage/src/mage/abilities/effects/AsThoughEffectImpl.java index 5b2812b01d5..eb72239187f 100644 --- a/Mage/src/mage/abilities/effects/AsThoughEffectImpl.java +++ b/Mage/src/mage/abilities/effects/AsThoughEffectImpl.java @@ -1,16 +1,16 @@ /* * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. - * + * * Redistribution and use in source and binary forms, with or without modification, are * permitted provided that the following conditions are met: - * + * * 1. Redistributions of source code must retain the above copyright notice, this list of * conditions and the following disclaimer. - * + * * 2. Redistributions in binary form must reproduce the above copyright notice, this list * of conditions and the following disclaimer in the documentation and/or other materials * provided with the distribution. - * + * * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR @@ -20,12 +20,11 @@ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * + * * The views and conclusions contained in the software and documentation are those of the * authors and should not be interpreted as representing official policies, either expressed * or implied, of BetaSteward_at_googlemail.com. */ - package mage.abilities.effects; import java.util.UUID; @@ -33,8 +32,10 @@ import mage.abilities.Ability; import mage.constants.AsThoughEffectType; import mage.constants.Duration; import mage.constants.EffectType; +import mage.constants.ManaType; import mage.constants.Outcome; import mage.game.Game; +import mage.players.ManaPoolItem; /** * @@ -54,12 +55,17 @@ public abstract class AsThoughEffectImpl extends ContinuousEffectImpl implements super(effect); this.type = effect.type; } - + @Override public boolean applies(UUID objectId, Ability affectedAbility, Ability source, Game game) { return applies(objectId, source, affectedAbility.getControllerId(), game); } + @Override + public boolean applies(UUID sourceId, Ability source, UUID affectedControllerId, Game game, ManaType manaType, ManaPoolItem mana) { + return false; + } + @Override public AsThoughEffectType getAsThoughEffectType() { return type; diff --git a/Mage/src/mage/abilities/effects/ContinuousEffects.java b/Mage/src/mage/abilities/effects/ContinuousEffects.java index 29bf3662dac..00133342fc6 100644 --- a/Mage/src/mage/abilities/effects/ContinuousEffects.java +++ b/Mage/src/mage/abilities/effects/ContinuousEffects.java @@ -55,6 +55,7 @@ import mage.constants.CostModificationType; import mage.constants.Duration; import mage.constants.EffectType; import mage.constants.Layer; +import mage.constants.ManaType; import mage.constants.Outcome; import mage.constants.SpellAbilityType; import mage.constants.SubLayer; @@ -70,6 +71,7 @@ import mage.game.events.ZoneChangeEvent; import mage.game.permanent.Permanent; import mage.game.permanent.PermanentCard; import mage.game.stack.Spell; +import mage.players.ManaPoolItem; import mage.players.Player; import mage.target.common.TargetCardInHand; import org.apache.log4j.Logger; @@ -546,6 +548,26 @@ public class ContinuousEffects implements Serializable { } + public boolean asThoughMana(UUID objectId, AsThoughEffectType type, Ability affectedAbility, UUID controllerId, Game game, ManaType manaType, ManaPoolItem mana) { + List asThoughEffectsList = getApplicableAsThoughEffects(type, game); + for (AsThoughEffect effect : asThoughEffectsList) { + HashSet abilities = asThoughEffectsMap.get(type).getAbility(effect.getId()); + for (Ability ability : abilities) { + if (affectedAbility == null) { + if (effect.applies(objectId, ability, controllerId, game)) { + return true; + } + } else { + if (effect.applies(objectId, affectedAbility, ability, game)) { + return true; + } + } + } + } + return false; + + } + /** * Filters out asThough effects that are not active. * diff --git a/Mage/src/mage/constants/AsThoughEffectType.java b/Mage/src/mage/constants/AsThoughEffectType.java index 61c98018f24..768d14f37b2 100644 --- a/Mage/src/mage/constants/AsThoughEffectType.java +++ b/Mage/src/mage/constants/AsThoughEffectType.java @@ -5,12 +5,13 @@ package mage.constants; * @author North */ public enum AsThoughEffectType { + ATTACK, ACTIVATE_HASTE, BLOCK_TAPPED, BLOCK_SHADOW, BLOCK_DRAGON, - BE_BLOCKED, + BE_BLOCKED, PLAY_FROM_NOT_OWN_HAND_ZONE, CAST_AS_INSTANT, ACTIVATE_AS_INSTANT, @@ -19,5 +20,6 @@ public enum AsThoughEffectType { PAY, LOOK_AT_FACE_DOWN, SPEND_ANY_MANA, + SPEND_COLORLESS_MANA, TARGET } diff --git a/Mage/src/mage/players/ManaPool.java b/Mage/src/mage/players/ManaPool.java index f4745ac20ca..e2fe28e201d 100644 --- a/Mage/src/mage/players/ManaPool.java +++ b/Mage/src/mage/players/ManaPool.java @@ -65,6 +65,13 @@ public class ManaPool implements Serializable { private final Set doNotEmptyManaTypes = new HashSet<>(); + private enum SpendType { + + NORMAL, + ANY, + COLORLESS + } + public ManaPool(UUID playerId) { this.playerId = playerId; autoPayment = true; @@ -138,29 +145,37 @@ public class ManaPool implements Serializable { // no mana added beyond the stock so don't auto pay this continue; } - boolean spendAnyMana = spendAnyMana(ability, game); - if (mana.get(manaType) > 0 || (spendAnyMana && mana.count() > 0)) { - GameEvent event = new GameEvent(GameEvent.EventType.MANA_PAYED, ability.getId(), mana.getSourceId(), ability.getControllerId(), 0, mana.getFlag()); - event.setData(mana.getOriginalId().toString()); - game.fireEvent(event); - if (spendAnyMana) { - mana.removeAny(); - } else { - mana.remove(manaType); + SpendType spendType = getSpendType(ability, game, manaType, mana); + if (!SpendType.COLORLESS.equals(spendType) || ManaType.COLORLESS.equals(manaType)) { + if (mana.get(manaType) > 0 || (spendType.equals(SpendType.ANY) && mana.count() > 0)) { + GameEvent event = new GameEvent(GameEvent.EventType.MANA_PAYED, ability.getId(), mana.getSourceId(), ability.getControllerId(), 0, mana.getFlag()); + event.setData(mana.getOriginalId().toString()); + game.fireEvent(event); + if (!SpendType.NORMAL.equals(spendType)) { + mana.removeAny(); + } else { + mana.remove(manaType); + } + if (mana.count() == 0) { // so no items with count 0 stay in list + manaItems.remove(mana); + } + lockManaType(); // pay only one mana if mana payment is set to manually + return true; } - if (mana.count() == 0) { // so no items with count 0 stay in list - manaItems.remove(mana); - } - lockManaType(); // pay only one mana if mana payment is set to manually - return true; } } return false; } // check if any mana can be spend to cast the mana cost of an ability - private boolean spendAnyMana(Ability ability, Game game) { - return game.getContinuousEffects().asThough(ability.getSourceId(), AsThoughEffectType.SPEND_ANY_MANA, ability, ability.getControllerId(), game); + private SpendType getSpendType(Ability ability, Game game, ManaType manaType, ManaPoolItem mana) { + if (game.getContinuousEffects().asThoughMana(ability.getSourceId(), AsThoughEffectType.SPEND_ANY_MANA, ability, ability.getControllerId(), game, manaType, mana)) { + return SpendType.ANY; + } + if (game.getContinuousEffects().asThoughMana(ability.getSourceId(), AsThoughEffectType.SPEND_COLORLESS_MANA, ability, ability.getControllerId(), game, manaType, mana)) { + return SpendType.COLORLESS; + } + return SpendType.NORMAL; } public int get(ManaType manaType) { From cc21f8c8b13e5551182bf321a03d19a5ffd58514 Mon Sep 17 00:00:00 2001 From: LoneFox Date: Mon, 5 Oct 2015 19:47:21 +0300 Subject: [PATCH 021/268] Implement cards: Khabal Ghoul, Osai Vultures, and Scavenging Ghoul --- .../mage/sets/arabiannights/KhabalGhoul.java | 54 +++++++++++++ .../mage/sets/fourthedition/OsaiVultures.java | 54 +++++++++++++ .../sets/fourthedition/ScavengingGhoul.java | 52 ++++++++++++ .../src/mage/sets/legends/OsaiVultures.java | 80 +++++++++++++++++++ .../sets/limitedalpha/ScavengingGhoul.java | 75 +++++++++++++++++ .../sets/limitedbeta/ScavengingGhoul.java | 52 ++++++++++++ .../mage/sets/mastersedition/KhabalGhoul.java | 68 ++++++++++++++++ .../sets/masterseditioniv/OsaiVultures.java | 52 ++++++++++++ .../masterseditioniv/ScavengingGhoul.java | 52 ++++++++++++ .../sets/revisededition/ScavengingGhoul.java | 52 ++++++++++++ .../unlimitededition/ScavengingGhoul.java | 52 ++++++++++++ .../common/CreaturesDiedThisTurnCount.java | 65 +++++++++++++++ Mage/src/mage/counters/CounterType.java | 2 + 13 files changed, 710 insertions(+) create mode 100644 Mage.Sets/src/mage/sets/arabiannights/KhabalGhoul.java create mode 100644 Mage.Sets/src/mage/sets/fourthedition/OsaiVultures.java create mode 100644 Mage.Sets/src/mage/sets/fourthedition/ScavengingGhoul.java create mode 100644 Mage.Sets/src/mage/sets/legends/OsaiVultures.java create mode 100644 Mage.Sets/src/mage/sets/limitedalpha/ScavengingGhoul.java create mode 100644 Mage.Sets/src/mage/sets/limitedbeta/ScavengingGhoul.java create mode 100644 Mage.Sets/src/mage/sets/mastersedition/KhabalGhoul.java create mode 100644 Mage.Sets/src/mage/sets/masterseditioniv/OsaiVultures.java create mode 100644 Mage.Sets/src/mage/sets/masterseditioniv/ScavengingGhoul.java create mode 100644 Mage.Sets/src/mage/sets/revisededition/ScavengingGhoul.java create mode 100644 Mage.Sets/src/mage/sets/unlimitededition/ScavengingGhoul.java create mode 100644 Mage/src/mage/abilities/dynamicvalue/common/CreaturesDiedThisTurnCount.java diff --git a/Mage.Sets/src/mage/sets/arabiannights/KhabalGhoul.java b/Mage.Sets/src/mage/sets/arabiannights/KhabalGhoul.java new file mode 100644 index 00000000000..6ba202dbc5f --- /dev/null +++ b/Mage.Sets/src/mage/sets/arabiannights/KhabalGhoul.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.arabiannights; + +import java.util.UUID; +import mage.constants.Rarity; + +/** + * + * @author LoneFox + */ +public class KhabalGhoul extends mage.sets.mastersedition.KhabalGhoul { + + public KhabalGhoul(UUID ownerId) { + super(ownerId); + this.cardNumber = 10; + this.expansionSetCode = "ARN"; + this.rarity = Rarity.UNCOMMON; + } + + public KhabalGhoul(final KhabalGhoul card) { + super(card); + } + + @Override + public KhabalGhoul copy() { + return new KhabalGhoul(this); + } +} diff --git a/Mage.Sets/src/mage/sets/fourthedition/OsaiVultures.java b/Mage.Sets/src/mage/sets/fourthedition/OsaiVultures.java new file mode 100644 index 00000000000..2bbcdbce66b --- /dev/null +++ b/Mage.Sets/src/mage/sets/fourthedition/OsaiVultures.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.fourthedition; + +import java.util.UUID; +import mage.constants.Rarity; + +/** + * + * @author LoneFox + */ +public class OsaiVultures extends mage.sets.legends.OsaiVultures { + + public OsaiVultures(UUID ownerId) { + super(ownerId); + this.cardNumber = 288; + this.expansionSetCode = "4ED"; + this.rarity = Rarity.UNCOMMON; + } + + public OsaiVultures(final OsaiVultures card) { + super(card); + } + + @Override + public OsaiVultures copy() { + return new OsaiVultures(this); + } +} diff --git a/Mage.Sets/src/mage/sets/fourthedition/ScavengingGhoul.java b/Mage.Sets/src/mage/sets/fourthedition/ScavengingGhoul.java new file mode 100644 index 00000000000..e6c3af13f8a --- /dev/null +++ b/Mage.Sets/src/mage/sets/fourthedition/ScavengingGhoul.java @@ -0,0 +1,52 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.sets.fourthedition; + +import java.util.UUID; + +/** + * + * @author LoneFox + */ +public class ScavengingGhoul extends mage.sets.limitedalpha.ScavengingGhoul { + + public ScavengingGhoul(UUID ownerId) { + super(ownerId); + this.cardNumber = 43; + this.expansionSetCode = "4ED"; + } + + public ScavengingGhoul(final ScavengingGhoul card) { + super(card); + } + + @Override + public ScavengingGhoul copy() { + return new ScavengingGhoul(this); + } +} diff --git a/Mage.Sets/src/mage/sets/legends/OsaiVultures.java b/Mage.Sets/src/mage/sets/legends/OsaiVultures.java new file mode 100644 index 00000000000..1aa3c739ff8 --- /dev/null +++ b/Mage.Sets/src/mage/sets/legends/OsaiVultures.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.MageInt; +import mage.abilities.common.BeginningOfEndStepTriggeredAbility; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.condition.common.MorbidCondition; +import mage.abilities.costs.common.RemoveCountersSourceCost; +import mage.abilities.decorator.ConditionalTriggeredAbility; +import mage.abilities.effects.common.continuous.BoostSourceEffect; +import mage.abilities.effects.common.counter.AddCountersSourceEffect; +import mage.abilities.keyword.FlyingAbility; +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.counters.CounterType; + +/** + * + * @author LoneFox + */ +public class OsaiVultures extends CardImpl { + + public OsaiVultures(UUID ownerId) { + super(ownerId, 198, "Osai Vultures", Rarity.COMMON, new CardType[]{CardType.CREATURE}, "{1}{W}"); + this.expansionSetCode = "LEG"; + this.subtype.add("Bird"); + this.power = new MageInt(1); + this.toughness = new MageInt(1); + + // Flying + this.addAbility(FlyingAbility.getInstance()); + // At the beginning of each end step, if a creature died this turn, put a carrion counter on Osai Vultures. + this.addAbility(new ConditionalTriggeredAbility(new BeginningOfEndStepTriggeredAbility( + new AddCountersSourceEffect(CounterType.CARRION.createInstance()), TargetController.ANY, false), MorbidCondition.getInstance(), + "At the beginning of each end step, if a creature died this turn, put a carrion counter on {this}.")); + // Remove two carrion counters from Osai Vultures: Osai Vultures gets +1/+1 until end of turn. + this.addAbility(new SimpleActivatedAbility(Zone.BATTLEFIELD, new BoostSourceEffect(1, 1, Duration.EndOfTurn), + new RemoveCountersSourceCost(CounterType.CARRION.createInstance(2)))); + } + + public OsaiVultures(final OsaiVultures card) { + super(card); + } + + @Override + public OsaiVultures copy() { + return new OsaiVultures(this); + } +} diff --git a/Mage.Sets/src/mage/sets/limitedalpha/ScavengingGhoul.java b/Mage.Sets/src/mage/sets/limitedalpha/ScavengingGhoul.java new file mode 100644 index 00000000000..d69bbee0f1d --- /dev/null +++ b/Mage.Sets/src/mage/sets/limitedalpha/ScavengingGhoul.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.limitedalpha; + +import java.util.UUID; +import mage.MageInt; +import mage.abilities.common.BeginningOfEndStepTriggeredAbility; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.costs.common.RemoveCountersSourceCost; +import mage.abilities.dynamicvalue.common.CreaturesDiedThisTurnCount; +import mage.abilities.effects.common.RegenerateSourceEffect; +import mage.abilities.effects.common.counter.AddCountersSourceEffect; +import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.Rarity; +import mage.constants.TargetController; +import mage.constants.Zone; +import mage.counters.CounterType; +import mage.watchers.common.CreaturesDiedWatcher; + +/** + * + * @author LoneFox + */ +public class ScavengingGhoul extends CardImpl { + + public ScavengingGhoul(UUID ownerId) { + super(ownerId, 35, "Scavenging Ghoul", Rarity.UNCOMMON, new CardType[]{CardType.CREATURE}, "{3}{B}"); + this.expansionSetCode = "LEA"; + this.subtype.add("Zombie"); + this.power = new MageInt(2); + this.toughness = new MageInt(2); + + // At the beginning of each end step, put a corpse counter on Scavenging Ghoul for each creature that died this turn. + this.addAbility(new BeginningOfEndStepTriggeredAbility(new AddCountersSourceEffect(CounterType.CORPSE.createInstance(), + new CreaturesDiedThisTurnCount(), true), TargetController.ANY, false), new CreaturesDiedWatcher()); + // Remove a corpse counter from Scavenging Ghoul: Regenerate Scavenging Ghoul. + this.addAbility(new SimpleActivatedAbility(Zone.BATTLEFIELD, new RegenerateSourceEffect(), + new RemoveCountersSourceCost(CounterType.CORPSE.createInstance()))); + } + + public ScavengingGhoul(final ScavengingGhoul card) { + super(card); + } + + @Override + public ScavengingGhoul copy() { + return new ScavengingGhoul(this); + } +} diff --git a/Mage.Sets/src/mage/sets/limitedbeta/ScavengingGhoul.java b/Mage.Sets/src/mage/sets/limitedbeta/ScavengingGhoul.java new file mode 100644 index 00000000000..b3c4bb3cc12 --- /dev/null +++ b/Mage.Sets/src/mage/sets/limitedbeta/ScavengingGhoul.java @@ -0,0 +1,52 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.sets.limitedbeta; + +import java.util.UUID; + +/** + * + * @author LoneFox + */ +public class ScavengingGhoul extends mage.sets.limitedalpha.ScavengingGhoul { + + public ScavengingGhoul(UUID ownerId) { + super(ownerId); + this.cardNumber = 35; + this.expansionSetCode = "LEB"; + } + + public ScavengingGhoul(final ScavengingGhoul card) { + super(card); + } + + @Override + public ScavengingGhoul copy() { + return new ScavengingGhoul(this); + } +} diff --git a/Mage.Sets/src/mage/sets/mastersedition/KhabalGhoul.java b/Mage.Sets/src/mage/sets/mastersedition/KhabalGhoul.java new file mode 100644 index 00000000000..b8e28ac2e5e --- /dev/null +++ b/Mage.Sets/src/mage/sets/mastersedition/KhabalGhoul.java @@ -0,0 +1,68 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.sets.mastersedition; + +import java.util.UUID; +import mage.MageInt; +import mage.abilities.common.BeginningOfEndStepTriggeredAbility; +import mage.abilities.dynamicvalue.common.CreaturesDiedThisTurnCount; +import mage.abilities.effects.common.counter.AddCountersSourceEffect; +import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.Rarity; +import mage.constants.TargetController; +import mage.counters.CounterType; +import mage.watchers.common.CreaturesDiedWatcher; + +/** + * + * @author LoneFox + */ +public class KhabalGhoul extends CardImpl { + + public KhabalGhoul(UUID ownerId) { + super(ownerId, 75, "Khabal Ghoul", Rarity.RARE, new CardType[]{CardType.CREATURE}, "{2}{B}"); + this.expansionSetCode = "MED"; + this.subtype.add("Zombie"); + this.power = new MageInt(1); + this.toughness = new MageInt(1); + + // At the beginning of each end step, put a +1/+1 counter on Khabal Ghoul for each creature that died this turn. + this.addAbility(new BeginningOfEndStepTriggeredAbility(new AddCountersSourceEffect(CounterType.P1P1.createInstance(), + new CreaturesDiedThisTurnCount(), true), TargetController.ANY, false), new CreaturesDiedWatcher()); + } + + public KhabalGhoul(final KhabalGhoul card) { + super(card); + } + + @Override + public KhabalGhoul copy() { + return new KhabalGhoul(this); + } +} diff --git a/Mage.Sets/src/mage/sets/masterseditioniv/OsaiVultures.java b/Mage.Sets/src/mage/sets/masterseditioniv/OsaiVultures.java new file mode 100644 index 00000000000..f7d15e66619 --- /dev/null +++ b/Mage.Sets/src/mage/sets/masterseditioniv/OsaiVultures.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.masterseditioniv; + +import java.util.UUID; + +/** + * + * @author LoneFox + */ +public class OsaiVultures extends mage.sets.legends.OsaiVultures { + + public OsaiVultures(UUID ownerId) { + super(ownerId); + this.cardNumber = 21; + this.expansionSetCode = "ME4"; + } + + public OsaiVultures(final OsaiVultures card) { + super(card); + } + + @Override + public OsaiVultures copy() { + return new OsaiVultures(this); + } +} diff --git a/Mage.Sets/src/mage/sets/masterseditioniv/ScavengingGhoul.java b/Mage.Sets/src/mage/sets/masterseditioniv/ScavengingGhoul.java new file mode 100644 index 00000000000..700e284c555 --- /dev/null +++ b/Mage.Sets/src/mage/sets/masterseditioniv/ScavengingGhoul.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.masterseditioniv; + +import java.util.UUID; + +/** + * + * @author LoneFox + */ +public class ScavengingGhoul extends mage.sets.limitedalpha.ScavengingGhoul { + + public ScavengingGhoul(UUID ownerId) { + super(ownerId); + this.cardNumber = 95; + this.expansionSetCode = "ME4"; + } + + public ScavengingGhoul(final ScavengingGhoul card) { + super(card); + } + + @Override + public ScavengingGhoul copy() { + return new ScavengingGhoul(this); + } +} diff --git a/Mage.Sets/src/mage/sets/revisededition/ScavengingGhoul.java b/Mage.Sets/src/mage/sets/revisededition/ScavengingGhoul.java new file mode 100644 index 00000000000..2fcc75753e8 --- /dev/null +++ b/Mage.Sets/src/mage/sets/revisededition/ScavengingGhoul.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.revisededition; + +import java.util.UUID; + +/** + * + * @author LoneFox + */ +public class ScavengingGhoul extends mage.sets.limitedalpha.ScavengingGhoul { + + public ScavengingGhoul(UUID ownerId) { + super(ownerId); + this.cardNumber = 36; + this.expansionSetCode = "3ED"; + } + + public ScavengingGhoul(final ScavengingGhoul card) { + super(card); + } + + @Override + public ScavengingGhoul copy() { + return new ScavengingGhoul(this); + } +} diff --git a/Mage.Sets/src/mage/sets/unlimitededition/ScavengingGhoul.java b/Mage.Sets/src/mage/sets/unlimitededition/ScavengingGhoul.java new file mode 100644 index 00000000000..b98e8feaee5 --- /dev/null +++ b/Mage.Sets/src/mage/sets/unlimitededition/ScavengingGhoul.java @@ -0,0 +1,52 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.sets.unlimitededition; + +import java.util.UUID; + +/** + * + * @author LoneFox + */ +public class ScavengingGhoul extends mage.sets.limitedalpha.ScavengingGhoul { + + public ScavengingGhoul(UUID ownerId) { + super(ownerId); + this.cardNumber = 35; + this.expansionSetCode = "2ED"; + } + + public ScavengingGhoul(final ScavengingGhoul card) { + super(card); + } + + @Override + public ScavengingGhoul copy() { + return new ScavengingGhoul(this); + } +} diff --git a/Mage/src/mage/abilities/dynamicvalue/common/CreaturesDiedThisTurnCount.java b/Mage/src/mage/abilities/dynamicvalue/common/CreaturesDiedThisTurnCount.java new file mode 100644 index 00000000000..5f596b83536 --- /dev/null +++ b/Mage/src/mage/abilities/dynamicvalue/common/CreaturesDiedThisTurnCount.java @@ -0,0 +1,65 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.abilities.dynamicvalue.common; + +import mage.abilities.Ability; +import mage.abilities.dynamicvalue.DynamicValue; +import mage.abilities.effects.Effect; +import mage.game.Game; +import mage.watchers.common.CreaturesDiedWatcher; + +/** + * @author LoneFox + */ +public class CreaturesDiedThisTurnCount implements DynamicValue { + + @Override + public int calculate(Game game, Ability sourceAbility, Effect effect) { + CreaturesDiedWatcher watcher = (CreaturesDiedWatcher)game.getState().getWatchers().get("CreaturesDiedWatcher"); + if (watcher != null) { + return watcher.getAmountOfCreaturesDiesThisTurn(); + } + return 0; + } + + @Override + public CreaturesDiedThisTurnCount copy() { + return new CreaturesDiedThisTurnCount(); + } + + @Override + public String toString() { + return "X"; + } + + @Override + public String getMessage() { + return "creature that died this turn"; + } + +} diff --git a/Mage/src/mage/counters/CounterType.java b/Mage/src/mage/counters/CounterType.java index 3f952c8ef96..86abda9c383 100644 --- a/Mage/src/mage/counters/CounterType.java +++ b/Mage/src/mage/counters/CounterType.java @@ -40,7 +40,9 @@ public enum CounterType { AWAKENING("awakening"), BLAZE("blaze"), BRIBERY("bribery"), + CARRION("carrion"), CHARGE("charge"), + CORPSE("corpse"), CRYSTAL("crystal"), DELAY("delay"), DEPLETION("depletion"), From 6a78684da8428cb702d8593482871e16d8688e6f Mon Sep 17 00:00:00 2001 From: LevelX2 Date: Tue, 6 Oct 2015 00:47:17 +0200 Subject: [PATCH 022/268] * Blatant Thievery - Changed handling to custom target. --- .../mage/sets/magic2015/SoulOfShandalar.java | 9 +- .../mage/sets/onslaught/BlatantThievery.java | 132 +++++++++++++++--- .../mage/sets/planechase2012/MassMutiny.java | 18 ++- .../effects/common/BasicManaEffect.java | 5 +- Mage/src/mage/filter/FilterPermanent.java | 57 ++++---- 5 files changed, 158 insertions(+), 63 deletions(-) diff --git a/Mage.Sets/src/mage/sets/magic2015/SoulOfShandalar.java b/Mage.Sets/src/mage/sets/magic2015/SoulOfShandalar.java index 7c26bd21618..98de37ffeab 100644 --- a/Mage.Sets/src/mage/sets/magic2015/SoulOfShandalar.java +++ b/Mage.Sets/src/mage/sets/magic2015/SoulOfShandalar.java @@ -27,6 +27,9 @@ */ package mage.sets.magic2015; +import java.util.HashSet; +import java.util.Set; +import java.util.UUID; import mage.MageInt; import mage.MageObject; import mage.abilities.Ability; @@ -48,10 +51,6 @@ import mage.players.Player; import mage.target.TargetPermanent; import mage.target.TargetPlayer; -import java.util.HashSet; -import java.util.Set; -import java.util.UUID; - /** * @author noxx */ @@ -145,7 +144,7 @@ class SoulOfShandalarTarget extends TargetPermanent { @Override public Set possibleTargets(UUID sourceId, UUID sourceControllerId, Game game) { Set availablePossibleTargets = super.possibleTargets(sourceId, sourceControllerId, game); - Set possibleTargets = new HashSet(); + Set possibleTargets = new HashSet<>(); MageObject object = game.getObject(sourceId); for (StackObject item : game.getState().getStack()) { diff --git a/Mage.Sets/src/mage/sets/onslaught/BlatantThievery.java b/Mage.Sets/src/mage/sets/onslaught/BlatantThievery.java index 09586f61089..b4ec25b2bc3 100644 --- a/Mage.Sets/src/mage/sets/onslaught/BlatantThievery.java +++ b/Mage.Sets/src/mage/sets/onslaught/BlatantThievery.java @@ -27,7 +27,12 @@ */ package mage.sets.onslaught; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; import java.util.UUID; +import mage.MageObject; import mage.abilities.Ability; import mage.abilities.SpellAbility; import mage.abilities.effects.ContinuousEffect; @@ -39,10 +44,8 @@ import mage.constants.Duration; import mage.constants.Outcome; import mage.constants.Rarity; import mage.filter.FilterPermanent; -import mage.filter.predicate.permanent.ControllerIdPredicate; import mage.game.Game; -import mage.players.Player; -import mage.target.Target; +import mage.game.permanent.Permanent; import mage.target.TargetPermanent; import mage.target.targetpointer.FixedTarget; @@ -63,19 +66,12 @@ public class BlatantThievery extends CardImpl { public BlatantThievery(final BlatantThievery card) { super(card); } - + @Override public void adjustTargets(Ability ability, Game game) { if (ability instanceof SpellAbility) { ability.getTargets().clear(); - for (UUID opponentId : game.getOpponents(ability.getControllerId())) { - Player opponent = game.getPlayer(opponentId); - if (opponent != null) { - FilterPermanent filter = new FilterPermanent("permanent controlled by " + opponent.getName()); - filter.add(new ControllerIdPredicate(opponentId)); - ability.addTarget(new TargetPermanent(filter)); - } - } + ability.addTarget(new BlatantThieveryTarget(game.getOpponents(ability.getControllerId()).size())); } } @@ -86,28 +82,128 @@ public class BlatantThievery extends CardImpl { } class BlatantThieveryEffect extends OneShotEffect { - + BlatantThieveryEffect() { super(Outcome.GainControl); this.staticText = "For each opponent, gain control of target permanent that player controls"; } - + BlatantThieveryEffect(final BlatantThieveryEffect effect) { super(effect); } - + @Override public BlatantThieveryEffect copy() { return new BlatantThieveryEffect(this); } - + @Override public boolean apply(Game game, Ability source) { - for (Target target : source.getTargets()) { + for (UUID targetId : getTargetPointer().getTargets(game, source)) { ContinuousEffect effect = new GainControlTargetEffect(Duration.EndOfGame); - effect.setTargetPointer(new FixedTarget(target.getFirstTarget())); + effect.setTargetPointer(new FixedTarget(targetId)); game.addEffect(effect, source); } return true; } } + +class BlatantThieveryTarget extends TargetPermanent { + + Map targetOpponent = new HashMap<>(); + + public BlatantThieveryTarget(int opponents) { + super(opponents, opponents, new FilterPermanent("a permanent for each opponent"), false); + } + + public BlatantThieveryTarget(final BlatantThieveryTarget target) { + super(target); + this.targetOpponent.putAll(target.targetOpponent); + } + + @Override + public boolean canTarget(UUID controllerId, UUID objectId, Ability source, Game game) { + Permanent targetObject = game.getPermanent(objectId); + if (targetObject == null || !game.getOpponents(source.getControllerId()).contains(targetObject.getControllerId())) { + return false; + } + // If a permanent changes controller after being targeted but before this spell resolves, you won't gain control of that permanent. + if (targetOpponent.containsKey(objectId)) { + if (!targetOpponent.get(objectId).equals(targetObject.getControllerId())) { + return false; + } + } else { + // if already a target from this opponent exists, another can't be target + if (targetOpponent.values().contains(targetObject.getControllerId())) { + return false; + } + } + return super.canTarget(controllerId, objectId, source, game); + } + + @Override + public Set possibleTargets(UUID sourceId, UUID sourceControllerId, Game game) { + Set opponents = new HashSet<>(); + for (UUID targetId : getTargets()) { + Permanent oldTargets = game.getPermanent(targetId); + if (oldTargets != null) { + opponents.add(oldTargets.getControllerId()); + } + } + Set possibleTargets = new HashSet<>(); + MageObject mageObject = game.getObject(sourceId); + if (mageObject == null) { + return possibleTargets; + } + for (UUID opponentId : game.getOpponents(sourceControllerId)) { + if (opponents.contains(opponentId)) { + // Target for this opponent already selected + continue; + } + for (Permanent permanent : game.getBattlefield().getAllActivePermanents(opponentId)) { + if (permanent.canBeTargetedBy(mageObject, sourceControllerId, game)) { + possibleTargets.add(permanent.getId()); + } + } + } + return possibleTargets; + } + + @Override + public boolean canChoose(UUID sourceId, UUID sourceControllerId, Game game) { + for (UUID opponentId : game.getOpponents(sourceControllerId)) { + boolean targetAvailable = false; + for (Permanent permanent : game.getBattlefield().getAllActivePermanents(opponentId)) { + if (!targets.containsKey(permanent.getId())) { + MageObject mageObject = game.getObject(sourceId); + if (mageObject != null && permanent.canBeTargetedBy(mageObject, sourceControllerId, game)) { + targetAvailable = true; + break; + } + + } else { + targetAvailable = true; + break; + } + } + if (!targetAvailable) { + return false; + } + } + return true; + } + + @Override + public void addTarget(UUID objectId, int amount, Ability source, Game game, boolean skipEvent) { + Permanent targetObject = game.getPermanent(objectId); + if (targetObject != null) { + targetOpponent.put(objectId, targetObject.getControllerId()); + } + super.addTarget(objectId, amount, source, game, skipEvent); + } + + @Override + public BlatantThieveryTarget copy() { + return new BlatantThieveryTarget(this); + } +} diff --git a/Mage.Sets/src/mage/sets/planechase2012/MassMutiny.java b/Mage.Sets/src/mage/sets/planechase2012/MassMutiny.java index fd242dfa30e..3931ee3e8ec 100644 --- a/Mage.Sets/src/mage/sets/planechase2012/MassMutiny.java +++ b/Mage.Sets/src/mage/sets/planechase2012/MassMutiny.java @@ -28,11 +28,6 @@ package mage.sets.planechase2012; 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.SpellAbility; import mage.abilities.effects.ContinuousEffect; @@ -41,6 +36,10 @@ import mage.abilities.effects.common.continuous.GainAbilityTargetEffect; import mage.abilities.effects.common.continuous.GainControlTargetEffect; import mage.abilities.keyword.HasteAbility; import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.Outcome; +import mage.constants.Rarity; import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.permanent.ControllerIdPredicate; import mage.game.Game; @@ -60,20 +59,20 @@ public class MassMutiny extends CardImpl { super(ownerId, 48, "Mass Mutiny", Rarity.RARE, new CardType[]{CardType.SORCERY}, "{3}{R}{R}"); this.expansionSetCode = "PC2"; - this.getSpellAbility().addEffect(new MassMutinyEffect()); // For each opponent, gain control of up to one target creature that player controls until end of turn. Untap those creatures. They gain haste until end of turn. + this.getSpellAbility().addEffect(new MassMutinyEffect()); } @Override public void adjustTargets(Ability ability, Game game) { if (ability instanceof SpellAbility) { - for(UUID opponentId : game.getOpponents(ability.getControllerId())) { + for (UUID opponentId : game.getOpponents(ability.getControllerId())) { Player opponent = game.getPlayer(opponentId); if (opponent != null) { ability.getTargets().clear(); FilterCreaturePermanent filter = new FilterCreaturePermanent("creature from opponent " + opponent.getLogName()); filter.add(new ControllerIdPredicate(opponentId)); - TargetCreaturePermanent target = new TargetCreaturePermanent(0,1, filter,false); + TargetCreaturePermanent target = new TargetCreaturePermanent(0, 1, filter, false); ability.addTarget(target); } } @@ -90,7 +89,6 @@ public class MassMutiny extends CardImpl { } } - class MassMutinyEffect extends OneShotEffect { public MassMutinyEffect() { @@ -110,7 +108,7 @@ class MassMutinyEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { boolean result = false; - for (Target target: source.getTargets()) { + for (Target target : source.getTargets()) { if (target instanceof TargetCreaturePermanent) { Permanent targetCreature = game.getPermanent(target.getFirstTarget()); if (targetCreature != null) { diff --git a/Mage/src/mage/abilities/effects/common/BasicManaEffect.java b/Mage/src/mage/abilities/effects/common/BasicManaEffect.java index b98d1dd7efb..95e7faa8eac 100644 --- a/Mage/src/mage/abilities/effects/common/BasicManaEffect.java +++ b/Mage/src/mage/abilities/effects/common/BasicManaEffect.java @@ -6,18 +6,19 @@ import mage.abilities.Ability; import mage.game.Game; public class BasicManaEffect extends ManaEffect { + protected Mana mana; public BasicManaEffect(Mana mana) { super(); this.mana = mana; - staticText = "Add " + mana.toString() + " to your mana pool"; + staticText = "add " + mana.toString() + " to your mana pool"; } public BasicManaEffect(ConditionalMana conditionalMana) { super(); this.mana = conditionalMana; - staticText = "Add " + mana.toString() + " to your mana pool. " + conditionalMana.getDescription(); + staticText = "add " + mana.toString() + " to your mana pool. " + conditionalMana.getDescription(); } public BasicManaEffect(final BasicManaEffect effect) { diff --git a/Mage/src/mage/filter/FilterPermanent.java b/Mage/src/mage/filter/FilterPermanent.java index 24b5418451a..5e14f969cc1 100644 --- a/Mage/src/mage/filter/FilterPermanent.java +++ b/Mage/src/mage/filter/FilterPermanent.java @@ -1,31 +1,30 @@ /* -* Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. -* -* Redistribution and use in source and binary forms, with or without modification, are -* permitted provided that the following conditions are met: -* -* 1. Redistributions of source code must retain the above copyright notice, this list of -* conditions and the following disclaimer. -* -* 2. Redistributions in binary form must reproduce the above copyright notice, this list -* of conditions and the following disclaimer in the documentation and/or other materials -* provided with the distribution. -* -* THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED -* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND -* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR -* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR -* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON -* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING -* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF -* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -* -* The views and conclusions contained in the software and documentation are those of the -* authors and should not be interpreted as representing official policies, either expressed -* or implied, of BetaSteward_at_googlemail.com. -*/ - + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ package mage.filter; import java.util.ArrayList; @@ -44,6 +43,7 @@ import mage.game.permanent.Permanent; * @author North */ public class FilterPermanent extends FilterObject implements FilterInPlay { + protected List>> extraPredicates = new ArrayList<>(); public FilterPermanent() { @@ -58,12 +58,13 @@ public class FilterPermanent extends FilterObject implements FilterIn public FilterPermanent(String name) { super(name); } - + public FilterPermanent(String subtype, String name) { super(name); this.add(new SubtypePredicate(subtype)); } + @Override public boolean match(Permanent permanent, UUID sourceId, UUID playerId, Game game) { if (!this.match(permanent, game)) { return false; From 5b4248f81dd7ce73f9bbe1cab4a2d3a51e2a773f Mon Sep 17 00:00:00 2001 From: LevelX2 Date: Tue, 6 Oct 2015 00:53:40 +0200 Subject: [PATCH 023/268] * Blatant Thievery - Changed handling to custom target. --- Mage.Sets/src/mage/sets/onslaught/BlatantThievery.java | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/Mage.Sets/src/mage/sets/onslaught/BlatantThievery.java b/Mage.Sets/src/mage/sets/onslaught/BlatantThievery.java index b4ec25b2bc3..12c5dc8cfe9 100644 --- a/Mage.Sets/src/mage/sets/onslaught/BlatantThievery.java +++ b/Mage.Sets/src/mage/sets/onslaught/BlatantThievery.java @@ -202,6 +202,12 @@ class BlatantThieveryTarget extends TargetPermanent { super.addTarget(objectId, amount, source, game, skipEvent); } + @Override + public void remove(UUID id) { + super.remove(id); + targetOpponent.remove(id); + } + @Override public BlatantThieveryTarget copy() { return new BlatantThieveryTarget(this); From 625aa29d6e7ac9476c363efb3698156134286a66 Mon Sep 17 00:00:00 2001 From: LevelX2 Date: Tue, 6 Oct 2015 17:28:59 +0200 Subject: [PATCH 024/268] Rework of "spend mana as though it were mana of" handling. --- .../java/mage/player/ai/ComputerPlayer.java | 2 +- .../mage/sets/darksteel/MycosynthLattice.java | 12 +- .../src/mage/sets/theros/DaxosOfMeletis.java | 17 +-- .../mage/sets/theros/PsychicIntrusion.java | 15 +-- .../mage/sets/timeshifted/CelestialDawn.java | 30 ++--- .../abilities/effects/AsThoughEffect.java | 4 - .../abilities/effects/AsThoughEffectImpl.java | 7 -- .../abilities/effects/AsThoughManaEffect.java | 45 +++++++ .../abilities/effects/ContinuousEffects.java | 35 ++++-- .../mage/constants/AsThoughEffectType.java | 4 +- Mage/src/mage/players/ManaPool.java | 48 ++----- Mage/src/mage/players/ManaPoolItem.java | 117 +++++++++--------- 12 files changed, 184 insertions(+), 152 deletions(-) create mode 100644 Mage/src/mage/abilities/effects/AsThoughManaEffect.java diff --git a/Mage.Server.Plugins/Mage.Player.AI/src/main/java/mage/player/ai/ComputerPlayer.java b/Mage.Server.Plugins/Mage.Player.AI/src/main/java/mage/player/ai/ComputerPlayer.java index c9913b4f111..f8666697568 100644 --- a/Mage.Server.Plugins/Mage.Player.AI/src/main/java/mage/player/ai/ComputerPlayer.java +++ b/Mage.Server.Plugins/Mage.Player.AI/src/main/java/mage/player/ai/ComputerPlayer.java @@ -1135,7 +1135,7 @@ public class ComputerPlayer extends PlayerImpl implements Player { protected boolean playManaHandling(Ability ability, ManaCost unpaid, Game game) { // log.info("paying for " + unpaid.getText()); - boolean spendAnyMana = game.getContinuousEffects().asThough(ability.getSourceId(), AsThoughEffectType.SPEND_ANY_MANA, ability, ability.getControllerId(), game); + boolean spendAnyMana = game.getContinuousEffects().asThough(ability.getSourceId(), AsThoughEffectType.SPEND_OTHER_MANA, ability, ability.getControllerId(), game); ManaCost cost; List producers; if (unpaid instanceof ManaCosts) { diff --git a/Mage.Sets/src/mage/sets/darksteel/MycosynthLattice.java b/Mage.Sets/src/mage/sets/darksteel/MycosynthLattice.java index fa2aa3f3c0b..b4932f89001 100644 --- a/Mage.Sets/src/mage/sets/darksteel/MycosynthLattice.java +++ b/Mage.Sets/src/mage/sets/darksteel/MycosynthLattice.java @@ -34,6 +34,7 @@ import mage.ObjectColor; import mage.abilities.Ability; import mage.abilities.common.SimpleStaticAbility; import mage.abilities.effects.AsThoughEffectImpl; +import mage.abilities.effects.AsThoughManaEffect; import mage.abilities.effects.ContinuousEffectImpl; import mage.cards.Card; import mage.cards.CardImpl; @@ -170,10 +171,10 @@ class EverythingIsColorlessEffect extends ContinuousEffectImpl { } } -class ManaCanBeSpentAsAnyColorEffect extends AsThoughEffectImpl { +class ManaCanBeSpentAsAnyColorEffect extends AsThoughEffectImpl implements AsThoughManaEffect { public ManaCanBeSpentAsAnyColorEffect() { - super(AsThoughEffectType.SPEND_ANY_MANA, Duration.WhileOnBattlefield, Outcome.Benefit); + super(AsThoughEffectType.SPEND_OTHER_MANA, Duration.WhileOnBattlefield, Outcome.Benefit); staticText = "Players may spend mana as though it were mana of any color"; } @@ -184,12 +185,13 @@ class ManaCanBeSpentAsAnyColorEffect extends AsThoughEffectImpl { @Override public boolean applies(UUID objectId, Ability source, UUID affectedControllerId, Game game) { - return true; // not used for mana thought as effects + Player controller = game.getPlayer(source.getControllerId()); + return controller != null && controller.getInRange().contains(affectedControllerId); } @Override - public boolean applies(UUID objectId, Ability source, UUID affectedControllerId, Game game, ManaType manaType, ManaPoolItem mana) { - return true; + public ManaType getAsThoughtManaType(ManaType manaType, ManaPoolItem mana, UUID affectedControllerId, Ability source, Game game) { + return mana.getFirstAvailable(); } @Override diff --git a/Mage.Sets/src/mage/sets/theros/DaxosOfMeletis.java b/Mage.Sets/src/mage/sets/theros/DaxosOfMeletis.java index e0208b506f0..adc2d74bae0 100644 --- a/Mage.Sets/src/mage/sets/theros/DaxosOfMeletis.java +++ b/Mage.Sets/src/mage/sets/theros/DaxosOfMeletis.java @@ -34,6 +34,7 @@ import mage.abilities.Ability; import mage.abilities.common.DealsCombatDamageToAPlayerTriggeredAbility; import mage.abilities.common.SimpleEvasionAbility; import mage.abilities.effects.AsThoughEffectImpl; +import mage.abilities.effects.AsThoughManaEffect; import mage.abilities.effects.ContinuousEffect; import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.combat.CantBeBlockedByCreaturesSourceEffect; @@ -183,10 +184,10 @@ class DaxosOfMeletisCastFromExileEffect extends AsThoughEffectImpl { } } -class DaxosOfMeletisSpendAnyManaEffect extends AsThoughEffectImpl { +class DaxosOfMeletisSpendAnyManaEffect extends AsThoughEffectImpl implements AsThoughManaEffect { public DaxosOfMeletisSpendAnyManaEffect() { - super(AsThoughEffectType.SPEND_ANY_MANA, Duration.EndOfTurn, Outcome.Benefit); + super(AsThoughEffectType.SPEND_OTHER_MANA, Duration.EndOfTurn, Outcome.Benefit); staticText = "you may spend mana as though it were mana of any color to cast it"; } @@ -206,14 +207,16 @@ class DaxosOfMeletisSpendAnyManaEffect extends AsThoughEffectImpl { @Override public boolean applies(UUID objectId, Ability source, UUID affectedControllerId, Game game) { - return true; // not used for mana thought as effects - } - - @Override - public boolean applies(UUID objectId, Ability source, UUID affectedControllerId, Game game, ManaType manaType, ManaPoolItem mana) { return source.getControllerId().equals(affectedControllerId) && objectId == ((FixedTarget) getTargetPointer()).getTarget() && ((FixedTarget) getTargetPointer()).getZoneChangeCounter() + 1 == game.getState().getZoneChangeCounter(objectId) + && (((FixedTarget) getTargetPointer()).getZoneChangeCounter() + 1 == game.getState().getZoneChangeCounter(objectId)) && game.getState().getZone(objectId).equals(Zone.STACK); } + + @Override + public ManaType getAsThoughtManaType(ManaType manaType, ManaPoolItem mana, UUID affectedControllerId, Ability source, Game game) { + return mana.getFirstAvailable(); + } + } diff --git a/Mage.Sets/src/mage/sets/theros/PsychicIntrusion.java b/Mage.Sets/src/mage/sets/theros/PsychicIntrusion.java index ed5d78e197c..d8e0268ba84 100644 --- a/Mage.Sets/src/mage/sets/theros/PsychicIntrusion.java +++ b/Mage.Sets/src/mage/sets/theros/PsychicIntrusion.java @@ -31,6 +31,7 @@ import java.util.UUID; import mage.MageObject; import mage.abilities.Ability; import mage.abilities.effects.AsThoughEffectImpl; +import mage.abilities.effects.AsThoughManaEffect; import mage.abilities.effects.ContinuousEffect; import mage.abilities.effects.OneShotEffect; import mage.cards.Card; @@ -190,10 +191,10 @@ class PsychicIntrusionCastFromExileEffect extends AsThoughEffectImpl { } } -class PsychicIntrusionSpendAnyManaEffect extends AsThoughEffectImpl { +class PsychicIntrusionSpendAnyManaEffect extends AsThoughEffectImpl implements AsThoughManaEffect { public PsychicIntrusionSpendAnyManaEffect() { - super(AsThoughEffectType.SPEND_ANY_MANA, Duration.Custom, Outcome.Benefit); + super(AsThoughEffectType.SPEND_OTHER_MANA, Duration.Custom, Outcome.Benefit); staticText = "you may spend mana as though it were mana of any color to cast it"; } @@ -213,11 +214,6 @@ class PsychicIntrusionSpendAnyManaEffect extends AsThoughEffectImpl { @Override public boolean applies(UUID objectId, Ability source, UUID affectedControllerId, Game game) { - return true; // not used for mana thought as effects - } - - @Override - public boolean applies(UUID objectId, Ability source, UUID affectedControllerId, Game game, ManaType manaType, ManaPoolItem mana) { if (objectId.equals(((FixedTarget) getTargetPointer()).getTarget()) && game.getState().getZoneChangeCounter(objectId) <= ((FixedTarget) getTargetPointer()).getZoneChangeCounter() + 1) { @@ -236,4 +232,9 @@ class PsychicIntrusionSpendAnyManaEffect extends AsThoughEffectImpl { } return false; } + + @Override + public ManaType getAsThoughtManaType(ManaType manaType, ManaPoolItem mana, UUID affectedControllerId, Ability source, Game game) { + return mana.getFirstAvailable(); + } } diff --git a/Mage.Sets/src/mage/sets/timeshifted/CelestialDawn.java b/Mage.Sets/src/mage/sets/timeshifted/CelestialDawn.java index e899f506b68..5bd296b7084 100644 --- a/Mage.Sets/src/mage/sets/timeshifted/CelestialDawn.java +++ b/Mage.Sets/src/mage/sets/timeshifted/CelestialDawn.java @@ -33,6 +33,7 @@ import mage.ObjectColor; import mage.abilities.Ability; import mage.abilities.common.SimpleStaticAbility; import mage.abilities.effects.AsThoughEffectImpl; +import mage.abilities.effects.AsThoughManaEffect; import mage.abilities.effects.ContinuousEffectImpl; import mage.abilities.mana.WhiteManaAbility; import mage.cards.Card; @@ -146,7 +147,6 @@ class CelestialDawnToWhiteEffect extends ContinuousEffectImpl { public CelestialDawnToWhiteEffect() { super(Duration.WhileOnBattlefield, Layer.ColorChangingEffects_5, SubLayer.NA, Outcome.Benefit); staticText = "Nonland cards you own that aren't on the battlefield, spells you control, and nonland permanents you control are white"; - staticText = "All cards that aren't on the battlefield, spells, and permanents are the chosen color in addition to their other colors"; } @Override @@ -213,10 +213,10 @@ class CelestialDawnToWhiteEffect extends ContinuousEffectImpl { } -class CelestialDawnSpendAnyManaEffect extends AsThoughEffectImpl { +class CelestialDawnSpendAnyManaEffect extends AsThoughEffectImpl implements AsThoughManaEffect { public CelestialDawnSpendAnyManaEffect() { - super(AsThoughEffectType.SPEND_ANY_MANA, Duration.Custom, Outcome.Benefit); + super(AsThoughEffectType.SPEND_OTHER_MANA, Duration.Custom, Outcome.Benefit); staticText = "You may spend white mana as though it were mana of any color"; } @@ -236,22 +236,22 @@ class CelestialDawnSpendAnyManaEffect extends AsThoughEffectImpl { @Override public boolean applies(UUID objectId, Ability source, UUID affectedControllerId, Game game) { - return true; // not used for mana thought as effects + return affectedControllerId.equals(source.getControllerId()); } @Override - public boolean applies(UUID objectId, Ability source, UUID affectedControllerId, Game game, ManaType manaType, ManaPoolItem mana) { - if (affectedControllerId.equals(source.getControllerId())) { - return mana.getWhite() > 0; + public ManaType getAsThoughtManaType(ManaType manaType, ManaPoolItem mana, UUID affectedControllerId, Ability source, Game game) { + if (mana.getWhite() > 0) { + return ManaType.WHITE; } - return false; + return null; } } -class CelestialDawnSpendColorlessManaEffect extends AsThoughEffectImpl { +class CelestialDawnSpendColorlessManaEffect extends AsThoughEffectImpl implements AsThoughManaEffect { public CelestialDawnSpendColorlessManaEffect() { - super(AsThoughEffectType.SPEND_COLORLESS_MANA, Duration.Custom, Outcome.Detriment); + super(AsThoughEffectType.SPEND_ONLY_MANA, Duration.Custom, Outcome.Detriment); staticText = "You may spend other mana only as though it were colorless mana"; } @@ -271,14 +271,14 @@ class CelestialDawnSpendColorlessManaEffect extends AsThoughEffectImpl { @Override public boolean applies(UUID objectId, Ability source, UUID affectedControllerId, Game game) { - return true; // not used for mana thought as effects + return affectedControllerId.equals(source.getControllerId()); } @Override - public boolean applies(UUID objectId, Ability source, UUID affectedControllerId, Game game, ManaType manaType, ManaPoolItem mana) { - if (affectedControllerId.equals(source.getControllerId())) { - return mana.getWhite() == 0; + public ManaType getAsThoughtManaType(ManaType manaType, ManaPoolItem mana, UUID affectedControllerId, Ability source, Game game) { + if (mana.getWhite() == 0 && !ManaType.COLORLESS.equals(manaType)) { + return null; } - return false; + return manaType; } } diff --git a/Mage/src/mage/abilities/effects/AsThoughEffect.java b/Mage/src/mage/abilities/effects/AsThoughEffect.java index 21d77b1bfdc..a134aa53b72 100644 --- a/Mage/src/mage/abilities/effects/AsThoughEffect.java +++ b/Mage/src/mage/abilities/effects/AsThoughEffect.java @@ -30,9 +30,7 @@ package mage.abilities.effects; import java.util.UUID; import mage.abilities.Ability; import mage.constants.AsThoughEffectType; -import mage.constants.ManaType; import mage.game.Game; -import mage.players.ManaPoolItem; /** * @@ -44,8 +42,6 @@ public interface AsThoughEffect extends ContinuousEffect { boolean applies(UUID sourceId, Ability source, UUID affectedControllerId, Game game); - boolean applies(UUID sourceId, Ability source, UUID affectedControllerId, Game game, ManaType manaType, ManaPoolItem mana); - AsThoughEffectType getAsThoughEffectType(); @Override diff --git a/Mage/src/mage/abilities/effects/AsThoughEffectImpl.java b/Mage/src/mage/abilities/effects/AsThoughEffectImpl.java index eb72239187f..bd1448d8e9f 100644 --- a/Mage/src/mage/abilities/effects/AsThoughEffectImpl.java +++ b/Mage/src/mage/abilities/effects/AsThoughEffectImpl.java @@ -32,10 +32,8 @@ import mage.abilities.Ability; import mage.constants.AsThoughEffectType; import mage.constants.Duration; import mage.constants.EffectType; -import mage.constants.ManaType; import mage.constants.Outcome; import mage.game.Game; -import mage.players.ManaPoolItem; /** * @@ -61,11 +59,6 @@ public abstract class AsThoughEffectImpl extends ContinuousEffectImpl implements return applies(objectId, source, affectedAbility.getControllerId(), game); } - @Override - public boolean applies(UUID sourceId, Ability source, UUID affectedControllerId, Game game, ManaType manaType, ManaPoolItem mana) { - return false; - } - @Override public AsThoughEffectType getAsThoughEffectType() { return type; diff --git a/Mage/src/mage/abilities/effects/AsThoughManaEffect.java b/Mage/src/mage/abilities/effects/AsThoughManaEffect.java new file mode 100644 index 00000000000..4ff137fc8ed --- /dev/null +++ b/Mage/src/mage/abilities/effects/AsThoughManaEffect.java @@ -0,0 +1,45 @@ +/* + * 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; + +import java.util.UUID; +import mage.abilities.Ability; +import mage.constants.ManaType; +import mage.game.Game; +import mage.players.ManaPoolItem; + +/** + * + * @author LevelX2 + */ +public interface AsThoughManaEffect extends AsThoughEffect { + + // return a mana type that can be used to pay a mana cost instead of the normally needed mana type + ManaType getAsThoughtManaType(ManaType manaType, ManaPoolItem mana, UUID affectedControllerId, Ability source, Game game); + +} diff --git a/Mage/src/mage/abilities/effects/ContinuousEffects.java b/Mage/src/mage/abilities/effects/ContinuousEffects.java index 00133342fc6..003f61542b9 100644 --- a/Mage/src/mage/abilities/effects/ContinuousEffects.java +++ b/Mage/src/mage/abilities/effects/ContinuousEffects.java @@ -548,24 +548,35 @@ public class ContinuousEffects implements Serializable { } - public boolean asThoughMana(UUID objectId, AsThoughEffectType type, Ability affectedAbility, UUID controllerId, Game game, ManaType manaType, ManaPoolItem mana) { - List asThoughEffectsList = getApplicableAsThoughEffects(type, game); + public ManaType asThoughMana(ManaType manaType, ManaPoolItem mana, UUID objectId, Ability affectedAbility, UUID controllerId, Game game) { + // First check existing only effects + List asThoughEffectsList = getApplicableAsThoughEffects(AsThoughEffectType.SPEND_ONLY_MANA, game); for (AsThoughEffect effect : asThoughEffectsList) { - HashSet abilities = asThoughEffectsMap.get(type).getAbility(effect.getId()); + HashSet abilities = asThoughEffectsMap.get(AsThoughEffectType.SPEND_ONLY_MANA).getAbility(effect.getId()); for (Ability ability : abilities) { - if (affectedAbility == null) { - if (effect.applies(objectId, ability, controllerId, game)) { - return true; - } - } else { - if (effect.applies(objectId, affectedAbility, ability, game)) { - return true; + if ((affectedAbility == null && effect.applies(objectId, ability, controllerId, game)) + || effect.applies(objectId, affectedAbility, ability, game)) { + if (((AsThoughManaEffect) effect).getAsThoughtManaType(manaType, mana, controllerId, ability, game) == null) { + return null; } } } } - return false; - + // then check effects that allow to use other mana types to pay the current mana type to pay + asThoughEffectsList = getApplicableAsThoughEffects(AsThoughEffectType.SPEND_OTHER_MANA, game); + for (AsThoughEffect effect : asThoughEffectsList) { + HashSet abilities = asThoughEffectsMap.get(AsThoughEffectType.SPEND_OTHER_MANA).getAbility(effect.getId()); + for (Ability ability : abilities) { + if ((affectedAbility == null && effect.applies(objectId, ability, controllerId, game)) + || effect.applies(objectId, affectedAbility, ability, game)) { + ManaType usableManaType = ((AsThoughManaEffect) effect).getAsThoughtManaType(manaType, mana, controllerId, ability, game); + if (usableManaType != null) { + return usableManaType; + } + } + } + } + return manaType; } /** diff --git a/Mage/src/mage/constants/AsThoughEffectType.java b/Mage/src/mage/constants/AsThoughEffectType.java index 768d14f37b2..546483c9d72 100644 --- a/Mage/src/mage/constants/AsThoughEffectType.java +++ b/Mage/src/mage/constants/AsThoughEffectType.java @@ -19,7 +19,7 @@ public enum AsThoughEffectType { HEXPROOF, PAY, LOOK_AT_FACE_DOWN, - SPEND_ANY_MANA, - SPEND_COLORLESS_MANA, + SPEND_OTHER_MANA, + SPEND_ONLY_MANA, TARGET } diff --git a/Mage/src/mage/players/ManaPool.java b/Mage/src/mage/players/ManaPool.java index e2fe28e201d..04aec4fa846 100644 --- a/Mage/src/mage/players/ManaPool.java +++ b/Mage/src/mage/players/ManaPool.java @@ -38,7 +38,6 @@ import mage.ConditionalMana; import mage.MageObject; import mage.Mana; import mage.abilities.Ability; -import mage.constants.AsThoughEffectType; import mage.constants.Duration; import mage.constants.ManaType; import mage.constants.TurnPhase; @@ -65,13 +64,6 @@ public class ManaPool implements Serializable { private final Set doNotEmptyManaTypes = new HashSet<>(); - private enum SpendType { - - NORMAL, - ANY, - COLORLESS - } - public ManaPool(UUID playerId) { this.playerId = playerId; autoPayment = true; @@ -145,39 +137,25 @@ public class ManaPool implements Serializable { // no mana added beyond the stock so don't auto pay this continue; } - SpendType spendType = getSpendType(ability, game, manaType, mana); - if (!SpendType.COLORLESS.equals(spendType) || ManaType.COLORLESS.equals(manaType)) { - if (mana.get(manaType) > 0 || (spendType.equals(SpendType.ANY) && mana.count() > 0)) { - GameEvent event = new GameEvent(GameEvent.EventType.MANA_PAYED, ability.getId(), mana.getSourceId(), ability.getControllerId(), 0, mana.getFlag()); - event.setData(mana.getOriginalId().toString()); - game.fireEvent(event); - if (!SpendType.NORMAL.equals(spendType)) { - mana.removeAny(); - } else { - mana.remove(manaType); - } - if (mana.count() == 0) { // so no items with count 0 stay in list - manaItems.remove(mana); - } - lockManaType(); // pay only one mana if mana payment is set to manually - return true; + ManaType usableManaType = game.getContinuousEffects().asThoughMana(manaType, mana, ability.getSourceId(), ability, ability.getControllerId(), game); + if (usableManaType == null) { + continue; + } + if (mana.get(usableManaType) > 0) { + GameEvent event = new GameEvent(GameEvent.EventType.MANA_PAYED, ability.getId(), mana.getSourceId(), ability.getControllerId(), 0, mana.getFlag()); + event.setData(mana.getOriginalId().toString()); + game.fireEvent(event); + mana.remove(usableManaType); + if (mana.count() == 0) { // so no items with count 0 stay in list + manaItems.remove(mana); } + lockManaType(); // pay only one mana if mana payment is set to manually + return true; } } return false; } - // check if any mana can be spend to cast the mana cost of an ability - private SpendType getSpendType(Ability ability, Game game, ManaType manaType, ManaPoolItem mana) { - if (game.getContinuousEffects().asThoughMana(ability.getSourceId(), AsThoughEffectType.SPEND_ANY_MANA, ability, ability.getControllerId(), game, manaType, mana)) { - return SpendType.ANY; - } - if (game.getContinuousEffects().asThoughMana(ability.getSourceId(), AsThoughEffectType.SPEND_COLORLESS_MANA, ability, ability.getControllerId(), game, manaType, mana)) { - return SpendType.COLORLESS; - } - return SpendType.NORMAL; - } - public int get(ManaType manaType) { return getMana().get(manaType); } diff --git a/Mage/src/mage/players/ManaPoolItem.java b/Mage/src/mage/players/ManaPoolItem.java index b6a8f796b9a..9c380389a3d 100644 --- a/Mage/src/mage/players/ManaPoolItem.java +++ b/Mage/src/mage/players/ManaPoolItem.java @@ -1,30 +1,30 @@ /* -* Copyright 2011 BetaSteward_at_googlemail.com. All rights reserved. -* -* Redistribution and use in source and binary forms, with or without modification, are -* permitted provided that the following conditions are met: -* -* 1. Redistributions of source code must retain the above copyright notice, this list of -* conditions and the following disclaimer. -* -* 2. Redistributions in binary form must reproduce the above copyright notice, this list -* of conditions and the following disclaimer in the documentation and/or other materials -* provided with the distribution. -* -* THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED -* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND -* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR -* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR -* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON -* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING -* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF -* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -* -* The views and conclusions contained in the software and documentation are those of the -* authors and should not be interpreted as representing official policies, either expressed -* or implied, of BetaSteward_at_googlemail.com. -*/ + * Copyright 2011 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ package mage.players; import java.io.Serializable; @@ -53,7 +53,8 @@ public class ManaPoolItem implements Serializable { private Duration duration; private int stock; // amount the item had at the start of casting something - public ManaPoolItem() {} + public ManaPoolItem() { + } public ManaPoolItem(int red, int green, int blue, int white, int black, int colorless, UUID sourceId, UUID originalId, boolean flag) { this.red = red; @@ -75,7 +76,7 @@ public class ManaPoolItem implements Serializable { this.conditionalMana.setManaProducerId(sourceId); this.conditionalMana.setManaProducerOriginalId(originalId); this.flag = conditionalMana.getFlag(); - this.duration = Duration.EndOfStep; + this.duration = Duration.EndOfStep; } public ManaPoolItem(final ManaPoolItem item) { @@ -191,7 +192,7 @@ public class ManaPoolItem implements Serializable { } public int get(ManaType manaType) { - switch(manaType) { + switch (manaType) { case BLACK: return black; case BLUE: @@ -208,29 +209,26 @@ public class ManaPoolItem implements Serializable { return 0; } - public void removeAny() { - int oldCount = count(); + public ManaType getFirstAvailable() { if (black > 0) { - black--; + return ManaType.BLACK; } else if (blue > 0) { - blue--; + return ManaType.BLUE; } else if (green > 0) { - green--; + return ManaType.GREEN; } else if (red > 0) { - red--; + return ManaType.RED; } else if (white > 0) { - white--; + return ManaType.WHITE; } else if (colorless > 0) { - colorless--; - } - if (stock == oldCount && oldCount > count()) { - stock--; - } + return ManaType.COLORLESS; + } + return null; } - + public void remove(ManaType manaType) { int oldCount = count(); - switch(manaType) { + switch (manaType) { case BLACK: if (black > 0) { black--; @@ -264,11 +262,11 @@ public class ManaPoolItem implements Serializable { } if (stock == oldCount && oldCount > count()) { stock--; - } + } } - + public void clear(ManaType manaType) { - switch(manaType) { + switch (manaType) { case BLACK: black = 0; break; @@ -287,31 +285,36 @@ public class ManaPoolItem implements Serializable { case COLORLESS: colorless = 0; break; - } + } } - + public void add(ManaType manaType, int amount) { - switch(manaType) { + switch (manaType) { case BLACK: black += amount; break; case BLUE: - blue += amount;; + blue += amount; + ; break; case GREEN: - green += amount;; + green += amount; + ; break; case RED: - red += amount;; + red += amount; + ; break; case WHITE: - white += amount;; + white += amount; + ; break; case COLORLESS: - colorless += amount;; + colorless += amount; + ; break; - } - } + } + } public Duration getDuration() { return duration; @@ -328,5 +331,5 @@ public class ManaPoolItem implements Serializable { public void setStock(int stock) { this.stock = stock; } - + } From 7f8854aa0f3386f15cfa664af9c45be5f035f82e Mon Sep 17 00:00:00 2001 From: LevelX2 Date: Tue, 6 Oct 2015 17:29:19 +0200 Subject: [PATCH 025/268] Added Sunglasses of Urza. --- .../sets/fourthedition/SunglassesOfUrza.java | 52 +++++++++ .../sets/limitedalpha/SunglassesOfUrza.java | 103 ++++++++++++++++++ .../sets/limitedbeta/SunglassesOfUrza.java | 52 +++++++++ .../sets/revisededition/SunglassesOfUrza.java | 52 +++++++++ .../unlimitededition/SunglassesOfUrza.java | 52 +++++++++ 5 files changed, 311 insertions(+) create mode 100644 Mage.Sets/src/mage/sets/fourthedition/SunglassesOfUrza.java create mode 100644 Mage.Sets/src/mage/sets/limitedalpha/SunglassesOfUrza.java create mode 100644 Mage.Sets/src/mage/sets/limitedbeta/SunglassesOfUrza.java create mode 100644 Mage.Sets/src/mage/sets/revisededition/SunglassesOfUrza.java create mode 100644 Mage.Sets/src/mage/sets/unlimitededition/SunglassesOfUrza.java diff --git a/Mage.Sets/src/mage/sets/fourthedition/SunglassesOfUrza.java b/Mage.Sets/src/mage/sets/fourthedition/SunglassesOfUrza.java new file mode 100644 index 00000000000..c7285a4f278 --- /dev/null +++ b/Mage.Sets/src/mage/sets/fourthedition/SunglassesOfUrza.java @@ -0,0 +1,52 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.sets.fourthedition; + +import java.util.UUID; + +/** + * + * @author LevelX2 + */ +public class SunglassesOfUrza extends mage.sets.limitedalpha.SunglassesOfUrza { + + public SunglassesOfUrza(UUID ownerId) { + super(ownerId); + this.cardNumber = 365; + this.expansionSetCode = "4ED"; + } + + public SunglassesOfUrza(final SunglassesOfUrza card) { + super(card); + } + + @Override + public SunglassesOfUrza copy() { + return new SunglassesOfUrza(this); + } +} diff --git a/Mage.Sets/src/mage/sets/limitedalpha/SunglassesOfUrza.java b/Mage.Sets/src/mage/sets/limitedalpha/SunglassesOfUrza.java new file mode 100644 index 00000000000..983095cfb13 --- /dev/null +++ b/Mage.Sets/src/mage/sets/limitedalpha/SunglassesOfUrza.java @@ -0,0 +1,103 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.sets.limitedalpha; + +import java.util.UUID; +import mage.abilities.Ability; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.effects.AsThoughEffectImpl; +import mage.abilities.effects.AsThoughManaEffect; +import mage.cards.CardImpl; +import mage.constants.AsThoughEffectType; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.ManaType; +import mage.constants.Outcome; +import mage.constants.Rarity; +import mage.constants.Zone; +import mage.game.Game; +import mage.players.ManaPoolItem; + +/** + * + * @author LevelX2 + */ +public class SunglassesOfUrza extends CardImpl { + + public SunglassesOfUrza(UUID ownerId) { + super(ownerId, 271, "Sunglasses of Urza", Rarity.RARE, new CardType[]{CardType.ARTIFACT}, "{3}"); + this.expansionSetCode = "LEA"; + + // You may spend white mana as though it were red mana. + this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new SunglassesOfUrzaManaAsThoughtEffect())); + } + + public SunglassesOfUrza(final SunglassesOfUrza card) { + super(card); + } + + @Override + public SunglassesOfUrza copy() { + return new SunglassesOfUrza(this); + } +} + +class SunglassesOfUrzaManaAsThoughtEffect extends AsThoughEffectImpl implements AsThoughManaEffect { + + public SunglassesOfUrzaManaAsThoughtEffect() { + super(AsThoughEffectType.SPEND_OTHER_MANA, Duration.WhileOnBattlefield, Outcome.Benefit); + staticText = "You may spend white mana as though it were red mana"; + } + + @Override + public boolean apply(Game game, Ability source) { + return true; + } + + @Override + public boolean applies(UUID objectId, Ability source, UUID affectedControllerId, Game game) { + return affectedControllerId.equals(source.getControllerId()); + } + + @Override + public ManaType getAsThoughtManaType(ManaType manaType, ManaPoolItem mana, UUID affectedControllerId, Ability source, Game game) { + if (mana.getWhite() > 0 && ManaType.RED.equals(manaType)) { + return ManaType.WHITE; + } + return manaType; + } + + @Override + public SunglassesOfUrzaManaAsThoughtEffect copy() { + return new SunglassesOfUrzaManaAsThoughtEffect(this); + } + + private SunglassesOfUrzaManaAsThoughtEffect(SunglassesOfUrzaManaAsThoughtEffect effect) { + super(effect); + } +} diff --git a/Mage.Sets/src/mage/sets/limitedbeta/SunglassesOfUrza.java b/Mage.Sets/src/mage/sets/limitedbeta/SunglassesOfUrza.java new file mode 100644 index 00000000000..ac7d7fb2671 --- /dev/null +++ b/Mage.Sets/src/mage/sets/limitedbeta/SunglassesOfUrza.java @@ -0,0 +1,52 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.sets.limitedbeta; + +import java.util.UUID; + +/** + * + * @author LevelX2 + */ +public class SunglassesOfUrza extends mage.sets.limitedalpha.SunglassesOfUrza { + + public SunglassesOfUrza(UUID ownerId) { + super(ownerId); + this.cardNumber = 273; + this.expansionSetCode = "LEB"; + } + + public SunglassesOfUrza(final SunglassesOfUrza card) { + super(card); + } + + @Override + public SunglassesOfUrza copy() { + return new SunglassesOfUrza(this); + } +} diff --git a/Mage.Sets/src/mage/sets/revisededition/SunglassesOfUrza.java b/Mage.Sets/src/mage/sets/revisededition/SunglassesOfUrza.java new file mode 100644 index 00000000000..a9bb3451932 --- /dev/null +++ b/Mage.Sets/src/mage/sets/revisededition/SunglassesOfUrza.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.revisededition; + +import java.util.UUID; + +/** + * + * @author LevelX2 + */ +public class SunglassesOfUrza extends mage.sets.limitedalpha.SunglassesOfUrza { + + public SunglassesOfUrza(UUID ownerId) { + super(ownerId); + this.cardNumber = 276; + this.expansionSetCode = "3ED"; + } + + public SunglassesOfUrza(final SunglassesOfUrza card) { + super(card); + } + + @Override + public SunglassesOfUrza copy() { + return new SunglassesOfUrza(this); + } +} diff --git a/Mage.Sets/src/mage/sets/unlimitededition/SunglassesOfUrza.java b/Mage.Sets/src/mage/sets/unlimitededition/SunglassesOfUrza.java new file mode 100644 index 00000000000..b0f22438e9a --- /dev/null +++ b/Mage.Sets/src/mage/sets/unlimitededition/SunglassesOfUrza.java @@ -0,0 +1,52 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.sets.unlimitededition; + +import java.util.UUID; + +/** + * + * @author LevelX2 + */ +public class SunglassesOfUrza extends mage.sets.limitedalpha.SunglassesOfUrza { + + public SunglassesOfUrza(UUID ownerId) { + super(ownerId); + this.cardNumber = 272; + this.expansionSetCode = "2ED"; + } + + public SunglassesOfUrza(final SunglassesOfUrza card) { + super(card); + } + + @Override + public SunglassesOfUrza copy() { + return new SunglassesOfUrza(this); + } +} From cf5fa1915ed7f7d676b443134234d2226fc8ac91 Mon Sep 17 00:00:00 2001 From: LoneFox Date: Tue, 6 Oct 2015 20:01:36 +0300 Subject: [PATCH 026/268] Implement cards: Bounty Hunter, Chandler, Downhill Charge, and Roterothopter --- .../src/mage/sets/homelands/Chandler.java | 81 +++++++++++++++++ .../mage/sets/homelands/Roterothopter.java | 69 ++++++++++++++ .../sets/masterseditionii/Roterothopter.java | 52 +++++++++++ .../src/mage/sets/nemesis/DownhillCharge.java | 79 ++++++++++++++++ .../src/mage/sets/tempest/BountyHunter.java | 90 +++++++++++++++++++ .../sets/venservskoth/DownhillCharge.java | 52 +++++++++++ Mage/src/mage/counters/CounterType.java | 1 + 7 files changed, 424 insertions(+) create mode 100644 Mage.Sets/src/mage/sets/homelands/Chandler.java create mode 100644 Mage.Sets/src/mage/sets/homelands/Roterothopter.java create mode 100644 Mage.Sets/src/mage/sets/masterseditionii/Roterothopter.java create mode 100644 Mage.Sets/src/mage/sets/nemesis/DownhillCharge.java create mode 100644 Mage.Sets/src/mage/sets/tempest/BountyHunter.java create mode 100644 Mage.Sets/src/mage/sets/venservskoth/DownhillCharge.java diff --git a/Mage.Sets/src/mage/sets/homelands/Chandler.java b/Mage.Sets/src/mage/sets/homelands/Chandler.java new file mode 100644 index 00000000000..a14bed9ddb5 --- /dev/null +++ b/Mage.Sets/src/mage/sets/homelands/Chandler.java @@ -0,0 +1,81 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.sets.homelands; + +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.costs.mana.ManaCostsImpl; +import mage.abilities.effects.common.DestroyTargetEffect; +import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.Rarity; +import mage.constants.Zone; +import mage.filter.common.FilterCreaturePermanent; +import mage.filter.predicate.mageobject.CardTypePredicate; +import mage.target.common.TargetCreaturePermanent; + +/** + * + * @author LoneFox + */ +public class Chandler extends CardImpl { + + private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("artifact creature"); + + static { + filter.add(new CardTypePredicate(CardType.ARTIFACT)); + } + + public Chandler(UUID ownerId) { + super(ownerId, 88, "Chandler", Rarity.COMMON, new CardType[]{CardType.CREATURE}, "{4}{R}"); + this.expansionSetCode = "HML"; + this.supertype.add("Legendary"); + this.subtype.add("Human"); + this.subtype.add("Rogue"); + this.power = new MageInt(3); + this.toughness = new MageInt(3); + + // {R}{R}{R}, {tap}: Destroy target artifact creature. + Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new DestroyTargetEffect(), new ManaCostsImpl("{R}{R}{R}")); + ability.addCost(new TapSourceCost()); + ability.addTarget(new TargetCreaturePermanent(filter)); + this.addAbility(ability); + } + + public Chandler(final Chandler card) { + super(card); + } + + @Override + public Chandler copy() { + return new Chandler(this); + } +} diff --git a/Mage.Sets/src/mage/sets/homelands/Roterothopter.java b/Mage.Sets/src/mage/sets/homelands/Roterothopter.java new file mode 100644 index 00000000000..40fabe57d8d --- /dev/null +++ b/Mage.Sets/src/mage/sets/homelands/Roterothopter.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.homelands; + +import java.util.UUID; +import mage.MageInt; +import mage.abilities.common.LimitedTimesPerTurnActivatedAbility; +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.effects.common.continuous.BoostSourceEffect; +import mage.abilities.keyword.FlyingAbility; +import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.Rarity; +import mage.constants.Zone; + +/** + * + * @author LoneFox + */ +public class Roterothopter extends CardImpl { + + public Roterothopter(UUID ownerId) { + super(ownerId, 134, "Roterothopter", Rarity.COMMON, new CardType[]{CardType.ARTIFACT, CardType.CREATURE}, "{1}"); + this.expansionSetCode = "HML"; + this.subtype.add("Thopter"); + this.power = new MageInt(0); + this.toughness = new MageInt(2); + + // Flying + this.addAbility(FlyingAbility.getInstance()); + // {2}: Roterothopter gets +1/+0 until end of turn. Activate this ability no more than twice each turn. + this.addAbility(new LimitedTimesPerTurnActivatedAbility(Zone.BATTLEFIELD, new BoostSourceEffect(1, 0, Duration.EndOfTurn), new ManaCostsImpl("{2}"), 2)); + } + + public Roterothopter(final Roterothopter card) { + super(card); + } + + @Override + public Roterothopter copy() { + return new Roterothopter(this); + } +} diff --git a/Mage.Sets/src/mage/sets/masterseditionii/Roterothopter.java b/Mage.Sets/src/mage/sets/masterseditionii/Roterothopter.java new file mode 100644 index 00000000000..1f9a63dd49f --- /dev/null +++ b/Mage.Sets/src/mage/sets/masterseditionii/Roterothopter.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.masterseditionii; + +import java.util.UUID; + +/** + * + * @author LoneFox + */ +public class Roterothopter extends mage.sets.homelands.Roterothopter { + + public Roterothopter(UUID ownerId) { + super(ownerId); + this.cardNumber = 218; + this.expansionSetCode = "ME2"; + } + + public Roterothopter(final Roterothopter card) { + super(card); + } + + @Override + public Roterothopter copy() { + return new Roterothopter(this); + } +} diff --git a/Mage.Sets/src/mage/sets/nemesis/DownhillCharge.java b/Mage.Sets/src/mage/sets/nemesis/DownhillCharge.java new file mode 100644 index 00000000000..cddd20e8ac1 --- /dev/null +++ b/Mage.Sets/src/mage/sets/nemesis/DownhillCharge.java @@ -0,0 +1,79 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.sets.nemesis; + +import java.util.UUID; +import mage.abilities.costs.AlternativeCostSourceAbility; +import mage.abilities.costs.common.SacrificeTargetCost; +import mage.abilities.dynamicvalue.common.PermanentsOnBattlefieldCount; +import mage.abilities.dynamicvalue.common.StaticValue; +import mage.abilities.effects.Effect; +import mage.abilities.effects.common.continuous.BoostTargetEffect; +import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.Rarity; +import mage.filter.common.FilterControlledPermanent; +import mage.filter.predicate.mageobject.SubtypePredicate; +import mage.target.common.TargetControlledPermanent; +import mage.target.common.TargetCreaturePermanent; + +/** + * + * @author LoneFox + */ +public class DownhillCharge extends CardImpl { + + private static final FilterControlledPermanent filter = new FilterControlledPermanent("a Mountain"); + + static { + filter.add(new SubtypePredicate("Mountain")); + } + + public DownhillCharge(UUID ownerId) { + super(ownerId, 79, "Downhill Charge", Rarity.COMMON, new CardType[]{CardType.INSTANT}, "{2}{R}"); + this.expansionSetCode = "NMS"; + + // You may sacrifice a Mountain rather than pay Downhill Charge's mana cost. + this.addAbility(new AlternativeCostSourceAbility(new SacrificeTargetCost(new TargetControlledPermanent(filter)))); + // Target creature gets +X/+0 until end of turn, where X is the number of Mountains you control. + Effect effect = new BoostTargetEffect(new PermanentsOnBattlefieldCount(filter), new StaticValue(0), Duration.EndOfTurn); + effect.setText("Target creature gets +X/+0 until end of turn, where X is the number of Mountains you control."); + this.getSpellAbility().addEffect(effect); + this.getSpellAbility().addTarget(new TargetCreaturePermanent()); + } + + public DownhillCharge(final DownhillCharge card) { + super(card); + } + + @Override + public DownhillCharge copy() { + return new DownhillCharge(this); + } +} diff --git a/Mage.Sets/src/mage/sets/tempest/BountyHunter.java b/Mage.Sets/src/mage/sets/tempest/BountyHunter.java new file mode 100644 index 00000000000..d73314cfd38 --- /dev/null +++ b/Mage.Sets/src/mage/sets/tempest/BountyHunter.java @@ -0,0 +1,90 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.sets.tempest; + +import java.util.UUID; +import mage.MageInt; +import mage.ObjectColor; +import mage.abilities.Ability; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.costs.common.TapSourceCost; +import mage.abilities.effects.common.DestroyTargetEffect; +import mage.abilities.effects.common.counter.AddCountersTargetEffect; +import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.Rarity; +import mage.constants.Zone; +import mage.counters.CounterType; +import mage.filter.common.FilterCreaturePermanent; +import mage.filter.predicate.Predicates; +import mage.filter.predicate.mageobject.ColorPredicate; +import mage.filter.predicate.permanent.CounterPredicate; +import mage.target.common.TargetCreaturePermanent; + +/** + * + * @author LoneFox + */ +public class BountyHunter extends CardImpl { + + private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("nonblack creature"); + private static final FilterCreaturePermanent filter2 = new FilterCreaturePermanent("creature with a bounty counter on it"); + + static { + filter.add(Predicates.not(new ColorPredicate(ObjectColor.BLACK))); + filter2.add(new CounterPredicate(CounterType.BOUNTY)); + } + + public BountyHunter(UUID ownerId) { + super(ownerId, 4, "Bounty Hunter", Rarity.RARE, new CardType[]{CardType.CREATURE}, "{2}{B}{B}"); + this.expansionSetCode = "TMP"; + this.subtype.add("Human"); + this.subtype.add("Archer"); + this.subtype.add("Minion"); + this.power = new MageInt(2); + this.toughness = new MageInt(2); + + // {tap}: Put a bounty counter on target nonblack creature. + Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new AddCountersTargetEffect(CounterType.BOUNTY.createInstance()), new TapSourceCost()); + ability.addTarget(new TargetCreaturePermanent(filter)); + this.addAbility(ability); + // {tap}: Destroy target creature with a bounty counter on it. + ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new DestroyTargetEffect(), new TapSourceCost()); + ability.addTarget(new TargetCreaturePermanent(filter2)); + this.addAbility(ability); + } + + public BountyHunter(final BountyHunter card) { + super(card); + } + + @Override + public BountyHunter copy() { + return new BountyHunter(this); + } +} diff --git a/Mage.Sets/src/mage/sets/venservskoth/DownhillCharge.java b/Mage.Sets/src/mage/sets/venservskoth/DownhillCharge.java new file mode 100644 index 00000000000..328f17486b5 --- /dev/null +++ b/Mage.Sets/src/mage/sets/venservskoth/DownhillCharge.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.venservskoth; + +import java.util.UUID; + +/** + * + * @author LoneFox + */ +public class DownhillCharge extends mage.sets.nemesis.DownhillCharge { + + public DownhillCharge(UUID ownerId) { + super(ownerId); + this.cardNumber = 69; + this.expansionSetCode = "DDI"; + } + + public DownhillCharge(final DownhillCharge card) { + super(card); + } + + @Override + public DownhillCharge copy() { + return new DownhillCharge(this); + } +} diff --git a/Mage/src/mage/counters/CounterType.java b/Mage/src/mage/counters/CounterType.java index 86abda9c383..eaf7bde19ef 100644 --- a/Mage/src/mage/counters/CounterType.java +++ b/Mage/src/mage/counters/CounterType.java @@ -39,6 +39,7 @@ public enum CounterType { ARROWHEAD("arrowhead"), AWAKENING("awakening"), BLAZE("blaze"), + BOUNTY("bounty"), BRIBERY("bribery"), CARRION("carrion"), CHARGE("charge"), From efae15f6c2b32c906a4af94af3a79dfc64c88d0a Mon Sep 17 00:00:00 2001 From: LoneFox Date: Tue, 6 Oct 2015 20:46:59 +0300 Subject: [PATCH 027/268] Implement cards: Despoil, Flowering Field, Heightened Awareness, and Spiketail Drake --- Mage.Sets/src/mage/sets/prophecy/Despoil.java | 62 ++++++++++++++ .../mage/sets/prophecy/FloweringField.java | 84 +++++++++++++++++++ .../sets/prophecy/HeightenedAwareness.java | 65 ++++++++++++++ .../mage/sets/prophecy/SpiketailDrake.java | 71 ++++++++++++++++ 4 files changed, 282 insertions(+) create mode 100644 Mage.Sets/src/mage/sets/prophecy/Despoil.java create mode 100644 Mage.Sets/src/mage/sets/prophecy/FloweringField.java create mode 100644 Mage.Sets/src/mage/sets/prophecy/HeightenedAwareness.java create mode 100644 Mage.Sets/src/mage/sets/prophecy/SpiketailDrake.java diff --git a/Mage.Sets/src/mage/sets/prophecy/Despoil.java b/Mage.Sets/src/mage/sets/prophecy/Despoil.java new file mode 100644 index 00000000000..9213946c2ef --- /dev/null +++ b/Mage.Sets/src/mage/sets/prophecy/Despoil.java @@ -0,0 +1,62 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.sets.prophecy; + +import java.util.UUID; +import mage.abilities.effects.common.DestroyTargetEffect; +import mage.abilities.effects.common.LoseLifeTargetControllerEffect; +import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.Rarity; +import mage.target.common.TargetLandPermanent; + +/** + * + * @author LoneFox + */ +public class Despoil extends CardImpl { + + public Despoil(UUID ownerId) { + super(ownerId, 62, "Despoil", Rarity.COMMON, new CardType[]{CardType.SORCERY}, "{3}{B}"); + this.expansionSetCode = "PCY"; + + // Destroy target land. Its controller loses 2 life. + this.getSpellAbility().addEffect(new DestroyTargetEffect()); + this.getSpellAbility().addEffect(new LoseLifeTargetControllerEffect(2)); + this.getSpellAbility().addTarget(new TargetLandPermanent()); + } + + public Despoil(final Despoil card) { + super(card); + } + + @Override + public Despoil copy() { + return new Despoil(this); + } +} diff --git a/Mage.Sets/src/mage/sets/prophecy/FloweringField.java b/Mage.Sets/src/mage/sets/prophecy/FloweringField.java new file mode 100644 index 00000000000..87415a3e34b --- /dev/null +++ b/Mage.Sets/src/mage/sets/prophecy/FloweringField.java @@ -0,0 +1,84 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.sets.prophecy; + +import java.util.UUID; +import mage.abilities.Ability; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.costs.common.TapSourceCost; +import mage.abilities.effects.Effect; +import mage.abilities.effects.common.AttachEffect; +import mage.abilities.effects.common.PreventDamageToTargetEffect; +import mage.abilities.effects.common.continuous.GainAbilityAttachedEffect; +import mage.abilities.keyword.EnchantAbility; +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.Zone; +import mage.target.TargetPermanent; +import mage.target.common.TargetCreatureOrPlayer; +import mage.target.common.TargetLandPermanent; + +/** + * + * @author LoneFox + */ +public class FloweringField extends CardImpl { + + public FloweringField(UUID ownerId) { + super(ownerId, 9, "Flowering Field", Rarity.UNCOMMON, new CardType[]{CardType.ENCHANTMENT}, "{1}{W}"); + this.expansionSetCode = "PCY"; + this.subtype.add("Aura"); + + // Enchant land + TargetPermanent auraTarget = new TargetLandPermanent(); + this.getSpellAbility().addTarget(auraTarget); + this.getSpellAbility().addEffect(new AttachEffect(Outcome.AddAbility)); + Ability ability = new EnchantAbility(auraTarget.getTargetName()); + this.addAbility(ability); + // Enchanted land has "{T}: Prevent the next 1 damage that would be dealt to target creature or player this turn." + ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new PreventDamageToTargetEffect(Duration.EndOfTurn, 1), new TapSourceCost()); + ability.addTarget(new TargetCreatureOrPlayer()); + Effect effect = new GainAbilityAttachedEffect(ability, AttachmentType.AURA); + effect.setText("Enchanted land has \"{T}: Prevent the next 1 damage that would be dealt to target creature or player this turn.\""); + this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, effect)); + } + + public FloweringField(final FloweringField card) { + super(card); + } + + @Override + public FloweringField copy() { + return new FloweringField(this); + } +} diff --git a/Mage.Sets/src/mage/sets/prophecy/HeightenedAwareness.java b/Mage.Sets/src/mage/sets/prophecy/HeightenedAwareness.java new file mode 100644 index 00000000000..777baabd404 --- /dev/null +++ b/Mage.Sets/src/mage/sets/prophecy/HeightenedAwareness.java @@ -0,0 +1,65 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.sets.prophecy; + +import java.util.UUID; +import mage.abilities.common.BeginningOfDrawTriggeredAbility; +import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.effects.common.DrawCardSourceControllerEffect; +import mage.abilities.effects.common.discard.DiscardHandControllerEffect; +import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.Rarity; +import mage.constants.TargetController; + +/** + * + * @author LoneFox + */ +public class HeightenedAwareness extends CardImpl { + + public HeightenedAwareness(UUID ownerId) { + super(ownerId, 37, "Heightened Awareness", Rarity.RARE, new CardType[]{CardType.ENCHANTMENT}, "{3}{U}{U}"); + this.expansionSetCode = "PCY"; + + // As Heightened Awareness enters the battlefield, discard your hand. + this.addAbility(new EntersBattlefieldTriggeredAbility(new DiscardHandControllerEffect())); + // At the beginning of your draw step, draw an additional card. + this.addAbility(new BeginningOfDrawTriggeredAbility(new DrawCardSourceControllerEffect(1), + TargetController.YOU, false)); + } + + public HeightenedAwareness(final HeightenedAwareness card) { + super(card); + } + + @Override + public HeightenedAwareness copy() { + return new HeightenedAwareness(this); + } +} diff --git a/Mage.Sets/src/mage/sets/prophecy/SpiketailDrake.java b/Mage.Sets/src/mage/sets/prophecy/SpiketailDrake.java new file mode 100644 index 00000000000..d63e858fa3d --- /dev/null +++ b/Mage.Sets/src/mage/sets/prophecy/SpiketailDrake.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.prophecy; + +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.costs.mana.ManaCostsImpl; +import mage.abilities.effects.common.CounterUnlessPaysEffect; +import mage.abilities.keyword.FlyingAbility; +import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.Rarity; +import mage.constants.Zone; +import mage.target.TargetSpell; + +/** + * + * @author LoneFox + */ +public class SpiketailDrake extends CardImpl { + + public SpiketailDrake(UUID ownerId) { + super(ownerId, 48, "Spiketail Drake", Rarity.UNCOMMON, new CardType[]{CardType.CREATURE}, "{3}{U}{U}"); + this.expansionSetCode = "PCY"; + this.subtype.add("Drake"); + this.power = new MageInt(3); + this.toughness = new MageInt(3); + + // Flying + this.addAbility(FlyingAbility.getInstance()); + // Sacrifice Spiketail Drake: Counter target spell unless its controller pays {3}. + Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new CounterUnlessPaysEffect(new ManaCostsImpl("{3}")), new SacrificeSourceCost()); ability.addTarget(new TargetSpell()); this.addAbility(ability); + } + + public SpiketailDrake(final SpiketailDrake card) { + super(card); + } + + @Override + public SpiketailDrake copy() { + return new SpiketailDrake(this); + } +} From 5e44c9bf2dc32438043fd52058249076436b8311 Mon Sep 17 00:00:00 2001 From: LoneFox Date: Tue, 6 Oct 2015 23:11:16 +0300 Subject: [PATCH 028/268] Implement cards: Fencer Clique, Mageta's Boon, Wall of Nets, and Weed-Pruner Poplar --- .../src/mage/sets/exodus/WallOfNets.java | 76 ++++++++++++++++++ .../mage/sets/morningtide/FencerClique.java | 69 ++++++++++++++++ .../sets/morningtide/WeedPrunerPoplar.java | 78 +++++++++++++++++++ .../src/mage/sets/prophecy/MagetasBoon.java | 77 ++++++++++++++++++ 4 files changed, 300 insertions(+) create mode 100644 Mage.Sets/src/mage/sets/exodus/WallOfNets.java create mode 100644 Mage.Sets/src/mage/sets/morningtide/FencerClique.java create mode 100644 Mage.Sets/src/mage/sets/morningtide/WeedPrunerPoplar.java create mode 100644 Mage.Sets/src/mage/sets/prophecy/MagetasBoon.java diff --git a/Mage.Sets/src/mage/sets/exodus/WallOfNets.java b/Mage.Sets/src/mage/sets/exodus/WallOfNets.java new file mode 100644 index 00000000000..9871010c3eb --- /dev/null +++ b/Mage.Sets/src/mage/sets/exodus/WallOfNets.java @@ -0,0 +1,76 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.sets.exodus; + +import java.util.UUID; +import mage.MageInt; +import mage.abilities.common.EndOfCombatTriggeredAbility; +import mage.abilities.common.LeavesBattlefieldTriggeredAbility; +import mage.abilities.effects.common.ExileAllEffect; +import mage.abilities.effects.common.ReturnFromExileEffect; +import mage.abilities.keyword.DefenderAbility; +import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.Rarity; +import mage.constants.Zone; +import mage.filter.common.FilterCreaturePermanent; +import mage.filter.predicate.permanent.BlockedByIdPredicate; + +/** + * + * @author LoneFox + */ +public class WallOfNets extends CardImpl { + + public WallOfNets(UUID ownerId) { + super(ownerId, 24, "Wall of Nets", Rarity.RARE, new CardType[]{CardType.CREATURE}, "{1}{W}{W}"); + this.expansionSetCode = "EXO"; + this.subtype.add("Wall"); + this.power = new MageInt(0); + this.toughness = new MageInt(7); + + // Defender + this.addAbility(DefenderAbility.getInstance()); + // At end of combat, exile all creatures blocked by Wall of Nets. + FilterCreaturePermanent filter = new FilterCreaturePermanent("creatures blocked by {this}"); + filter.add(new BlockedByIdPredicate(this.getId())); + this.addAbility(new EndOfCombatTriggeredAbility(new ExileAllEffect(filter, this.getId(), this.getIdName()), false)); + // When Wall of Nets leaves the battlefield, return all cards exiled with Wall of Nets to the battlefield under their owners' control. + this.addAbility(new LeavesBattlefieldTriggeredAbility(new ReturnFromExileEffect(this.getId(), + Zone.BATTLEFIELD, "return all cards exiled with {this} to the battlefield under their owners' control"), false)); + } + + public WallOfNets(final WallOfNets card) { + super(card); + } + + @Override + public WallOfNets copy() { + return new WallOfNets(this); + } +} diff --git a/Mage.Sets/src/mage/sets/morningtide/FencerClique.java b/Mage.Sets/src/mage/sets/morningtide/FencerClique.java new file mode 100644 index 00000000000..60f71959c35 --- /dev/null +++ b/Mage.Sets/src/mage/sets/morningtide/FencerClique.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.morningtide; + +import java.util.UUID; +import mage.MageInt; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.effects.common.PutOnLibrarySourceEffect; +import mage.abilities.keyword.FlyingAbility; +import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.Rarity; +import mage.constants.Zone; + +/** + * + * @author LoneFox + */ +public class FencerClique extends CardImpl { + + public FencerClique(UUID ownerId) { + super(ownerId, 33, "Fencer Clique", Rarity.COMMON, new CardType[]{CardType.CREATURE}, "{2}{U}{U}"); + this.expansionSetCode = "MOR"; + this.subtype.add("Faerie"); + this.subtype.add("Soldier"); + this.power = new MageInt(3); + this.toughness = new MageInt(2); + + // Flying + this.addAbility(FlyingAbility.getInstance()); + // {U}: Put Fencer Clique on top of its owner's library. + this.addAbility(new SimpleActivatedAbility(Zone.BATTLEFIELD, new PutOnLibrarySourceEffect(true), new ManaCostsImpl("{U}"))); + } + + public FencerClique(final FencerClique card) { + super(card); + } + + @Override + public FencerClique copy() { + return new FencerClique(this); + } +} diff --git a/Mage.Sets/src/mage/sets/morningtide/WeedPrunerPoplar.java b/Mage.Sets/src/mage/sets/morningtide/WeedPrunerPoplar.java new file mode 100644 index 00000000000..7bba0a6d3b1 --- /dev/null +++ b/Mage.Sets/src/mage/sets/morningtide/WeedPrunerPoplar.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.morningtide; + +import java.util.UUID; +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.BeginningOfUpkeepTriggeredAbility; +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.constants.TargetController; +import mage.filter.common.FilterCreaturePermanent; +import mage.filter.predicate.permanent.AnotherPredicate; +import mage.target.common.TargetCreaturePermanent; + +/** + * + * @author LoneFox + */ +public class WeedPrunerPoplar extends CardImpl { + + private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("creature other than {this}"); + + static { + filter.add(new AnotherPredicate()); + } + + public WeedPrunerPoplar(UUID ownerId) { + super(ownerId, 83, "Weed-Pruner Poplar", Rarity.COMMON, new CardType[]{CardType.CREATURE}, "{4}{B}"); + this.expansionSetCode = "MOR"; + this.subtype.add("Treefolk"); + this.subtype.add("Assassin"); + this.power = new MageInt(3); + this.toughness = new MageInt(3); + + // At the beginning of your upkeep, target creature other than Weed-Pruner Poplar gets -1/-1 until end of turn. + Ability ability = new BeginningOfUpkeepTriggeredAbility(new BoostTargetEffect(-1, -1, Duration.EndOfTurn), TargetController.YOU, false); + ability.addTarget(new TargetCreaturePermanent(filter)); + this.addAbility(ability); + } + + public WeedPrunerPoplar(final WeedPrunerPoplar card) { + super(card); + } + + @Override + public WeedPrunerPoplar copy() { + return new WeedPrunerPoplar(this); + } +} diff --git a/Mage.Sets/src/mage/sets/prophecy/MagetasBoon.java b/Mage.Sets/src/mage/sets/prophecy/MagetasBoon.java new file mode 100644 index 00000000000..5d793edf443 --- /dev/null +++ b/Mage.Sets/src/mage/sets/prophecy/MagetasBoon.java @@ -0,0 +1,77 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.sets.prophecy; + +import java.util.UUID; +import mage.abilities.Ability; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.effects.common.AttachEffect; +import mage.abilities.effects.common.continuous.BoostEnchantedEffect; +import mage.abilities.keyword.EnchantAbility; +import mage.abilities.keyword.FlashAbility; +import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.Outcome; +import mage.constants.Rarity; +import mage.constants.Zone; +import mage.target.TargetPermanent; +import mage.target.common.TargetCreaturePermanent; + +/** + * + * @author LoneFox + */ +public class MagetasBoon extends CardImpl { + + public MagetasBoon(UUID ownerId) { + super(ownerId, 14, "Mageta's Boon", Rarity.COMMON, new CardType[]{CardType.ENCHANTMENT}, "{1}{W}"); + this.expansionSetCode = "PCY"; + this.subtype.add("Aura"); + + // Flash + this.addAbility(FlashAbility.getInstance()); + // Enchant creature + TargetPermanent auraTarget = new TargetCreaturePermanent(); + this.getSpellAbility().addTarget(auraTarget); + this.getSpellAbility().addEffect(new AttachEffect(Outcome.BoostCreature)); + Ability ability = new EnchantAbility(auraTarget.getTargetName()); + this.addAbility(ability); + // Enchanted creature gets +1/+2. + this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new BoostEnchantedEffect(1, 2, Duration.WhileOnBattlefield))); + } + + public MagetasBoon(final MagetasBoon card) { + super(card); + } + + @Override + public MagetasBoon copy() { + return new MagetasBoon(this); + } +} From 017647844115aacabc3d08eb6ba3eacfe86542b0 Mon Sep 17 00:00:00 2001 From: LevelX2 Date: Tue, 6 Oct 2015 22:22:37 +0200 Subject: [PATCH 029/268] * Fixed a bug that caused creatures forced to attack could prevent to attack by deselecting the forced creature or be able to attack another defender by using the Attack All button. --- .../src/mage/player/human/HumanPlayer.java | 21 +++++++++--- .../gatecrash/GideonChampionOfJustice.java | 2 -- .../sets/magicorigins/GideonBattleForged.java | 33 +++++++++---------- Mage/src/mage/game/combat/Combat.java | 2 +- 4 files changed, 33 insertions(+), 25 deletions(-) diff --git a/Mage.Server.Plugins/Mage.Player.Human/src/mage/player/human/HumanPlayer.java b/Mage.Server.Plugins/Mage.Player.Human/src/mage/player/human/HumanPlayer.java index 7fb10c8bec2..ce033535822 100644 --- a/Mage.Server.Plugins/Mage.Player.Human/src/mage/player/human/HumanPlayer.java +++ b/Mage.Server.Plugins/Mage.Player.Human/src/mage/player/human/HumanPlayer.java @@ -905,6 +905,15 @@ public class HumanPlayer extends PlayerImpl { attackedDefender, attacker.getId(), attacker.getControllerId()), game)) { continue; } + // if attacker needs a specific defender to attack so select that one instead + if (game.getCombat().getCreaturesForcedToAttack().containsKey(attacker.getId())) { + Set possibleDefenders = game.getCombat().getCreaturesForcedToAttack().get(attacker.getId()); + if (!possibleDefenders.isEmpty() && !possibleDefenders.contains(attackedDefender)) { + declareAttacker(attacker.getId(), possibleDefenders.iterator().next(), game, false); + continue; + } + } + // attack selected default defender declareAttacker(attacker.getId(), attackedDefender, game, false); } } else if (response.getBoolean() != null) { @@ -926,14 +935,18 @@ public class HumanPlayer extends PlayerImpl { } else { Permanent creature = game.getPermanent(creatureId); if (creature != null) { - sb.append(creature.getName()).append(" "); + sb.append(creature.getIdName()).append(" "); } } } if (game.getCombat().getMaxAttackers() > forcedAttackers) { - game.informPlayer(this, sb.insert(0, " more attacker(s) that are forced to attack.\nCreatures forced to attack: ") - .insert(0, Math.min(game.getCombat().getMaxAttackers() - forcedAttackers, game.getCombat().getCreaturesForcedToAttack().size() - forcedAttackers)) + int requireToAttack = Math.min(game.getCombat().getMaxAttackers() - forcedAttackers, game.getCombat().getCreaturesForcedToAttack().size() - forcedAttackers); + String message = (requireToAttack == 1 ? " more attacker that is " : " more attackers that are ") + + "forced to attack.\nCreature" + + (requireToAttack == 1 ? "" : "s") + " forced to attack: "; + game.informPlayer(this, sb.insert(0, message) + .insert(0, requireToAttack) .insert(0, "You have to attack with ").toString()); continue; } @@ -989,7 +1002,7 @@ public class HumanPlayer extends PlayerImpl { possibleDefender = defenders; } if (possibleDefender.size() == 1) { - declareAttacker(attackerId, defenders.iterator().next(), game, true); + declareAttacker(attackerId, possibleDefender.iterator().next(), game, true); return true; } else { TargetDefender target = new TargetDefender(possibleDefender, attackerId); diff --git a/Mage.Sets/src/mage/sets/gatecrash/GideonChampionOfJustice.java b/Mage.Sets/src/mage/sets/gatecrash/GideonChampionOfJustice.java index ddff7d83638..60ce90daeed 100644 --- a/Mage.Sets/src/mage/sets/gatecrash/GideonChampionOfJustice.java +++ b/Mage.Sets/src/mage/sets/gatecrash/GideonChampionOfJustice.java @@ -32,10 +32,8 @@ import mage.abilities.Ability; import mage.abilities.LoyaltyAbility; import mage.abilities.common.EntersBattlefieldAbility; import mage.abilities.common.SimpleStaticAbility; -import mage.abilities.dynamicvalue.DynamicValue; import mage.abilities.dynamicvalue.common.CountersCount; import mage.abilities.dynamicvalue.common.PermanentsTargetOpponentControlsCount; -import mage.abilities.effects.Effect; import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.PreventAllDamageToSourceEffect; import mage.abilities.effects.common.continuous.BecomesCreatureSourceEffect; diff --git a/Mage.Sets/src/mage/sets/magicorigins/GideonBattleForged.java b/Mage.Sets/src/mage/sets/magicorigins/GideonBattleForged.java index 67c718987ce..926b6fab831 100644 --- a/Mage.Sets/src/mage/sets/magicorigins/GideonBattleForged.java +++ b/Mage.Sets/src/mage/sets/magicorigins/GideonBattleForged.java @@ -62,27 +62,27 @@ import mage.target.common.TargetCreaturePermanent; public class GideonBattleForged extends CardImpl { private final static FilterCreaturePermanent filter = new FilterCreaturePermanent(); - + static { filter.add(new ControllerPredicate(TargetController.OPPONENT)); } - + public GideonBattleForged(UUID ownerId) { super(ownerId, 23, "Gideon, Battle-Forged", Rarity.MYTHIC, new CardType[]{CardType.PLANESWALKER}, ""); this.expansionSetCode = "ORI"; this.subtype.add("Gideon"); - + this.color.setWhite(true); - + this.nightCard = true; this.canTransform = true; - + this.addAbility(new EntersBattlefieldAbility(new AddCountersSourceEffect(CounterType.LOYALTY.createInstance(3)), false)); - - // +2: Up to one target creature an opponent controls attacks Gideon, Battle-Forged during its controller's next turn if able. + + // +2: Up to one target creature an opponent controls attacks Gideon, Battle-Forged during its controller's next turn if able. LoyaltyAbility loyaltyAbility = new LoyaltyAbility(new GideonBattleForgedAttacksIfAbleTargetEffect(Duration.Custom), 2); - loyaltyAbility.addTarget(new TargetCreaturePermanent(0,1,filter, false)); - this.addAbility(loyaltyAbility); + loyaltyAbility.addTarget(new TargetCreaturePermanent(0, 1, filter, false)); + this.addAbility(loyaltyAbility); // +1: Until your next turn, target creature gains indestructible. Untap that creature. Effect effect = new GainAbilityTargetEffect(IndestructibleAbility.getInstance(), Duration.UntilYourNextTurn); @@ -92,14 +92,14 @@ public class GideonBattleForged extends CardImpl { effect = new UntapTargetEffect(); effect.setText("Untap that creature"); loyaltyAbility.addEffect(effect); - this.addAbility(loyaltyAbility); + this.addAbility(loyaltyAbility); // 0: Until end of turn, Gideon, Battle-Forged becomes a 4/4 Human Soldier creature with indestructible that's still a planeswalker. Prevent all damage that would be dealt to him this turn. LoyaltyAbility ability3 = new LoyaltyAbility(new BecomesCreatureSourceEffect(new GideonBattleForgedToken(), "planeswalker", Duration.EndOfTurn), 0); effect = new PreventAllDamageToSourceEffect(Duration.EndOfTurn); effect.setText("Prevent all damage that would be dealt to him this turn"); ability3.addEffect(effect); - this.addAbility(ability3); + this.addAbility(ability3); } @@ -131,7 +131,7 @@ class GideonBattleForgedAttacksIfAbleTargetEffect extends RequirementEffect { int nextTurnTargetController = 0; protected MageObjectReference targetPermanentReference; - + public GideonBattleForgedAttacksIfAbleTargetEffect(Duration duration) { super(duration); staticText = "Up to one target creature an opponent controls attacks {this} during its controller's next turn if able"; @@ -147,7 +147,7 @@ class GideonBattleForgedAttacksIfAbleTargetEffect extends RequirementEffect { public GideonBattleForgedAttacksIfAbleTargetEffect copy() { return new GideonBattleForgedAttacksIfAbleTargetEffect(this); } - + @Override public boolean isInactive(Ability source, Game game) { if (targetPermanentReference == null) { @@ -160,10 +160,7 @@ class GideonBattleForgedAttacksIfAbleTargetEffect extends RequirementEffect { if (nextTurnTargetController == 0 && startingTurn != game.getTurnNum() && game.getActivePlayerId().equals(targetPermanent.getControllerId())) { nextTurnTargetController = game.getTurnNum(); } - if (game.getPhase().getType() == TurnPhase.END && nextTurnTargetController > 0 && game.getTurnNum() > nextTurnTargetController) { - return true; - } - return false; + return game.getPhase().getType() == TurnPhase.END && nextTurnTargetController > 0 && game.getTurnNum() > nextTurnTargetController; } @Override @@ -175,7 +172,7 @@ class GideonBattleForgedAttacksIfAbleTargetEffect extends RequirementEffect { targetPermanentReference = new MageObjectReference(getTargetPointer().getFirst(game, source), game); } } - + @Override public boolean applies(Permanent permanent, Ability source, Game game) { if (permanent.getId().equals(getTargetPointer().getFirst(game, source))) { diff --git a/Mage/src/mage/game/combat/Combat.java b/Mage/src/mage/game/combat/Combat.java index b07f052ff3c..1aa89433f70 100644 --- a/Mage/src/mage/game/combat/Combat.java +++ b/Mage/src/mage/game/combat/Combat.java @@ -294,9 +294,9 @@ public class Combat implements Serializable, Copyable { } // force attack only if a defender can be attacked without paying a cost if (!defendersCostlessAttackable.isEmpty()) { + creaturesForcedToAttack.put(creature.getId(), defendersForcedToAttack); // No need to attack a special defender if (defendersForcedToAttack.isEmpty()) { - creaturesForcedToAttack.put(creature.getId(), defendersForcedToAttack); if (defendersForcedToAttack.isEmpty()) { if (defendersCostlessAttackable.size() == 1) { player.declareAttacker(creature.getId(), defenders.iterator().next(), game, false); From 22e558cd6fcfad9b05ce28b6e4244c33567cf318 Mon Sep 17 00:00:00 2001 From: LevelX2 Date: Tue, 6 Oct 2015 22:24:06 +0200 Subject: [PATCH 030/268] * Fixed a spelling error. --- Mage.Sets/src/mage/sets/darksteel/MycosynthLattice.java | 2 +- Mage.Sets/src/mage/sets/limitedalpha/SunglassesOfUrza.java | 2 +- Mage.Sets/src/mage/sets/theros/DaxosOfMeletis.java | 2 +- Mage.Sets/src/mage/sets/theros/PsychicIntrusion.java | 2 +- Mage.Sets/src/mage/sets/timeshifted/CelestialDawn.java | 4 ++-- Mage/src/mage/abilities/effects/AsThoughManaEffect.java | 2 +- Mage/src/mage/abilities/effects/ContinuousEffects.java | 4 ++-- 7 files changed, 9 insertions(+), 9 deletions(-) diff --git a/Mage.Sets/src/mage/sets/darksteel/MycosynthLattice.java b/Mage.Sets/src/mage/sets/darksteel/MycosynthLattice.java index b4932f89001..4696750cc39 100644 --- a/Mage.Sets/src/mage/sets/darksteel/MycosynthLattice.java +++ b/Mage.Sets/src/mage/sets/darksteel/MycosynthLattice.java @@ -190,7 +190,7 @@ class ManaCanBeSpentAsAnyColorEffect extends AsThoughEffectImpl implements AsTho } @Override - public ManaType getAsThoughtManaType(ManaType manaType, ManaPoolItem mana, UUID affectedControllerId, Ability source, Game game) { + public ManaType getAsThoughManaType(ManaType manaType, ManaPoolItem mana, UUID affectedControllerId, Ability source, Game game) { return mana.getFirstAvailable(); } diff --git a/Mage.Sets/src/mage/sets/limitedalpha/SunglassesOfUrza.java b/Mage.Sets/src/mage/sets/limitedalpha/SunglassesOfUrza.java index 983095cfb13..36adde1b27c 100644 --- a/Mage.Sets/src/mage/sets/limitedalpha/SunglassesOfUrza.java +++ b/Mage.Sets/src/mage/sets/limitedalpha/SunglassesOfUrza.java @@ -85,7 +85,7 @@ class SunglassesOfUrzaManaAsThoughtEffect extends AsThoughEffectImpl implements } @Override - public ManaType getAsThoughtManaType(ManaType manaType, ManaPoolItem mana, UUID affectedControllerId, Ability source, Game game) { + public ManaType getAsThoughManaType(ManaType manaType, ManaPoolItem mana, UUID affectedControllerId, Ability source, Game game) { if (mana.getWhite() > 0 && ManaType.RED.equals(manaType)) { return ManaType.WHITE; } diff --git a/Mage.Sets/src/mage/sets/theros/DaxosOfMeletis.java b/Mage.Sets/src/mage/sets/theros/DaxosOfMeletis.java index adc2d74bae0..d1537527af2 100644 --- a/Mage.Sets/src/mage/sets/theros/DaxosOfMeletis.java +++ b/Mage.Sets/src/mage/sets/theros/DaxosOfMeletis.java @@ -215,7 +215,7 @@ class DaxosOfMeletisSpendAnyManaEffect extends AsThoughEffectImpl implements AsT } @Override - public ManaType getAsThoughtManaType(ManaType manaType, ManaPoolItem mana, UUID affectedControllerId, Ability source, Game game) { + public ManaType getAsThoughManaType(ManaType manaType, ManaPoolItem mana, UUID affectedControllerId, Ability source, Game game) { return mana.getFirstAvailable(); } diff --git a/Mage.Sets/src/mage/sets/theros/PsychicIntrusion.java b/Mage.Sets/src/mage/sets/theros/PsychicIntrusion.java index d8e0268ba84..2598d6fab96 100644 --- a/Mage.Sets/src/mage/sets/theros/PsychicIntrusion.java +++ b/Mage.Sets/src/mage/sets/theros/PsychicIntrusion.java @@ -234,7 +234,7 @@ class PsychicIntrusionSpendAnyManaEffect extends AsThoughEffectImpl implements A } @Override - public ManaType getAsThoughtManaType(ManaType manaType, ManaPoolItem mana, UUID affectedControllerId, Ability source, Game game) { + public ManaType getAsThoughManaType(ManaType manaType, ManaPoolItem mana, UUID affectedControllerId, Ability source, Game game) { return mana.getFirstAvailable(); } } diff --git a/Mage.Sets/src/mage/sets/timeshifted/CelestialDawn.java b/Mage.Sets/src/mage/sets/timeshifted/CelestialDawn.java index 5bd296b7084..2fd31ec7fe3 100644 --- a/Mage.Sets/src/mage/sets/timeshifted/CelestialDawn.java +++ b/Mage.Sets/src/mage/sets/timeshifted/CelestialDawn.java @@ -240,7 +240,7 @@ class CelestialDawnSpendAnyManaEffect extends AsThoughEffectImpl implements AsTh } @Override - public ManaType getAsThoughtManaType(ManaType manaType, ManaPoolItem mana, UUID affectedControllerId, Ability source, Game game) { + public ManaType getAsThoughManaType(ManaType manaType, ManaPoolItem mana, UUID affectedControllerId, Ability source, Game game) { if (mana.getWhite() > 0) { return ManaType.WHITE; } @@ -275,7 +275,7 @@ class CelestialDawnSpendColorlessManaEffect extends AsThoughEffectImpl implement } @Override - public ManaType getAsThoughtManaType(ManaType manaType, ManaPoolItem mana, UUID affectedControllerId, Ability source, Game game) { + public ManaType getAsThoughManaType(ManaType manaType, ManaPoolItem mana, UUID affectedControllerId, Ability source, Game game) { if (mana.getWhite() == 0 && !ManaType.COLORLESS.equals(manaType)) { return null; } diff --git a/Mage/src/mage/abilities/effects/AsThoughManaEffect.java b/Mage/src/mage/abilities/effects/AsThoughManaEffect.java index 4ff137fc8ed..e6ba34f0f3d 100644 --- a/Mage/src/mage/abilities/effects/AsThoughManaEffect.java +++ b/Mage/src/mage/abilities/effects/AsThoughManaEffect.java @@ -40,6 +40,6 @@ import mage.players.ManaPoolItem; public interface AsThoughManaEffect extends AsThoughEffect { // return a mana type that can be used to pay a mana cost instead of the normally needed mana type - ManaType getAsThoughtManaType(ManaType manaType, ManaPoolItem mana, UUID affectedControllerId, Ability source, Game game); + ManaType getAsThoughManaType(ManaType manaType, ManaPoolItem mana, UUID affectedControllerId, Ability source, Game game); } diff --git a/Mage/src/mage/abilities/effects/ContinuousEffects.java b/Mage/src/mage/abilities/effects/ContinuousEffects.java index 003f61542b9..3477010296d 100644 --- a/Mage/src/mage/abilities/effects/ContinuousEffects.java +++ b/Mage/src/mage/abilities/effects/ContinuousEffects.java @@ -556,7 +556,7 @@ public class ContinuousEffects implements Serializable { for (Ability ability : abilities) { if ((affectedAbility == null && effect.applies(objectId, ability, controllerId, game)) || effect.applies(objectId, affectedAbility, ability, game)) { - if (((AsThoughManaEffect) effect).getAsThoughtManaType(manaType, mana, controllerId, ability, game) == null) { + if (((AsThoughManaEffect) effect).getAsThoughManaType(manaType, mana, controllerId, ability, game) == null) { return null; } } @@ -569,7 +569,7 @@ public class ContinuousEffects implements Serializable { for (Ability ability : abilities) { if ((affectedAbility == null && effect.applies(objectId, ability, controllerId, game)) || effect.applies(objectId, affectedAbility, ability, game)) { - ManaType usableManaType = ((AsThoughManaEffect) effect).getAsThoughtManaType(manaType, mana, controllerId, ability, game); + ManaType usableManaType = ((AsThoughManaEffect) effect).getAsThoughManaType(manaType, mana, controllerId, ability, game); if (usableManaType != null) { return usableManaType; } From 0c08784fe9ad2e0e953434c57ddcf9b979ee6347 Mon Sep 17 00:00:00 2001 From: LevelX2 Date: Tue, 6 Oct 2015 22:40:54 +0200 Subject: [PATCH 031/268] * Fixed a bug that a commander on the stack could not be returned to command zone if an end turn effect resolved (e.g. from Sundial of the Infinite). --- .../common/continuous/CommanderReplacementEffect.java | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/Mage/src/mage/abilities/effects/common/continuous/CommanderReplacementEffect.java b/Mage/src/mage/abilities/effects/common/continuous/CommanderReplacementEffect.java index c2cc74dd6e3..cc5e2c0ad7f 100644 --- a/Mage/src/mage/abilities/effects/common/continuous/CommanderReplacementEffect.java +++ b/Mage/src/mage/abilities/effects/common/continuous/CommanderReplacementEffect.java @@ -108,6 +108,12 @@ public class CommanderReplacementEffect extends ReplacementEffectImpl { } case GRAVEYARD: case EXILED: + if (((ZoneChangeEvent) event).getFromZone().equals(Zone.STACK)) { + Spell spell = game.getStack().getSpell(event.getTargetId()); + if (spell != null && commanderId.equals(spell.getSourceId())) { + return true; + } + } if (commanderId.equals(event.getTargetId())) { return true; } From ac35b41e26ec5e772706bf146db1e0957128f642 Mon Sep 17 00:00:00 2001 From: LevelX2 Date: Tue, 6 Oct 2015 22:52:04 +0200 Subject: [PATCH 032/268] * Avatar of Slaughter - Fixe dthat it gave double strike also to non creature permanents. --- Mage.Sets/src/mage/sets/commander/AvatarOfSlaughter.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Mage.Sets/src/mage/sets/commander/AvatarOfSlaughter.java b/Mage.Sets/src/mage/sets/commander/AvatarOfSlaughter.java index da89c528bdd..2213b77abfe 100644 --- a/Mage.Sets/src/mage/sets/commander/AvatarOfSlaughter.java +++ b/Mage.Sets/src/mage/sets/commander/AvatarOfSlaughter.java @@ -57,7 +57,7 @@ public class AvatarOfSlaughter extends CardImpl { this.toughness = new MageInt(8); // All creatures have double strike and attack each turn if able. - Effect effect = new GainAbilityAllEffect(DoubleStrikeAbility.getInstance(), Duration.WhileOnBattlefield); + Effect effect = new GainAbilityAllEffect(DoubleStrikeAbility.getInstance(), Duration.WhileOnBattlefield, new FilterCreaturePermanent("creatures")); effect.setText("All creatures have double strike"); Ability ability = new SimpleStaticAbility(Zone.BATTLEFIELD, effect); effect = new AttacksIfAbleAllEffect(new FilterCreaturePermanent("creatures")); From af61e8b43b21de6ec6f36807affe46a54a28e105 Mon Sep 17 00:00:00 2001 From: LevelX2 Date: Tue, 6 Oct 2015 23:26:22 +0200 Subject: [PATCH 033/268] * Fixed some cards with "When a spell or ability an opponent controls causes you to discard" trigger (e.g. Guerilla Tactics). --- .../src/mage/sets/futuresight/Quagnoth.java | 16 +++++++++----- .../sets/ninthedition/GuerrillaTactics.java | 11 ++++++---- .../saviorsofkamigawa/PureIntentions.java | 22 +++++++++++++------ 3 files changed, 32 insertions(+), 17 deletions(-) diff --git a/Mage.Sets/src/mage/sets/futuresight/Quagnoth.java b/Mage.Sets/src/mage/sets/futuresight/Quagnoth.java index 83c191c5817..bd4fa8f57e3 100644 --- a/Mage.Sets/src/mage/sets/futuresight/Quagnoth.java +++ b/Mage.Sets/src/mage/sets/futuresight/Quagnoth.java @@ -57,10 +57,10 @@ public class Quagnoth extends CardImpl { // Split second this.addAbility(new SplitSecondAbility()); - + // Shroud this.addAbility(ShroudAbility.getInstance()); - + // When a spell or ability an opponent controls causes you to discard Quagnoth, return it to your hand. this.addAbility(new QuagnothTriggeredAbility()); } @@ -97,13 +97,17 @@ class QuagnothTriggeredAbility extends TriggeredAbilityImpl { @Override public boolean checkTrigger(GameEvent event, Game game) { - return game.getOpponents(this.getControllerId()).contains(game.getControllerId(event.getSourceId())) && - StackObject.class.isInstance(game.getObject(event.getSourceId())) && - getSourceId().equals(event.getTargetId()); + if (getSourceId().equals(event.getTargetId())) { + StackObject stackObject = game.getStack().getStackObject(event.getSourceId()); + if (stackObject != null) { + return game.getOpponents(this.getControllerId()).contains(stackObject.getControllerId()); + } + } + return false; } @Override public String getRule() { return "When a spell or ability an opponent controls causes you to discard {this}, " + super.getRule(); } -} \ No newline at end of file +} diff --git a/Mage.Sets/src/mage/sets/ninthedition/GuerrillaTactics.java b/Mage.Sets/src/mage/sets/ninthedition/GuerrillaTactics.java index 052be88b5cf..e49ec5a5267 100644 --- a/Mage.Sets/src/mage/sets/ninthedition/GuerrillaTactics.java +++ b/Mage.Sets/src/mage/sets/ninthedition/GuerrillaTactics.java @@ -50,7 +50,6 @@ public class GuerrillaTactics extends CardImpl { super(ownerId, 196, "Guerrilla Tactics", Rarity.UNCOMMON, new CardType[]{CardType.INSTANT}, "{1}{R}"); this.expansionSetCode = "9ED"; - // Guerrilla Tactics deals 2 damage to target creature or player. this.getSpellAbility().addEffect(new DamageTargetEffect(2)); this.getSpellAbility().addTarget(new TargetCreatureOrPlayer()); @@ -91,9 +90,13 @@ class GuerrillaTacticsTriggeredAbility extends TriggeredAbilityImpl { @Override public boolean checkTrigger(GameEvent event, Game game) { - return game.getOpponents(this.getControllerId()).contains(game.getControllerId(event.getSourceId())) && - StackObject.class.isInstance(game.getObject(event.getSourceId())) && - getSourceId().equals(event.getTargetId()); + if (getSourceId().equals(event.getTargetId())) { + StackObject stackObject = game.getStack().getStackObject(event.getSourceId()); + if (stackObject != null) { + return game.getOpponents(this.getControllerId()).contains(stackObject.getControllerId()); + } + } + return false; } @Override diff --git a/Mage.Sets/src/mage/sets/saviorsofkamigawa/PureIntentions.java b/Mage.Sets/src/mage/sets/saviorsofkamigawa/PureIntentions.java index 7a1ccdf9675..e3ae09ccbe2 100644 --- a/Mage.Sets/src/mage/sets/saviorsofkamigawa/PureIntentions.java +++ b/Mage.Sets/src/mage/sets/saviorsofkamigawa/PureIntentions.java @@ -92,11 +92,12 @@ class PureIntentionsAllTriggeredAbility extends DelayedTriggeredAbility { @Override public boolean checkTrigger(GameEvent event, Game game) { - if (game.getOpponents(this.getControllerId()).contains(game.getControllerId(event.getSourceId())) && - StackObject.class.isInstance(game.getObject(event.getSourceId()))) { + StackObject stackObject = game.getStack().getStackObject(event.getSourceId()); + if (stackObject != null + && game.getOpponents(this.getControllerId()).contains(stackObject.getControllerId())) { Card card = game.getCard(event.getTargetId()); if (card != null && card.getOwnerId().equals(getControllerId())) { - for(Effect effect : getEffects()) { + for (Effect effect : getEffects()) { effect.setTargetPointer(new FixedTarget(event.getTargetId())); } return true; @@ -116,7 +117,6 @@ class PureIntentionsAllTriggeredAbility extends DelayedTriggeredAbility { } } - class PureIntentionsTriggeredAbility extends TriggeredAbilityImpl { public PureIntentionsTriggeredAbility() { @@ -140,9 +140,17 @@ class PureIntentionsTriggeredAbility extends TriggeredAbilityImpl { @Override public boolean checkTrigger(GameEvent event, Game game) { - return game.getOpponents(this.getControllerId()).contains(game.getControllerId(event.getSourceId())) && - StackObject.class.isInstance(game.getObject(event.getSourceId())) && - event.getTargetId().equals(getSourceId()); + if (getSourceId().equals(event.getTargetId())) { + StackObject stackObject = game.getStack().getStackObject(event.getSourceId()); + if (stackObject != null + && game.getOpponents(this.getControllerId()).contains(stackObject.getControllerId())) { + for (Effect effect : getEffects()) { + effect.setTargetPointer(new FixedTarget(event.getTargetId())); + } + return true; + } + } + return false; } @Override From b4061b2f4a00cf0b5178d99f6d4929cbc838e002 Mon Sep 17 00:00:00 2001 From: LevelX2 Date: Wed, 7 Oct 2015 00:15:26 +0200 Subject: [PATCH 034/268] * Chorus of the Conclave - Fixed that the addional counters were sometimes also added to the cast creature if the costs were paid for another instance of the spell (e.g. Guile). --- .../sets/commander/ChorusOfTheConclave.java | 22 +++++++-------- Mage.Sets/src/mage/sets/lorwyn/Guile.java | 28 ++++++++++--------- 2 files changed, 26 insertions(+), 24 deletions(-) diff --git a/Mage.Sets/src/mage/sets/commander/ChorusOfTheConclave.java b/Mage.Sets/src/mage/sets/commander/ChorusOfTheConclave.java index 7454b495669..83774981509 100644 --- a/Mage.Sets/src/mage/sets/commander/ChorusOfTheConclave.java +++ b/Mage.Sets/src/mage/sets/commander/ChorusOfTheConclave.java @@ -48,7 +48,6 @@ import mage.counters.CounterType; import mage.game.Game; import mage.game.events.GameEvent; import mage.game.permanent.Permanent; -import mage.game.stack.Spell; import mage.players.Player; /** @@ -116,13 +115,13 @@ class ChorusOfTheConclaveReplacementEffect extends ReplacementEffectImpl { xCost += playerPaysXGenericMana(you, source, game); // save the x value to be available for ETB replacement effect Object object = game.getState().getValue("spellX" + source.getSourceId()); - Map spellX; + Map spellX; if (object != null && object instanceof Map) { - spellX = (Map) object; + spellX = (Map) object; } else { spellX = new HashMap<>(); } - spellX.put(event.getSourceId(), xCost); + spellX.put(event.getSourceId().toString() + game.getState().getZoneChangeCounter(event.getSourceId()), xCost); game.getState().setValue("spellX" + source.getSourceId(), spellX); } } @@ -157,7 +156,7 @@ class ChorusOfTheConclaveReplacementEffect extends ReplacementEffectImpl { payed = true; } } - game.informPlayers(new StringBuilder(player.getLogName()).append(" pays {").append(xValue).append("}.").toString()); + game.informPlayers(player.getLogName() + " pays {" + xValue + "}"); return xValue; } @@ -191,22 +190,23 @@ class ChorusOfTheConclaveReplacementEffect2 extends ReplacementEffectImpl { @Override public boolean applies(GameEvent event, Ability source, Game game) { - Map spellX = (Map) game.getState().getValue("spellX" + source.getSourceId()); - return spellX != null && spellX.containsKey(event.getSourceId()); + Map spellX = (Map) game.getState().getValue("spellX" + source.getSourceId()); + return spellX != null && event.getSourceId() != null && spellX.containsKey(event.getSourceId().toString() + (game.getState().getZoneChangeCounter(event.getSourceId()) - 2)); } @Override public boolean replaceEvent(GameEvent event, Ability source, Game game) { Permanent creature = game.getPermanent(event.getSourceId()); - Map spellX = (Map) game.getState().getValue("spellX" + source.getSourceId()); + Map spellX = (Map) game.getState().getValue("spellX" + source.getSourceId()); MageObject sourceObject = source.getSourceObject(game); if (sourceObject != null && creature != null && spellX != null) { - int xValue = spellX.get(event.getSourceId()); + String key = event.getSourceId().toString() + (game.getState().getZoneChangeCounter(event.getSourceId()) - 2); + int xValue = spellX.get(key); if (xValue > 0) { creature.addCounters(CounterType.P1P1.createInstance(xValue), game); - game.informPlayers(sourceObject.getName() +": Added " + xValue +" +1/+1 counter" + (xValue > 1 ? "s":"") + "on " + creature.getName()); + game.informPlayers(sourceObject.getLogName() + ": " + creature.getLogName() + " enters the battlefield with " + xValue + " +1/+1 counter" + (xValue > 1 ? "s" : "") + " on it"); } - spellX.remove(event.getSourceId()); + spellX.remove(key); } return false; } diff --git a/Mage.Sets/src/mage/sets/lorwyn/Guile.java b/Mage.Sets/src/mage/sets/lorwyn/Guile.java index 4e9977188f4..a945a8c5c54 100644 --- a/Mage.Sets/src/mage/sets/lorwyn/Guile.java +++ b/Mage.Sets/src/mage/sets/lorwyn/Guile.java @@ -65,10 +65,10 @@ public class Guile extends CardImpl { // Guile can't be blocked except by three or more creatures. this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new CantBeBlockedByOneEffect(3))); - + // If a spell or ability you control would counter a spell, instead exile that spell and you may play that card without paying its mana cost. this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new GuileReplacementEffect())); - + // When Guile is put into a graveyard from anywhere, shuffle it into its owner's library. this.addAbility(new PutIntoGraveFromAnywhereSourceTriggeredAbility(new ShuffleIntoLibrarySourceEffect())); } @@ -107,28 +107,30 @@ class GuileReplacementEffect extends ReplacementEffectImpl { @Override public boolean replaceEvent(GameEvent event, Ability source, Game game) { Spell spell = game.getStack().getSpell(event.getTargetId()); - Player guileController = game.getPlayer(source.getControllerId()); - if (spell != null && guileController != null) { - Card spellCard = spell.getCard(); - guileController.moveCardToExileWithInfo(spellCard, null, "", source.getSourceId(), game, Zone.STACK, true); - if (guileController.chooseUse(Outcome.PlayForFree, "Cast that card for free?", source, game)) { - guileController.cast(spellCard.getSpellAbility(), game, true); + Player controller = game.getPlayer(source.getControllerId()); + if (spell != null && controller != null) { + controller.moveCards(spell, null, Zone.EXILED, source, game); + if (!spell.isCopy()) { + Card spellCard = spell.getCard(); + if (spellCard != null && controller.chooseUse(Outcome.PlayForFree, "Cast " + spellCard.getIdName() + " for free?", source, game)) { + controller.cast(spellCard.getSpellAbility(), game, true); + } + return true; } - return true; } return false; } - - @Override + + @Override public boolean checksEventType(GameEvent event, Game game) { return event.getType() == EventType.COUNTER; } - + @Override public boolean applies(GameEvent event, Ability source, Game game) { Spell counteredSpell = game.getStack().getSpell(event.getTargetId()); StackObject counteringObject = game.getStack().getStackObject(event.getSourceId()); - return counteredSpell != null + return counteredSpell != null && counteringObject != null && counteringObject.getControllerId().equals(source.getControllerId()); } From b8bd54533d442d2fd936d9ceb2dad5a0455a8deb Mon Sep 17 00:00:00 2001 From: LoneFox Date: Wed, 7 Oct 2015 08:11:08 +0300 Subject: [PATCH 035/268] Implement cards: Boris Devilboon, Disciple of Tevesh Szat, Fugitive Druid, and Metrognome --- .../sets/coldsnap/DiscipleOfTeveshSzat.java | 79 +++++++++++ .../src/mage/sets/legends/BorisDevilboon.java | 85 ++++++++++++ .../masterseditioniii/BorisDevilboon.java | 54 ++++++++ .../src/mage/sets/tempest/FugitiveDruid.java | 72 ++++++++++ .../src/mage/sets/urzassaga/Metrognome.java | 123 ++++++++++++++++++ .../common/BecomesTargetTriggeredAbility.java | 17 ++- 6 files changed, 427 insertions(+), 3 deletions(-) create mode 100644 Mage.Sets/src/mage/sets/coldsnap/DiscipleOfTeveshSzat.java create mode 100644 Mage.Sets/src/mage/sets/legends/BorisDevilboon.java create mode 100644 Mage.Sets/src/mage/sets/masterseditioniii/BorisDevilboon.java create mode 100644 Mage.Sets/src/mage/sets/tempest/FugitiveDruid.java create mode 100644 Mage.Sets/src/mage/sets/urzassaga/Metrognome.java diff --git a/Mage.Sets/src/mage/sets/coldsnap/DiscipleOfTeveshSzat.java b/Mage.Sets/src/mage/sets/coldsnap/DiscipleOfTeveshSzat.java new file mode 100644 index 00000000000..4d5297e1013 --- /dev/null +++ b/Mage.Sets/src/mage/sets/coldsnap/DiscipleOfTeveshSzat.java @@ -0,0 +1,79 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.sets.coldsnap; + +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.costs.common.TapSourceCost; +import mage.abilities.costs.mana.ManaCostsImpl; +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.constants.Zone; +import mage.target.common.TargetCreaturePermanent; + +/** + * + * @author LoneFox + */ +public class DiscipleOfTeveshSzat extends CardImpl { + + public DiscipleOfTeveshSzat(UUID ownerId) { + super(ownerId, 55, "Disciple of Tevesh Szat", Rarity.COMMON, new CardType[]{CardType.CREATURE}, "{2}{B}{B}"); + this.expansionSetCode = "CSP"; + this.subtype.add("Human"); + this.subtype.add("Cleric"); + this.power = new MageInt(3); + this.toughness = new MageInt(1); + + // {tap}: Target creature gets -1/-1 until end of turn. + Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new BoostTargetEffect(-1, -1, Duration.EndOfTurn), new TapSourceCost()); + ability.addTarget(new TargetCreaturePermanent()); + this.addAbility(ability); + // {4}{B}{B}, {tap}, Sacrifice Disciple of Tevesh Szat: Target creature gets -6/-6 until end of turn. + ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new BoostTargetEffect(-6, -6, Duration.EndOfTurn), new ManaCostsImpl("{4}{B}{B}")); + ability.addCost(new TapSourceCost()); + ability.addCost(new SacrificeSourceCost()); + ability.addTarget(new TargetCreaturePermanent()); + this.addAbility(ability); + } + + public DiscipleOfTeveshSzat(final DiscipleOfTeveshSzat card) { + super(card); + } + + @Override + public DiscipleOfTeveshSzat copy() { + return new DiscipleOfTeveshSzat(this); + } +} diff --git a/Mage.Sets/src/mage/sets/legends/BorisDevilboon.java b/Mage.Sets/src/mage/sets/legends/BorisDevilboon.java new file mode 100644 index 00000000000..cda9278c4cb --- /dev/null +++ b/Mage.Sets/src/mage/sets/legends/BorisDevilboon.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.legends; + +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.costs.mana.ManaCostsImpl; +import mage.abilities.effects.common.CreateTokenEffect; +import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.Rarity; +import mage.constants.Zone; +import mage.game.permanent.token.Token; + +/** + * + * @author LoneFox + */ +public class BorisDevilboon extends CardImpl { + + public BorisDevilboon(UUID ownerId) { + super(ownerId, 263, "Boris Devilboon", Rarity.RARE, new CardType[]{CardType.CREATURE}, "{3}{B}{R}"); + this.expansionSetCode = "LEG"; + this.supertype.add("Legendary"); + this.subtype.add("Zombie"); + this.subtype.add("Wizard"); + this.power = new MageInt(2); + this.toughness = new MageInt(2); + + // {2}{B}{R}, {tap}: Put a 1/1 black and red Demon creature token named Minor Demon onto the battlefield. + Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new CreateTokenEffect(new MinorDemonToken()), new ManaCostsImpl("{2}{B}{R}")); + ability.addCost(new TapSourceCost()); + this.addAbility(ability); + } + + public BorisDevilboon(final BorisDevilboon card) { + super(card); + } + + @Override + public BorisDevilboon copy() { + return new BorisDevilboon(this); + } +} + +class MinorDemonToken extends Token { + + public MinorDemonToken() { + super("Minor Demon", "1/1 black and red Demon creature token named Minor Demon"); + cardType.add(CardType.CREATURE); + color.setBlack(true); + color.setRed(true); + subtype.add("Demon"); + power = new MageInt(1); + toughness = new MageInt(1); + } +} diff --git a/Mage.Sets/src/mage/sets/masterseditioniii/BorisDevilboon.java b/Mage.Sets/src/mage/sets/masterseditioniii/BorisDevilboon.java new file mode 100644 index 00000000000..ad273286c8b --- /dev/null +++ b/Mage.Sets/src/mage/sets/masterseditioniii/BorisDevilboon.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.masterseditioniii; + +import java.util.UUID; +import mage.constants.Rarity; + +/** + * + * @author LoneFox + */ +public class BorisDevilboon extends mage.sets.legends.BorisDevilboon { + + public BorisDevilboon(UUID ownerId) { + super(ownerId); + this.cardNumber = 146; + this.expansionSetCode = "ME3"; + this.rarity = Rarity.UNCOMMON; + } + + public BorisDevilboon(final BorisDevilboon card) { + super(card); + } + + @Override + public BorisDevilboon copy() { + return new BorisDevilboon(this); + } +} diff --git a/Mage.Sets/src/mage/sets/tempest/FugitiveDruid.java b/Mage.Sets/src/mage/sets/tempest/FugitiveDruid.java new file mode 100644 index 00000000000..a2811d685bb --- /dev/null +++ b/Mage.Sets/src/mage/sets/tempest/FugitiveDruid.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.tempest; + +import java.util.UUID; +import mage.MageInt; +import mage.abilities.common.BecomesTargetTriggeredAbility; +import mage.abilities.effects.common.DrawCardSourceControllerEffect; +import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.Rarity; +import mage.filter.FilterSpell; +import mage.filter.predicate.mageobject.SubtypePredicate; + +/** + * + * @author LoneFox + */ +public class FugitiveDruid extends CardImpl { + + private static final FilterSpell filter = new FilterSpell("an Aura spell"); + + static { + filter.add(new SubtypePredicate("Aura")); + } + + public FugitiveDruid(UUID ownerId) { + super(ownerId, 123, "Fugitive Druid", Rarity.RARE, new CardType[]{CardType.CREATURE}, "{3}{G}"); + this.expansionSetCode = "TMP"; + this.subtype.add("Human"); + this.subtype.add("Druid"); + this.power = new MageInt(3); + this.toughness = new MageInt(2); + + // Whenever Fugitive Druid becomes the target of an Aura spell, you draw a card. + this.addAbility(new BecomesTargetTriggeredAbility(new DrawCardSourceControllerEffect(1), filter)); + } + + public FugitiveDruid(final FugitiveDruid card) { + super(card); + } + + @Override + public FugitiveDruid copy() { + return new FugitiveDruid(this); + } +} diff --git a/Mage.Sets/src/mage/sets/urzassaga/Metrognome.java b/Mage.Sets/src/mage/sets/urzassaga/Metrognome.java new file mode 100644 index 00000000000..4bae5c0bea0 --- /dev/null +++ b/Mage.Sets/src/mage/sets/urzassaga/Metrognome.java @@ -0,0 +1,123 @@ +/* + * 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.Ability; +import mage.abilities.TriggeredAbilityImpl; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.costs.common.TapSourceCost; +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.effects.common.CreateTokenEffect; +import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.Rarity; +import mage.constants.Zone; +import mage.game.Game; +import mage.game.events.GameEvent.EventType; +import mage.game.events.GameEvent; +import mage.game.permanent.token.Token; +import mage.game.stack.StackObject; + +/** + * + * @author LoneFox + */ +public class Metrognome extends CardImpl { + + public Metrognome(UUID ownerId) { + super(ownerId, 301, "Metrognome", Rarity.RARE, new CardType[]{CardType.ARTIFACT}, "{4}"); + this.expansionSetCode = "USG"; + + // When a spell or ability an opponent controls causes you to discard Metrognome, put four 1/1 colorless Gnome artifact creature tokens onto the battlefield. + this.addAbility(new MetrognomeTriggeredAbility()); + // {4}, {tap}: Put a 1/1 colorless Gnome artifact creature token onto the battlefield. + Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new CreateTokenEffect(new GnomeToken()), new ManaCostsImpl("{4}")); + ability.addCost(new TapSourceCost()); + this.addAbility(ability); + } + + public Metrognome(final Metrognome card) { + super(card); + } + + @Override + public Metrognome copy() { + return new Metrognome(this); + } +} + +class MetrognomeTriggeredAbility extends TriggeredAbilityImpl { + + MetrognomeTriggeredAbility() { + super(Zone.ALL, new CreateTokenEffect(new GnomeToken(), 4)); + } + + MetrognomeTriggeredAbility(final MetrognomeTriggeredAbility ability) { + super(ability); + } + + @Override + public MetrognomeTriggeredAbility copy() { + return new MetrognomeTriggeredAbility(this); + } + + @Override + public boolean checkEventType(GameEvent event, Game game) { + return event.getType() == EventType.DISCARDED_CARD; + } + + @Override + public boolean checkTrigger(GameEvent event, Game game) { + if (getSourceId().equals(event.getTargetId())) { + StackObject stackObject = game.getStack().getStackObject(event.getSourceId()); + if (stackObject != null) { + return game.getOpponents(this.getControllerId()).contains(stackObject.getControllerId()); + } + } + return false; + } + + @Override + public String getRule() { + return "When a spell or ability an opponent controls causes you to discard {this}, " + super.getRule(); + } +} + +class GnomeToken extends Token { + + public GnomeToken() { + super("Gnome", "1/1 colorless Gnome artifact creature token"); + cardType.add(CardType.ARTIFACT); + cardType.add(CardType.CREATURE); + subtype.add("Gnome"); + power = new MageInt(1); + toughness = new MageInt(1); + } +} diff --git a/Mage/src/mage/abilities/common/BecomesTargetTriggeredAbility.java b/Mage/src/mage/abilities/common/BecomesTargetTriggeredAbility.java index c80efba2104..8232f7e1b2e 100644 --- a/Mage/src/mage/abilities/common/BecomesTargetTriggeredAbility.java +++ b/Mage/src/mage/abilities/common/BecomesTargetTriggeredAbility.java @@ -27,11 +27,13 @@ */ package mage.abilities.common; -import mage.constants.Zone; import mage.abilities.TriggeredAbilityImpl; import mage.abilities.effects.Effect; +import mage.constants.Zone; +import mage.filter.FilterStackObject; import mage.game.Game; import mage.game.events.GameEvent; +import mage.game.stack.StackObject; /** * @@ -39,12 +41,20 @@ import mage.game.events.GameEvent; */ public class BecomesTargetTriggeredAbility extends TriggeredAbilityImpl { + private final FilterStackObject filter; + public BecomesTargetTriggeredAbility(Effect effect) { + this(effect, new FilterStackObject("a spell or ability")); + } + + public BecomesTargetTriggeredAbility(Effect effect, FilterStackObject filter) { super(Zone.BATTLEFIELD, effect); + this.filter = filter.copy(); } public BecomesTargetTriggeredAbility(final BecomesTargetTriggeredAbility ability) { super(ability); + this.filter = ability.filter.copy(); } @Override @@ -59,11 +69,12 @@ public class BecomesTargetTriggeredAbility extends TriggeredAbilityImpl { @Override public boolean checkTrigger(GameEvent event, Game game) { - return event.getTargetId().equals(getSourceId()); + StackObject sourceObject = game.getStack().getStackObject(event.getSourceId()); + return event.getTargetId().equals(getSourceId()) && filter.match(sourceObject, getSourceId(), getControllerId(), game); } @Override public String getRule() { - return "When {this} becomes the target of a spell or ability, " + super.getRule(); + return "When {this} becomes the target of " + filter.getMessage() + ", " + super.getRule(); } } From 3a426e3cd87a743cde5069aeb4c49ef0812e663e Mon Sep 17 00:00:00 2001 From: LevelX2 Date: Wed, 7 Oct 2015 08:18:35 +0200 Subject: [PATCH 036/268] * Lighthouse Chronologist - Removed custom classes. --- .../LighthouseChronologist.java | 83 +++---------------- .../condition/common/NotMyTurnCondition.java | 7 +- 2 files changed, 19 insertions(+), 71 deletions(-) diff --git a/Mage.Sets/src/mage/sets/riseoftheeldrazi/LighthouseChronologist.java b/Mage.Sets/src/mage/sets/riseoftheeldrazi/LighthouseChronologist.java index 9271b8d212a..8018972095c 100644 --- a/Mage.Sets/src/mage/sets/riseoftheeldrazi/LighthouseChronologist.java +++ b/Mage.Sets/src/mage/sets/riseoftheeldrazi/LighthouseChronologist.java @@ -1,16 +1,16 @@ /* * Copyright 2011 BetaSteward_at_googlemail.com. All rights reserved. - * + * * Redistribution and use in source and binary forms, with or without modification, are * permitted provided that the following conditions are met: - * + * * 1. Redistributions of source code must retain the above copyright notice, this list of * conditions and the following disclaimer. - * + * * 2. Redistributions in binary form must reproduce the above copyright notice, this list * of conditions and the following disclaimer in the documentation and/or other materials * provided with the distribution. - * + * * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR @@ -20,12 +20,11 @@ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * + * * The views and conclusions contained in the software and documentation are those of the * authors and should not be interpreted as representing official policies, either expressed * or implied, of BetaSteward_at_googlemail.com. */ - package mage.sets.riseoftheeldrazi; import java.util.UUID; @@ -33,20 +32,17 @@ import mage.MageInt; import mage.abilities.Abilities; import mage.abilities.AbilitiesImpl; import mage.abilities.Ability; -import mage.abilities.TriggeredAbilityImpl; +import mage.abilities.common.BeginningOfEndStepTriggeredAbility; +import mage.abilities.condition.common.NotMyTurnCondition; import mage.abilities.costs.mana.ManaCostsImpl; -import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.turn.AddExtraTurnControllerEffect; import mage.abilities.keyword.LevelUpAbility; import mage.abilities.keyword.LevelerCardBuilder; import mage.cards.LevelerCard; import mage.constants.CardType; -import mage.constants.Outcome; import mage.constants.Rarity; +import mage.constants.TargetController; import mage.constants.Zone; -import mage.game.Game; -import mage.game.events.GameEvent; -import mage.game.events.GameEvent.EventType; -import mage.game.turn.TurnMod; /** * @@ -54,7 +50,7 @@ import mage.game.turn.TurnMod; */ public class LighthouseChronologist extends LevelerCard { - public LighthouseChronologist (UUID ownerId) { + public LighthouseChronologist(UUID ownerId) { super(ownerId, 75, "Lighthouse Chronologist", Rarity.MYTHIC, new CardType[]{CardType.CREATURE}, "{1}{U}"); this.expansionSetCode = "ROE"; this.subtype.add("Human"); @@ -73,7 +69,8 @@ public class LighthouseChronologist extends LevelerCard { // 3/5 // At the beginning of each end step, if it's not your turn, take an extra turn after this one. Abilities abilities2 = new AbilitiesImpl<>(); - abilities2.add(new LighthouseChronologistAbility()); + abilities2.add(new BeginningOfEndStepTriggeredAbility( + Zone.BATTLEFIELD, new AddExtraTurnControllerEffect(false), TargetController.ANY, NotMyTurnCondition.getInstance(), false)); this.addAbilities(LevelerCardBuilder.construct( new LevelerCardBuilder.LevelAbility(4, 6, abilities1, 2, 4), @@ -82,7 +79,7 @@ public class LighthouseChronologist extends LevelerCard { setMaxLevelCounters(7); } - public LighthouseChronologist (final LighthouseChronologist card) { + public LighthouseChronologist(final LighthouseChronologist card) { super(card); } @@ -92,57 +89,3 @@ public class LighthouseChronologist extends LevelerCard { } } - -class LighthouseChronologistAbility extends TriggeredAbilityImpl { - - public LighthouseChronologistAbility() { - super(Zone.BATTLEFIELD, new LighthouseChronologistEffect(), false); - } - - public LighthouseChronologistAbility(final LighthouseChronologistAbility ability) { - super(ability); - } - - @Override - public LighthouseChronologistAbility copy() { - return new LighthouseChronologistAbility(this); - } - - @Override - public boolean checkEventType(GameEvent event, Game game) { - return event.getType() == EventType.END_TURN_STEP_PRE; - } - - @Override - public boolean checkTrigger(GameEvent event, Game game) { - return !game.getActivePlayerId().equals(this.controllerId); - } - - @Override - public String getRule() { - return "At the beginning of each end step, if it's not your turn, take an extra turn after this one."; - } -} - -class LighthouseChronologistEffect extends OneShotEffect { - - public LighthouseChronologistEffect() { - super(Outcome.ExtraTurn); - } - - public LighthouseChronologistEffect(final LighthouseChronologistEffect effect) { - super(effect); - } - - @Override - public LighthouseChronologistEffect copy() { - return new LighthouseChronologistEffect(this); - } - - @Override - public boolean apply(Game game, Ability source) { - game.getState().getTurnMods().add(new TurnMod(source.getControllerId(), false)); - return true; - } - -} \ No newline at end of file diff --git a/Mage/src/mage/abilities/condition/common/NotMyTurnCondition.java b/Mage/src/mage/abilities/condition/common/NotMyTurnCondition.java index c7940eeed00..6a1755e773c 100644 --- a/Mage/src/mage/abilities/condition/common/NotMyTurnCondition.java +++ b/Mage/src/mage/abilities/condition/common/NotMyTurnCondition.java @@ -33,7 +33,7 @@ import mage.abilities.condition.Condition; import mage.game.Game; public class NotMyTurnCondition implements Condition { - + private static final NotMyTurnCondition fInstance = new NotMyTurnCondition(); public static Condition getInstance() { @@ -48,4 +48,9 @@ public class NotMyTurnCondition implements Condition { } return false; } + + @Override + public String toString() { + return "if it's not your turn"; + } } From ddba778c63ff98314150f6687fd9c50a1a8664ae Mon Sep 17 00:00:00 2001 From: Thomas Dwyer Date: Wed, 7 Oct 2015 00:04:15 -0700 Subject: [PATCH 037/268] Added Pardic Lancer and Hell-Bent Raider --- .../src/mage/sets/torment/HellBentRaider.java | 85 +++++++++++++++++++ .../src/mage/sets/torment/PardicLancer.java | 77 +++++++++++++++++ 2 files changed, 162 insertions(+) create mode 100644 Mage.Sets/src/mage/sets/torment/HellBentRaider.java create mode 100644 Mage.Sets/src/mage/sets/torment/PardicLancer.java diff --git a/Mage.Sets/src/mage/sets/torment/HellBentRaider.java b/Mage.Sets/src/mage/sets/torment/HellBentRaider.java new file mode 100644 index 00000000000..b504970e282 --- /dev/null +++ b/Mage.Sets/src/mage/sets/torment/HellBentRaider.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.torment; + +import java.util.UUID; +import mage.MageInt; +import mage.abilities.Ability; +import mage.ObjectColor; +import mage.abilities.keyword.FirstStrikeAbility; +import mage.abilities.keyword.HasteAbility; +import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.Rarity; +import mage.abilities.costs.common.DiscardCardCost; +import mage.abilities.effects.common.continuous.GainAbilitySourceEffect; +import mage.constants.Zone; +import mage.filter.FilterCard; +import mage.filter.predicate.mageobject.ColorPredicate; +import mage.abilities.common.SimpleActivatedAbility; +import mage.constants.Duration; +import mage.abilities.keyword.ProtectionAbility; +/** + * + * @author tomd1990 + */ +public class HellBentRaider extends CardImpl { + private static final FilterCard protectionFilter = new FilterCard("White"); + + static { + protectionFilter.add(new ColorPredicate(ObjectColor.WHITE)); + } + + public HellBentRaider(UUID ownerId) { + super(ownerId, 101, "Hell-Bent Raider", Rarity.RARE, new CardType[]{CardType.CREATURE}, "{1}{R}{R}"); + this.expansionSetCode = "TOR"; + this.subtype.add("Human"); + this.subtype.add("Barbarian"); + this.power = new MageInt(2); + this.toughness = new MageInt(2); + + // First strike + this.addAbility(FirstStrikeAbility.getInstance()); + // Haste + this.addAbility(HasteAbility.getInstance()); + // Discard a card at random: Hell-Bent Raider gains protection from white until end of turn. + Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, + new GainAbilitySourceEffect( new ProtectionAbility(protectionFilter), Duration.EndOfTurn), + new DiscardCardCost(true)); + this.addAbility(ability); + } + + public HellBentRaider(final HellBentRaider card) { + super(card); + } + + @Override + public HellBentRaider copy() { + return new HellBentRaider(this); + } +} \ No newline at end of file diff --git a/Mage.Sets/src/mage/sets/torment/PardicLancer.java b/Mage.Sets/src/mage/sets/torment/PardicLancer.java new file mode 100644 index 00000000000..878cad07acc --- /dev/null +++ b/Mage.Sets/src/mage/sets/torment/PardicLancer.java @@ -0,0 +1,77 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.sets.torment; + +import java.util.UUID; +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.costs.common.DiscardCardCost; +import mage.abilities.effects.common.continuous.BoostSourceEffect; +import mage.abilities.effects.common.continuous.GainAbilitySourceEffect; +import mage.abilities.keyword.FirstStrikeAbility; +import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.Rarity; +import mage.constants.Zone; +import mage.abilities.effects.Effect; + +/** + * + * @author tomd1990 + */ +public class PardicLancer extends CardImpl { + + public PardicLancer(UUID ownerId) { + super(ownerId, 107, "Pardic Lancer", Rarity.COMMON, new CardType[]{CardType.CREATURE}, "{4}{R}"); + this.expansionSetCode = "TOR"; + this.subtype.add("Human"); + this.subtype.add("Barbarian"); + this.power = new MageInt(3); + this.toughness = new MageInt(2); + + // Discard a card at random: Pardic Lancer gets +1/+0 and gains first strike until end of turn. + Effect effect = new BoostSourceEffect(1,0,Duration.EndOfTurn); + effect.setText("{this} gets +1/+0"); + Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, effect, new DiscardCardCost(true)); + effect = new GainAbilitySourceEffect(FirstStrikeAbility.getInstance(), Duration.EndOfTurn); + effect.setText("and gains first strike until end of turn"); + ability.addEffect(effect); + this.addAbility(ability); + } + + public PardicLancer(final PardicLancer card) { + super(card); + } + + @Override + public PardicLancer copy() { + return new PardicLancer(this); + } +} \ No newline at end of file From 8f3025cd234da5503565d133f2dbaa337f0ff1e7 Mon Sep 17 00:00:00 2001 From: Thomas Dwyer Date: Wed, 7 Oct 2015 01:21:20 -0700 Subject: [PATCH 038/268] Added Enslaved Dward to Torment --- .../src/mage/sets/torment/EnslavedDwarf.java | 89 +++++++++++++++++++ 1 file changed, 89 insertions(+) create mode 100644 Mage.Sets/src/mage/sets/torment/EnslavedDwarf.java diff --git a/Mage.Sets/src/mage/sets/torment/EnslavedDwarf.java b/Mage.Sets/src/mage/sets/torment/EnslavedDwarf.java new file mode 100644 index 00000000000..5ca796ddc0e --- /dev/null +++ b/Mage.Sets/src/mage/sets/torment/EnslavedDwarf.java @@ -0,0 +1,89 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.sets.torment; + +import java.util.UUID; +import mage.MageInt; +import mage.ObjectColor; +import mage.abilities.Ability; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.costs.common.SacrificeSourceCost; +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.effects.Effect; +import mage.abilities.effects.common.continuous.BoostTargetEffect; +import mage.abilities.effects.common.continuous.GainAbilityTargetEffect; +import mage.abilities.keyword.FirstStrikeAbility; +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.mageobject.ColorPredicate; +import mage.target.common.TargetCreaturePermanent; + +/** + * + * @author tomd1990 + */ +public class EnslavedDwarf extends CardImpl { + + private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("black creature"); + + static { + filter.add(new ColorPredicate(ObjectColor.BLACK)); + } + + public EnslavedDwarf(UUID ownerId) { + super(ownerId, 96, "Enslaved Dwarf", Rarity.COMMON, new CardType[]{CardType.CREATURE}, "{R}"); + this.expansionSetCode = "TOR"; + this.subtype.add("Dwarf"); + this.power = new MageInt(1); + this.toughness = new MageInt(1); + + // {R}, Sacrifice Enslaved Dwarf: Target black creature gets +1/+0 and gains first strike until end of turn. + Effect effect = new BoostTargetEffect(1,0,Duration.EndOfTurn); + effect.setText("Target black creature gets +1/+0"); + Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, effect, new ManaCostsImpl<>("{R}")); + ability.addCost(new SacrificeSourceCost()); + effect = new GainAbilityTargetEffect(FirstStrikeAbility.getInstance(), Duration.EndOfTurn); + effect.setText("and gains first strike until end of turn"); + ability.addEffect(effect); + ability.addTarget(new TargetCreaturePermanent(filter)); + this.addAbility(ability); + } + + public EnslavedDwarf(final EnslavedDwarf card) { + super(card); + } + + @Override + public EnslavedDwarf copy() { + return new EnslavedDwarf(this); + } +} From 06f61ce616e8ed11f4751a45fc46a79125313d95 Mon Sep 17 00:00:00 2001 From: LoneFox Date: Wed, 7 Oct 2015 12:25:31 +0300 Subject: [PATCH 039/268] Implement cards: Caribou Range, Fatespinner, Hibernation's End, and Safe Haven --- .../mage/sets/coldsnap/HibernationsEnd.java | 141 +++++++++++++++ .../mage/sets/fifthedition/CaribouRange.java | 114 ++++++++++++ .../src/mage/sets/iceage/CaribouRange.java | 52 ++++++ .../sets/masterseditionii/CaribouRange.java | 52 ++++++ .../src/mage/sets/mirrodin/Fatespinner.java | 168 ++++++++++++++++++ .../src/mage/sets/thedark/SafeHaven.java | 78 ++++++++ .../src/mage/sets/timeshifted/SafeHaven.java | 54 ++++++ .../keyword/CumulativeUpkeepAbility.java | 2 + Mage/src/mage/game/events/GameEvent.java | 1 + 9 files changed, 662 insertions(+) create mode 100644 Mage.Sets/src/mage/sets/coldsnap/HibernationsEnd.java create mode 100644 Mage.Sets/src/mage/sets/fifthedition/CaribouRange.java create mode 100644 Mage.Sets/src/mage/sets/iceage/CaribouRange.java create mode 100644 Mage.Sets/src/mage/sets/masterseditionii/CaribouRange.java create mode 100644 Mage.Sets/src/mage/sets/mirrodin/Fatespinner.java create mode 100644 Mage.Sets/src/mage/sets/thedark/SafeHaven.java create mode 100644 Mage.Sets/src/mage/sets/timeshifted/SafeHaven.java diff --git a/Mage.Sets/src/mage/sets/coldsnap/HibernationsEnd.java b/Mage.Sets/src/mage/sets/coldsnap/HibernationsEnd.java new file mode 100644 index 00000000000..e62a91d9b36 --- /dev/null +++ b/Mage.Sets/src/mage/sets/coldsnap/HibernationsEnd.java @@ -0,0 +1,141 @@ +/* + * 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.abilities.Ability; +import mage.abilities.TriggeredAbilityImpl; +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.search.SearchLibraryPutInPlayEffect; +import mage.abilities.keyword.CumulativeUpkeepAbility; +import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.Outcome; +import mage.constants.Rarity; +import mage.constants.Zone; +import mage.filter.Filter; +import mage.filter.FilterCard; +import mage.filter.predicate.mageobject.CardTypePredicate; +import mage.filter.predicate.mageobject.ConvertedManaCostPredicate; +import mage.game.Game; +import mage.game.events.GameEvent.EventType; +import mage.game.events.GameEvent; +import mage.game.permanent.Permanent; +import mage.players.Player; +import mage.target.common.TargetCardInLibrary; + +/** + * + * @author LoneFox + */ +public class HibernationsEnd extends CardImpl { + + public HibernationsEnd(UUID ownerId) { + super(ownerId, 110, "Hibernation's End", Rarity.RARE, new CardType[]{CardType.ENCHANTMENT}, "{4}{G}"); + this.expansionSetCode = "CSP"; + + // Cumulative upkeep {1} + this.addAbility(new CumulativeUpkeepAbility(new ManaCostsImpl("{1}"))); + // Whenever you pay Hibernation's End's cumulative upkeep, you may search your library for a creature card with converted mana cost equal to the number of age counters on Hibernation's End and put it onto the battlefield. If you do, shuffle your library. + this.addAbility(new HibernationsEndAbility()); + } + + public HibernationsEnd(final HibernationsEnd card) { + super(card); + } + + @Override + public HibernationsEnd copy() { + return new HibernationsEnd(this); + } +} + +class HibernationsEndAbility extends TriggeredAbilityImpl { + + public HibernationsEndAbility() { + super(Zone.BATTLEFIELD, new HibernationsEndEffect(), true); + } + + public HibernationsEndAbility(final HibernationsEndAbility ability) { + super(ability); + } + + @Override + public HibernationsEndAbility copy() { + return new HibernationsEndAbility(this); + } + + @Override + public boolean checkEventType(GameEvent event, Game game) { + return event.getType() == EventType.PAID_CUMULATIVE_UPKEEP; + } + + @Override + public boolean checkTrigger(GameEvent event, Game game) { + return event.getSourceId() == this.getSourceId(); + } + + @Override + public String getRule() { + return "Whenever you pay {this}'s cumulative upkeep, " + super.getRule(); + } +} + +class HibernationsEndEffect extends OneShotEffect { + + public HibernationsEndEffect() { + super(Outcome.Benefit); + this.staticText = "search your library for a creature card with converted mana cost equal to the number of age counters on {this} and put it onto the battlefield. If you do, shuffle your library."; + } + + public HibernationsEndEffect(final HibernationsEndEffect effect) { + super(effect); + } + + @Override + public HibernationsEndEffect copy() { + return new HibernationsEndEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player player = game.getPlayer(source.getControllerId()); + Permanent sourcePermanent = game.getPermanentOrLKIBattlefield(source.getSourceId()); + if(sourcePermanent != null && player != null) { + int newConvertedCost = sourcePermanent.getCounters().getCount("age"); + FilterCard filter = new FilterCard("creature card with converted mana cost " + newConvertedCost); + filter.add(new ConvertedManaCostPredicate(Filter.ComparisonType.Equal, newConvertedCost)); + filter.add(new CardTypePredicate(CardType.CREATURE)); + TargetCardInLibrary target = new TargetCardInLibrary(filter); + return new SearchLibraryPutInPlayEffect(target).apply(game, source); + } + return false; + } +} + diff --git a/Mage.Sets/src/mage/sets/fifthedition/CaribouRange.java b/Mage.Sets/src/mage/sets/fifthedition/CaribouRange.java new file mode 100644 index 00000000000..d107abb2957 --- /dev/null +++ b/Mage.Sets/src/mage/sets/fifthedition/CaribouRange.java @@ -0,0 +1,114 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.sets.fifthedition; + +import java.util.UUID; +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.costs.common.SacrificeTargetCost; +import mage.abilities.costs.common.TapSourceCost; +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.effects.Effect; +import mage.abilities.effects.common.AttachEffect; +import mage.abilities.effects.common.CreateTokenEffect; +import mage.abilities.effects.common.GainLifeEffect; +import mage.abilities.effects.common.continuous.GainAbilityAttachedEffect; +import mage.abilities.keyword.EnchantAbility; +import mage.cards.CardImpl; +import mage.constants.AttachmentType; +import mage.constants.CardType; +import mage.constants.Outcome; +import mage.constants.Rarity; +import mage.constants.Zone; +import mage.filter.common.FilterControlledCreaturePermanent; +import mage.filter.common.FilterControlledLandPermanent; +import mage.filter.predicate.mageobject.SubtypePredicate; +import mage.filter.predicate.permanent.TokenPredicate; +import mage.game.permanent.token.Token; +import mage.target.TargetPermanent; +import mage.target.common.TargetControlledCreaturePermanent; +import mage.target.common.TargetControlledPermanent; + +/** + * + * @author LoneFox + */ +public class CaribouRange extends CardImpl { + + static FilterControlledCreaturePermanent filter = new FilterControlledCreaturePermanent("a Caribou token"); + + static { + filter.add(new TokenPredicate()); + filter.add(new SubtypePredicate("Caribou")); + } + + public CaribouRange(UUID ownerId) { + super(ownerId, 290, "Caribou Range", Rarity.RARE, new CardType[]{CardType.ENCHANTMENT}, "{2}{W}{W}"); + this.expansionSetCode = "5ED"; + this.subtype.add("Aura"); + + // Enchant land you control + TargetPermanent auraTarget = new TargetControlledPermanent(new FilterControlledLandPermanent("land you control")); + this.getSpellAbility().addTarget(auraTarget); + this.getSpellAbility().addEffect(new AttachEffect(Outcome.AddAbility)); + Ability ability = new EnchantAbility(auraTarget.getTargetName()); + this.addAbility(ability); + // Enchanted land has "{W}{W}, {T}: Put a 0/1 white Caribou creature token onto the battlefield." + ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new CreateTokenEffect(new CaribouToken()), new ManaCostsImpl("{W}{W}")); + ability.addCost(new TapSourceCost()); + Effect effect = new GainAbilityAttachedEffect(ability, AttachmentType.AURA); + effect.setText("Enchanted land has \"{W}{W}, {T}: Put a 0/1 white Caribou creature token onto the battlefield.\""); + this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, effect)); + // Sacrifice a Caribou token: You gain 1 life. + this.addAbility(new SimpleActivatedAbility(Zone.BATTLEFIELD, new GainLifeEffect(1), + new SacrificeTargetCost(new TargetControlledCreaturePermanent(filter)))); + } + + public CaribouRange(final CaribouRange card) { + super(card); + } + + @Override + public CaribouRange copy() { + return new CaribouRange(this); + } +} + +class CaribouToken extends Token { + + public CaribouToken() { + super("Caribou", "0/1 white Caribou creature token"); + cardType.add(CardType.CREATURE); + color.setWhite(true); + subtype.add("Caribou"); + power = new MageInt(0); + toughness = new MageInt(1); + } +} diff --git a/Mage.Sets/src/mage/sets/iceage/CaribouRange.java b/Mage.Sets/src/mage/sets/iceage/CaribouRange.java new file mode 100644 index 00000000000..e9452f4c5f7 --- /dev/null +++ b/Mage.Sets/src/mage/sets/iceage/CaribouRange.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.iceage; + +import java.util.UUID; + +/** + * + * @author LoneFox + */ +public class CaribouRange extends mage.sets.fifthedition.CaribouRange { + + public CaribouRange(UUID ownerId) { + super(ownerId); + this.cardNumber = 235; + this.expansionSetCode = "ICE"; + } + + public CaribouRange(final CaribouRange card) { + super(card); + } + + @Override + public CaribouRange copy() { + return new CaribouRange(this); + } +} diff --git a/Mage.Sets/src/mage/sets/masterseditionii/CaribouRange.java b/Mage.Sets/src/mage/sets/masterseditionii/CaribouRange.java new file mode 100644 index 00000000000..e5099cbf06a --- /dev/null +++ b/Mage.Sets/src/mage/sets/masterseditionii/CaribouRange.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.masterseditionii; + +import java.util.UUID; + +/** + * + * @author LoneFox + */ +public class CaribouRange extends mage.sets.fifthedition.CaribouRange { + + public CaribouRange(UUID ownerId) { + super(ownerId); + this.cardNumber = 8; + this.expansionSetCode = "ME2"; + } + + public CaribouRange(final CaribouRange card) { + super(card); + } + + @Override + public CaribouRange copy() { + return new CaribouRange(this); + } +} diff --git a/Mage.Sets/src/mage/sets/mirrodin/Fatespinner.java b/Mage.Sets/src/mage/sets/mirrodin/Fatespinner.java new file mode 100644 index 00000000000..344f8ac9b3b --- /dev/null +++ b/Mage.Sets/src/mage/sets/mirrodin/Fatespinner.java @@ -0,0 +1,168 @@ +/* + * 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.mirrodin; + +import java.util.HashSet; +import java.util.UUID; +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.BeginningOfUpkeepTriggeredAbility; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.ReplacementEffectImpl; +import mage.cards.CardImpl; +import mage.choices.Choice; +import mage.choices.ChoiceImpl; +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.game.Game; +import mage.game.events.GameEvent.EventType; +import mage.game.events.GameEvent; +import mage.players.Player; + +/** + * + * @author LoneFox + */ +public class Fatespinner extends CardImpl { + + public Fatespinner(UUID ownerId) { + super(ownerId, 36, "Fatespinner", Rarity.RARE, new CardType[]{CardType.CREATURE}, "{1}{U}{U}"); + this.expansionSetCode = "MRD"; + this.subtype.add("Human"); + this.subtype.add("Wizard"); + this.power = new MageInt(1); + this.toughness = new MageInt(2); + + // At the beginning of each opponent's upkeep, that player chooses draw step, main phase, or combat phase. The player skips each instance of the chosen step or phase this turn. + this.addAbility(new BeginningOfUpkeepTriggeredAbility(Zone.BATTLEFIELD, new FatespinnerChooseEffect(), + TargetController.OPPONENT, false, true)); + } + + public Fatespinner(final Fatespinner card) { + super(card); + } + + @java.lang.Override + public Fatespinner copy() { + return new Fatespinner(this); + } +} + +class FatespinnerChooseEffect extends OneShotEffect { + + private static final HashSet choices = new HashSet<>(); + + static { + choices.add("Draw step"); + choices.add("Main phase"); + choices.add("Combat phase"); + } + + public FatespinnerChooseEffect() { + super(Outcome.Detriment); + staticText = "At the beginning of each opponent's upkeep, that player chooses draw step, main phase, or combat phase. The player skips each instance of the chosen step or phase this turn."; + } + + public FatespinnerChooseEffect(final FatespinnerChooseEffect effect) { + super(effect); + } + + @java.lang.Override + public FatespinnerChooseEffect copy() { + return new FatespinnerChooseEffect(this); + } + + @java.lang.Override + public boolean apply(Game game, Ability source) { + Player player = game.getPlayer(getTargetPointer().getFirst(game, source)); + if(player != null) { + Choice choice = new ChoiceImpl(true); + choice.setMessage("Choose phase or step to skip"); + choice.setChoices(choices); + while(!player.choose(outcome, choice, game)) { + if(player.canRespond()) { + return false; + } + } + String chosenPhase = choice.getChoice(); + game.informPlayers(player.getLogName() + " has chosen to skip " + chosenPhase.toLowerCase() + "."); + game.addEffect(new FatespinnerSkipEffect(chosenPhase), source); + return true; + } + return false; + } +} + +class FatespinnerSkipEffect extends ReplacementEffectImpl { + + private final String phase; + + public FatespinnerSkipEffect(String phase) { + super(Duration.EndOfTurn, Outcome.Detriment); + this.phase = phase; + } + + public FatespinnerSkipEffect(final FatespinnerSkipEffect effect) { + super(effect); + this.phase = effect.phase; + } + + @java.lang.Override + public FatespinnerSkipEffect copy() { + return new FatespinnerSkipEffect(this); + } + + @java.lang.Override + public boolean apply(Game game, Ability source) { + return true; + } + + @java.lang.Override + public boolean replaceEvent(GameEvent event, Ability source, Game game) { + EventType type = event.getType(); + return ((phase.equals("Draw step") && type == EventType.DRAW_STEP) + || (phase.equals("Main phase") && (type == EventType.PRECOMBAT_MAIN_PHASE || type == EventType.POSTCOMBAT_MAIN_PHASE)) + || (phase.equals("Combat phase") && type == EventType.COMBAT_PHASE)); + } + + @java.lang.Override + public boolean checksEventType(GameEvent event, Game game) { + EventType type = event.getType(); + return (type == EventType.DRAW_STEP || type == EventType.PRECOMBAT_MAIN_PHASE + || type == EventType.POSTCOMBAT_MAIN_PHASE || type == EventType.COMBAT_PHASE); + } + + @java.lang.Override + public boolean applies(GameEvent event, Ability source, Game game) { + return true; + } +} diff --git a/Mage.Sets/src/mage/sets/thedark/SafeHaven.java b/Mage.Sets/src/mage/sets/thedark/SafeHaven.java new file mode 100644 index 00000000000..d9e0dd30cbf --- /dev/null +++ b/Mage.Sets/src/mage/sets/thedark/SafeHaven.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.thedark; + +import java.util.UUID; +import mage.abilities.Ability; +import mage.abilities.common.BeginningOfUpkeepTriggeredAbility; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.costs.common.TapSourceCost; +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.effects.common.ExileTargetEffect; +import mage.abilities.effects.common.ReturnFromExileEffect; +import mage.abilities.effects.common.SacrificeSourceEffect; +import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.Rarity; +import mage.constants.TargetController; +import mage.constants.Zone; +import mage.target.common.TargetControlledCreaturePermanent; + +/** + * + * @author LoneFox + */ +public class SafeHaven extends CardImpl { + + public SafeHaven(UUID ownerId) { + super(ownerId, 115, "Safe Haven", Rarity.RARE, new CardType[]{CardType.LAND}, ""); + this.expansionSetCode = "DRK"; + + // {2}, {tap}: Exile target creature you control. + Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new ExileTargetEffect(this.getId(), + this.getIdName()), new ManaCostsImpl("{2}")); + ability.addCost(new TapSourceCost()); + ability.addTarget(new TargetControlledCreaturePermanent()); + this.addAbility(ability); + // At the beginning of your upkeep, you may sacrifice Safe Haven. If you do, return each card exiled with Safe Haven to the battlefield under its owner's control. + ability = new BeginningOfUpkeepTriggeredAbility(Zone.BATTLEFIELD, new SacrificeSourceEffect(), + TargetController.YOU, true); + ability.addEffect(new ReturnFromExileEffect(this.getId(), Zone.BATTLEFIELD, + "If you do, return each card exiled with {this} to the battlefield under its owner's control")); + this.addAbility(ability); + } + + public SafeHaven(final SafeHaven card) { + super(card); + } + + @Override + public SafeHaven copy() { + return new SafeHaven(this); + } +} diff --git a/Mage.Sets/src/mage/sets/timeshifted/SafeHaven.java b/Mage.Sets/src/mage/sets/timeshifted/SafeHaven.java new file mode 100644 index 00000000000..30cbfa71d1b --- /dev/null +++ b/Mage.Sets/src/mage/sets/timeshifted/SafeHaven.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.timeshifted; + +import java.util.UUID; +import mage.constants.Rarity; + +/** + * + * @author LoneFox + */ +public class SafeHaven extends mage.sets.thedark.SafeHaven { + + public SafeHaven(UUID ownerId) { + super(ownerId); + this.cardNumber = 121; + this.expansionSetCode = "TSB"; + this.rarity = Rarity.SPECIAL; + } + + public SafeHaven(final SafeHaven card) { + super(card); + } + + @Override + public SafeHaven copy() { + return new SafeHaven(this); + } +} diff --git a/Mage/src/mage/abilities/keyword/CumulativeUpkeepAbility.java b/Mage/src/mage/abilities/keyword/CumulativeUpkeepAbility.java index 4077074fa77..2e6c6d83fca 100644 --- a/Mage/src/mage/abilities/keyword/CumulativeUpkeepAbility.java +++ b/Mage/src/mage/abilities/keyword/CumulativeUpkeepAbility.java @@ -107,6 +107,7 @@ class CumulativeUpkeepEffect extends OneShotEffect { if (player.chooseUse(Outcome.Benefit, "Pay " + totalCost.getText() + "?", source, game)) { totalCost.clearPaid(); if (totalCost.payOrRollback(source, game, source.getSourceId(), source.getControllerId())) { + game.fireEvent(new GameEvent(EventType.PAID_CUMULATIVE_UPKEEP, permanent.getId(), permanent.getId(), player.getId(), ageCounter, false)); return true; } } @@ -122,6 +123,7 @@ class CumulativeUpkeepEffect extends OneShotEffect { totalCost.clearPaid(); int bookmark = game.bookmarkState(); if (totalCost.pay(source, game, source.getSourceId(), source.getControllerId(), false)) { + game.fireEvent(new GameEvent(EventType.PAID_CUMULATIVE_UPKEEP, permanent.getId(), permanent.getId(), player.getId(), ageCounter, false)); return true; } else { game.restoreState(bookmark, source.getRule()); diff --git a/Mage/src/mage/game/events/GameEvent.java b/Mage/src/mage/game/events/GameEvent.java index a6909fe7293..38e9ebeefe8 100644 --- a/Mage/src/mage/game/events/GameEvent.java +++ b/Mage/src/mage/game/events/GameEvent.java @@ -185,6 +185,7 @@ public class GameEvent implements Serializable { ENCHANT_PLAYER, ENCHANTED_PLAYER, CAN_TAKE_MULLIGAN, FLIP_COIN, COIN_FLIPPED, SCRY, FATESEAL, + PAID_CUMULATIVE_UPKEEP, DIDNT_PAY_CUMULATIVE_UPKEEP, //permanent events ENTERS_THE_BATTLEFIELD, From cb250a065a1d933a61437f84b819d529c06b6134 Mon Sep 17 00:00:00 2001 From: LevelX2 Date: Wed, 7 Oct 2015 17:47:25 +0200 Subject: [PATCH 040/268] Fixed that triggered abilities from sacrificed permanents did also trigger if the permanent was face down before the sacrifice. --- .../SmotheringAbomination.java | 1 - .../sets/mirrodinbesieged/KnowledgePool.java | 41 +++++++++------ .../abilities/keywords/ManifestTest.java | 52 +++++++++++++++++++ .../mage/abilities/TriggeredAbilities.java | 2 +- 4 files changed, 77 insertions(+), 19 deletions(-) diff --git a/Mage.Sets/src/mage/sets/battleforzendikar/SmotheringAbomination.java b/Mage.Sets/src/mage/sets/battleforzendikar/SmotheringAbomination.java index 93158d66475..e7d2ec93608 100644 --- a/Mage.Sets/src/mage/sets/battleforzendikar/SmotheringAbomination.java +++ b/Mage.Sets/src/mage/sets/battleforzendikar/SmotheringAbomination.java @@ -113,4 +113,3 @@ class SmotheringAbominationTriggeredAbility extends TriggeredAbilityImpl { return "Whenever you sacrifice a creature, " + super.getRule(); } } - diff --git a/Mage.Sets/src/mage/sets/mirrodinbesieged/KnowledgePool.java b/Mage.Sets/src/mage/sets/mirrodinbesieged/KnowledgePool.java index 40475118a59..ec5fbc6e9ff 100644 --- a/Mage.Sets/src/mage/sets/mirrodinbesieged/KnowledgePool.java +++ b/Mage.Sets/src/mage/sets/mirrodinbesieged/KnowledgePool.java @@ -1,16 +1,16 @@ /* * Copyright 2011 BetaSteward_at_googlemail.com. All rights reserved. - * + * * Redistribution and use in source and binary forms, with or without modification, are * permitted provided that the following conditions are met: - * + * * 1. Redistributions of source code must retain the above copyright notice, this list of * conditions and the following disclaimer. - * + * * 2. Redistributions in binary form must reproduce the above copyright notice, this list * of conditions and the following disclaimer in the documentation and/or other materials * provided with the distribution. - * + * * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR @@ -20,7 +20,7 @@ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * + * * The views and conclusions contained in the software and documentation are those of the * authors and should not be interpreted as representing official policies, either expressed * or implied, of BetaSteward_at_googlemail.com. @@ -28,6 +28,7 @@ package mage.sets.mirrodinbesieged; import java.util.UUID; +import mage.MageObject; import mage.abilities.Ability; import mage.abilities.TriggeredAbilityImpl; import mage.abilities.common.EntersBattlefieldTriggeredAbility; @@ -47,6 +48,7 @@ import mage.game.stack.Spell; import mage.players.Player; import mage.target.common.TargetCardInExile; import mage.target.targetpointer.FixedTarget; +import mage.util.CardUtil; /** * @@ -87,14 +89,16 @@ class KnowledgePoolEffect1 extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { - Player sourcePlayer = game.getPlayer(source.getControllerId()); - for (UUID playerId: sourcePlayer.getInRange()) { + Player controller = game.getPlayer(source.getControllerId()); + MageObject sourceObject = game.getObject(source.getSourceId()); + if (controller == null || sourceObject == null) { + return false; + } + for (UUID playerId : controller.getInRange()) { Player player = game.getPlayer(playerId); if (player != null) { - int amount = Math.min(3, player.getLibrary().size()); - for (int i = 0; i < amount; i++) { - player.getLibrary().removeFromTop(game).moveToExile(source.getSourceId(), "Knowledge Pool Exile", source.getSourceId(), game); - } + player.moveCardsToExile(player.getLibrary().getTopCards(game, 3), source, game, true, + CardUtil.getObjectExileZoneId(game, sourceObject), sourceObject.getIdName() + " (" + sourceObject.getZoneChangeCounter(game) + ")"); } } return true; @@ -129,7 +133,7 @@ class KnowledgePoolAbility extends TriggeredAbilityImpl { @Override public boolean checkTrigger(GameEvent event, Game game) { - if (event.getZone() == Zone.HAND) { + if (event.getZone() == Zone.HAND) { Spell spell = game.getStack().getSpell(event.getTargetId()); if (spell != null) { for (Effect effect : this.getEffects()) { @@ -159,12 +163,15 @@ class KnowledgePoolEffect2 extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { Spell spell = game.getStack().getSpell(targetPointer.getFirst(game, source)); - if (spell != null) { - if (spell.moveToExile(source.getSourceId(), "Knowledge Pool Exile", source.getSourceId(), game)) { + MageObject sourceObject = game.getObject(source.getSourceId()); + Player controller = game.getPlayer(source.getControllerId()); + if (controller != null && spell != null && sourceObject != null) { + UUID exileZoneId = CardUtil.getObjectExileZoneId(game, sourceObject); + if (controller.moveCardsToExile(spell, source, game, true, exileZoneId, sourceObject.getIdName())) { Player player = game.getPlayer(spell.getControllerId()); - if (player != null && player.chooseUse(Outcome.PlayForFree, "Cast another nonland card exiled with Knowledge Pool without paying that card's mana cost?", source, game)) { + if (player != null && player.chooseUse(Outcome.PlayForFree, "Cast another nonland card exiled with " + sourceObject.getLogName() + " without paying that card's mana cost?", source, game)) { TargetCardInExile target = new TargetCardInExile(filter, source.getSourceId()); - while (player.choose(Outcome.PlayForFree, game.getExile().getExileZone(source.getSourceId()), target, game)) { + while (player.choose(Outcome.PlayForFree, game.getExile().getExileZone(exileZoneId), target, game)) { Card card = game.getCard(target.getFirstTarget()); if (card != null && !card.getId().equals(spell.getSourceId())) { game.getExile().removeCard(card, game); @@ -184,4 +191,4 @@ class KnowledgePoolEffect2 extends OneShotEffect { return new KnowledgePoolEffect2(this); } -} \ No newline at end of file +} diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/abilities/keywords/ManifestTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/abilities/keywords/ManifestTest.java index 7c63a8447f1..e3cfc186491 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/abilities/keywords/ManifestTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/abilities/keywords/ManifestTest.java @@ -400,4 +400,56 @@ public class ManifestTest extends CardTestPlayerBase { assertPermanentCount(playerB, "", 2); } + + /** + * I sacrificed a manifested face-down Smothering Abomination to Nantuko + * Husk and it made me draw a card. + * + */ + @Test + public void testDiesTriggeredAbilitiesOfManifestedCreatures() { + + addCard(Zone.BATTLEFIELD, playerB, "Swamp", 2); + + // Sacrifice a creature: Nantuko Husk gets +2/+2 until end of turn. + addCard(Zone.BATTLEFIELD, playerB, "Nantuko Husk", 1); + + // {1}{B}, {T}, Sacrifice another creature: Manifest the top card of your library. + addCard(Zone.BATTLEFIELD, playerB, "Qarsi High Priest", 1); + addCard(Zone.BATTLEFIELD, playerB, "Silvercoat Lion", 1); + + // Devoid + // Flying + // At the beginning of your upkeep, sacrifice a creature + // Whenever you sacrifice a creature, draw a card. + addCard(Zone.LIBRARY, playerB, "Mountain", 1); + addCard(Zone.LIBRARY, playerB, "Smothering Abomination", 1); + addCard(Zone.LIBRARY, playerB, "Mountain", 1); + + skipInitShuffling(); + + activateAbility(2, PhaseStep.PRECOMBAT_MAIN, playerB, "{1}{B},{T}, Sacrifice another creature"); + setChoice(playerB, "Silvercoat Lion"); + + activateAbility(2, PhaseStep.POSTCOMBAT_MAIN, playerB, "Sacrifice a creature"); + setChoice(playerB, ""); + + setStopAt(2, PhaseStep.END_TURN); + execute(); + + // no life gain + assertLife(playerA, 20); + assertLife(playerB, 20); + + assertPermanentCount(playerB, "Qarsi High Priest", 1); + assertPermanentCount(playerB, "Nantuko Husk", 1); + + assertGraveyardCount(playerB, "Silvercoat Lion", 1); + assertGraveyardCount(playerB, "Smothering Abomination", 1); + + assertPowerToughness(playerB, "Nantuko Husk", 4, 4); + + assertHandCount(playerB, "Mountain", 1); + + } } diff --git a/Mage/src/mage/abilities/TriggeredAbilities.java b/Mage/src/mage/abilities/TriggeredAbilities.java index 599e44068c0..2a9d07b1c99 100644 --- a/Mage/src/mage/abilities/TriggeredAbilities.java +++ b/Mage/src/mage/abilities/TriggeredAbilities.java @@ -95,7 +95,7 @@ public class TriggeredAbilities extends ConcurrentHashMap Date: Wed, 7 Oct 2015 19:34:16 +0300 Subject: [PATCH 041/268] Implement cards: Hulking Ogre, Marker Beetles, Metathran Soldier, and Rescue --- .../mage/sets/starter1999/HulkingOgre.java | 62 +++++++++++++++ .../mage/sets/urzasdestiny/HulkingOgre.java | 54 +++++++++++++ .../mage/sets/urzasdestiny/MarkerBeetles.java | 77 +++++++++++++++++++ .../sets/urzasdestiny/MetathranSoldier.java | 63 +++++++++++++++ .../src/mage/sets/urzasdestiny/Rescue.java | 60 +++++++++++++++ 5 files changed, 316 insertions(+) create mode 100644 Mage.Sets/src/mage/sets/starter1999/HulkingOgre.java create mode 100644 Mage.Sets/src/mage/sets/urzasdestiny/HulkingOgre.java create mode 100644 Mage.Sets/src/mage/sets/urzasdestiny/MarkerBeetles.java create mode 100644 Mage.Sets/src/mage/sets/urzasdestiny/MetathranSoldier.java create mode 100644 Mage.Sets/src/mage/sets/urzasdestiny/Rescue.java diff --git a/Mage.Sets/src/mage/sets/starter1999/HulkingOgre.java b/Mage.Sets/src/mage/sets/starter1999/HulkingOgre.java new file mode 100644 index 00000000000..f80a7b480c1 --- /dev/null +++ b/Mage.Sets/src/mage/sets/starter1999/HulkingOgre.java @@ -0,0 +1,62 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.sets.starter1999; + +import java.util.UUID; +import mage.MageInt; +import mage.abilities.common.CantBlockAbility; +import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.Rarity; + +/** + * + * @author LoneFox + */ +public class HulkingOgre extends CardImpl { + + public HulkingOgre(UUID ownerId) { + super(ownerId, 108, "Hulking Ogre", Rarity.UNCOMMON, new CardType[]{CardType.CREATURE}, "{2}{R}"); + this.expansionSetCode = "S99"; + this.subtype.add("Ogre"); + this.power = new MageInt(3); + this.toughness = new MageInt(3); + + // Hulking Ogre can't block. + this.addAbility(new CantBlockAbility()); + } + + public HulkingOgre(final HulkingOgre card) { + super(card); + } + + @Override + public HulkingOgre copy() { + return new HulkingOgre(this); + } +} diff --git a/Mage.Sets/src/mage/sets/urzasdestiny/HulkingOgre.java b/Mage.Sets/src/mage/sets/urzasdestiny/HulkingOgre.java new file mode 100644 index 00000000000..ca75ebcb2c5 --- /dev/null +++ b/Mage.Sets/src/mage/sets/urzasdestiny/HulkingOgre.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.urzasdestiny; + +import java.util.UUID; +import mage.constants.Rarity; + +/** + * + * @author LoneFox + */ +public class HulkingOgre extends mage.sets.starter1999.HulkingOgre { + + public HulkingOgre(UUID ownerId) { + super(ownerId); + this.cardNumber = 87; + this.expansionSetCode = "UDS"; + this.rarity = Rarity.COMMON; + } + + public HulkingOgre(final HulkingOgre card) { + super(card); + } + + @Override + public HulkingOgre copy() { + return new HulkingOgre(this); + } +} diff --git a/Mage.Sets/src/mage/sets/urzasdestiny/MarkerBeetles.java b/Mage.Sets/src/mage/sets/urzasdestiny/MarkerBeetles.java new file mode 100644 index 00000000000..bae7f803909 --- /dev/null +++ b/Mage.Sets/src/mage/sets/urzasdestiny/MarkerBeetles.java @@ -0,0 +1,77 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.sets.urzasdestiny; + +import java.util.UUID; +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.DiesTriggeredAbility; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.costs.common.SacrificeSourceCost; +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.effects.common.DrawCardSourceControllerEffect; +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.constants.Zone; +import mage.target.common.TargetCreaturePermanent; + +/** + * + * @author LoneFox + */ +public class MarkerBeetles extends CardImpl { + + public MarkerBeetles(UUID ownerId) { + super(ownerId, 112, "Marker Beetles", Rarity.COMMON, new CardType[]{CardType.CREATURE}, "{1}{G}{G}"); + this.expansionSetCode = "UDS"; + this.subtype.add("Insect"); + this.power = new MageInt(2); + this.toughness = new MageInt(3); + + // When Marker Beetles dies, target creature gets +1/+1 until end of turn. + Ability ability = new DiesTriggeredAbility(new BoostTargetEffect(1, 1, Duration.EndOfTurn), false); + ability.addTarget(new TargetCreaturePermanent()); + this.addAbility(ability); + // {2}, Sacrifice Marker Beetles: Draw a card. + ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new DrawCardSourceControllerEffect(1), new ManaCostsImpl("{2}")); + ability.addCost(new SacrificeSourceCost()); + this.addAbility(ability); + } + + public MarkerBeetles(final MarkerBeetles card) { + super(card); + } + + @Override + public MarkerBeetles copy() { + return new MarkerBeetles(this); + } +} diff --git a/Mage.Sets/src/mage/sets/urzasdestiny/MetathranSoldier.java b/Mage.Sets/src/mage/sets/urzasdestiny/MetathranSoldier.java new file mode 100644 index 00000000000..db7a06eac8b --- /dev/null +++ b/Mage.Sets/src/mage/sets/urzasdestiny/MetathranSoldier.java @@ -0,0 +1,63 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.sets.urzasdestiny; + +import java.util.UUID; +import mage.MageInt; +import mage.abilities.keyword.CantBeBlockedSourceAbility; +import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.Rarity; + +/** + * + * @author LoneFox + */ +public class MetathranSoldier extends CardImpl { + + public MetathranSoldier(UUID ownerId) { + super(ownerId, 39, "Metathran Soldier", Rarity.COMMON, new CardType[]{CardType.CREATURE}, "{1}{U}"); + this.expansionSetCode = "UDS"; + this.subtype.add("Metathran"); + this.subtype.add("Soldier"); + this.power = new MageInt(1); + this.toughness = new MageInt(1); + + // Metathran Soldier is unblockable. + this.addAbility(new CantBeBlockedSourceAbility()); + } + + public MetathranSoldier(final MetathranSoldier card) { + super(card); + } + + @Override + public MetathranSoldier copy() { + return new MetathranSoldier(this); + } +} diff --git a/Mage.Sets/src/mage/sets/urzasdestiny/Rescue.java b/Mage.Sets/src/mage/sets/urzasdestiny/Rescue.java new file mode 100644 index 00000000000..dfa985e378d --- /dev/null +++ b/Mage.Sets/src/mage/sets/urzasdestiny/Rescue.java @@ -0,0 +1,60 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.sets.urzasdestiny; + +import java.util.UUID; +import mage.abilities.effects.common.ReturnToHandTargetEffect; +import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.Rarity; +import mage.target.common.TargetControlledPermanent; + +/** + * + * @author LoneFox + */ +public class Rescue extends CardImpl { + + public Rescue(UUID ownerId) { + super(ownerId, 44, "Rescue", Rarity.COMMON, new CardType[]{CardType.INSTANT}, "{U}"); + this.expansionSetCode = "UDS"; + + // Return target permanent you control to its owner's hand. + this.getSpellAbility().addEffect(new ReturnToHandTargetEffect()); + this.getSpellAbility().addTarget(new TargetControlledPermanent()); + } + + public Rescue(final Rescue card) { + super(card); + } + + @Override + public Rescue copy() { + return new Rescue(this); + } +} From 6ec79040edc23e1b28953c75f408421c698e0f51 Mon Sep 17 00:00:00 2001 From: LevelX2 Date: Wed, 7 Oct 2015 19:42:16 +0200 Subject: [PATCH 042/268] * Strionic Resonator - Fixed that also not controlled abilities could be targeted, fixed a bug of the tooltip text. --- .../sets/magic2014/StrionicResonator.java | 22 +++++++++++-------- 1 file changed, 13 insertions(+), 9 deletions(-) diff --git a/Mage.Sets/src/mage/sets/magic2014/StrionicResonator.java b/Mage.Sets/src/mage/sets/magic2014/StrionicResonator.java index 154ad1a4758..63a97aa79b4 100644 --- a/Mage.Sets/src/mage/sets/magic2014/StrionicResonator.java +++ b/Mage.Sets/src/mage/sets/magic2014/StrionicResonator.java @@ -123,7 +123,7 @@ class StrionicResonatorEffect extends OneShotEffect { @Override public String getText(Mode mode) { StringBuilder sb = new StringBuilder(); - sb.append("Copy target ").append(mode.getTargets().get(0).getTargetName()).append(". You may choose new targets for the copy"); + sb.append("Copy ").append(mode.getTargets().get(0).getTargetName()).append(". You may choose new targets for the copy"); return sb.toString(); } } @@ -134,7 +134,7 @@ class TargetTriggeredAbility extends TargetObject { this.minNumberOfTargets = 1; this.maxNumberOfTargets = 1; this.zone = Zone.STACK; - this.targetName = "target triggered ability"; + this.targetName = "target triggered ability you control"; } public TargetTriggeredAbility(final TargetTriggeredAbility target) { @@ -148,10 +148,10 @@ class TargetTriggeredAbility extends TargetObject { } StackObject stackObject = game.getStack().getStackObject(id); - if (stackObject.getStackAbility() != null && stackObject.getStackAbility() instanceof TriggeredAbility) { - return true; - } - return false; + return stackObject.getStackAbility() != null + && (stackObject.getStackAbility() instanceof TriggeredAbility) + && source != null + && stackObject.getStackAbility().getControllerId().equals(source.getControllerId()); } @Override @@ -162,7 +162,9 @@ class TargetTriggeredAbility extends TargetObject { @Override public boolean canChoose(UUID sourceControllerId, Game game) { for (StackObject stackObject : game.getStack()) { - if (stackObject.getStackAbility() != null && stackObject.getStackAbility() instanceof TriggeredAbility && game.getPlayer(sourceControllerId).getInRange().contains(stackObject.getStackAbility().getControllerId())) { + if (stackObject.getStackAbility() != null + && stackObject.getStackAbility() instanceof TriggeredAbility + && stackObject.getStackAbility().getControllerId().equals(sourceControllerId)) { return true; } } @@ -176,9 +178,11 @@ class TargetTriggeredAbility extends TargetObject { @Override public Set possibleTargets(UUID sourceControllerId, Game game) { - Set possibleTargets = new HashSet(); + Set possibleTargets = new HashSet<>(); for (StackObject stackObject : game.getStack()) { - if (stackObject.getStackAbility() != null && stackObject.getStackAbility() instanceof TriggeredAbility && game.getPlayer(sourceControllerId).getInRange().contains(stackObject.getStackAbility().getControllerId())) { + if (stackObject.getStackAbility() != null + && stackObject.getStackAbility() instanceof TriggeredAbility + && stackObject.getStackAbility().getControllerId().equals(sourceControllerId)) { possibleTargets.add(stackObject.getStackAbility().getId()); } } From f90f79693ef7f5e923db4ec917e626984a4c634d Mon Sep 17 00:00:00 2001 From: LevelX2 Date: Wed, 7 Oct 2015 19:57:42 +0200 Subject: [PATCH 043/268] * Knowledge Pool - Fixed exile zone handling. --- Mage.Sets/src/mage/sets/mirrodinbesieged/KnowledgePool.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Mage.Sets/src/mage/sets/mirrodinbesieged/KnowledgePool.java b/Mage.Sets/src/mage/sets/mirrodinbesieged/KnowledgePool.java index ec5fbc6e9ff..98c1aa29bea 100644 --- a/Mage.Sets/src/mage/sets/mirrodinbesieged/KnowledgePool.java +++ b/Mage.Sets/src/mage/sets/mirrodinbesieged/KnowledgePool.java @@ -59,8 +59,10 @@ public class KnowledgePool extends CardImpl { public KnowledgePool(UUID ownerId) { super(ownerId, 111, "Knowledge Pool", Rarity.RARE, new CardType[]{CardType.ARTIFACT}, "{6}"); this.expansionSetCode = "MBS"; + // Imprint - When Knowledge Pool enters the battlefield, each player exiles the top three cards of his or her library this.addAbility(new EntersBattlefieldTriggeredAbility(new KnowledgePoolEffect1(), false)); + // Whenever a player casts a spell from his or her hand, that player exiles it. If the player does, he or she may cast another nonland card exiled with Knowledge Pool without paying that card's mana cost. this.addAbility(new KnowledgePoolAbility()); } From d78f6af412909f77a3b861b73281193ee28913c2 Mon Sep 17 00:00:00 2001 From: LoneFox Date: Thu, 8 Oct 2015 10:27:25 +0300 Subject: [PATCH 044/268] Implement cards: Disease Carriers, Flame Jet, Kingfisher, and Phyrexian Monitor --- .../sets/urzasdestiny/DiseaseCarriers.java | 68 +++++++++++++++++++ .../src/mage/sets/urzasdestiny/FlameJet.java | 64 +++++++++++++++++ .../mage/sets/urzasdestiny/Kingfisher.java | 66 ++++++++++++++++++ .../sets/urzasdestiny/PhyrexianMonitor.java | 65 ++++++++++++++++++ 4 files changed, 263 insertions(+) create mode 100644 Mage.Sets/src/mage/sets/urzasdestiny/DiseaseCarriers.java create mode 100644 Mage.Sets/src/mage/sets/urzasdestiny/FlameJet.java create mode 100644 Mage.Sets/src/mage/sets/urzasdestiny/Kingfisher.java create mode 100644 Mage.Sets/src/mage/sets/urzasdestiny/PhyrexianMonitor.java diff --git a/Mage.Sets/src/mage/sets/urzasdestiny/DiseaseCarriers.java b/Mage.Sets/src/mage/sets/urzasdestiny/DiseaseCarriers.java new file mode 100644 index 00000000000..e72bac6b43f --- /dev/null +++ b/Mage.Sets/src/mage/sets/urzasdestiny/DiseaseCarriers.java @@ -0,0 +1,68 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.sets.urzasdestiny; + +import java.util.UUID; +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.DiesTriggeredAbility; +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 DiseaseCarriers extends CardImpl { + + public DiseaseCarriers(UUID ownerId) { + super(ownerId, 57, "Disease Carriers", Rarity.COMMON, new CardType[]{CardType.CREATURE}, "{2}{B}{B}"); + this.expansionSetCode = "UDS"; + this.subtype.add("Rat"); + this.power = new MageInt(2); + this.toughness = new MageInt(2); + + // When Disease Carriers dies, target creature gets -2/-2 until end of turn. + Ability ability = new DiesTriggeredAbility(new BoostTargetEffect(-2, -2, Duration.EndOfTurn), false); + ability.addTarget(new TargetCreaturePermanent()); + this.addAbility(ability); + } + + public DiseaseCarriers(final DiseaseCarriers card) { + super(card); + } + + @Override + public DiseaseCarriers copy() { + return new DiseaseCarriers(this); + } +} diff --git a/Mage.Sets/src/mage/sets/urzasdestiny/FlameJet.java b/Mage.Sets/src/mage/sets/urzasdestiny/FlameJet.java new file mode 100644 index 00000000000..617fb0ad9d7 --- /dev/null +++ b/Mage.Sets/src/mage/sets/urzasdestiny/FlameJet.java @@ -0,0 +1,64 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.sets.urzasdestiny; + +import java.util.UUID; +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.effects.common.DamageTargetEffect; +import mage.abilities.keyword.CyclingAbility; +import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.Rarity; +import mage.target.TargetPlayer; + +/** + * + * @author LoneFox + */ +public class FlameJet extends CardImpl { + + public FlameJet(UUID ownerId) { + super(ownerId, 81, "Flame Jet", Rarity.COMMON, new CardType[]{CardType.SORCERY}, "{1}{R}"); + this.expansionSetCode = "UDS"; + + // Flame Jet deals 3 damage to target player. + this.getSpellAbility().addEffect(new DamageTargetEffect(3)); + this.getSpellAbility().addTarget(new TargetPlayer()); + // Cycling {2} + this.addAbility(new CyclingAbility(new ManaCostsImpl("{2}"))); + } + + public FlameJet(final FlameJet card) { + super(card); + } + + @Override + public FlameJet copy() { + return new FlameJet(this); + } +} diff --git a/Mage.Sets/src/mage/sets/urzasdestiny/Kingfisher.java b/Mage.Sets/src/mage/sets/urzasdestiny/Kingfisher.java new file mode 100644 index 00000000000..8b8ca589828 --- /dev/null +++ b/Mage.Sets/src/mage/sets/urzasdestiny/Kingfisher.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.urzasdestiny; + +import java.util.UUID; +import mage.MageInt; +import mage.abilities.common.DiesTriggeredAbility; +import mage.abilities.effects.common.DrawCardSourceControllerEffect; +import mage.abilities.keyword.FlyingAbility; +import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.Rarity; + +/** + * + * @author LoneFox + */ +public class Kingfisher extends CardImpl { + + public Kingfisher(UUID ownerId) { + super(ownerId, 36, "Kingfisher", Rarity.COMMON, new CardType[]{CardType.CREATURE}, "{3}{U}"); + this.expansionSetCode = "UDS"; + this.subtype.add("Bird"); + this.power = new MageInt(2); + this.toughness = new MageInt(2); + + // Flying + this.addAbility(FlyingAbility.getInstance()); + // When Kingfisher dies, draw a card. + this.addAbility(new DiesTriggeredAbility(new DrawCardSourceControllerEffect(1), false)); + } + + public Kingfisher(final Kingfisher card) { + super(card); + } + + @Override + public Kingfisher copy() { + return new Kingfisher(this); + } +} diff --git a/Mage.Sets/src/mage/sets/urzasdestiny/PhyrexianMonitor.java b/Mage.Sets/src/mage/sets/urzasdestiny/PhyrexianMonitor.java new file mode 100644 index 00000000000..c025a391e60 --- /dev/null +++ b/Mage.Sets/src/mage/sets/urzasdestiny/PhyrexianMonitor.java @@ -0,0 +1,65 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.sets.urzasdestiny; + +import java.util.UUID; +import mage.MageInt; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.effects.common.RegenerateSourceEffect; +import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.Rarity; +import mage.constants.Zone; + +/** + * + * @author LoneFox + */ +public class PhyrexianMonitor extends CardImpl { + + public PhyrexianMonitor(UUID ownerId) { + super(ownerId, 64, "Phyrexian Monitor", Rarity.COMMON, new CardType[]{CardType.CREATURE}, "{3}{B}"); + this.expansionSetCode = "UDS"; + this.subtype.add("Skeleton"); + this.power = new MageInt(2); + this.toughness = new MageInt(2); + + // {B}: Regenerate Phyrexian Monitor. + this.addAbility(new SimpleActivatedAbility(Zone.BATTLEFIELD, new RegenerateSourceEffect(), new ManaCostsImpl("{B}"))); + } + + public PhyrexianMonitor(final PhyrexianMonitor card) { + super(card); + } + + @Override + public PhyrexianMonitor copy() { + return new PhyrexianMonitor(this); + } +} From fdf8ad7a1d637b8355a3099c6597be8691e5e25e Mon Sep 17 00:00:00 2001 From: LoneFox Date: Thu, 8 Oct 2015 11:05:54 +0300 Subject: [PATCH 045/268] Implement cards: Capashen Standard, Mental Discipline, Reliquary Monk, and Slinking Skirge --- .../sets/urzasdestiny/CapashenStandard.java | 82 +++++++++++++++++++ .../sets/urzasdestiny/MentalDiscipline.java | 65 +++++++++++++++ .../mage/sets/urzasdestiny/ReliquaryMonk.java | 70 ++++++++++++++++ .../sets/urzasdestiny/SlinkingSkirge.java | 72 ++++++++++++++++ 4 files changed, 289 insertions(+) create mode 100644 Mage.Sets/src/mage/sets/urzasdestiny/CapashenStandard.java create mode 100644 Mage.Sets/src/mage/sets/urzasdestiny/MentalDiscipline.java create mode 100644 Mage.Sets/src/mage/sets/urzasdestiny/ReliquaryMonk.java create mode 100644 Mage.Sets/src/mage/sets/urzasdestiny/SlinkingSkirge.java diff --git a/Mage.Sets/src/mage/sets/urzasdestiny/CapashenStandard.java b/Mage.Sets/src/mage/sets/urzasdestiny/CapashenStandard.java new file mode 100644 index 00000000000..5e23a8041ca --- /dev/null +++ b/Mage.Sets/src/mage/sets/urzasdestiny/CapashenStandard.java @@ -0,0 +1,82 @@ +/* + * 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.urzasdestiny; + +import java.util.UUID; +import mage.abilities.Ability; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.costs.common.SacrificeSourceCost; +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.effects.common.AttachEffect; +import mage.abilities.effects.common.DrawCardSourceControllerEffect; +import mage.abilities.effects.common.continuous.BoostEnchantedEffect; +import mage.abilities.keyword.EnchantAbility; +import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.Outcome; +import mage.constants.Rarity; +import mage.constants.Zone; +import mage.target.TargetPermanent; +import mage.target.common.TargetCreaturePermanent; + +/** + * + * @author LoneFox + */ +public class CapashenStandard extends CardImpl { + + public CapashenStandard(UUID ownerId) { + super(ownerId, 4, "Capashen Standard", Rarity.COMMON, new CardType[]{CardType.ENCHANTMENT}, "{W}"); + this.expansionSetCode = "UDS"; + this.subtype.add("Aura"); + + // Enchant creature + TargetPermanent auraTarget = new TargetCreaturePermanent(); + this.getSpellAbility().addTarget(auraTarget); + this.getSpellAbility().addEffect(new AttachEffect(Outcome.BoostCreature)); + Ability ability = new EnchantAbility(auraTarget.getTargetName()); + this.addAbility(ability); + // Enchanted creature gets +1/+1. + this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new BoostEnchantedEffect(1, 1, Duration.WhileOnBattlefield))); + // {2}, Sacrifice Capashen Standard: Draw a card. + ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new DrawCardSourceControllerEffect(1), new ManaCostsImpl("{2}")); + ability.addCost(new SacrificeSourceCost()); + this.addAbility(ability); + } + + public CapashenStandard(final CapashenStandard card) { + super(card); + } + + @Override + public CapashenStandard copy() { + return new CapashenStandard(this); + } +} diff --git a/Mage.Sets/src/mage/sets/urzasdestiny/MentalDiscipline.java b/Mage.Sets/src/mage/sets/urzasdestiny/MentalDiscipline.java new file mode 100644 index 00000000000..d6cd85c3cb3 --- /dev/null +++ b/Mage.Sets/src/mage/sets/urzasdestiny/MentalDiscipline.java @@ -0,0 +1,65 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.sets.urzasdestiny; + +import java.util.UUID; +import mage.abilities.Ability; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.costs.common.DiscardCardCost; +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.effects.common.DrawCardSourceControllerEffect; +import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.Rarity; +import mage.constants.Zone; + +/** + * + * @author LoneFox + */ +public class MentalDiscipline extends CardImpl { + + public MentalDiscipline(UUID ownerId) { + super(ownerId, 37, "Mental Discipline", Rarity.COMMON, new CardType[]{CardType.ENCHANTMENT}, "{1}{U}{U}"); + this.expansionSetCode = "UDS"; + + // {1}{U}, Discard a card: Draw a card. + Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new DrawCardSourceControllerEffect(1), new ManaCostsImpl("{1}{U}")); + ability.addCost(new DiscardCardCost()); + this.addAbility(ability); + } + + public MentalDiscipline(final MentalDiscipline card) { + super(card); + } + + @Override + public MentalDiscipline copy() { + return new MentalDiscipline(this); + } +} diff --git a/Mage.Sets/src/mage/sets/urzasdestiny/ReliquaryMonk.java b/Mage.Sets/src/mage/sets/urzasdestiny/ReliquaryMonk.java new file mode 100644 index 00000000000..dd5ebf7730d --- /dev/null +++ b/Mage.Sets/src/mage/sets/urzasdestiny/ReliquaryMonk.java @@ -0,0 +1,70 @@ +/* + * 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.urzasdestiny; + +import java.util.UUID; +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.DiesTriggeredAbility; +import mage.abilities.effects.common.DestroyTargetEffect; +import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.Rarity; +import mage.filter.common.FilterArtifactOrEnchantmentPermanent; +import mage.target.TargetPermanent; + +/** + * + * @author LoneFox + */ +public class ReliquaryMonk extends CardImpl { + + public ReliquaryMonk(UUID ownerId) { + super(ownerId, 14, "Reliquary Monk", Rarity.COMMON, new CardType[]{CardType.CREATURE}, "{2}{W}"); + this.expansionSetCode = "UDS"; + this.subtype.add("Human"); + this.subtype.add("Monk"); + this.subtype.add("Cleric"); + this.power = new MageInt(2); + this.toughness = new MageInt(2); + + // When Reliquary Monk dies, destroy target artifact or enchantment. + Ability ability = new DiesTriggeredAbility(new DestroyTargetEffect(), false); + ability.addTarget(new TargetPermanent(new FilterArtifactOrEnchantmentPermanent())); + this.addAbility(ability); + } + + public ReliquaryMonk(final ReliquaryMonk card) { + super(card); + } + + @Override + public ReliquaryMonk copy() { + return new ReliquaryMonk(this); + } +} diff --git a/Mage.Sets/src/mage/sets/urzasdestiny/SlinkingSkirge.java b/Mage.Sets/src/mage/sets/urzasdestiny/SlinkingSkirge.java new file mode 100644 index 00000000000..2c47c409286 --- /dev/null +++ b/Mage.Sets/src/mage/sets/urzasdestiny/SlinkingSkirge.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.urzasdestiny; + +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.costs.mana.ManaCostsImpl; +import mage.abilities.effects.common.DrawCardSourceControllerEffect; +import mage.abilities.keyword.FlyingAbility; +import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.Rarity; +import mage.constants.Zone; + +/** + * + * @author LoneFox + */ +public class SlinkingSkirge extends CardImpl { + + public SlinkingSkirge(UUID ownerId) { + super(ownerId, 71, "Slinking Skirge", Rarity.COMMON, new CardType[]{CardType.CREATURE}, "{3}{B}"); + this.expansionSetCode = "UDS"; + this.subtype.add("Imp"); + this.power = new MageInt(2); + this.toughness = new MageInt(1); + + // Flying + this.addAbility(FlyingAbility.getInstance()); + // {2}, Sacrifice Slinking Skirge: Draw a card. + Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new DrawCardSourceControllerEffect(1), new ManaCostsImpl("{2}")); + ability.addCost(new SacrificeSourceCost()); + this.addAbility(ability); + } + + public SlinkingSkirge(final SlinkingSkirge card) { + super(card); + } + + @Override + public SlinkingSkirge copy() { + return new SlinkingSkirge(this); + } +} From d5856d10ccd13b5d9881c020ea3648487ebeff1d Mon Sep 17 00:00:00 2001 From: LoneFox Date: Thu, 8 Oct 2015 11:44:56 +0300 Subject: [PATCH 046/268] Implement cards: Encroach, Field Surgeon, Illuminated Wings, and Magnify --- .../src/mage/sets/urzasdestiny/Encroach.java | 71 ++++++++++++++++ .../mage/sets/urzasdestiny/FieldSurgeon.java | 82 ++++++++++++++++++ .../sets/urzasdestiny/IlluminatedWings.java | 84 +++++++++++++++++++ .../src/mage/sets/urzasdestiny/Magnify.java | 59 +++++++++++++ 4 files changed, 296 insertions(+) create mode 100644 Mage.Sets/src/mage/sets/urzasdestiny/Encroach.java create mode 100644 Mage.Sets/src/mage/sets/urzasdestiny/FieldSurgeon.java create mode 100644 Mage.Sets/src/mage/sets/urzasdestiny/IlluminatedWings.java create mode 100644 Mage.Sets/src/mage/sets/urzasdestiny/Magnify.java diff --git a/Mage.Sets/src/mage/sets/urzasdestiny/Encroach.java b/Mage.Sets/src/mage/sets/urzasdestiny/Encroach.java new file mode 100644 index 00000000000..08ea3ed41b1 --- /dev/null +++ b/Mage.Sets/src/mage/sets/urzasdestiny/Encroach.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.urzasdestiny; + +import java.util.UUID; +import mage.abilities.effects.common.discard.DiscardCardYouChooseTargetEffect; +import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.Rarity; +import mage.filter.FilterCard; +import mage.filter.predicate.Predicates; +import mage.filter.predicate.mageobject.CardTypePredicate; +import mage.filter.predicate.mageobject.SupertypePredicate; +import mage.target.common.TargetOpponent; + +/** + * + * @author LoneFox + */ +public class Encroach extends CardImpl { + + private static final FilterCard filter = new FilterCard("a nonbasic land card"); + + static { + filter.add(Predicates.not(new SupertypePredicate("Basic"))); + filter.add(new CardTypePredicate(CardType.LAND)); + } + + public Encroach(UUID ownerId) { + super(ownerId, 59, "Encroach", Rarity.UNCOMMON, new CardType[]{CardType.SORCERY}, "{B}"); + this.expansionSetCode = "UDS"; + + // Target player reveals his or her hand. You choose a nonbasic land card from it. That player discards that card. + this.getSpellAbility().addEffect(new DiscardCardYouChooseTargetEffect(filter)); + this.getSpellAbility().addTarget(new TargetOpponent()); + } + + public Encroach(final Encroach card) { + super(card); + } + + @Override + public Encroach copy() { + return new Encroach(this); + } +} diff --git a/Mage.Sets/src/mage/sets/urzasdestiny/FieldSurgeon.java b/Mage.Sets/src/mage/sets/urzasdestiny/FieldSurgeon.java new file mode 100644 index 00000000000..bfc228d3424 --- /dev/null +++ b/Mage.Sets/src/mage/sets/urzasdestiny/FieldSurgeon.java @@ -0,0 +1,82 @@ +/* + * 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.urzasdestiny; + +import java.util.UUID; +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.costs.common.TapTargetCost; +import mage.abilities.effects.common.PreventDamageToTargetEffect; +import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.Rarity; +import mage.constants.Zone; +import mage.filter.common.FilterControlledCreaturePermanent; +import mage.filter.predicate.Predicates; +import mage.filter.predicate.permanent.TappedPredicate; +import mage.target.common.TargetControlledCreaturePermanent; +import mage.target.common.TargetCreaturePermanent; + +/** + * + * @author LoneFox + */ +public class FieldSurgeon extends CardImpl { + + private static final FilterControlledCreaturePermanent filter = new FilterControlledCreaturePermanent("an untapped creature you control"); + + static { + filter.add(Predicates.not(new TappedPredicate())); + } + + public FieldSurgeon(UUID ownerId) { + super(ownerId, 8, "Field Surgeon", Rarity.COMMON, new CardType[]{CardType.CREATURE}, "{1}{W}"); + this.expansionSetCode = "UDS"; + this.subtype.add("Human"); + this.subtype.add("Cleric"); + this.power = new MageInt(1); + this.toughness = new MageInt(1); + + // Tap an untapped creature you control: Prevent the next 1 damage that would be dealt to target creature this turn. + Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new PreventDamageToTargetEffect(Duration.EndOfTurn, 1), + new TapTargetCost(new TapTargetCost(new TargetControlledCreaturePermanent(filter)))); + ability.addTarget(new TargetCreaturePermanent()); + this.addAbility(ability); + } + + public FieldSurgeon(final FieldSurgeon card) { + super(card); + } + + @Override + public FieldSurgeon copy() { + return new FieldSurgeon(this); + } +} diff --git a/Mage.Sets/src/mage/sets/urzasdestiny/IlluminatedWings.java b/Mage.Sets/src/mage/sets/urzasdestiny/IlluminatedWings.java new file mode 100644 index 00000000000..248051c64e8 --- /dev/null +++ b/Mage.Sets/src/mage/sets/urzasdestiny/IlluminatedWings.java @@ -0,0 +1,84 @@ +/* + * 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.urzasdestiny; + +import java.util.UUID; +import mage.abilities.Ability; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.costs.common.SacrificeSourceCost; +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.effects.common.AttachEffect; +import mage.abilities.effects.common.DrawCardSourceControllerEffect; +import mage.abilities.effects.common.continuous.GainAbilityAttachedEffect; +import mage.abilities.keyword.EnchantAbility; +import mage.abilities.keyword.FlyingAbility; +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.Zone; +import mage.target.TargetPermanent; +import mage.target.common.TargetCreaturePermanent; + +/** + * + * @author LoneFox + */ +public class IlluminatedWings extends CardImpl { + + public IlluminatedWings(UUID ownerId) { + super(ownerId, 34, "Illuminated Wings", Rarity.COMMON, new CardType[]{CardType.ENCHANTMENT}, "{1}{U}"); + this.expansionSetCode = "UDS"; + this.subtype.add("Aura"); + + // Enchant creature + TargetPermanent auraTarget = new TargetCreaturePermanent(); + this.getSpellAbility().addTarget(auraTarget); + this.getSpellAbility().addEffect(new AttachEffect(Outcome.AddAbility)); + Ability ability = new EnchantAbility(auraTarget.getTargetName()); + this.addAbility(ability); + // Enchanted creature has flying. + this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new GainAbilityAttachedEffect(FlyingAbility.getInstance(), AttachmentType.AURA))); + // {2}, Sacrifice Illuminated Wings: Draw a card. + ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new DrawCardSourceControllerEffect(1), new ManaCostsImpl("{2}")); + ability.addCost(new SacrificeSourceCost()); + this.addAbility(ability); + } + + public IlluminatedWings(final IlluminatedWings card) { + super(card); + } + + @Override + public IlluminatedWings copy() { + return new IlluminatedWings(this); + } +} diff --git a/Mage.Sets/src/mage/sets/urzasdestiny/Magnify.java b/Mage.Sets/src/mage/sets/urzasdestiny/Magnify.java new file mode 100644 index 00000000000..2a1171cca54 --- /dev/null +++ b/Mage.Sets/src/mage/sets/urzasdestiny/Magnify.java @@ -0,0 +1,59 @@ +/* + * 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.urzasdestiny; + +import java.util.UUID; +import mage.abilities.effects.common.continuous.BoostAllEffect; +import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.Rarity; + +/** + * + * @author LoneFox + */ +public class Magnify extends CardImpl { + + public Magnify(UUID ownerId) { + super(ownerId, 111, "Magnify", Rarity.COMMON, new CardType[]{CardType.INSTANT}, "{G}"); + this.expansionSetCode = "UDS"; + + // All creatures get +1/+1 until end of turn. + this.getSpellAbility().addEffect(new BoostAllEffect(1, 1, Duration.EndOfTurn)); + } + + public Magnify(final Magnify card) { + super(card); + } + + @Override + public Magnify copy() { + return new Magnify(this); + } +} From 7b6bdd0a0b544efbd10562745014a34ca1ddc209 Mon Sep 17 00:00:00 2001 From: LoneFox Date: Thu, 8 Oct 2015 12:37:06 +0300 Subject: [PATCH 047/268] Implement cards: Dying Wail, Mark of Fury, Plague Dogs, and Urza's Incubator --- .../src/mage/sets/urzasdestiny/DyingWail.java | 75 +++++++++++++++++ .../mage/sets/urzasdestiny/MarkOfFury.java | 80 +++++++++++++++++++ .../mage/sets/urzasdestiny/PlagueDogs.java | 75 +++++++++++++++++ .../sets/urzasdestiny/UrzasIncubator.java | 69 ++++++++++++++++ 4 files changed, 299 insertions(+) create mode 100644 Mage.Sets/src/mage/sets/urzasdestiny/DyingWail.java create mode 100644 Mage.Sets/src/mage/sets/urzasdestiny/MarkOfFury.java create mode 100644 Mage.Sets/src/mage/sets/urzasdestiny/PlagueDogs.java create mode 100644 Mage.Sets/src/mage/sets/urzasdestiny/UrzasIncubator.java diff --git a/Mage.Sets/src/mage/sets/urzasdestiny/DyingWail.java b/Mage.Sets/src/mage/sets/urzasdestiny/DyingWail.java new file mode 100644 index 00000000000..b3a9815c520 --- /dev/null +++ b/Mage.Sets/src/mage/sets/urzasdestiny/DyingWail.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.urzasdestiny; + +import java.util.UUID; +import mage.abilities.Ability; +import mage.abilities.common.DiesAttachedTriggeredAbility; +import mage.abilities.effects.common.AttachEffect; +import mage.abilities.effects.common.discard.DiscardTargetEffect; +import mage.abilities.keyword.EnchantAbility; +import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.Outcome; +import mage.constants.Rarity; +import mage.target.TargetPermanent; +import mage.target.TargetPlayer; +import mage.target.common.TargetCreaturePermanent; + +/** + * + * @author LoneFox + */ +public class DyingWail extends CardImpl { + + public DyingWail(UUID ownerId) { + super(ownerId, 58, "Dying Wail", Rarity.COMMON, new CardType[]{CardType.ENCHANTMENT}, "{1}{B}"); + this.expansionSetCode = "UDS"; + this.subtype.add("Aura"); + + // Enchant creature + TargetPermanent auraTarget = new TargetCreaturePermanent(); + this.getSpellAbility().addTarget(auraTarget); + this.getSpellAbility().addEffect(new AttachEffect(Outcome.AddAbility)); + Ability ability = new EnchantAbility(auraTarget.getTargetName()); + this.addAbility(ability); + // When enchanted creature dies, target player discards two cards. + ability = new DiesAttachedTriggeredAbility(new DiscardTargetEffect(2), "enchanted creature"); + ability.addTarget(new TargetPlayer()); + this.addAbility(ability); + } + + public DyingWail(final DyingWail card) { + super(card); + } + + @Override + public DyingWail copy() { + return new DyingWail(this); + } +} diff --git a/Mage.Sets/src/mage/sets/urzasdestiny/MarkOfFury.java b/Mage.Sets/src/mage/sets/urzasdestiny/MarkOfFury.java new file mode 100644 index 00000000000..1323172005d --- /dev/null +++ b/Mage.Sets/src/mage/sets/urzasdestiny/MarkOfFury.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.urzasdestiny; + +import java.util.UUID; +import mage.abilities.Ability; +import mage.abilities.common.BeginningOfEndStepTriggeredAbility; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.effects.common.AttachEffect; +import mage.abilities.effects.common.ReturnToHandSourceEffect; +import mage.abilities.effects.common.continuous.GainAbilityAttachedEffect; +import mage.abilities.keyword.EnchantAbility; +import mage.abilities.keyword.HasteAbility; +import mage.cards.CardImpl; +import mage.constants.AttachmentType; +import mage.constants.CardType; +import mage.constants.Outcome; +import mage.constants.Rarity; +import mage.constants.TargetController; +import mage.constants.Zone; +import mage.target.TargetPermanent; +import mage.target.common.TargetCreaturePermanent; + +/** + * + * @author LoneFox + */ +public class MarkOfFury extends CardImpl { + + public MarkOfFury(UUID ownerId) { + super(ownerId, 93, "Mark of Fury", Rarity.COMMON, new CardType[]{CardType.ENCHANTMENT}, "{R}"); + this.expansionSetCode = "UDS"; + this.subtype.add("Aura"); + + // Enchant creature + TargetPermanent auraTarget = new TargetCreaturePermanent(); + this.getSpellAbility().addTarget(auraTarget); + this.getSpellAbility().addEffect(new AttachEffect(Outcome.AddAbility)); + Ability ability = new EnchantAbility(auraTarget.getTargetName()); + this.addAbility(ability); + // Enchanted creature has haste. + this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new GainAbilityAttachedEffect(HasteAbility.getInstance(), AttachmentType.AURA))); + // At the beginning of the end step, return Mark of Fury to its owner's hand. + this.addAbility(new BeginningOfEndStepTriggeredAbility(new ReturnToHandSourceEffect(true), TargetController.YOU, false)); + } + + public MarkOfFury(final MarkOfFury card) { + super(card); + } + + @Override + public MarkOfFury copy() { + return new MarkOfFury(this); + } +} diff --git a/Mage.Sets/src/mage/sets/urzasdestiny/PlagueDogs.java b/Mage.Sets/src/mage/sets/urzasdestiny/PlagueDogs.java new file mode 100644 index 00000000000..533484e968e --- /dev/null +++ b/Mage.Sets/src/mage/sets/urzasdestiny/PlagueDogs.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.urzasdestiny; + +import java.util.UUID; +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.DiesTriggeredAbility; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.costs.common.SacrificeSourceCost; +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.effects.common.DrawCardSourceControllerEffect; +import mage.abilities.effects.common.continuous.BoostAllEffect; +import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.Rarity; +import mage.constants.Zone; + +/** + * + * @author LoneFox + */ +public class PlagueDogs extends CardImpl { + + public PlagueDogs(UUID ownerId) { + super(ownerId, 66, "Plague Dogs", Rarity.UNCOMMON, new CardType[]{CardType.CREATURE}, "{4}{B}"); + this.expansionSetCode = "UDS"; + this.subtype.add("Zombie"); + this.subtype.add("Hound"); + this.power = new MageInt(3); + this.toughness = new MageInt(3); + + // When Plague Dogs dies, all creatures get -1/-1 until end of turn. + this.addAbility(new DiesTriggeredAbility(new BoostAllEffect(-1, -1, Duration.EndOfTurn), false)); + // {2}, Sacrifice Plague Dogs: Draw a card. + Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new DrawCardSourceControllerEffect(1), new ManaCostsImpl("{2}")); + ability.addCost(new SacrificeSourceCost()); + this.addAbility(ability); + } + + public PlagueDogs(final PlagueDogs card) { + super(card); + } + + @Override + public PlagueDogs copy() { + return new PlagueDogs(this); + } +} diff --git a/Mage.Sets/src/mage/sets/urzasdestiny/UrzasIncubator.java b/Mage.Sets/src/mage/sets/urzasdestiny/UrzasIncubator.java new file mode 100644 index 00000000000..e91445dce38 --- /dev/null +++ b/Mage.Sets/src/mage/sets/urzasdestiny/UrzasIncubator.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.urzasdestiny; + +import java.util.UUID; +import mage.abilities.common.AsEntersBattlefieldAbility; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.effects.common.ChooseCreatureTypeEffect; +import mage.abilities.effects.common.cost.SpellsCostReductionAllEffect; +import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.Outcome; +import mage.constants.Rarity; +import mage.constants.Zone; +import mage.filter.common.FilterCreatureCard; +import mage.filter.predicate.mageobject.ChosenSubtypePredicate; + +/** + * + * @author LoneFox + */ +public class UrzasIncubator extends CardImpl { + + public UrzasIncubator(UUID ownerId) { + super(ownerId, 142, "Urza's Incubator", Rarity.RARE, new CardType[]{CardType.ARTIFACT}, "{3}"); + this.expansionSetCode = "UDS"; + + // As Urza's Incubator enters the battlefield, choose a creature type. + this.addAbility(new AsEntersBattlefieldAbility(new ChooseCreatureTypeEffect(Outcome.BoostCreature))); + // Creature spells of the chosen type cost {2} less to cast. + FilterCreatureCard filter = new FilterCreatureCard("creature spells of the chosen type"); + filter.add(new ChosenSubtypePredicate(this.getId())); + this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new SpellsCostReductionAllEffect(filter, 2))); + } + + public UrzasIncubator(final UrzasIncubator card) { + super(card); + } + + @Override + public UrzasIncubator copy() { + return new UrzasIncubator(this); + } +} From 5b7105a44050915fac88aad89e58d21406cfd329 Mon Sep 17 00:00:00 2001 From: LevelX2 Date: Fri, 9 Oct 2015 00:11:48 +0200 Subject: [PATCH 048/268] * Spreading Seas - Fixed that the target did not become colorless. --- Mage.Sets/src/mage/sets/zendikar/SpreadingSeas.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Mage.Sets/src/mage/sets/zendikar/SpreadingSeas.java b/Mage.Sets/src/mage/sets/zendikar/SpreadingSeas.java index ab0741a212c..24b3df5f4a3 100644 --- a/Mage.Sets/src/mage/sets/zendikar/SpreadingSeas.java +++ b/Mage.Sets/src/mage/sets/zendikar/SpreadingSeas.java @@ -55,13 +55,16 @@ public class SpreadingSeas extends CardImpl { this.subtype.add("Aura"); + // Enchant land TargetPermanent auraTarget = new TargetLandPermanent(); this.getSpellAbility().addTarget(auraTarget); this.getSpellAbility().addEffect(new AttachEffect(Outcome.Detriment)); Ability ability = new EnchantAbility(auraTarget.getTargetName()); this.addAbility(ability); + // When Spreading Seas enters the battlefield, draw a card. this.addAbility(new EntersBattlefieldTriggeredAbility(new DrawCardSourceControllerEffect(1), false)); + // Enchanted land is an Island. this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new BecomesBasicLandEnchantedEffect("Island"))); From ebd8ecd494d4fb34e268f52bbb54fb497e1efca8 Mon Sep 17 00:00:00 2001 From: LevelX2 Date: Fri, 9 Oct 2015 00:12:21 +0200 Subject: [PATCH 049/268] * Songs of the Dryad - Fixed that the target did not become colorless. --- .../sets/commander2014/SongOfTheDryads.java | 69 ++++++++++++++++++- 1 file changed, 66 insertions(+), 3 deletions(-) diff --git a/Mage.Sets/src/mage/sets/commander2014/SongOfTheDryads.java b/Mage.Sets/src/mage/sets/commander2014/SongOfTheDryads.java index 8af2e622f3c..f37d1508087 100644 --- a/Mage.Sets/src/mage/sets/commander2014/SongOfTheDryads.java +++ b/Mage.Sets/src/mage/sets/commander2014/SongOfTheDryads.java @@ -30,14 +30,20 @@ package mage.sets.commander2014; import java.util.UUID; import mage.abilities.Ability; import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.effects.ContinuousEffectImpl; import mage.abilities.effects.common.AttachEffect; -import mage.abilities.effects.common.continuous.BecomesBasicLandEnchantedEffect; import mage.abilities.keyword.EnchantAbility; +import mage.abilities.mana.GreenManaAbility; import mage.cards.CardImpl; import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.Layer; import mage.constants.Outcome; import mage.constants.Rarity; +import mage.constants.SubLayer; import mage.constants.Zone; +import mage.game.Game; +import mage.game.permanent.Permanent; import mage.target.TargetPermanent; /** @@ -51,7 +57,6 @@ public class SongOfTheDryads extends CardImpl { this.expansionSetCode = "C14"; this.subtype.add("Aura"); - // Enchant permanent TargetPermanent auraTarget = new TargetPermanent(); this.getSpellAbility().addTarget(auraTarget); @@ -60,7 +65,7 @@ public class SongOfTheDryads extends CardImpl { this.addAbility(ability); // Enchanted permanent is a colorless Forest land. - this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new BecomesBasicLandEnchantedEffect("Forest"))); + this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new BecomesColorlessForestLandEffect())); } @@ -73,3 +78,61 @@ public class SongOfTheDryads extends CardImpl { return new SongOfTheDryads(this); } } + +class BecomesColorlessForestLandEffect extends ContinuousEffectImpl { + + public BecomesColorlessForestLandEffect() { + super(Duration.WhileOnBattlefield, Outcome.Detriment); + this.staticText = "Enchanted permanent is a colorless Forest land"; + } + + public BecomesColorlessForestLandEffect(final BecomesColorlessForestLandEffect effect) { + super(effect); + } + + @Override + public boolean apply(Game game, Ability source) { + return false; + } + + @Override + public BecomesColorlessForestLandEffect copy() { + return new BecomesColorlessForestLandEffect(this); + } + + @Override + public boolean apply(Layer layer, SubLayer sublayer, Ability source, Game game) { + Permanent enchantment = game.getPermanent(source.getSourceId()); + if (enchantment != null && enchantment.getAttachedTo() != null) { + Permanent permanent = game.getPermanent(enchantment.getAttachedTo()); + if (permanent != null) { + switch (layer) { + case ColorChangingEffects_5: + permanent.getColor(game).setWhite(false); + permanent.getColor(game).setGreen(false); + permanent.getColor(game).setBlack(false); + permanent.getColor(game).setBlue(false); + permanent.getColor(game).setRed(false); + break; + case AbilityAddingRemovingEffects_6: + permanent.removeAllAbilities(source.getSourceId(), game); + permanent.addAbility(new GreenManaAbility(), source.getSourceId(), game); + break; + case TypeChangingEffects_4: + permanent.getCardType().clear(); + permanent.getCardType().add(CardType.LAND); + permanent.getSubtype().clear(); + permanent.getSubtype().add("Forest"); + break; + } + return true; + } + } + return false; + } + + @Override + public boolean hasLayer(Layer layer) { + return layer == Layer.AbilityAddingRemovingEffects_6 || layer == Layer.ColorChangingEffects_5 || layer == Layer.TypeChangingEffects_4; + } +} From d8cf0d7a4b4fbeceba5b778d71b0d48f12871562 Mon Sep 17 00:00:00 2001 From: LevelX2 Date: Fri, 9 Oct 2015 00:13:41 +0200 Subject: [PATCH 050/268] Fixed that land enchantments that caused the enchanted land to become a basic land type removed wrongly other card types than Land and non basic land subtypes (e.g. Spreding Seas enchanting animated Blinkmoth Nexus). --- .../cards/enchantments/SpreadingSeasTest.java | 87 +++++++++++++++++++ .../BecomesBasicLandEnchantedEffect.java | 22 ++--- 2 files changed, 98 insertions(+), 11 deletions(-) create mode 100644 Mage.Tests/src/test/java/org/mage/test/cards/enchantments/SpreadingSeasTest.java diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/enchantments/SpreadingSeasTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/enchantments/SpreadingSeasTest.java new file mode 100644 index 00000000000..1c5f87fabb9 --- /dev/null +++ b/Mage.Tests/src/test/java/org/mage/test/cards/enchantments/SpreadingSeasTest.java @@ -0,0 +1,87 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package org.mage.test.cards.enchantments; + +import mage.constants.PhaseStep; +import mage.constants.Zone; +import org.junit.Test; +import org.mage.test.serverside.base.CardTestPlayerBase; + +/** + * + * @author LevelX2 + */ +public class SpreadingSeasTest extends CardTestPlayerBase { + + /** + * Played Spreading Seas on opps manland (e.g. Blinkmoth Nexus) . He + * activated it on response, seas resolves but the manland loses creature + * type what should not happened. + * + * 305.7. If an effect changes a land’s subtype to one or more of the basic + * land types, the land no longer has its old land type. It loses all + * abilities generated from its rules text and its old land types, and it + * gains the appropriate mana ability for each new basic land type. Note + * that this doesn’t remove any abilities that were granted to the land by + * other effects. Changing a land’s subtype doesn’t add or remove any card + * types (such as creature) or supertypes (such as basic, legendary, and + * snow) the land may have. If a land gains one or more land types in + * addition to its own, it keeps its land types and rules text, and it gains + * the new land types and mana abilities. + * + */ + @Test + public void testCreatureTypeStays() { + // Enchant land + // When Spreading Seas enters the battlefield, draw a card. + // Enchanted land is an Island. + addCard(Zone.HAND, playerA, "Spreading Seas", 1); // {1}{U} + addCard(Zone.BATTLEFIELD, playerA, "Island", 2); + + addCard(Zone.BATTLEFIELD, playerB, "Island", 1); + // Tap: Add 1 to your mana pool. + // {1}: Blinkmoth Nexus becomes a 1/1 Blinkmoth artifact creature with flying until end of turn. It's still a land. + // {1}, {T}: Target Blinkmoth gets +1/+1 until end of turn. + addCard(Zone.BATTLEFIELD, playerB, "Blinkmoth Nexus"); + + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Spreading Seas", "Blinkmoth Nexus"); + + activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerB, "{1}:", NO_TARGET, "Spreading Seas"); + + setStopAt(1, PhaseStep.BEGIN_COMBAT); + execute(); + + assertHandCount(playerA, "Spreading Seas", 0); + assertGraveyardCount(playerA, "Spreading Seas", 0); + assertPowerToughness(playerB, "Blinkmoth Nexus", 1, 1); + + assertPermanentCount(playerA, "Spreading Seas", 1); + assertHandCount(playerA, 1); + } + +} diff --git a/Mage/src/mage/abilities/effects/common/continuous/BecomesBasicLandEnchantedEffect.java b/Mage/src/mage/abilities/effects/common/continuous/BecomesBasicLandEnchantedEffect.java index 41f4c112c21..5bb693449ef 100644 --- a/Mage/src/mage/abilities/effects/common/continuous/BecomesBasicLandEnchantedEffect.java +++ b/Mage/src/mage/abilities/effects/common/continuous/BecomesBasicLandEnchantedEffect.java @@ -36,7 +36,6 @@ import mage.abilities.mana.BlueManaAbility; import mage.abilities.mana.GreenManaAbility; import mage.abilities.mana.RedManaAbility; import mage.abilities.mana.WhiteManaAbility; -import mage.constants.CardType; import mage.constants.Duration; import mage.constants.Layer; import mage.constants.Outcome; @@ -46,6 +45,16 @@ import mage.game.permanent.Permanent; public class BecomesBasicLandEnchantedEffect extends ContinuousEffectImpl { + protected final static ArrayList allLandTypes = new ArrayList<>(); + + static { + allLandTypes.add("Forest"); + allLandTypes.add("Swamp"); + allLandTypes.add("Plains"); + allLandTypes.add("Mountains"); + allLandTypes.add("Island"); + } + protected ArrayList landTypes = new ArrayList<>(); public BecomesBasicLandEnchantedEffect(String... landNames) { @@ -76,13 +85,6 @@ public class BecomesBasicLandEnchantedEffect extends ContinuousEffectImpl { Permanent permanent = game.getPermanent(enchantment.getAttachedTo()); if (permanent != null) { switch (layer) { - case ColorChangingEffects_5: - permanent.getColor(game).setWhite(false); - permanent.getColor(game).setGreen(false); - permanent.getColor(game).setBlack(false); - permanent.getColor(game).setBlue(false); - permanent.getColor(game).setRed(false); - break; case AbilityAddingRemovingEffects_6: permanent.removeAllAbilities(source.getSourceId(), game); for (String landType : landTypes) { @@ -106,9 +108,7 @@ public class BecomesBasicLandEnchantedEffect extends ContinuousEffectImpl { } break; case TypeChangingEffects_4: - permanent.getCardType().clear(); - permanent.getCardType().add(CardType.LAND); - permanent.getSubtype().clear(); + permanent.getSubtype().removeAll(allLandTypes); permanent.getSubtype().addAll(landTypes); break; } From 8a65ef67665327a8e5dcb7b7f8f556c9be8d1ddb Mon Sep 17 00:00:00 2001 From: LevelX2 Date: Fri, 9 Oct 2015 00:26:39 +0200 Subject: [PATCH 051/268] * Death Wish - Fixed that multiple cards could be selected instead of only one and added missing text to the tooltip. --- .../src/mage/sets/judgment/DeathWish.java | 71 +++++++------------ 1 file changed, 24 insertions(+), 47 deletions(-) diff --git a/Mage.Sets/src/mage/sets/judgment/DeathWish.java b/Mage.Sets/src/mage/sets/judgment/DeathWish.java index f6129647953..a753d3032ee 100644 --- a/Mage.Sets/src/mage/sets/judgment/DeathWish.java +++ b/Mage.Sets/src/mage/sets/judgment/DeathWish.java @@ -27,12 +27,13 @@ */ package mage.sets.judgment; +import java.util.UUID; import mage.abilities.Ability; import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.ExileSourceEffect; 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; @@ -42,9 +43,6 @@ import mage.game.Game; import mage.players.Player; import mage.target.TargetCard; -import java.util.Set; -import java.util.UUID; - /** * * @author Plopman @@ -55,9 +53,9 @@ public class DeathWish extends CardImpl { super(ownerId, 64, "Death Wish", Rarity.RARE, new CardType[]{CardType.SORCERY}, "{1}{B}{B}"); this.expansionSetCode = "JUD"; - // You may choose a card you own from outside the game and put it into your hand. You lose half your life, rounded up. Exile Death Wish. this.getSpellAbility().addEffect(new DeathWishEffect()); + this.getSpellAbility().addEffect(new ExileSourceEffect()); } public DeathWish(final DeathWish card) { @@ -74,12 +72,9 @@ class DeathWishEffect extends OneShotEffect { private static final String choiceText = "Choose a card you own from outside the game, and put it into your hand"; - private static final FilterCard filter = new FilterCard("card"); - - public DeathWishEffect() { super(Outcome.Benefit); - this.staticText = "You may choose a card you own from outside the game, reveal that card, and put it into your hand. Exile Death Wish"; + this.staticText = "You may choose a card you own from outside the game, reveal that card, and put it into your hand. You lose half your life, rounded up"; } public DeathWishEffect(final DeathWishEffect effect) { @@ -93,48 +88,30 @@ class DeathWishEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { - Player player = game.getPlayer(source.getControllerId()); - if (player != null) { - while (player.chooseUse(Outcome.Benefit, choiceText, source, game)) { - Cards cards = player.getSideboard(); - if(cards.isEmpty()) { - game.informPlayer(player, "You have no cards outside the game."); - break; - } - - Set filtered = cards.getCards(filter, game); - if (filtered.isEmpty()) { - game.informPlayer(player, "You have no " + filter.getMessage() + " outside the game."); - break; - } - - Cards filteredCards = new CardsImpl(); - for (Card card : filtered) { - filteredCards.add(card.getId()); - } - - TargetCard target = new TargetCard(Zone.PICK, filter); - if (player.choose(Outcome.Benefit, filteredCards, target, game)) { - Card card = player.getSideboard().get(target.getFirstTarget(), game); - if (card != null) { - card.moveToZone(Zone.HAND, source.getSourceId(), game, false); + Player controller = game.getPlayer(source.getControllerId()); + if (controller != null) { + if (controller.chooseUse(Outcome.Benefit, choiceText, source, game)) { + Cards cards = controller.getSideboard(); + if (cards.isEmpty()) { + game.informPlayer(controller, "You have no cards outside the game."); + } else { + TargetCard target = new TargetCard(Zone.OUTSIDE, new FilterCard()); + if (controller.choose(Outcome.Benefit, cards, target, game)) { + Card card = controller.getSideboard().get(target.getFirstTarget(), game); + if (card != null) { + controller.moveCards(card, null, Zone.HAND, source, game); + } } } } - - int amount = (player.getLife() + 1)/2; - if(amount > 0) - { - player.loseLife(amount, game); - } - - Card cardToExile = game.getCard(source.getSourceId()); - if(cardToExile != null) - { - cardToExile.moveToExile(null, "", source.getSourceId(), game); + + int amount = (controller.getLife() + 1) / 2; + if (amount > 0) { + controller.loseLife(amount, game); } + return true; } - return true; + return false; } -} \ No newline at end of file +} From 816c4bf6526aba41942681f8133e297eedf5e376 Mon Sep 17 00:00:00 2001 From: LevelX2 Date: Fri, 9 Oct 2015 11:08:02 +0200 Subject: [PATCH 052/268] * Mayael's Aria - Fixed that triggered ability did not work. --- Mage.Sets/src/mage/sets/alarareborn/MayaelsAria.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Mage.Sets/src/mage/sets/alarareborn/MayaelsAria.java b/Mage.Sets/src/mage/sets/alarareborn/MayaelsAria.java index 3d80d2b1c01..a23c65749a7 100644 --- a/Mage.Sets/src/mage/sets/alarareborn/MayaelsAria.java +++ b/Mage.Sets/src/mage/sets/alarareborn/MayaelsAria.java @@ -96,7 +96,7 @@ class MayaelsAriaEffect extends OneShotEffect { // put a +1/+1 counter on each creature you control if you control a creature with power 5 or greater. FilterCreaturePermanent filter = new FilterCreaturePermanent(); filter.add(new PowerPredicate(Filter.ComparisonType.GreaterThan, 4)); - if (game.getState().getBattlefield().countAll(filter, id, game) > 0) { + if (game.getState().getBattlefield().countAll(filter, controller.getId(), game) > 0) { for (Permanent creature : game.getBattlefield().getAllActivePermanents(filter, source.getControllerId(), game)) { creature.addCounters(CounterType.P1P1.createInstance(), game); } @@ -106,14 +106,14 @@ class MayaelsAriaEffect extends OneShotEffect { // Then you gain 10 life if you control a creature with power 10 or greater. filter = new FilterCreaturePermanent(); filter.add(new PowerPredicate(Filter.ComparisonType.GreaterThan, 9)); - if (game.getState().getBattlefield().countAll(filter, id, game) > 0) { + if (game.getState().getBattlefield().countAll(filter, controller.getId(), game) > 0) { controller.gainLife(10, game); } // Then you win the game if you control a creature with power 20 or greater. filter = new FilterCreaturePermanent(); filter.add(new PowerPredicate(Filter.ComparisonType.GreaterThan, 19)); - if (game.getState().getBattlefield().countAll(filter, id, game) > 0) { + if (game.getState().getBattlefield().countAll(filter, controller.getId(), game) > 0) { controller.won(game); } return true; From 8d1b807976b4d3fd6e75dea457ac161b14e61732 Mon Sep 17 00:00:00 2001 From: Rudyards Date: Fri, 9 Oct 2015 02:16:28 -0700 Subject: [PATCH 053/268] Added Douse, Lifeforce, Vedalken Aethermage. --- .../src/mage/sets/fifthedition/Lifeforce.java | 54 +++++++++++ .../mage/sets/fourthedition/Lifeforce.java | 54 +++++++++++ .../sets/futuresight/VedalkenAEthermage.java | 92 +++++++++++++++++++ .../src/mage/sets/limitedalpha/Lifeforce.java | 54 +++++++++++ .../src/mage/sets/limitedbeta/Lifeforce.java | 54 +++++++++++ .../mage/sets/masterseditioniv/Lifeforce.java | 73 +++++++++++++++ .../mage/sets/revisededition/Lifeforce.java | 54 +++++++++++ .../mage/sets/unlimitededition/Lifeforce.java | 54 +++++++++++ Mage.Sets/src/mage/sets/urzassaga/Douse.java | 73 +++++++++++++++ 9 files changed, 562 insertions(+) create mode 100644 Mage.Sets/src/mage/sets/fifthedition/Lifeforce.java create mode 100644 Mage.Sets/src/mage/sets/fourthedition/Lifeforce.java create mode 100644 Mage.Sets/src/mage/sets/futuresight/VedalkenAEthermage.java create mode 100644 Mage.Sets/src/mage/sets/limitedalpha/Lifeforce.java create mode 100644 Mage.Sets/src/mage/sets/limitedbeta/Lifeforce.java create mode 100644 Mage.Sets/src/mage/sets/masterseditioniv/Lifeforce.java create mode 100644 Mage.Sets/src/mage/sets/revisededition/Lifeforce.java create mode 100644 Mage.Sets/src/mage/sets/unlimitededition/Lifeforce.java create mode 100644 Mage.Sets/src/mage/sets/urzassaga/Douse.java diff --git a/Mage.Sets/src/mage/sets/fifthedition/Lifeforce.java b/Mage.Sets/src/mage/sets/fifthedition/Lifeforce.java new file mode 100644 index 00000000000..530955f41a5 --- /dev/null +++ b/Mage.Sets/src/mage/sets/fifthedition/Lifeforce.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.fifthedition; + +import java.util.UUID; +import mage.constants.Rarity; + +/** + * + * @author anonymous + */ +public class Lifeforce extends mage.sets.masterseditioniv.Lifeforce { + + public Lifeforce(UUID ownerId) { + super(ownerId); + this.cardNumber = 172; + this.expansionSetCode = "5ED"; + this.rarity = Rarity.UNCOMMON; + } + + public Lifeforce(final Lifeforce card) { + super(card); + } + + @Override + public Lifeforce copy() { + return new Lifeforce(this); + } +} diff --git a/Mage.Sets/src/mage/sets/fourthedition/Lifeforce.java b/Mage.Sets/src/mage/sets/fourthedition/Lifeforce.java new file mode 100644 index 00000000000..4e4b04d2815 --- /dev/null +++ b/Mage.Sets/src/mage/sets/fourthedition/Lifeforce.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.fourthedition; + +import java.util.UUID; +import mage.constants.Rarity; + +/** + * + * @author anonymous + */ +public class Lifeforce extends mage.sets.masterseditioniv.Lifeforce { + + public Lifeforce(UUID ownerId) { + super(ownerId); + this.cardNumber = 141; + this.expansionSetCode = "4ED"; + this.rarity = Rarity.UNCOMMON; + } + + public Lifeforce(final Lifeforce card) { + super(card); + } + + @Override + public Lifeforce copy() { + return new Lifeforce(this); + } +} diff --git a/Mage.Sets/src/mage/sets/futuresight/VedalkenAEthermage.java b/Mage.Sets/src/mage/sets/futuresight/VedalkenAEthermage.java new file mode 100644 index 00000000000..a62f3bf06e0 --- /dev/null +++ b/Mage.Sets/src/mage/sets/futuresight/VedalkenAEthermage.java @@ -0,0 +1,92 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.sets.futuresight; + +import java.util.UUID; +import mage.MageInt; +import mage.ObjectColor; +import mage.abilities.Ability; +import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.effects.common.ReturnToHandTargetEffect; +import mage.abilities.keyword.CyclingAbility; +import mage.abilities.keyword.FlashAbility; +import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.Rarity; +import mage.filter.FilterCard; +import mage.filter.FilterPermanent; +import mage.filter.FilterSpell; +import mage.filter.common.FilterCreaturePermanent; +import mage.filter.predicate.mageobject.ColorPredicate; +import mage.filter.predicate.mageobject.SubtypePredicate; +import mage.target.TargetPermanent; +import mage.target.common.TargetCreaturePermanent; + +/** + * + * @author anonymous + */ +public class VedalkenAEthermage extends CardImpl { + + private static final FilterPermanent filter = new FilterPermanent("Sliver"); + private static final FilterCard filter2 = new FilterCard("Wizard"); + + static { + filter.add(new SubtypePredicate("Sliver")); + filter2.add(new SubtypePredicate("Wizard")); + } + + public VedalkenAEthermage(UUID ownerId) { + super(ownerId, 61, "Vedalken AEthermage", Rarity.COMMON, new CardType[]{CardType.CREATURE}, "{1}{U}"); + this.expansionSetCode = "FUT"; + this.subtype.add("Vedalken"); + this.subtype.add("Wizard"); + this.power = new MageInt(1); + this.toughness = new MageInt(2); + + // Flash + this.addAbility(FlashAbility.getInstance()); + // When Vedalken Æthermage enters the battlefield, return target Sliver to its owner's hand. + Ability ability = new EntersBattlefieldTriggeredAbility(new ReturnToHandTargetEffect()); + ability.addTarget(new TargetPermanent(filter)); + this.addAbility(ability); + + // Wizardcycling {3} + this.addAbility(new CyclingAbility(new ManaCostsImpl("{3}"), filter2, "Wizardcycling")); + } + + public VedalkenAEthermage(final VedalkenAEthermage card) { + super(card); + } + + @Override + public VedalkenAEthermage copy() { + return new VedalkenAEthermage(this); + } +} diff --git a/Mage.Sets/src/mage/sets/limitedalpha/Lifeforce.java b/Mage.Sets/src/mage/sets/limitedalpha/Lifeforce.java new file mode 100644 index 00000000000..681dcf589ff --- /dev/null +++ b/Mage.Sets/src/mage/sets/limitedalpha/Lifeforce.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.limitedalpha; + +import java.util.UUID; +import mage.constants.Rarity; + +/** + * + * @author anonymous + */ +public class Lifeforce extends mage.sets.masterseditioniv.Lifeforce { + + public Lifeforce(UUID ownerId) { + super(ownerId); + this.cardNumber = 115; + this.expansionSetCode = "LEA"; + this.rarity = Rarity.UNCOMMON; + } + + public Lifeforce(final Lifeforce card) { + super(card); + } + + @Override + public Lifeforce copy() { + return new Lifeforce(this); + } +} diff --git a/Mage.Sets/src/mage/sets/limitedbeta/Lifeforce.java b/Mage.Sets/src/mage/sets/limitedbeta/Lifeforce.java new file mode 100644 index 00000000000..6d61a4df792 --- /dev/null +++ b/Mage.Sets/src/mage/sets/limitedbeta/Lifeforce.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.limitedbeta; + +import java.util.UUID; +import mage.constants.Rarity; + +/** + * + * @author anonymous + */ +public class Lifeforce extends mage.sets.masterseditioniv.Lifeforce { + + public Lifeforce(UUID ownerId) { + super(ownerId); + this.cardNumber = 115; + this.expansionSetCode = "LEB"; + this.rarity = Rarity.UNCOMMON; + } + + public Lifeforce(final Lifeforce card) { + super(card); + } + + @Override + public Lifeforce copy() { + return new Lifeforce(this); + } +} diff --git a/Mage.Sets/src/mage/sets/masterseditioniv/Lifeforce.java b/Mage.Sets/src/mage/sets/masterseditioniv/Lifeforce.java new file mode 100644 index 00000000000..0b37d2e5ba4 --- /dev/null +++ b/Mage.Sets/src/mage/sets/masterseditioniv/Lifeforce.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.masterseditioniv; + +import java.util.UUID; +import mage.ObjectColor; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.effects.common.CounterTargetEffect; +import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.Rarity; +import mage.constants.Zone; +import mage.filter.FilterSpell; +import mage.filter.predicate.mageobject.ColorPredicate; +import mage.target.TargetSpell; + +/** + * + * @author anonymous + */ +public class Lifeforce extends CardImpl { + + private static final FilterSpell filter = new FilterSpell("black spell"); + + static { + filter.add(new ColorPredicate(ObjectColor.BLACK)); + } + + public Lifeforce(UUID ownerId) { + super(ownerId, 160, "Lifeforce", Rarity.RARE, new CardType[]{CardType.ENCHANTMENT}, "{G}{G}"); + this.expansionSetCode = "ME4"; + + // {G}{G}: Counter target black spell. + SimpleActivatedAbility ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new CounterTargetEffect(), new ManaCostsImpl("{G}{G}")); + ability.addTarget(new TargetSpell(filter)); + this.addAbility(ability); + } + + public Lifeforce(final Lifeforce card) { + super(card); + } + + @Override + public Lifeforce copy() { + return new Lifeforce(this); + } +} diff --git a/Mage.Sets/src/mage/sets/revisededition/Lifeforce.java b/Mage.Sets/src/mage/sets/revisededition/Lifeforce.java new file mode 100644 index 00000000000..e5328eb3b10 --- /dev/null +++ b/Mage.Sets/src/mage/sets/revisededition/Lifeforce.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.revisededition; + +import java.util.UUID; +import mage.constants.Rarity; + +/** + * + * @author anonymous + */ +public class Lifeforce extends mage.sets.masterseditioniv.Lifeforce { + + public Lifeforce(UUID ownerId) { + super(ownerId); + this.cardNumber = 114; + this.expansionSetCode = "3ED"; + this.rarity = Rarity.UNCOMMON; + } + + public Lifeforce(final Lifeforce card) { + super(card); + } + + @Override + public Lifeforce copy() { + return new Lifeforce(this); + } +} diff --git a/Mage.Sets/src/mage/sets/unlimitededition/Lifeforce.java b/Mage.Sets/src/mage/sets/unlimitededition/Lifeforce.java new file mode 100644 index 00000000000..688270c6f3a --- /dev/null +++ b/Mage.Sets/src/mage/sets/unlimitededition/Lifeforce.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.unlimitededition; + +import java.util.UUID; +import mage.constants.Rarity; + +/** + * + * @author anonymous + */ +public class Lifeforce extends mage.sets.masterseditioniv.Lifeforce { + + public Lifeforce(UUID ownerId) { + super(ownerId); + this.cardNumber = 115; + this.expansionSetCode = "2ED"; + this.rarity = Rarity.UNCOMMON; + } + + public Lifeforce(final Lifeforce card) { + super(card); + } + + @Override + public Lifeforce copy() { + return new Lifeforce(this); + } +} diff --git a/Mage.Sets/src/mage/sets/urzassaga/Douse.java b/Mage.Sets/src/mage/sets/urzassaga/Douse.java new file mode 100644 index 00000000000..95aad42e904 --- /dev/null +++ b/Mage.Sets/src/mage/sets/urzassaga/Douse.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.urzassaga; + +import java.util.UUID; +import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.ObjectColor; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.effects.common.CounterTargetEffect; +import mage.constants.Rarity; +import mage.constants.Zone; +import mage.filter.FilterSpell; +import mage.filter.predicate.mageobject.ColorPredicate; +import mage.target.TargetSpell; + +/** + * + * @author anonymous + */ +public class Douse extends CardImpl { + + private static final FilterSpell filter = new FilterSpell("red spell"); + + static { + filter.add(new ColorPredicate(ObjectColor.RED)); + } + + public Douse(UUID ownerId) { + super(ownerId, 70, "Douse", Rarity.UNCOMMON, new CardType[]{CardType.ENCHANTMENT}, "{2}{U}"); + this.expansionSetCode = "USG"; + + // {1}{U}: Counter target red spell. + SimpleActivatedAbility ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new CounterTargetEffect(), new ManaCostsImpl("{1}{U}")); + ability.addTarget(new TargetSpell(filter)); + this.addAbility(ability); + } + + public Douse(final Douse card) { + super(card); + } + + @Override + public Douse copy() { + return new Douse(this); + } +} From 987280c4e7f28d531246dc2f9864ea099adcb95c Mon Sep 17 00:00:00 2001 From: LevelX2 Date: Fri, 9 Oct 2015 14:22:21 +0200 Subject: [PATCH 054/268] * Blizzard Specter - Fixed that the seond mode (discard) did not work. --- .../mage/sets/coldsnap/BlizzardSpecter.java | 44 +-- .../sets/saviorsofkamigawa/BloodClock.java | 1 - .../modal/ModalTriggeredAbilityTest.java | 95 +++++ Mage/src/mage/abilities/Ability.java | 353 ++++++++++-------- Mage/src/mage/abilities/AbilityImpl.java | 9 + .../mage/abilities/TriggeredAbilityImpl.java | 5 - ...CombatDamageToAPlayerTriggeredAbility.java | 14 +- .../abilities/common/LandfallAbility.java | 2 +- 8 files changed, 322 insertions(+), 201 deletions(-) create mode 100644 Mage.Tests/src/test/java/org/mage/test/cards/modal/ModalTriggeredAbilityTest.java diff --git a/Mage.Sets/src/mage/sets/coldsnap/BlizzardSpecter.java b/Mage.Sets/src/mage/sets/coldsnap/BlizzardSpecter.java index e9e77e9fbdf..dbebe6e16fc 100644 --- a/Mage.Sets/src/mage/sets/coldsnap/BlizzardSpecter.java +++ b/Mage.Sets/src/mage/sets/coldsnap/BlizzardSpecter.java @@ -32,7 +32,6 @@ import mage.MageInt; import mage.abilities.Ability; import mage.abilities.Mode; import mage.abilities.common.DealsCombatDamageToAPlayerTriggeredAbility; -import mage.abilities.costs.common.DiscardTargetCost; import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.discard.DiscardTargetEffect; import mage.abilities.keyword.FlyingAbility; @@ -41,7 +40,6 @@ import mage.constants.CardType; import mage.constants.Outcome; import mage.constants.Rarity; import mage.constants.Zone; -import mage.filter.common.FilterControlledCreaturePermanent; import mage.filter.common.FilterControlledPermanent; import mage.game.Game; import mage.game.permanent.Permanent; @@ -65,14 +63,17 @@ public class BlizzardSpecter extends CardImpl { // Flying this.addAbility(FlyingAbility.getInstance()); - // Whenever Blizzard Specter deals combat damage to a player, choose one - That player returns a permanent he or she controls to its owner's hand; or that player discards a card. - Ability ability2 = new DealsCombatDamageToAPlayerTriggeredAbility(new ReturnToHandEffect(), false); - - Mode mode2 = new Mode(); - mode2.getEffects().add(new DiscardTargetEffect(1, false)); - ability2.addMode(mode2); - - this.addAbility(ability2); + + // Whenever Blizzard Specter deals combat damage to a player, choose one + // - That player returns a permanent he or she controls to its owner's hand; + Ability ability = new DealsCombatDamageToAPlayerTriggeredAbility(new ReturnToHandEffect(), false, true); + + // or that player discards a card. + Mode mode = new Mode(); + mode.getEffects().add(new DiscardTargetEffect(1, false)); + ability.addMode(mode); + + this.addAbility(ability); } public BlizzardSpecter(final BlizzardSpecter card) { @@ -103,26 +104,19 @@ class ReturnToHandEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { - boolean result = false; - - Player player = game.getPlayer(targetPointer.getFirst(game, source)); - if (player == null) { + Player targetPlayer = game.getPlayer(targetPointer.getFirst(game, source)); + if (targetPlayer == null) { return false; } - Target target = new TargetControlledPermanent(1, 1, new FilterControlledPermanent(), true); - if (target.canChoose(player.getId(), game)) { - while (player.canRespond() && !target.isChosen() && target.canChoose(player.getId(), game)) { - player.chooseTarget(Outcome.ReturnToHand, target, source, game); + if (target.canChoose(targetPlayer.getId(), game)) { + targetPlayer.chooseTarget(Outcome.ReturnToHand, target, source, game); + Permanent permanent = game.getPermanent(target.getFirstTarget()); + if (permanent != null) { + targetPlayer.moveCards(permanent, null, Zone.HAND, source, game); } - for (UUID targetId: target.getTargets()) { - Permanent permanent = game.getPermanent(targetId); - if (permanent != null) { - result |= permanent.moveToZone(Zone.HAND, source.getSourceId(), game, false); - } - } } - return result; + return true; } } diff --git a/Mage.Sets/src/mage/sets/saviorsofkamigawa/BloodClock.java b/Mage.Sets/src/mage/sets/saviorsofkamigawa/BloodClock.java index 6beffb21683..cc29c54cda9 100644 --- a/Mage.Sets/src/mage/sets/saviorsofkamigawa/BloodClock.java +++ b/Mage.Sets/src/mage/sets/saviorsofkamigawa/BloodClock.java @@ -41,7 +41,6 @@ import mage.game.Game; import mage.game.permanent.Permanent; import mage.players.Player; import mage.target.Target; -import mage.target.TargetPermanent; import mage.target.common.TargetControlledPermanent; /** diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/modal/ModalTriggeredAbilityTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/modal/ModalTriggeredAbilityTest.java new file mode 100644 index 00000000000..750d5f83474 --- /dev/null +++ b/Mage.Tests/src/test/java/org/mage/test/cards/modal/ModalTriggeredAbilityTest.java @@ -0,0 +1,95 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package org.mage.test.cards.modal; + +import mage.constants.PhaseStep; +import mage.constants.Zone; +import org.junit.Test; +import org.mage.test.serverside.base.CardTestPlayerBase; + +/** + * + * @author LevelX2 + */ +public class ModalTriggeredAbilityTest extends CardTestPlayerBase { + + @Test + public void testBlizzardSpecterReturn() { + // Flying + // Whenever Blizzard Specter deals combat damage to a player, choose one + // - That player returns a permanent he or she controls to its owner's hand; + // or that player discards a card. + addCard(Zone.BATTLEFIELD, playerB, "Blizzard Specter"); + + addCard(Zone.BATTLEFIELD, playerA, "Silvercoat Lion"); + addCard(Zone.HAND, playerA, "Pillarfield Ox"); + + attack(2, playerB, "Blizzard Specter"); + setModeChoice(playerB, "1"); + + setStopAt(2, PhaseStep.POSTCOMBAT_MAIN); + execute(); + + assertHandCount(playerA, "Silvercoat Lion", 1); + assertHandCount(playerA, "Pillarfield Ox", 1); + + assertLife(playerA, 18); + assertLife(playerB, 20); + + } + + @Test + public void testBlizzardSpecterDiscard() { + // Flying + // Whenever Blizzard Specter deals combat damage to a player, choose one + // - That player returns a permanent he or she controls to its owner's hand; + // or that player discards a card. + addCard(Zone.BATTLEFIELD, playerB, "Blizzard Specter"); + + addCard(Zone.BATTLEFIELD, playerA, "Silvercoat Lion"); + addCard(Zone.HAND, playerA, "Pillarfield Ox"); + + attack(2, playerB, "Blizzard Specter"); + setModeChoice(playerB, "2"); + + setStopAt(2, PhaseStep.POSTCOMBAT_MAIN); + execute(); + + assertPermanentCount(playerA, "Silvercoat Lion", 1); + + assertHandCount(playerA, "Silvercoat Lion", 0); + assertHandCount(playerA, "Pillarfield Ox", 0); + + assertGraveyardCount(playerA, "Pillarfield Ox", 1); + + assertLife(playerA, 18); + assertLife(playerB, 20); + + } + +} diff --git a/Mage/src/mage/abilities/Ability.java b/Mage/src/mage/abilities/Ability.java index 81393981ce2..fedff00e85d 100644 --- a/Mage/src/mage/abilities/Ability.java +++ b/Mage/src/mage/abilities/Ability.java @@ -1,31 +1,30 @@ /* -* Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. -* -* Redistribution and use in source and binary forms, with or without modification, are -* permitted provided that the following conditions are met: -* -* 1. Redistributions of source code must retain the above copyright notice, this list of -* conditions and the following disclaimer. -* -* 2. Redistributions in binary form must reproduce the above copyright notice, this list -* of conditions and the following disclaimer in the documentation and/or other materials -* provided with the distribution. -* -* THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED -* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND -* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR -* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR -* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON -* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING -* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF -* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -* -* The views and conclusions contained in the software and documentation are those of the -* authors and should not be interpreted as representing official policies, either expressed -* or implied, of BetaSteward_at_googlemail.com. -*/ - + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ package mage.abilities; import java.io.Serializable; @@ -54,48 +53,54 @@ import mage.target.Targets; import mage.watchers.Watcher; /** - * Practically everything in the game is started from an Ability. This - * interface describes what an Ability is composed of at the highest level. + * Practically everything in the game is started from an Ability. This interface + * describes what an Ability is composed of at the highest level. */ public interface Ability extends Controllable, Serializable { /** * Gets the globally unique id of the ability contained within the game. - * - * @return A {@link java.util.UUID} which the game will use to store and retrieve - * the exact instance of this ability. + * + * @return A {@link java.util.UUID} which the game will use to store and + * retrieve the exact instance of this ability. */ @Override UUID getId(); /** * Assigns a new {@link java.util.UUID} - * - * @see mage.players.PlayerImpl#playAbility(mage.abilities.ActivatedAbility, mage.game.Game) - * @see mage.game.GameImpl#addTriggeredAbility(mage.abilities.TriggeredAbility) - * @see mage.game.GameImpl#addDelayedTriggeredAbility(mage.abilities.DelayedTriggeredAbility) + * + * @see mage.players.PlayerImpl#playAbility(mage.abilities.ActivatedAbility, + * mage.game.Game) + * @see + * mage.game.GameImpl#addTriggeredAbility(mage.abilities.TriggeredAbility) + * @see + * mage.game.GameImpl#addDelayedTriggeredAbility(mage.abilities.DelayedTriggeredAbility) */ void newId(); /** * Assigns a new {@link java.util.UUID} - * - * @see mage.players.PlayerImpl#playAbility(mage.abilities.ActivatedAbility, mage.game.Game) - * @see mage.game.GameImpl#addTriggeredAbility(mage.abilities.TriggeredAbility) - * @see mage.game.GameImpl#addDelayedTriggeredAbility(mage.abilities.DelayedTriggeredAbility) + * + * @see mage.players.PlayerImpl#playAbility(mage.abilities.ActivatedAbility, + * mage.game.Game) + * @see + * mage.game.GameImpl#addTriggeredAbility(mage.abilities.TriggeredAbility) + * @see + * mage.game.GameImpl#addDelayedTriggeredAbility(mage.abilities.DelayedTriggeredAbility) */ void newOriginalId(); /** * Gets the {@link AbilityType} of this ability. - * + * * @return The {@link AbilityType type} of this ability. */ AbilityType getAbilityType(); /** * Gets the id of the player in control of this ability. - * + * * @return The {@link java.util.UUID} of the controlling player. */ @Override @@ -103,28 +108,29 @@ public interface Ability extends Controllable, Serializable { /** * Sets the id of the controller of this ability. - * + * * @param controllerId The {@link java.util.UUID} of the controller. */ void setControllerId(UUID controllerId); /** * Gets the id of the object which put this ability in motion. - * - * @return The {@link java.util.UUID} of the object this ability is associated with. + * + * @return The {@link java.util.UUID} of the object this ability is + * associated with. */ UUID getSourceId(); /** * Sets the id of the object which this ability orignates from. - * + * * @param sourceID {@link java.util.UUID} the source id to set. */ void setSourceId(UUID sourceID); /** * Gets all {@link Costs} associated with this ability. - * + * * @return All {@link Costs} associated with this ability. */ Costs getCosts(); @@ -132,25 +138,25 @@ public interface Ability extends Controllable, Serializable { /** * Adds a {@link Cost} to this ability that must be paid before this ability * is activated. - * + * * @param cost The {@link Cost} to add. */ void addCost(Cost cost); /** - * Gets all {@link ManaCosts} associated with this ability. These returned + * Gets all {@link ManaCosts} associated with this ability. These returned * costs should never be modified as they represent the base costs before * any modifications. - * + * * @return All {@link ManaCosts} that must be paid. */ ManaCosts getManaCosts(); /** * Gets all the {@link ManaCosts} that must be paid before activating this - * ability. These costs should be modified by any modification effects currently - * present within the game state. - * + * ability. These costs should be modified by any modification effects + * currently present within the game state. + * * @return All {@link ManaCosts} that must be paid. */ ManaCosts getManaCostsToPay(); @@ -158,52 +164,61 @@ public interface Ability extends Controllable, Serializable { /** * Adds a {@link ManaCost} to this ability that must be paid before this * ability is activated. - * + * * @param cost The {@link ManaCost} to add. */ void addManaCost(ManaCost cost); /** * Gets all {@link AlternativeCost} associated with this ability. - * - * @return All {@link AlternativeCost}'s that can be paid instead of the {@link ManaCosts} + * + * @return All {@link AlternativeCost}'s that can be paid instead of the + * {@link ManaCosts} */ List getAlternativeCosts(); /** * Adds an {@link AlternativeCost} this ability that may be paid instead of * any other cost. - * + * * @param cost The {@link AlternativeCost} to add. */ void addAlternativeCost(AlternativeCost cost); /** * TODO Method is unused, keep it around? - * - * Gets all costs that are optional to this ability. These costs can be paid + * + * Gets all costs that are optional to this ability. These costs can be paid * in addition to other costs to have other effects put into place. - * + * * @return All {@link Costs} that can be paid above and beyond other costs. */ Costs getOptionalCosts(); /** * Adds a {@link Cost} that is optional to this ability. - * + * * @param cost The {@link Cost} to add to the optional costs. */ void addOptionalCost(Cost cost); /** - * Retrieves the effects that are put into the place by the resolution of this - * ability. - * + * Retrieves the effects that are put into the place by the resolution of + * this ability. + * * @return All {@link Effects} that will be put into place by the resolution * of this ability. */ Effects getEffects(); + /** + * Retrieves all effects of an ability. That means effects from all modes + * event those modes that are not seleced (yet). + * + * @return All {@link Effects} of this ability. + */ + Effects getAllEffects(); + /** * Retrieves the effects of the specified {@link EffectType type} that are * put into place by the resolution of this ability. @@ -216,26 +231,28 @@ public interface Ability extends Controllable, Serializable { /** * Adds an effect to this ability. - * + * * @param effect The {@link Effect} to add. */ void addEffect(Effect effect); /** - * Retrieves all targets that must be satisfied before this ability is + * Retrieves all targets that must be satisfied before this ability is put + * onto the stack. + * + * @return All {@link Targets} that must be satisfied before this ability is * put onto the stack. - * - * @return All {@link Targets} that must be satisfied before this ability is put onto - * the stack. */ Targets getTargets(); /** - * Retrieves the {@link Target} located at the 0th index in the {@link Targets}. - * A call to the method is equivalent to {@link #getTargets()}.get(0).getFirstTarget(). - * - * @return The {@link java.util.UUID} of the first target within the targets list. - * + * Retrieves the {@link Target} located at the 0th index in the + * {@link Targets}. A call to the method is equivalent to + * {@link #getTargets()}.get(0).getFirstTarget(). + * + * @return The {@link java.util.UUID} of the first target within the targets + * list. + * * @see mage.target.Target */ UUID getFirstTarget(); @@ -243,53 +260,54 @@ public interface Ability extends Controllable, Serializable { /** * Adds a target to this ability that must be satisfied before this ability * is put onto the stack. - * + * * @param target The {@link Target} to add. */ void addTarget(Target target); /** * Choices - * - * @return + * + * @return */ Choices getChoices(); /** * TODO: Javadoc me - * - * @param choice + * + * @param choice */ void addChoice(Choice choice); /** * Retrieves the {@link Zone} that this ability is active within. - * - * @return + * + * @return */ Zone getZone(); /** * Retrieves whether or not this abilities activation will use the stack. - * - * @return + * + * @return */ boolean isUsesStack(); /** * Retrieves a human readable string representing what the ability states it - * accomplishes. This call is equivalent to {@link #getRule(boolean) getRule(false)} - * + * accomplishes. This call is equivalent to + * {@link #getRule(boolean) getRule(false)} + * * @return A human readable string representing what the ability states it * accomplishes */ String getRule(); /** - * Retrieves a human readable string including any costs associated with this - * ability if the all parameter is true, and just the abilities rule text if - * the all parameter is false. - * + * Retrieves a human readable string including any costs associated with + * this ability if the all parameter is true, and just the abilities rule + * text if the all parameter is false. + * * @param all True if costs are desired in the output, false otherwise. * @return */ @@ -297,51 +315,60 @@ public interface Ability extends Controllable, Serializable { /** * Retrieves the rule associated with the given source. - * + * * @param source - * @return + * @return */ String getRule(String source); /** * Activates this ability prompting the controller to pay any mandatory * {@link Costs} or {@link AlternativeCost} associated with this ability. - * - * @param game A reference the {@link Game} for which this ability should be activated within. + * + * @param game A reference the {@link Game} for which this ability should be + * activated within. * @param noMana Whether or not {@link ManaCosts} have to be paid. * @return True if this ability was successfully activated. - * - * @see mage.players.PlayerImpl#cast(mage.abilities.SpellAbility, mage.game.Game, boolean) - * @see mage.players.PlayerImpl#playAbility(mage.abilities.ActivatedAbility, mage.game.Game) - * @see mage.players.PlayerImpl#triggerAbility(mage.abilities.TriggeredAbility, mage.game.Game) + * + * @see mage.players.PlayerImpl#cast(mage.abilities.SpellAbility, + * mage.game.Game, boolean) + * @see mage.players.PlayerImpl#playAbility(mage.abilities.ActivatedAbility, + * mage.game.Game) + * @see + * mage.players.PlayerImpl#triggerAbility(mage.abilities.TriggeredAbility, + * mage.game.Game) */ boolean activate(Game game, boolean noMana); boolean isActivated(); - + /** - * Resolves this ability and puts any effects it produces into play. This - * method should only be called if the {@link #activate(mage.game.Game, boolean)} - * method returned true. - * + * Resolves this ability and puts any effects it produces into play. This + * method should only be called if the + * {@link #activate(mage.game.Game, boolean)} method returned true. + * * @param game The {@link Game} for which this ability resolves within. * @return Whether or not this ability successfully resolved. - * - * @see mage.players.PlayerImpl#playManaAbility(mage.abilities.mana.ManaAbility, mage.game.Game) - * @see mage.players.PlayerImpl#specialAction(mage.abilities.SpecialAction, mage.game.Game) + * + * @see + * mage.players.PlayerImpl#playManaAbility(mage.abilities.mana.ManaAbility, + * mage.game.Game) + * @see mage.players.PlayerImpl#specialAction(mage.abilities.SpecialAction, + * mage.game.Game) */ boolean resolve(Game game); /** * Used to reset the state of this ability. - * - * @param game + * + * @param game */ void reset(Game game); /** - * Overridden by triggered abilities with intervening if clauses - rule 20110715 - 603.4 - * + * Overridden by triggered abilities with intervening if clauses - rule + * 20110715 - 603.4 + * * @param game * @return Whether or not the intervening if clause is satisfied */ @@ -349,7 +376,7 @@ public interface Ability extends Controllable, Serializable { /** * Creates a fresh copy of this ability. - * + * * @return A new copy of this ability. */ Ability copy(); @@ -364,43 +391,47 @@ public interface Ability extends Controllable, Serializable { /** * Gets the list of sub-abilities associated with this ability. - * @return + * + * @return */ List getSubAbilities(); /** * Adds a sub-ability to this ability. - * + * * @param ability The {@link Ability} to add. */ void addSubAbility(Ability ability); List getWatchers(); + void addWatcher(Watcher watcher); - + /** * Returns true if this abilities source is in the zone for the ability - * + * * @param game * @param source * @param event - * @return + * @return */ boolean isInUseableZone(Game game, MageObject source, GameEvent event); /** - * Returns true if the source object has currently the ability - * (e.g. The object can have lost all or some abilities for some time (e.g. Turn to Frog) - * + * Returns true if the source object has currently the ability (e.g. The + * object can have lost all or some abilities for some time (e.g. Turn to + * Frog) + * * @param game * @param source * @param event - * @return + * @return */ boolean hasSourceObjectAbility(Game game, MageObject source, GameEvent event); /** - * Returns true if this ability has to be shown as topmost of all the rules of the object + * Returns true if this ability has to be shown as topmost of all the rules + * of the object * * @return */ @@ -415,10 +446,9 @@ public interface Ability extends Controllable, Serializable { */ void setRuleAtTheTop(boolean ruleAtTheTop); - /** - * Returns true if this ability has to work also with face down object - * (set to not visible normally). + * Returns true if this ability has to work also with face down object (set + * to not visible normally). * * @return */ @@ -439,20 +469,20 @@ public interface Ability extends Controllable, Serializable { * @return */ boolean getRuleVisible(); - /** * Sets the value for the ruleVisible attribute * - * true = rule will be shown for the card / permanent - * false = rule won't be shown + * true = rule will be shown for the card / permanent false = rule won't be + * shown * * @param ruleVisible */ void setRuleVisible(boolean ruleVisible); /** - * Returns true if the additional costs of the abilitiy should be visible on the tooltip text + * Returns true if the additional costs of the abilitiy should be visible on + * the tooltip text * * @return */ @@ -461,35 +491,34 @@ public interface Ability extends Controllable, Serializable { /** * Sets the value for the additional costs rule attribute * - * true = rule will be shown for the card / permanent - * false = rule won't be shown + * true = rule will be shown for the card / permanent false = rule won't be + * shown * * @param ruleAdditionalCostsVisible */ void setAdditionalCostsRuleVisible(boolean ruleAdditionalCostsVisible); - /** * Get the originalId of the ability - * + * * @return originalId */ UUID getOriginalId(); - + /** - * Sets the ability word for the given ability. - * An ability word is a word that, in essence, groups, and reminds players of, cards - * that have a common functionality and does not imply any particular rules. - * + * Sets the ability word for the given ability. An ability word is a word + * that, in essence, groups, and reminds players of, cards that have a + * common functionality and does not imply any particular rules. + * * --- Not usable yet for rule text generation of triggered abilities --- - * - * @param abilityWord + * + * @param abilityWord */ void setAbilityWord(AbilityWord abilityWord); /** - * Creates the message about the ability casting/triggering/activating to post in the game log - * before the ability resolves. + * Creates the message about the ability casting/triggering/activating to + * post in the game log before the ability resolves. * * @param game * @return @@ -497,46 +526,46 @@ public interface Ability extends Controllable, Serializable { String getGameLogMessage(Game game); /** - * Used to deactivate cost modification logic of ability activation for some special handling - * (e.g. FlashbackAbility gets cost modifiaction twice because of how it's handled now) + * Used to deactivate cost modification logic of ability activation for some + * special handling (e.g. FlashbackAbility gets cost modifiaction twice + * because of how it's handled now) * * @param active execute no cost modification */ void setCostModificationActive(boolean active); boolean activateAlternateOrAdditionalCosts(MageObject sourceObject, boolean noMana, Player controller, Game game); - + /** - * Sets the object that actually existed while a ability triggerd or - * an ability was activated. - * - * @param mageObject - * @param game + * Sets the object that actually existed while a ability triggerd or an + * ability was activated. + * + * @param mageObject + * @param game */ void setSourceObject(MageObject mageObject, Game game); - + /** - * Returns the object that actually existed while a ability triggerd or - * an ability was activated. - * If not set yet, the current object will be retrieved from the game. - * + * Returns the object that actually existed while a ability triggerd or an + * ability was activated. If not set yet, the current object will be + * retrieved from the game. + * * @param game - * @return + * @return */ MageObject getSourceObject(Game game); int getSourceObjectZoneChangeCounter(); - + /** - * Returns the object that actually existed while a ability triggerd or - * an ability was activated only if it has not changed zone meanwhile. - * If not set yet, the current object will be retrieved from the game. - * + * Returns the object that actually existed while a ability triggerd or an + * ability was activated only if it has not changed zone meanwhile. If not + * set yet, the current object will be retrieved from the game. + * * @param game - * @return + * @return */ - MageObject getSourceObjectIfItStillExists(Game game); - + String getTargetDescription(Targets targets, Game game); } diff --git a/Mage/src/mage/abilities/AbilityImpl.java b/Mage/src/mage/abilities/AbilityImpl.java index 150ddd0747f..821abd34d61 100644 --- a/Mage/src/mage/abilities/AbilityImpl.java +++ b/Mage/src/mage/abilities/AbilityImpl.java @@ -681,6 +681,15 @@ public abstract class AbilityImpl implements Ability { return modes.getMode().getEffects(); } + @Override + public Effects getAllEffects() { + Effects allEffects = new Effects(); + for (Mode mode : getModes().values()) { + allEffects.addAll(mode.getEffects()); + } + return allEffects; + } + @Override public Effects getEffects(Game game, EffectType effectType) { Effects typedEffects = new Effects(); diff --git a/Mage/src/mage/abilities/TriggeredAbilityImpl.java b/Mage/src/mage/abilities/TriggeredAbilityImpl.java index 0c9cf7411c5..aabda88d3c6 100644 --- a/Mage/src/mage/abilities/TriggeredAbilityImpl.java +++ b/Mage/src/mage/abilities/TriggeredAbilityImpl.java @@ -77,11 +77,6 @@ public abstract class TriggeredAbilityImpl extends AbilityImpl implements Trigge return true; } - // TODO: Implement for all TriggeredAbilities so this default method can be removed - /*@Override - public boolean checkEventType(GameEvent event, Game game) { - return true; - }*/ @Override public boolean resolve(Game game) { if (isOptional()) { diff --git a/Mage/src/mage/abilities/common/DealsCombatDamageToAPlayerTriggeredAbility.java b/Mage/src/mage/abilities/common/DealsCombatDamageToAPlayerTriggeredAbility.java index 38f3642e8a7..429f9c34340 100644 --- a/Mage/src/mage/abilities/common/DealsCombatDamageToAPlayerTriggeredAbility.java +++ b/Mage/src/mage/abilities/common/DealsCombatDamageToAPlayerTriggeredAbility.java @@ -1,16 +1,16 @@ /* * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. - * + * * Redistribution and use in source and binary forms, with or without modification, are * permitted provided that the following conditions are met: - * + * * 1. Redistributions of source code must retain the above copyright notice, this list of * conditions and the following disclaimer. - * + * * 2. Redistributions in binary form must reproduce the above copyright notice, this list * of conditions and the following disclaimer in the documentation and/or other materials * provided with the distribution. - * + * * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR @@ -20,16 +20,16 @@ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * + * * The views and conclusions contained in the software and documentation are those of the * authors and should not be interpreted as representing official policies, either expressed * or implied, of BetaSteward_at_googlemail.com. */ package mage.abilities.common; -import mage.constants.Zone; import mage.abilities.TriggeredAbilityImpl; import mage.abilities.effects.Effect; +import mage.constants.Zone; import mage.game.Game; import mage.game.events.DamagedPlayerEvent; import mage.game.events.GameEvent; @@ -72,7 +72,7 @@ public class DealsCombatDamageToAPlayerTriggeredAbility extends TriggeredAbility if (event.getSourceId().equals(getSourceId()) && ((DamagedPlayerEvent) event).isCombatDamage()) { if (setTargetPointer) { - for (Effect effect : this.getEffects()) { + for (Effect effect : this.getAllEffects()) { effect.setTargetPointer(new FixedTarget(event.getPlayerId())); effect.setValue("damage", event.getAmount()); } diff --git a/Mage/src/mage/abilities/common/LandfallAbility.java b/Mage/src/mage/abilities/common/LandfallAbility.java index 17560ca6926..6e8651d8f00 100644 --- a/Mage/src/mage/abilities/common/LandfallAbility.java +++ b/Mage/src/mage/abilities/common/LandfallAbility.java @@ -78,7 +78,7 @@ public class LandfallAbility extends TriggeredAbilityImpl { && permanent.getControllerId().equals(this.controllerId)) { triggeringLand = permanent; if (setTargetPointer.equals(SetTargetPointer.PERMANENT)) { - for (Effect effect : getEffects()) { + for (Effect effect : getAllEffects()) { effect.setTargetPointer(new FixedTarget(permanent, game)); } } From 819d341fbb15c5cee4e5c8d30cc4a7707051b67d Mon Sep 17 00:00:00 2001 From: LevelX2 Date: Fri, 9 Oct 2015 14:55:39 +0200 Subject: [PATCH 055/268] * Nissa, Sage Animist - Added test for +1 ability. --- .../sets/magicorigins/NissaSageAnimist.java | 14 ++++++------- .../abilities/keywords/TransformTest.java | 20 +++++++++++++++---- 2 files changed, 23 insertions(+), 11 deletions(-) diff --git a/Mage.Sets/src/mage/sets/magicorigins/NissaSageAnimist.java b/Mage.Sets/src/mage/sets/magicorigins/NissaSageAnimist.java index 7959cf7f6b3..d3a209c463a 100644 --- a/Mage.Sets/src/mage/sets/magicorigins/NissaSageAnimist.java +++ b/Mage.Sets/src/mage/sets/magicorigins/NissaSageAnimist.java @@ -28,6 +28,7 @@ package mage.sets.magicorigins; import java.util.UUID; +import mage.MageObject; import mage.abilities.Ability; import mage.abilities.LoyaltyAbility; import mage.abilities.common.EntersBattlefieldAbility; @@ -112,19 +113,18 @@ class NissaSageAnimistPlusOneEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { Player controller = game.getPlayer(source.getControllerId()); - if (controller != null && controller.getLibrary().size() > 0) { + MageObject sourceObject = game.getObject(source.getSourceId()); + if (sourceObject != null && controller != null && controller.getLibrary().size() > 0) { Card card = controller.getLibrary().getFromTop(game); if (card == null) { return false; } - CardsImpl cards = new CardsImpl(); - cards.add(card); - controller.revealCards("Nissa, Sage Animist", cards, game); + controller.revealCards(sourceObject.getIdName(), new CardsImpl(card), game); + Zone targetZone = Zone.HAND; if (card.getCardType().contains(CardType.LAND)) { - return controller.putOntoBattlefieldWithInfo(card, game, Zone.LIBRARY, source.getSourceId()); - } else { - return controller.moveCards(card, Zone.LIBRARY, Zone.HAND, source, game); + targetZone = Zone.BATTLEFIELD; } + return controller.moveCards(card, null, targetZone, source, game); } return true; } diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/abilities/keywords/TransformTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/abilities/keywords/TransformTest.java index 14e6c0db6a3..d37249116ca 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/abilities/keywords/TransformTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/abilities/keywords/TransformTest.java @@ -44,23 +44,35 @@ public class TransformTest extends CardTestPlayerBase { addCard(Zone.LIBRARY, playerA, "Forest"); - addCard(Zone.BATTLEFIELD, playerA, "Forest", 6); + addCard(Zone.BATTLEFIELD, playerA, "Forest", 5); + addCard(Zone.BATTLEFIELD, playerA, "Swamp", 1); // When Nissa, Vastwood Seer enters the battlefield, you may search your library for a basic Forest card, reveal it, put it into your hand, then shuffle your library. // Whenever a land enters the battlefield under your control, if you control seven or more lands, exile Nissa, then return her to the battlefield transformed under her owner's control. addCard(Zone.HAND, playerA, "Nissa, Vastwood Seer"); + addCard(Zone.BATTLEFIELD, playerB, "Forest", 2); + // {G}{G}, Sacrifice Rootrunner: Put target land on top of its owner's library. + addCard(Zone.BATTLEFIELD, playerB, "Rootrunner"); // {2}{G}{G} + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Nissa, Vastwood Seer"); playLand(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Forest"); - setStopAt(1, PhaseStep.BEGIN_COMBAT); + activateAbility(1, PhaseStep.POSTCOMBAT_MAIN, playerB, "{G}{G}", "Swamp"); + activateAbility(1, PhaseStep.POSTCOMBAT_MAIN, playerA, "+1: Reveal"); + + setStopAt(1, PhaseStep.END_TURN); execute(); - assertPermanentCount(playerA, "Forest", 7); + assertGraveyardCount(playerB, "Rootrunner", 1); assertPermanentCount(playerA, "Nissa, Vastwood Seer", 0); assertPermanentCount(playerA, "Nissa, Sage Animist", 1); - assertCounterCount("Nissa, Sage Animist", CounterType.LOYALTY, 3); + + assertCounterCount("Nissa, Sage Animist", CounterType.LOYALTY, 4); + assertPermanentCount(playerA, "Forest", 6); + assertPermanentCount(playerA, "Swamp", 1); + } @Test From 1739bcab56382f00ff377f704dd271ffd5fd1386 Mon Sep 17 00:00:00 2001 From: LevelX2 Date: Fri, 9 Oct 2015 16:29:51 +0200 Subject: [PATCH 056/268] * Added missing override of getAllEffects. --- Mage/src/mage/game/stack/StackAbility.java | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/Mage/src/mage/game/stack/StackAbility.java b/Mage/src/mage/game/stack/StackAbility.java index aa8d58de407..157dace466c 100644 --- a/Mage/src/mage/game/stack/StackAbility.java +++ b/Mage/src/mage/game/stack/StackAbility.java @@ -237,6 +237,11 @@ public class StackAbility extends StackObjImpl implements Ability { return ability.getEffects(); } + @Override + public Effects getAllEffects() { + return ability.getAllEffects(); + } + @Override public Effects getEffects(Game game, EffectType effectType) { return ability.getEffects(game, effectType); From abc6b11c32e4350e8846963b454ebe3adfe00cc9 Mon Sep 17 00:00:00 2001 From: LevelX2 Date: Fri, 9 Oct 2015 16:30:28 +0200 Subject: [PATCH 057/268] * Mizzium Meddler - Fixed target change handling --- .../sets/magicorigins/MizziumMeddler.java | 106 +------------- .../src/mage/sets/newphyrexia/Spellskite.java | 120 +--------------- ...getOfTargetSpellAbilityToSourceEffect.java | 130 ++++++++++++++++++ 3 files changed, 136 insertions(+), 220 deletions(-) create mode 100644 Mage/src/mage/abilities/effects/common/ChangeATargetOfTargetSpellAbilityToSourceEffect.java diff --git a/Mage.Sets/src/mage/sets/magicorigins/MizziumMeddler.java b/Mage.Sets/src/mage/sets/magicorigins/MizziumMeddler.java index c0a7dc19aec..a59cd456d34 100644 --- a/Mage.Sets/src/mage/sets/magicorigins/MizziumMeddler.java +++ b/Mage.Sets/src/mage/sets/magicorigins/MizziumMeddler.java @@ -29,23 +29,14 @@ package mage.sets.magicorigins; import java.util.UUID; import mage.MageInt; -import mage.MageObject; import mage.abilities.Ability; import mage.abilities.common.EntersBattlefieldTriggeredAbility; -import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.ChangeATargetOfTargetSpellAbilityToSourceEffect; import mage.abilities.keyword.FlashAbility; import mage.cards.CardImpl; import mage.constants.CardType; -import mage.constants.Outcome; import mage.constants.Rarity; -import mage.game.Game; -import mage.game.stack.Spell; -import mage.game.stack.StackAbility; -import mage.game.stack.StackObject; -import mage.players.Player; -import mage.target.Target; import mage.target.TargetStackObject; -import mage.target.Targets; /** * @@ -63,9 +54,9 @@ public class MizziumMeddler extends CardImpl { // Flash this.addAbility(FlashAbility.getInstance()); - - // When Mizzium Meddler enters the battlefield, change a target of target spell or ability to Mizzium Meddler. - Ability ability = new EntersBattlefieldTriggeredAbility(new MizziumMeddlerEffect()); + + // When Mizzium Meddler enters the battlefield, you may change a target of target spell or ability to Mizzium Meddler. + Ability ability = new EntersBattlefieldTriggeredAbility(new ChangeATargetOfTargetSpellAbilityToSourceEffect(), true); ability.addTarget(new TargetStackObject()); this.addAbility(ability); } @@ -79,92 +70,3 @@ public class MizziumMeddler extends CardImpl { return new MizziumMeddler(this); } } - -class MizziumMeddlerEffect extends OneShotEffect { - - public MizziumMeddlerEffect() { - super(Outcome.Neutral); - staticText = "Change a target of target spell or ability to {this}"; - } - - public MizziumMeddlerEffect(final MizziumMeddlerEffect effect) { - super(effect); - } - - @Override - public boolean apply(Game game, Ability source) { - StackObject stackObject = game.getStack().getStackObject(source.getFirstTarget()); - MageObject sourceObject = game.getObject(source.getSourceId()); - if (stackObject != null && sourceObject != null) { - Targets targets; - Ability sourceAbility; - MageObject oldTarget = null; - if (stackObject instanceof Spell) { - Spell spell = (Spell)stackObject; - sourceAbility = spell.getSpellAbility(); - targets = spell.getSpellAbility().getTargets(); - } else if (stackObject instanceof StackAbility) { - StackAbility stackAbility = (StackAbility)stackObject; - sourceAbility = stackAbility; - targets = stackAbility.getTargets(); - } else { - return false; - } - boolean twoTimesTarget = false; - if (targets.size() == 1 && targets.get(0).getTargets().size() == 1) { - Target target = targets.get(0); - if (target.canTarget(stackObject.getControllerId(), source.getSourceId(), sourceAbility, game)) { - oldTarget = game.getObject(targets.getFirstTarget()); - 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()) { - MageObject object = game.getObject(targetId); - String name; - if (object == null) { - Player targetPlayer = game.getPlayer(targetId); - name = targetPlayer.getLogName(); - } else { - name = object.getName(); - } - if (!targetId.equals(source.getSourceId()) && target.getTargets().contains(source.getSourceId())) { - // you can't change this target to MizziumMeddler because MizziumMeddler 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 (target.canTarget(stackObject.getControllerId(), source.getSourceId(), sourceAbility, game)) { - oldTarget = game.getObject(targets.getFirstTarget()); - target.remove(targetId); - // The source is still the spell on the stack - target.addTarget(source.getSourceId(), stackObject.getStackAbility(), game); - break; - } - } - } - } - } - if (oldTarget != null) { - 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()); - } else { - game.informPlayers(sourceObject.getLogName() + ": Target not changed to " + sourceObject.getLogName() + " because its no valid target for " + stackObject.getName()); - } - } - return true; - } - return false; - } - - @Override - public MizziumMeddlerEffect copy() { - return new MizziumMeddlerEffect(this); - } - -} \ No newline at end of file diff --git a/Mage.Sets/src/mage/sets/newphyrexia/Spellskite.java b/Mage.Sets/src/mage/sets/newphyrexia/Spellskite.java index ca7cfbd7e8c..4e127421977 100644 --- a/Mage.Sets/src/mage/sets/newphyrexia/Spellskite.java +++ b/Mage.Sets/src/mage/sets/newphyrexia/Spellskite.java @@ -29,24 +29,15 @@ package mage.sets.newphyrexia; import java.util.UUID; import mage.MageInt; -import mage.MageObject; import mage.abilities.Ability; import mage.abilities.common.SimpleActivatedAbility; import mage.abilities.costs.mana.ManaCostsImpl; -import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.ChangeATargetOfTargetSpellAbilityToSourceEffect; import mage.cards.CardImpl; import mage.constants.CardType; -import mage.constants.Outcome; import mage.constants.Rarity; import mage.constants.Zone; -import mage.game.Game; -import mage.game.stack.Spell; -import mage.game.stack.StackAbility; -import mage.game.stack.StackObject; -import mage.players.Player; -import mage.target.Target; import mage.target.TargetStackObject; -import mage.target.Targets; /** * @@ -62,7 +53,7 @@ public class Spellskite extends CardImpl { this.toughness = new MageInt(4); // {UP}: Change a target of target spell or ability to Spellskite. - Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new SpellskiteEffect(), new ManaCostsImpl("{UP}")); + Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new ChangeATargetOfTargetSpellAbilityToSourceEffect(), new ManaCostsImpl("{UP}")); ability.addTarget(new TargetStackObject()); this.addAbility(ability); } @@ -76,110 +67,3 @@ public class Spellskite extends CardImpl { return new Spellskite(this); } } - -class SpellskiteEffect extends OneShotEffect { - - public SpellskiteEffect() { - super(Outcome.Neutral); - staticText = "Change a target of target spell or ability to {this}"; - } - - public SpellskiteEffect(final SpellskiteEffect effect) { - super(effect); - } - - @Override - public boolean apply(Game game, Ability source) { - StackObject stackObject = game.getStack().getStackObject(source.getFirstTarget()); - MageObject sourceObject = game.getObject(source.getSourceId()); - if (stackObject != null && sourceObject != null) { - Targets targets = new Targets(); - Ability sourceAbility; - String oldTargetName = null; - if (stackObject instanceof Spell) { - Spell spell = (Spell) stackObject; - sourceAbility = spell.getSpellAbility(); - } else if (stackObject instanceof StackAbility) { - StackAbility stackAbility = (StackAbility) stackObject; - sourceAbility = stackAbility; - } 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); - if (target.canTarget(stackObject.getControllerId(), source.getSourceId(), sourceAbility, game)) { - oldTargetName = getTargetName(targets.getFirstTarget(), game); - target.clearChosen(); - // The source is still the spell on the stack - target.addTarget(source.getSourceId(), stackObject.getStackAbility(), game); - } - } else { - Player controller = game.getPlayer(source.getControllerId()); - boolean validTargets = false; - do { - for (Target target : targets) { - for (UUID targetId : target.getTargets()) { - String name = getTargetName(targets.getFirstTarget(), game); - 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 (target.canTarget(stackObject.getControllerId(), source.getSourceId(), sourceAbility, game)) { - validTargets = true; - if (name != null - && controller.chooseUse(Outcome.Neutral, "Change target from " + name + " to " + sourceObject.getLogName() + "?", source, game)) { - oldTargetName = getTargetName(targetId, game); - target.remove(targetId); - // The source is still the spell on the stack - target.addTarget(source.getSourceId(), stackObject.getStackAbility(), game); - break; - } - } - } - if (oldTargetName != null) { - break; - } - } - if (oldTargetName == null) { - game.informPlayer(controller, "You have to select at least one target to change to spellskite!"); - } - } while (validTargets && oldTargetName == null); - } - if (oldTargetName != null) { - game.informPlayers(sourceObject.getLogName() + ": Changed target of " + stackObject.getLogName() + " from " + oldTargetName + " 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.getLogName()); - } else { - game.informPlayers(sourceObject.getLogName() + ": Target not changed to " + sourceObject.getLogName() + " because its no valid target for " + stackObject.getLogName()); - } - } - return true; - } - return false; - } - - @Override - public SpellskiteEffect copy() { - return new SpellskiteEffect(this); - } - - private String getTargetName(UUID objectId, Game game) { - MageObject object = game.getObject(objectId); - if (object != null) { - return object.getLogName(); - } - Player player = game.getPlayer(objectId); - if (player != null) { - return player.getLogName(); - } - return null; - } -} diff --git a/Mage/src/mage/abilities/effects/common/ChangeATargetOfTargetSpellAbilityToSourceEffect.java b/Mage/src/mage/abilities/effects/common/ChangeATargetOfTargetSpellAbilityToSourceEffect.java new file mode 100644 index 00000000000..e660cd19671 --- /dev/null +++ b/Mage/src/mage/abilities/effects/common/ChangeATargetOfTargetSpellAbilityToSourceEffect.java @@ -0,0 +1,130 @@ +/* + * To change this license header, choose License Headers in Project Properties. + * To change this template file, choose Tools | Templates + * and open the template in the editor. + */ +package mage.abilities.effects.common; + +import java.util.UUID; +import mage.MageObject; +import mage.abilities.Ability; +import mage.abilities.effects.OneShotEffect; +import mage.constants.Outcome; +import mage.game.Game; +import mage.game.stack.Spell; +import mage.game.stack.StackAbility; +import mage.game.stack.StackObject; +import mage.players.Player; +import mage.target.Target; +import mage.target.Targets; + +/** + * + * @author LevelX2 + */ +public class ChangeATargetOfTargetSpellAbilityToSourceEffect extends OneShotEffect { + + public ChangeATargetOfTargetSpellAbilityToSourceEffect() { + super(Outcome.Neutral); + staticText = "Change a target of target spell or ability to {this}"; + } + + public ChangeATargetOfTargetSpellAbilityToSourceEffect(final ChangeATargetOfTargetSpellAbilityToSourceEffect effect) { + super(effect); + } + + @Override + public boolean apply(Game game, Ability source) { + StackObject stackObject = game.getStack().getStackObject(source.getFirstTarget()); + MageObject sourceObject = game.getObject(source.getSourceId()); + if (stackObject != null && sourceObject != null) { + Targets targets = new Targets(); + Ability sourceAbility; + String oldTargetName = null; + if (stackObject instanceof Spell) { + Spell spell = (Spell) stackObject; + sourceAbility = spell.getSpellAbility(); + } else if (stackObject instanceof StackAbility) { + StackAbility stackAbility = (StackAbility) stackObject; + sourceAbility = stackAbility; + } 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); + if (target.canTarget(stackObject.getControllerId(), source.getSourceId(), sourceAbility, game)) { + oldTargetName = getTargetName(targets.getFirstTarget(), game); + target.clearChosen(); + // The source is still the spell on the stack + target.addTarget(source.getSourceId(), stackObject.getStackAbility(), game); + } + } else { + Player controller = game.getPlayer(source.getControllerId()); + boolean validTargets = false; + do { + for (Target target : targets) { + for (UUID targetId : target.getTargets()) { + String name = getTargetName(targets.getFirstTarget(), game); + if (!targetId.equals(source.getSourceId()) && target.getTargets().contains(source.getSourceId())) { + // you can't change this target to source because the source is already another targetId of that target. + twoTimesTarget = true; + continue; + } + if (target.canTarget(stackObject.getControllerId(), source.getSourceId(), sourceAbility, game)) { + validTargets = true; + if (name != null + && controller.chooseUse(Outcome.Neutral, "Change target from " + name + " to " + sourceObject.getLogName() + "?", source, game)) { + oldTargetName = getTargetName(targetId, game); + target.remove(targetId); + // The source is still the spell on the stack + target.addTarget(source.getSourceId(), stackObject.getStackAbility(), game); + break; + } + } + } + if (oldTargetName != null) { + break; + } + } + if (oldTargetName == null) { + game.informPlayer(controller, "You have to select at least one target to change to " + sourceObject.getIdName() + "!"); + } + } while (validTargets && oldTargetName == null); + } + if (oldTargetName != null) { + game.informPlayers(sourceObject.getLogName() + ": Changed target of " + stackObject.getLogName() + " from " + oldTargetName + " 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.getLogName()); + } else { + game.informPlayers(sourceObject.getLogName() + ": Target not changed to " + sourceObject.getLogName() + " because its no valid target for " + stackObject.getLogName()); + } + } + return true; + } + return false; + } + + @Override + public ChangeATargetOfTargetSpellAbilityToSourceEffect copy() { + return new ChangeATargetOfTargetSpellAbilityToSourceEffect(this); + } + + private String getTargetName(UUID objectId, Game game) { + MageObject object = game.getObject(objectId); + if (object != null) { + return object.getLogName(); + } + Player player = game.getPlayer(objectId); + if (player != null) { + return player.getLogName(); + } + return null; + } +} From bdbfe633d58b66156de7c4e978e178caca061bf9 Mon Sep 17 00:00:00 2001 From: Jeff Date: Fri, 9 Oct 2015 14:13:59 -0500 Subject: [PATCH 058/268] - Fixed text Nim Abomination. --- .../mage/sets/darksteel/NimAbomination.java | 33 ++++++++++++++++--- 1 file changed, 29 insertions(+), 4 deletions(-) diff --git a/Mage.Sets/src/mage/sets/darksteel/NimAbomination.java b/Mage.Sets/src/mage/sets/darksteel/NimAbomination.java index d13bc0e2504..23c0aa159ef 100644 --- a/Mage.Sets/src/mage/sets/darksteel/NimAbomination.java +++ b/Mage.Sets/src/mage/sets/darksteel/NimAbomination.java @@ -29,20 +29,22 @@ package mage.sets.darksteel; import java.util.UUID; import mage.MageInt; +import mage.abilities.Ability; import mage.abilities.common.BeginningOfEndStepTriggeredAbility; -import mage.abilities.condition.InvertCondition; -import mage.abilities.condition.common.SourceTappedCondition; +import mage.abilities.condition.Condition; import mage.abilities.effects.common.LoseLifeSourceControllerEffect; import mage.cards.CardImpl; import mage.constants.CardType; import mage.constants.Rarity; import mage.constants.TargetController; import mage.constants.Zone; +import mage.game.Game; +import mage.game.permanent.Permanent; /** * * @author LoneFox - + * */ public class NimAbomination extends CardImpl { @@ -55,7 +57,7 @@ public class NimAbomination extends CardImpl { // At the beginning of your end step, if Nim Abomination is untapped, you lose 3 life. this.addAbility(new BeginningOfEndStepTriggeredAbility(Zone.BATTLEFIELD, new LoseLifeSourceControllerEffect(3), - TargetController.YOU, new InvertCondition(new SourceTappedCondition()), false)); + TargetController.YOU, new SourceUntappedCondition(), false)); } public NimAbomination(final NimAbomination card) { @@ -67,3 +69,26 @@ public class NimAbomination extends CardImpl { return new NimAbomination(this); } } + +class SourceUntappedCondition implements Condition { + + private static final SourceUntappedCondition fInstance = new SourceUntappedCondition(); + + public static SourceUntappedCondition getInstance() { + return fInstance; + } + + @Override + public boolean apply(Game game, Ability source) { + Permanent permanent = game.getBattlefield().getPermanent(source.getSourceId()); + if (permanent != null) { + return !permanent.isTapped(); + } + return false; + } + + @Override + public String toString() { + return "if {this} is untapped"; + } +} From 62ab3758e9e37041855fd341cf9d2c67914f4a21 Mon Sep 17 00:00:00 2001 From: LoneFox Date: Fri, 9 Oct 2015 22:15:53 +0300 Subject: [PATCH 059/268] Fix Land Cap's card number --- Mage.Sets/src/mage/sets/iceage/LandCap.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Mage.Sets/src/mage/sets/iceage/LandCap.java b/Mage.Sets/src/mage/sets/iceage/LandCap.java index ebb3dcb35f5..c430a5be249 100644 --- a/Mage.Sets/src/mage/sets/iceage/LandCap.java +++ b/Mage.Sets/src/mage/sets/iceage/LandCap.java @@ -55,7 +55,7 @@ import mage.counters.CounterType; public class LandCap extends CardImpl { public LandCap(UUID ownerId) { - super(ownerId, 319, "Land Cap", Rarity.RARE, new CardType[]{CardType.LAND}, ""); + super(ownerId, 338, "Land Cap", Rarity.RARE, new CardType[]{CardType.LAND}, ""); this.expansionSetCode = "ICE"; // Land Cap doesn't untap during your untap step if it has a depletion counter on it. From 8b8097878cb1234a27c90cb8c619e310747dfae3 Mon Sep 17 00:00:00 2001 From: LevelX2 Date: Sun, 11 Oct 2015 03:52:38 +0200 Subject: [PATCH 060/268] * Reworked/Cleaned card movement handling. --- .../src/mage/player/ai/ComputerPlayer6.java | 21 +- .../avacynrestored/InfiniteReflection.java | 24 +- .../sets/dragonsmaze/PossibilityStorm.java | 1 - .../mage/sets/fifthdawn/MycosynthGolem.java | 36 ++- .../mage/sets/gatecrash/ThespiansStage.java | 11 +- .../sets/guildpact/MizziumTransreliquat.java | 14 +- .../sets/journeyintonyx/PolymorphousRush.java | 15 +- .../mage/sets/judgment/WorldgorgerDragon.java | 4 +- .../mage/sets/limitedalpha/CopyArtifact.java | 6 +- .../src/mage/sets/lorwyn/Shapesharer.java | 14 +- Mage.Sets/src/mage/sets/magic2012/Flight.java | 15 +- .../mage/sets/magic2012/PhantasmalImage.java | 6 +- .../sets/magic2015/MercurialPretender.java | 7 +- .../sets/mirrodinbesieged/KnowledgePool.java | 7 +- .../sets/newphyrexia/PhyrexianMetamorph.java | 2 +- .../sets/planeshift/SkyshipWeatherlight.java | 2 +- .../RenegadeDoppelganger.java | 3 +- .../SakashimaTheImpostor.java | 6 +- .../mage/sets/shadowmoor/CemeteryPuca.java | 2 +- .../sets/shadowmoor/LureboundScarecrow.java | 42 +--- .../src/mage/sets/shadowmoor/Mirrorweave.java | 3 +- .../sets/shardsofalara/TidehollowSculler.java | 2 +- .../mage/sets/tempest/RootwaterMatriarch.java | 12 +- .../sets/theros/AshiokNightmareWeaver.java | 21 +- .../unlimitededition/VesuvanDoppelganger.java | 2 +- .../abilities/enters/ProteanHydraTest.java | 5 +- .../abilities/other/MycosynthGolemTest.java | 4 +- .../other/SoulfireGrandMasterTest.java | 6 +- .../conditional/RootwaterMatriarchTest.java | 46 ++-- .../test/cards/copy/PhantasmalImageTest.java | 107 ++++----- .../cards/copy/PhyrexianMetamorphTest.java | 117 +++++++--- .../java/org/mage/test/player/TestPlayer.java | 7 +- .../base/impl/CardTestPlayerAPIImpl.java | 2 +- .../common/DiesAttachedTriggeredAbility.java | 2 +- .../common/EnchantedTargetCondition.java | 6 +- .../effects/AuraReplacementEffect.java | 98 ++++---- .../abilities/effects/ContinuousEffects.java | 6 +- .../effects/ContinuousEffectsList.java | 81 +++---- .../effects/EntersBattlefieldEffect.java | 68 +++--- .../effects/common/CopyPermanentEffect.java | 18 +- .../CounterTargetWithReplacementEffect.java | 31 +-- Mage/src/mage/cards/Card.java | 5 + Mage/src/mage/cards/CardImpl.java | 214 ++++++------------ Mage/src/mage/game/CardState.java | 35 +-- Mage/src/mage/game/Game.java | 6 +- Mage/src/mage/game/GameImpl.java | 27 ++- Mage/src/mage/game/GameState.java | 2 +- .../mage/game/permanent/PermanentCard.java | 79 ++++--- Mage/src/mage/game/stack/Spell.java | 20 +- Mage/src/mage/game/stack/SpellStack.java | 14 +- Mage/src/mage/game/stack/StackAbility.java | 5 +- Mage/src/mage/players/Player.java | 14 ++ Mage/src/mage/players/PlayerImpl.java | 81 ++++++- Mage/src/mage/util/CardUtil.java | 17 -- 54 files changed, 714 insertions(+), 687 deletions(-) diff --git a/Mage.Server.Plugins/Mage.Player.AI.MA/src/mage/player/ai/ComputerPlayer6.java b/Mage.Server.Plugins/Mage.Player.AI.MA/src/mage/player/ai/ComputerPlayer6.java index 66fc062f4d7..022e7f9ee30 100644 --- a/Mage.Server.Plugins/Mage.Player.AI.MA/src/mage/player/ai/ComputerPlayer6.java +++ b/Mage.Server.Plugins/Mage.Player.AI.MA/src/mage/player/ai/ComputerPlayer6.java @@ -436,29 +436,32 @@ public class ComputerPlayer6 extends ComputerPlayer /*implements Player*/ { } protected void resolve(SimulationNode2 node, int depth, Game game) { - StackObject ability = game.getStack().pop(); - if (ability instanceof StackAbility) { - SearchEffect effect = getSearchEffect((StackAbility) ability); - if (effect != null && ability.getControllerId().equals(playerId)) { + StackObject stackObject = game.getStack().getFirst(); + if (stackObject instanceof StackAbility) { + SearchEffect effect = getSearchEffect((StackAbility) stackObject); + if (effect != null && stackObject.getControllerId().equals(playerId)) { Target target = effect.getTarget(); if (!target.doneChosing()) { - for (UUID targetId : target.possibleTargets(ability.getSourceId(), ability.getControllerId(), game)) { + for (UUID targetId : target.possibleTargets(stackObject.getSourceId(), stackObject.getControllerId(), game)) { Game sim = game.copy(); - StackAbility newAbility = (StackAbility) ability.copy(); + StackAbility newAbility = (StackAbility) stackObject.copy(); SearchEffect newEffect = getSearchEffect(newAbility); newEffect.getTarget().addTarget(targetId, newAbility, sim); sim.getStack().push(newAbility); - SimulationNode2 newNode = new SimulationNode2(node, sim, depth, ability.getControllerId()); + SimulationNode2 newNode = new SimulationNode2(node, sim, depth, stackObject.getControllerId()); node.children.add(newNode); newNode.getTargets().add(targetId); - logger.trace("Sim search -- node#: " + SimulationNode2.getCount() + " for player: " + sim.getPlayer(ability.getControllerId()).getName()); + logger.trace("Sim search -- node#: " + SimulationNode2.getCount() + " for player: " + sim.getPlayer(stackObject.getControllerId()).getName()); } return; } } } //logger.info("simulating resolve "); - ability.resolve(game); + stackObject.resolve(game); + if (stackObject instanceof StackAbility) { + game.getStack().remove(stackObject); + } game.applyEffects(); game.getPlayers().resetPassed(); game.getPlayerList().setCurrent(game.getActivePlayerId()); diff --git a/Mage.Sets/src/mage/sets/avacynrestored/InfiniteReflection.java b/Mage.Sets/src/mage/sets/avacynrestored/InfiniteReflection.java index 3f79caf503d..1744100e918 100644 --- a/Mage.Sets/src/mage/sets/avacynrestored/InfiniteReflection.java +++ b/Mage.Sets/src/mage/sets/avacynrestored/InfiniteReflection.java @@ -27,7 +27,8 @@ */ package mage.sets.avacynrestored; -import mage.constants.*; +import java.util.UUID; +import mage.MageObject; import mage.abilities.Ability; import mage.abilities.Mode; import mage.abilities.common.EntersBattlefieldTriggeredAbility; @@ -37,6 +38,11 @@ import mage.abilities.effects.ReplacementEffectImpl; import mage.abilities.effects.common.AttachEffect; import mage.abilities.keyword.EnchantAbility; import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.Outcome; +import mage.constants.Rarity; +import mage.constants.Zone; import mage.filter.FilterPermanent; import mage.filter.common.FilterControlledCreaturePermanent; import mage.game.Game; @@ -47,8 +53,6 @@ import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; import mage.util.functions.EmptyApplyToPermanent; -import java.util.UUID; - /** * * @author noxx @@ -60,7 +64,6 @@ public class InfiniteReflection extends CardImpl { this.expansionSetCode = "AVR"; this.subtype.add("Aura"); - // Enchant creature TargetPermanent auraTarget = new TargetCreaturePermanent(); this.getSpellAbility().addTarget(auraTarget); @@ -109,9 +112,9 @@ class InfiniteReflectionTriggeredEffect extends OneShotEffect { if (sourcePermanent != null && sourcePermanent.getAttachedTo() != null) { Permanent toCopyFromPermanent = game.getPermanent(sourcePermanent.getAttachedTo()); if (toCopyFromPermanent != null) { - for (Permanent toCopyToPermanent: game.getBattlefield().getAllActivePermanents(filter, source.getControllerId(), game)) { + for (Permanent toCopyToPermanent : game.getBattlefield().getAllActivePermanents(filter, source.getControllerId(), game)) { if (!toCopyToPermanent.equals(toCopyFromPermanent) && !(toCopyToPermanent instanceof PermanentToken)) { - game.copyPermanent(toCopyFromPermanent, toCopyToPermanent, source, new EmptyApplyToPermanent()); + game.copyPermanent(toCopyFromPermanent, toCopyToPermanent.getId(), source, new EmptyApplyToPermanent()); } } return true; @@ -135,7 +138,7 @@ class InfiniteReflectionEntersBattlefieldEffect extends ReplacementEffectImpl { public boolean checksEventType(GameEvent event, Game game) { return event.getType() == GameEvent.EventType.ENTERS_THE_BATTLEFIELD; } - + @Override public boolean applies(GameEvent event, Ability source, Game game) { Permanent permanent = game.getPermanent(event.getTargetId()); @@ -144,15 +147,14 @@ class InfiniteReflectionEntersBattlefieldEffect extends ReplacementEffectImpl { && !(permanent instanceof PermanentToken); } - @Override public boolean replaceEvent(GameEvent event, Ability source, Game game) { - Permanent toCopyToPermanent = game.getPermanent(event.getTargetId()); + MageObject toCopyToObject = game.getObject(event.getTargetId()); Permanent sourcePermanent = game.getPermanent(source.getSourceId()); - if (sourcePermanent != null && toCopyToPermanent != null && sourcePermanent.getAttachedTo() != null) { + if (sourcePermanent != null && toCopyToObject != null && sourcePermanent.getAttachedTo() != null) { Permanent toCopyFromPermanent = game.getPermanent(sourcePermanent.getAttachedTo()); if (toCopyFromPermanent != null) { - game.copyPermanent(toCopyFromPermanent, toCopyToPermanent, source, new EmptyApplyToPermanent()); + game.copyPermanent(toCopyFromPermanent, toCopyToObject.getId(), source, new EmptyApplyToPermanent()); } } return false; diff --git a/Mage.Sets/src/mage/sets/dragonsmaze/PossibilityStorm.java b/Mage.Sets/src/mage/sets/dragonsmaze/PossibilityStorm.java index 1c6e13edb20..392679db64c 100644 --- a/Mage.Sets/src/mage/sets/dragonsmaze/PossibilityStorm.java +++ b/Mage.Sets/src/mage/sets/dragonsmaze/PossibilityStorm.java @@ -157,7 +157,6 @@ class PossibilityStormEffect extends OneShotEffect { if (exile != null) { while (exile.size() > 0) { card = exile.getRandom(game); - exile.remove(card.getId()); spellController.moveCardToLibraryWithInfo(card, source.getSourceId(), game, Zone.EXILED, false, false); } } diff --git a/Mage.Sets/src/mage/sets/fifthdawn/MycosynthGolem.java b/Mage.Sets/src/mage/sets/fifthdawn/MycosynthGolem.java index 084fbf7fc3e..ea343a1c7cf 100644 --- a/Mage.Sets/src/mage/sets/fifthdawn/MycosynthGolem.java +++ b/Mage.Sets/src/mage/sets/fifthdawn/MycosynthGolem.java @@ -54,14 +54,7 @@ import mage.players.Player; * @author jeffwadsworth */ public class MycosynthGolem extends CardImpl { - - private static final FilterSpell filter = new FilterSpell("Artifact creature spells you cast"); - static { - filter.add(new CardTypePredicate(CardType.ARTIFACT)); - filter.add(new CardTypePredicate(CardType.CREATURE)); - } - public MycosynthGolem(UUID ownerId) { super(ownerId, 137, "Mycosynth Golem", Rarity.RARE, new CardType[]{CardType.ARTIFACT, CardType.CREATURE}, "{11}"); this.expansionSetCode = "5DN"; @@ -75,8 +68,8 @@ public class MycosynthGolem extends CardImpl { // Artifact creature spells you cast have affinity for artifacts. this.addAbility(new SimpleStaticAbility( - Zone.BATTLEFIELD, new MycosynthGolemGainAbilitySpellsEffect(new AffinityForArtifactsAbility(), filter))); - + Zone.BATTLEFIELD, new MycosynthGolemGainAbilitySpellsEffect())); + } public MycosynthGolem(final MycosynthGolem card) { @@ -91,20 +84,21 @@ public class MycosynthGolem extends CardImpl { class MycosynthGolemGainAbilitySpellsEffect extends ContinuousEffectImpl { - private final Ability ability; - private final FilterSpell filter; + private static final FilterSpell filter = new FilterSpell("Artifact creature spells you cast"); + private static final Ability ability = new AffinityForArtifactsAbility(); - public MycosynthGolemGainAbilitySpellsEffect(Ability ability, FilterSpell filter) { + static { + filter.add(new CardTypePredicate(CardType.ARTIFACT)); + filter.add(new CardTypePredicate(CardType.CREATURE)); + } + + public MycosynthGolemGainAbilitySpellsEffect() { super(Duration.WhileOnBattlefield, Layer.AbilityAddingRemovingEffects_6, SubLayer.NA, Outcome.AddAbility); - this.ability = ability; - this.filter = filter; - staticText = filter.getMessage() + " have " + ability.getRule(); + staticText = "Artifact creature spells you cast have affinity for artifacts"; } public MycosynthGolemGainAbilitySpellsEffect(final MycosynthGolemGainAbilitySpellsEffect effect) { super(effect); - this.ability = effect.ability; - this.filter = effect.filter; } @Override @@ -114,17 +108,15 @@ class MycosynthGolemGainAbilitySpellsEffect extends ContinuousEffectImpl { @Override public boolean apply(Game game, Ability source) { - Player player = game.getPlayer(source.getControllerId()); + Player controller = game.getPlayer(source.getControllerId()); Permanent permanent = game.getPermanent(source.getSourceId()); - if (player != null && permanent != null) { + if (controller != null && permanent != null) { for (StackObject stackObject : game.getStack()) { // only spells cast, so no copies of spells if ((stackObject instanceof Spell) && !stackObject.isCopy() && stackObject.getControllerId().equals(source.getControllerId())) { Spell spell = (Spell) stackObject; if (filter.match(spell, game)) { - if (!spell.getAbilities().contains(ability)) { - game.getState().addOtherAbility(spell.getCard(), ability); - } + game.getState().addOtherAbility(spell.getCard(), ability); } } } diff --git a/Mage.Sets/src/mage/sets/gatecrash/ThespiansStage.java b/Mage.Sets/src/mage/sets/gatecrash/ThespiansStage.java index fa629410a65..8fc75c855c8 100644 --- a/Mage.Sets/src/mage/sets/gatecrash/ThespiansStage.java +++ b/Mage.Sets/src/mage/sets/gatecrash/ThespiansStage.java @@ -28,10 +28,6 @@ package mage.sets.gatecrash; import java.util.UUID; - -import mage.constants.CardType; -import mage.constants.Outcome; -import mage.constants.Rarity; import mage.abilities.Ability; import mage.abilities.common.SimpleActivatedAbility; import mage.abilities.costs.common.TapSourceCost; @@ -39,6 +35,9 @@ import mage.abilities.costs.mana.GenericManaCost; import mage.abilities.effects.OneShotEffect; import mage.abilities.mana.ColorlessManaAbility; import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.Outcome; +import mage.constants.Rarity; import mage.constants.Zone; import mage.game.Game; import mage.game.permanent.Permanent; @@ -80,7 +79,7 @@ class ThespiansStageCopyEffect extends OneShotEffect { public ThespiansStageCopyEffect() { super(Outcome.Benefit); - this.staticText = "Thespian's Stage becomes a copy of target land and gains this ability"; + this.staticText = "{this} becomes a copy of target land and gains this ability"; } public ThespiansStageCopyEffect(final ThespiansStageCopyEffect effect) { @@ -97,7 +96,7 @@ class ThespiansStageCopyEffect extends OneShotEffect { Permanent sourcePermanent = game.getPermanent(source.getSourceId()); Permanent copyFromPermanent = game.getPermanent(getTargetPointer().getFirst(game, source)); if (sourcePermanent != null && copyFromPermanent != null) { - Permanent newPermanent = game.copyPermanent(copyFromPermanent, sourcePermanent, source, new EmptyApplyToPermanent()); + Permanent newPermanent = game.copyPermanent(copyFromPermanent, sourcePermanent.getId(), source, new EmptyApplyToPermanent()); Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new ThespiansStageCopyEffect(), new GenericManaCost(2)); ability.addCost(new TapSourceCost()); ability.addTarget(new TargetLandPermanent()); diff --git a/Mage.Sets/src/mage/sets/guildpact/MizziumTransreliquat.java b/Mage.Sets/src/mage/sets/guildpact/MizziumTransreliquat.java index c1c75827a9b..36802080cdc 100644 --- a/Mage.Sets/src/mage/sets/guildpact/MizziumTransreliquat.java +++ b/Mage.Sets/src/mage/sets/guildpact/MizziumTransreliquat.java @@ -57,7 +57,7 @@ public class MizziumTransreliquat extends CardImpl { Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new MizziumTransreliquatCopyEffect(), new ManaCostsImpl("{3}")); ability.addTarget(new TargetArtifactPermanent()); this.addAbility(ability); - + // {1}{U}{R}: Mizzium Transreliquat becomes a copy of target artifact and gains this ability. ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new MizziumTransreliquatCopyAndGainAbilityEffect(), new ManaCostsImpl("{1}{U}{R}")); ability.addTarget(new TargetArtifactPermanent()); @@ -74,12 +74,11 @@ public class MizziumTransreliquat extends CardImpl { } } - class MizziumTransreliquatCopyEffect extends OneShotEffect { public MizziumTransreliquatCopyEffect() { super(Outcome.Copy); - this.staticText = "Mizzium Transreliquat becomes a copy of target artifact until end of turn"; + this.staticText = "{this} becomes a copy of target artifact until end of turn"; } public MizziumTransreliquatCopyEffect(final MizziumTransreliquatCopyEffect effect) { @@ -96,17 +95,18 @@ class MizziumTransreliquatCopyEffect extends OneShotEffect { Permanent sourcePermanent = game.getPermanent(source.getSourceId()); Permanent copyFromPermanent = game.getPermanent(getTargetPointer().getFirst(game, source)); if (sourcePermanent != null && copyFromPermanent != null) { - game.copyPermanent(Duration.EndOfTurn, copyFromPermanent, sourcePermanent, source, new EmptyApplyToPermanent()); + game.copyPermanent(Duration.EndOfTurn, copyFromPermanent, sourcePermanent.getId(), source, new EmptyApplyToPermanent()); return true; } return false; } } + class MizziumTransreliquatCopyAndGainAbilityEffect extends OneShotEffect { public MizziumTransreliquatCopyAndGainAbilityEffect() { super(Outcome.Benefit); - this.staticText = "Mizzium Transreliquat becomes a copy of target artifact and gains this ability"; + this.staticText = "{this} becomes a copy of target artifact and gains this ability"; } public MizziumTransreliquatCopyAndGainAbilityEffect(final MizziumTransreliquatCopyAndGainAbilityEffect effect) { @@ -123,7 +123,7 @@ class MizziumTransreliquatCopyAndGainAbilityEffect extends OneShotEffect { Permanent sourcePermanent = game.getPermanent(source.getSourceId()); Permanent copyFromPermanent = game.getPermanent(getTargetPointer().getFirst(game, source)); if (sourcePermanent != null && copyFromPermanent != null) { - Permanent newPermanent = game.copyPermanent(copyFromPermanent, sourcePermanent, source, new EmptyApplyToPermanent()); + Permanent newPermanent = game.copyPermanent(copyFromPermanent, sourcePermanent.getId(), source, new EmptyApplyToPermanent()); Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new MizziumTransreliquatCopyAndGainAbilityEffect(), new ManaCostsImpl("{1}{U}{R}")); ability.addTarget(new TargetArtifactPermanent()); newPermanent.addAbility(ability, source.getSourceId(), game); @@ -131,4 +131,4 @@ class MizziumTransreliquatCopyAndGainAbilityEffect extends OneShotEffect { } return false; } -} \ No newline at end of file +} diff --git a/Mage.Sets/src/mage/sets/journeyintonyx/PolymorphousRush.java b/Mage.Sets/src/mage/sets/journeyintonyx/PolymorphousRush.java index fe4506ed668..333cbdde27e 100644 --- a/Mage.Sets/src/mage/sets/journeyintonyx/PolymorphousRush.java +++ b/Mage.Sets/src/mage/sets/journeyintonyx/PolymorphousRush.java @@ -64,7 +64,7 @@ public class PolymorphousRush extends CardImpl { // Strive - Polymorphous Rush costs {1}{U} more to cast for each target beyond the first. this.addAbility(new StriveAbility("{1}{U}")); - + // Choose a creature on the battlefield. Any number of target creatures you control each become a copy of that creature until end of turn. this.getSpellAbility().addTarget(new TargetCreaturePermanent(0, Integer.MAX_VALUE, filter, false)); this.getSpellAbility().addEffect(new PolymorphousRushCopyEffect()); @@ -82,21 +82,21 @@ public class PolymorphousRush extends CardImpl { } class PolymorphousRushCopyEffect extends OneShotEffect { - + public PolymorphousRushCopyEffect() { super(Outcome.Copy); this.staticText = "Choose a creature on the battlefield. Any number of target creatures you control each become a copy of that creature until end of turn"; } - + public PolymorphousRushCopyEffect(final PolymorphousRushCopyEffect effect) { super(effect); } - + @Override public PolymorphousRushCopyEffect copy() { return new PolymorphousRushCopyEffect(this); } - + @Override public boolean apply(Game game, Ability source) { Player controller = game.getPlayer(source.getControllerId()); @@ -107,10 +107,10 @@ class PolymorphousRushCopyEffect extends OneShotEffect { if (target.canChoose(source.getId(), controller.getId(), game) && controller.chooseTarget(outcome, target, source, game)) { Permanent copyFromCreature = game.getPermanent(target.getFirstTarget()); if (copyFromCreature != null) { - for (UUID copyToId: getTargetPointer().getTargets(game, source)) { + for (UUID copyToId : getTargetPointer().getTargets(game, source)) { Permanent copyToCreature = game.getPermanent(copyToId); if (copyToCreature != null) { - game.copyPermanent(Duration.EndOfTurn, copyFromCreature, copyToCreature, source, new EmptyApplyToPermanent()); + game.copyPermanent(Duration.EndOfTurn, copyFromCreature, copyToId, source, new EmptyApplyToPermanent()); } } } @@ -119,4 +119,5 @@ class PolymorphousRushCopyEffect extends OneShotEffect { } return false; } + } diff --git a/Mage.Sets/src/mage/sets/judgment/WorldgorgerDragon.java b/Mage.Sets/src/mage/sets/judgment/WorldgorgerDragon.java index 03ba405c9dd..ea74b1f8925 100644 --- a/Mage.Sets/src/mage/sets/judgment/WorldgorgerDragon.java +++ b/Mage.Sets/src/mage/sets/judgment/WorldgorgerDragon.java @@ -110,7 +110,7 @@ class WorldgorgerDragonEntersEffect extends OneShotEffect { Player controller = game.getPlayer(source.getControllerId()); MageObject sourceObject = source.getSourceObject(game); if (controller != null) { - UUID exileId = CardUtil.getObjectExileZoneId(game, sourceObject); + UUID exileId = CardUtil.getExileZoneId(game, source.getSourceId(), source.getSourceObjectZoneChangeCounter()); if (exileId != null) { for (Permanent permanent : game.getBattlefield().getAllActivePermanents(filter, source.getControllerId(), game)) { if (!permanent.getId().equals(source.getSourceId())) { // Another @@ -145,7 +145,7 @@ class WorldgorgerDragonLeavesEffect extends OneShotEffect { Player controller = game.getPlayer(source.getControllerId()); MageObject sourceObject = source.getSourceObject(game); if (controller != null && sourceObject != null) { - int zoneChangeCounter = (sourceObject instanceof PermanentToken) ? source.getSourceObjectZoneChangeCounter() : source.getSourceObjectZoneChangeCounter() -1; + int zoneChangeCounter = (sourceObject instanceof PermanentToken) ? source.getSourceObjectZoneChangeCounter() : source.getSourceObjectZoneChangeCounter() - 1; ExileZone exile = game.getExile().getExileZone(CardUtil.getExileZoneId(game, source.getSourceId(), zoneChangeCounter)); if (exile != null) { exile = exile.copy(); diff --git a/Mage.Sets/src/mage/sets/limitedalpha/CopyArtifact.java b/Mage.Sets/src/mage/sets/limitedalpha/CopyArtifact.java index ec4ca9b5e08..b1a99b0e249 100644 --- a/Mage.Sets/src/mage/sets/limitedalpha/CopyArtifact.java +++ b/Mage.Sets/src/mage/sets/limitedalpha/CopyArtifact.java @@ -114,15 +114,15 @@ class CopyArtifactEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { Player player = game.getPlayer(source.getControllerId()); - Permanent sourcePermanent = game.getPermanent(source.getSourceId()); - if (player != null && sourcePermanent != null) { + MageObject sourceObject = game.getObject(source.getSourceId()); + if (player != null && sourceObject != null) { Target target = new TargetPermanent(filter); target.setNotTarget(true); if (target.canChoose(source.getControllerId(), game)) { player.choose(Outcome.Copy, target, source.getSourceId(), game); Permanent copyFromPermanent = game.getPermanent(target.getFirstTarget()); if (copyFromPermanent != null) { - game.copyPermanent(copyFromPermanent, sourcePermanent, source, applier); + game.copyPermanent(copyFromPermanent, sourceObject.getId(), source, applier); return true; } } diff --git a/Mage.Sets/src/mage/sets/lorwyn/Shapesharer.java b/Mage.Sets/src/mage/sets/lorwyn/Shapesharer.java index 8cd1d570573..8f49981b4a3 100644 --- a/Mage.Sets/src/mage/sets/lorwyn/Shapesharer.java +++ b/Mage.Sets/src/mage/sets/lorwyn/Shapesharer.java @@ -48,7 +48,6 @@ import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; import mage.util.functions.EmptyApplyToPermanent; - /** * @author duncant */ @@ -68,11 +67,11 @@ public class Shapesharer extends CardImpl { this.power = new MageInt(1); this.toughness = new MageInt(1); this.addAbility(ChangelingAbility.getInstance()); - + // {2}{U}: Target Shapeshifter becomes a copy of target creature until your next turn. Ability copyAbility = new SimpleActivatedAbility(Zone.BATTLEFIELD, - new ShapesharerEffect(), - new ManaCostsImpl("{2}{U}")); + new ShapesharerEffect(), + new ManaCostsImpl("{2}{U}")); copyAbility.addTarget(new TargetPermanent(filterShapeshifter)); copyAbility.addTarget(new TargetCreaturePermanent()); this.addAbility(copyAbility); @@ -89,6 +88,7 @@ public class Shapesharer extends CardImpl { } class ShapesharerEffect extends OneShotEffect { + public ShapesharerEffect() { super(Outcome.Copy); this.staticText = "Target Shapeshifter becomes a copy of target creature until your next turn."; @@ -105,10 +105,12 @@ class ShapesharerEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability ability) { - Permanent copyTo = game.getPermanent(ability.getFirstTarget()); + Permanent copyTo = game.getPermanent(getTargetPointer().getFirst(game, ability)); if (copyTo != null) { Permanent copyFrom = game.getPermanentOrLKIBattlefield(ability.getTargets().get(1).getFirstTarget()); - game.copyPermanent(Duration.EndOfTurn, copyFrom, copyTo, ability, new EmptyApplyToPermanent()); + if (copyFrom != null) { + game.copyPermanent(Duration.EndOfTurn, copyFrom, copyTo.getId(), ability, new EmptyApplyToPermanent()); + } } return true; } diff --git a/Mage.Sets/src/mage/sets/magic2012/Flight.java b/Mage.Sets/src/mage/sets/magic2012/Flight.java index 198a3e6a8a5..0848e527c9c 100644 --- a/Mage.Sets/src/mage/sets/magic2012/Flight.java +++ b/Mage.Sets/src/mage/sets/magic2012/Flight.java @@ -25,12 +25,9 @@ * authors and should not be interpreted as representing official policies, either expressed * or implied, of BetaSteward_at_googlemail.com. */ - package mage.sets.magic2012; import java.util.UUID; - -import mage.constants.*; import mage.abilities.Ability; import mage.abilities.common.SimpleStaticAbility; import mage.abilities.effects.common.AttachEffect; @@ -38,6 +35,11 @@ import mage.abilities.effects.common.continuous.GainAbilityAttachedEffect; import mage.abilities.keyword.EnchantAbility; import mage.abilities.keyword.FlyingAbility; import mage.cards.CardImpl; +import mage.constants.AttachmentType; +import mage.constants.CardType; +import mage.constants.Outcome; +import mage.constants.Rarity; +import mage.constants.Zone; import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; @@ -47,20 +49,23 @@ import mage.target.common.TargetCreaturePermanent; */ public class Flight extends CardImpl { - public Flight (UUID ownerId) { + public Flight(UUID ownerId) { super(ownerId, 53, "Flight", Rarity.COMMON, new CardType[]{CardType.ENCHANTMENT}, "{U}"); this.expansionSetCode = "M12"; this.subtype.add("Aura"); + // Enchant creature TargetPermanent auraTarget = new TargetCreaturePermanent(); this.getSpellAbility().addTarget(auraTarget); this.getSpellAbility().addEffect(new AttachEffect(Outcome.AddAbility)); Ability ability = new EnchantAbility(auraTarget.getTargetName()); this.addAbility(ability); + + // Enchanted creature has flying. this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new GainAbilityAttachedEffect(FlyingAbility.getInstance(), AttachmentType.AURA))); } - public Flight (final Flight card) { + public Flight(final Flight card) { super(card); } diff --git a/Mage.Sets/src/mage/sets/magic2012/PhantasmalImage.java b/Mage.Sets/src/mage/sets/magic2012/PhantasmalImage.java index 54d717c7b30..82de7d6d4e8 100644 --- a/Mage.Sets/src/mage/sets/magic2012/PhantasmalImage.java +++ b/Mage.Sets/src/mage/sets/magic2012/PhantasmalImage.java @@ -97,15 +97,15 @@ class PhantasmalImageCopyEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { Player player = game.getPlayer(source.getControllerId()); - Permanent sourcePermanent = game.getPermanent(source.getSourceId()); - if (player != null && sourcePermanent != null) { + MageObject sourceObject = game.getObject(source.getSourceId()); + if (player != null && sourceObject != null) { Target target = new TargetPermanent(new FilterCreaturePermanent("creature (you copy from)")); target.setNotTarget(true); if (target.canChoose(source.getSourceId(), source.getControllerId(), game)) { player.choose(Outcome.Copy, target, source.getSourceId(), game); Permanent copyFromPermanent = game.getPermanent(target.getFirstTarget()); if (copyFromPermanent != null) { - game.copyPermanent(copyFromPermanent, sourcePermanent, source, new ApplyToPermanent() { + game.copyPermanent(copyFromPermanent, sourceObject.getId(), source, new ApplyToPermanent() { @Override public Boolean apply(Game game, Permanent permanent) { if (!permanent.getSubtype().contains("Illusion")) { diff --git a/Mage.Sets/src/mage/sets/magic2015/MercurialPretender.java b/Mage.Sets/src/mage/sets/magic2015/MercurialPretender.java index 6196ee8db79..1aa0cb0c7c6 100644 --- a/Mage.Sets/src/mage/sets/magic2015/MercurialPretender.java +++ b/Mage.Sets/src/mage/sets/magic2015/MercurialPretender.java @@ -29,6 +29,7 @@ package mage.sets.magic2015; import java.util.UUID; import mage.MageInt; +import mage.MageObject; import mage.abilities.Ability; import mage.abilities.common.SimpleActivatedAbility; import mage.abilities.common.SimpleStaticAbility; @@ -96,15 +97,15 @@ class MercurialPretenderCopyEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { Player player = game.getPlayer(source.getControllerId()); - Permanent sourcePermanent = game.getPermanent(source.getSourceId()); - if (player != null && sourcePermanent != null) { + MageObject sourceObject = game.getObject(source.getSourceId()); + if (player != null && sourceObject != null) { Target target = new TargetPermanent(new FilterControlledCreaturePermanent()); target.setNotTarget(true); if (target.canChoose(source.getSourceId(), source.getControllerId(), game)) { player.choose(Outcome.Copy, target, source.getSourceId(), game); Permanent copyFromPermanent = game.getPermanent(target.getFirstTarget()); if (copyFromPermanent != null) { - game.copyPermanent(copyFromPermanent, sourcePermanent, source, + game.copyPermanent(copyFromPermanent, sourceObject.getId(), source, // {2}{U}{U}: Return this creature to its owner's hand. new AbilityApplier(new SimpleActivatedAbility(Zone.BATTLEFIELD, new ReturnToHandSourceEffect(true), new ManaCostsImpl("{2}{U}{U}"))) ); diff --git a/Mage.Sets/src/mage/sets/mirrodinbesieged/KnowledgePool.java b/Mage.Sets/src/mage/sets/mirrodinbesieged/KnowledgePool.java index 98c1aa29bea..606fe4a93a0 100644 --- a/Mage.Sets/src/mage/sets/mirrodinbesieged/KnowledgePool.java +++ b/Mage.Sets/src/mage/sets/mirrodinbesieged/KnowledgePool.java @@ -44,6 +44,7 @@ import mage.filter.common.FilterNonlandCard; import mage.game.Game; import mage.game.events.GameEvent; import mage.game.events.GameEvent.EventType; +import mage.game.permanent.PermanentToken; import mage.game.stack.Spell; import mage.players.Player; import mage.target.common.TargetCardInExile; @@ -100,7 +101,8 @@ class KnowledgePoolEffect1 extends OneShotEffect { Player player = game.getPlayer(playerId); if (player != null) { player.moveCardsToExile(player.getLibrary().getTopCards(game, 3), source, game, true, - CardUtil.getObjectExileZoneId(game, sourceObject), sourceObject.getIdName() + " (" + sourceObject.getZoneChangeCounter(game) + ")"); + CardUtil.getExileZoneId(game, source.getSourceId(), source.getSourceObjectZoneChangeCounter()), + sourceObject.getIdName() + " (" + sourceObject.getZoneChangeCounter(game) + ")"); } } return true; @@ -168,7 +170,8 @@ class KnowledgePoolEffect2 extends OneShotEffect { MageObject sourceObject = game.getObject(source.getSourceId()); Player controller = game.getPlayer(source.getControllerId()); if (controller != null && spell != null && sourceObject != null) { - UUID exileZoneId = CardUtil.getObjectExileZoneId(game, sourceObject); + int zoneChangeCounter = (sourceObject instanceof PermanentToken) ? source.getSourceObjectZoneChangeCounter() : source.getSourceObjectZoneChangeCounter() - 1; + UUID exileZoneId = CardUtil.getExileZoneId(game, source.getSourceId(), zoneChangeCounter); if (controller.moveCardsToExile(spell, source, game, true, exileZoneId, sourceObject.getIdName())) { Player player = game.getPlayer(spell.getControllerId()); if (player != null && player.chooseUse(Outcome.PlayForFree, "Cast another nonland card exiled with " + sourceObject.getLogName() + " without paying that card's mana cost?", source, game)) { diff --git a/Mage.Sets/src/mage/sets/newphyrexia/PhyrexianMetamorph.java b/Mage.Sets/src/mage/sets/newphyrexia/PhyrexianMetamorph.java index 25a6c37427b..b6a7057dda5 100644 --- a/Mage.Sets/src/mage/sets/newphyrexia/PhyrexianMetamorph.java +++ b/Mage.Sets/src/mage/sets/newphyrexia/PhyrexianMetamorph.java @@ -88,7 +88,7 @@ public class PhyrexianMetamorph extends CardImpl { // You may have Phyrexian Metamorph enter the battlefield as a copy of any artifact or creature on the battlefield, except it's an artifact in addition to its other types. Effect effect = new CopyPermanentEffect(filter, phyrexianMetamorphApplier); effect.setText("You may have {this} enter the battlefield as a copy of any artifact or creature on the battlefield, except it's an artifact in addition to its other types"); - Ability ability = new SimpleStaticAbility(Zone.BATTLEFIELD, new EntersBattlefieldEffect(effect)); + Ability ability = new SimpleStaticAbility(Zone.ALL, new EntersBattlefieldEffect(effect)); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/sets/planeshift/SkyshipWeatherlight.java b/Mage.Sets/src/mage/sets/planeshift/SkyshipWeatherlight.java index 22a1c755e1b..06d9fb2a02c 100644 --- a/Mage.Sets/src/mage/sets/planeshift/SkyshipWeatherlight.java +++ b/Mage.Sets/src/mage/sets/planeshift/SkyshipWeatherlight.java @@ -92,7 +92,7 @@ class SkyshipWeatherlightEffect extends SearchEffect { MageObject sourceObject = source.getSourceObject(game); if (sourceObject != null && controller != null) { if (controller.searchLibrary(target, game)) { - UUID exileZone = CardUtil.getObjectExileZoneId(game, sourceObject); + UUID exileZone = CardUtil.getExileZoneId(game, source.getSourceId(), source.getSourceObjectZoneChangeCounter()); if (target.getTargets().size() > 0) { for (UUID cardID : target.getTargets()) { Card card = controller.getLibrary().getCard(cardID, game); diff --git a/Mage.Sets/src/mage/sets/riseoftheeldrazi/RenegadeDoppelganger.java b/Mage.Sets/src/mage/sets/riseoftheeldrazi/RenegadeDoppelganger.java index 2f8202380d3..07b9a9ac94a 100644 --- a/Mage.Sets/src/mage/sets/riseoftheeldrazi/RenegadeDoppelganger.java +++ b/Mage.Sets/src/mage/sets/riseoftheeldrazi/RenegadeDoppelganger.java @@ -46,7 +46,6 @@ import mage.game.permanent.Permanent; import mage.target.targetpointer.FixedTarget; import mage.util.functions.EmptyApplyToPermanent; - /** * * @author North @@ -142,7 +141,7 @@ class RenegadeDoppelgangerEffect extends OneShotEffect { return false; } - game.copyPermanent(Duration.EndOfTurn, targetCreature, permanent, source, new EmptyApplyToPermanent()); + game.copyPermanent(Duration.EndOfTurn, targetCreature, permanent.getId(), source, new EmptyApplyToPermanent()); return false; } } diff --git a/Mage.Sets/src/mage/sets/saviorsofkamigawa/SakashimaTheImpostor.java b/Mage.Sets/src/mage/sets/saviorsofkamigawa/SakashimaTheImpostor.java index b902d364f2d..3a4232607be 100644 --- a/Mage.Sets/src/mage/sets/saviorsofkamigawa/SakashimaTheImpostor.java +++ b/Mage.Sets/src/mage/sets/saviorsofkamigawa/SakashimaTheImpostor.java @@ -98,15 +98,15 @@ class SakashimaTheImpostorCopyEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { Player player = game.getPlayer(source.getControllerId()); - Permanent sourcePermanent = game.getPermanent(source.getSourceId()); - if (player != null && sourcePermanent != null) { + MageObject sourceObject = game.getObject(source.getSourceId()); + if (player != null && sourceObject != null) { Target target = new TargetPermanent(new FilterCreaturePermanent()); target.setNotTarget(true); if (target.canChoose(source.getSourceId(), source.getControllerId(), game)) { player.choose(Outcome.Copy, target, source.getSourceId(), game); Permanent copyFromPermanent = game.getPermanent(target.getFirstTarget()); if (copyFromPermanent != null) { - game.copyPermanent(copyFromPermanent, sourcePermanent, source, new ApplyToPermanent() { + game.copyPermanent(copyFromPermanent, sourceObject.getId(), source, new ApplyToPermanent() { @Override public Boolean apply(Game game, Permanent permanent) { if (!permanent.getSupertype().contains("Legendary")) { diff --git a/Mage.Sets/src/mage/sets/shadowmoor/CemeteryPuca.java b/Mage.Sets/src/mage/sets/shadowmoor/CemeteryPuca.java index e3bc6c33655..f97b818c753 100644 --- a/Mage.Sets/src/mage/sets/shadowmoor/CemeteryPuca.java +++ b/Mage.Sets/src/mage/sets/shadowmoor/CemeteryPuca.java @@ -99,7 +99,7 @@ class CemeteryPucaEffect extends OneShotEffect { if (copyToCreature != null) { Permanent copyFromCreature = (Permanent) game.getLastKnownInformation(targetPointer.getFirst(game, source), Zone.BATTLEFIELD); if (copyFromCreature != null) { - game.copyPermanent(Duration.WhileOnBattlefield, copyFromCreature, copyToCreature, source, new EmptyApplyToPermanent()); + game.copyPermanent(Duration.WhileOnBattlefield, copyFromCreature, copyToCreature.getId(), source, new EmptyApplyToPermanent()); ContinuousEffect effect = new GainAbilityTargetEffect(new DiesCreatureTriggeredAbility(new DoIfCostPaid(new CemeteryPucaEffect(), new ManaCostsImpl("{1}")), false, new FilterCreaturePermanent("a creature"), true), Duration.WhileOnBattlefield); effect.setTargetPointer(new FixedTarget(copyToCreature.getId())); game.addEffect(effect, source); diff --git a/Mage.Sets/src/mage/sets/shadowmoor/LureboundScarecrow.java b/Mage.Sets/src/mage/sets/shadowmoor/LureboundScarecrow.java index 9ab3c91bb7e..1964cd1cc43 100644 --- a/Mage.Sets/src/mage/sets/shadowmoor/LureboundScarecrow.java +++ b/Mage.Sets/src/mage/sets/shadowmoor/LureboundScarecrow.java @@ -30,22 +30,16 @@ package mage.sets.shadowmoor; import java.util.UUID; import mage.MageInt; import mage.ObjectColor; -import mage.abilities.Ability; import mage.abilities.StateTriggeredAbility; import mage.abilities.common.AsEntersBattlefieldAbility; -import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.SacrificeSourceEffect; import mage.cards.CardImpl; -import mage.choices.ChoiceColor; import mage.constants.CardType; -import mage.constants.Outcome; import mage.constants.Rarity; import mage.constants.Zone; import mage.game.Game; import mage.game.events.GameEvent; import mage.game.permanent.Permanent; -import mage.game.stack.StackObject; -import mage.players.Player; /** * @@ -62,7 +56,7 @@ public class LureboundScarecrow extends CardImpl { this.toughness = new MageInt(4); // As Lurebound Scarecrow enters the battlefield, choose a color. - this.addAbility(new AsEntersBattlefieldAbility(new LureboundScarecrowChooseColorEffect())); + this.addAbility(new AsEntersBattlefieldAbility(new ChooseColorEffect())); // When you control no permanents of the chosen color, sacrifice Lurebound Scarecrow. this.addAbility(new LureboundScarecrowTriggeredAbility()); @@ -78,40 +72,6 @@ public class LureboundScarecrow extends CardImpl { } } -class LureboundScarecrowChooseColorEffect extends OneShotEffect { - - public LureboundScarecrowChooseColorEffect() { - super(Outcome.BoostCreature); - staticText = "choose a color"; - } - - public LureboundScarecrowChooseColorEffect(final LureboundScarecrowChooseColorEffect effect) { - super(effect); - } - - @Override - public boolean apply(Game game, Ability source) { - Player player = game.getPlayer(source.getControllerId()); - StackObject sourceStackObject = game.getStack().getStackObject(source.getSourceId()); - Permanent permanent = game.getPermanent(source.getSourceId()); - if (player != null && sourceStackObject != null && permanent != null) { - ChoiceColor colorChoice = new ChoiceColor(); - if (player.choose(Outcome.BoostCreature, colorChoice, game)) { - game.informPlayers(sourceStackObject.getName() + ": " + player.getLogName() + " has chosen " + colorChoice.getChoice()); - game.getState().setValue(permanent.getId() + "_color", colorChoice.getColor()); - permanent.addInfo("chosen color", new StringBuilder("Chosen color: ").append(colorChoice.getColor().getDescription()).append("").toString(), game); - } - } - return false; - } - - @Override - public LureboundScarecrowChooseColorEffect copy() { - return new LureboundScarecrowChooseColorEffect(this); - } - -} - class LureboundScarecrowTriggeredAbility extends StateTriggeredAbility { private static final String staticText = "When you control no permanents of the chosen color, sacrifice {this}."; diff --git a/Mage.Sets/src/mage/sets/shadowmoor/Mirrorweave.java b/Mage.Sets/src/mage/sets/shadowmoor/Mirrorweave.java index fa2ecb5d7c0..571cf64174a 100644 --- a/Mage.Sets/src/mage/sets/shadowmoor/Mirrorweave.java +++ b/Mage.Sets/src/mage/sets/shadowmoor/Mirrorweave.java @@ -61,7 +61,6 @@ public class Mirrorweave extends CardImpl { super(ownerId, 143, "Mirrorweave", Rarity.RARE, new CardType[]{CardType.INSTANT}, "{2}{W/U}{W/U}"); this.expansionSetCode = "SHM"; - // Each other creature becomes a copy of target nonlegendary creature until end of turn. this.getSpellAbility().addEffect(new MirrorWeaveEffect()); this.getSpellAbility().addTarget(new TargetPermanent(filter)); @@ -105,7 +104,7 @@ class MirrorWeaveEffect extends OneShotEffect { filter.add(Predicates.not(new PermanentIdPredicate(copyFromCreature.getId()))); for (Permanent copyToCreature : game.getBattlefield().getAllActivePermanents(filter, game)) { if (copyToCreature != null) { - game.copyPermanent(Duration.EndOfTurn, copyFromCreature, copyToCreature, source, new EmptyApplyToPermanent()); + game.copyPermanent(Duration.EndOfTurn, copyFromCreature, copyToCreature.getId(), source, new EmptyApplyToPermanent()); } } } diff --git a/Mage.Sets/src/mage/sets/shardsofalara/TidehollowSculler.java b/Mage.Sets/src/mage/sets/shardsofalara/TidehollowSculler.java index e667e1d7cd6..3f728872269 100644 --- a/Mage.Sets/src/mage/sets/shardsofalara/TidehollowSculler.java +++ b/Mage.Sets/src/mage/sets/shardsofalara/TidehollowSculler.java @@ -114,7 +114,7 @@ class TidehollowScullerExileEffect extends OneShotEffect { if (controller.choose(Outcome.Exile, opponent.getHand(), target, game)) { Card card = opponent.getHand().get(target.getFirstTarget(), game); if (card != null) { - controller.moveCardToExileWithInfo(card, CardUtil.getObjectExileZoneId(game, sourcePermanent), sourcePermanent.getIdName(), source.getSourceId(), game, Zone.HAND, true); + controller.moveCardToExileWithInfo(card, CardUtil.getExileZoneId(game, source.getSourceId(), source.getSourceObjectZoneChangeCounter()), sourcePermanent.getIdName(), source.getSourceId(), game, Zone.HAND, true); } } diff --git a/Mage.Sets/src/mage/sets/tempest/RootwaterMatriarch.java b/Mage.Sets/src/mage/sets/tempest/RootwaterMatriarch.java index 39d3449e1f7..88a5d986851 100644 --- a/Mage.Sets/src/mage/sets/tempest/RootwaterMatriarch.java +++ b/Mage.Sets/src/mage/sets/tempest/RootwaterMatriarch.java @@ -28,9 +28,6 @@ package mage.sets.tempest; import java.util.UUID; - -import mage.constants.CardType; -import mage.constants.Rarity; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.SimpleActivatedAbility; @@ -39,7 +36,9 @@ import mage.abilities.costs.common.TapSourceCost; import mage.abilities.decorator.ConditionalContinuousEffect; import mage.abilities.effects.common.continuous.GainControlTargetEffect; 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; @@ -56,9 +55,10 @@ public class RootwaterMatriarch extends CardImpl { this.power = new MageInt(2); this.toughness = new MageInt(3); - - // {TAP}: Gain control of target creature for as long as that creature is enchanted - ConditionalContinuousEffect effect = new ConditionalContinuousEffect(new GainControlTargetEffect(Duration.OneUse), EnchantedTargetCondition.getInstance(), "Gain control of target creature for as long as that creature is enchanted"); + + // {T}: Gain control of target creature for as long as that creature is enchanted + ConditionalContinuousEffect effect = new ConditionalContinuousEffect(new GainControlTargetEffect(Duration.Custom), EnchantedTargetCondition.getInstance(), + "Gain control of target creature for as long as that creature is enchanted"); Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, effect, new TapSourceCost()); ability.addTarget(new TargetCreaturePermanent()); this.addAbility(ability); diff --git a/Mage.Sets/src/mage/sets/theros/AshiokNightmareWeaver.java b/Mage.Sets/src/mage/sets/theros/AshiokNightmareWeaver.java index f742e0790fb..25c3342c95b 100644 --- a/Mage.Sets/src/mage/sets/theros/AshiokNightmareWeaver.java +++ b/Mage.Sets/src/mage/sets/theros/AshiokNightmareWeaver.java @@ -73,7 +73,6 @@ public class AshiokNightmareWeaver extends CardImpl { this.expansionSetCode = "THS"; this.subtype.add("Ashiok"); - this.addAbility(new EntersBattlefieldAbility(new AddCountersSourceEffect(CounterType.LOYALTY.createInstance(3)), false)); // +2: Exile the top three cards of target opponent's library. @@ -121,14 +120,9 @@ class AshiokNightmareWeaverExileEffect extends OneShotEffect { Player controller = game.getPlayer(source.getControllerId()); MageObject sourceObject = source.getSourceObject(game); if (sourceObject != null && opponent != null && controller != null) { - UUID exileZone = CardUtil.getObjectExileZoneId(game, sourceObject); + UUID exileZone = CardUtil.getExileZoneId(game, source.getSourceId(), source.getSourceObjectZoneChangeCounter()); if (exileZone != null) { - for (int i = 0; i < 3; i++) { - Card card = opponent.getLibrary().getFromTop(game); - if (card != null) { - controller.moveCardToExileWithInfo(card, exileZone, sourceObject.getIdName(), source.getSourceId(), game, Zone.LIBRARY, true); - } - } + controller.moveCardsToExile(opponent.getLibrary().getTopCards(game, 3), source, game, true, exileZone, sourceObject.getIdName()); return true; } } @@ -167,11 +161,10 @@ class AshiokNightmareWeaverPutIntoPlayEffect extends OneShotEffect { } } - FilterCard filter = new FilterCreatureCard(new StringBuilder("creature card with converted mana cost {").append(cmc).append("} exiled with Ashiok, Nightmare Weaver").toString()); + FilterCard filter = new FilterCreatureCard("creature card with converted mana cost {" + cmc + "} exiled with " + sourceObject.getIdName()); filter.add(new ConvertedManaCostPredicate(Filter.ComparisonType.Equal, cmc)); - - Target target = new TargetCardInExile(filter, CardUtil.getObjectExileZoneId(game, sourceObject)); + Target target = new TargetCardInExile(filter, CardUtil.getExileZoneId(game, source.getSourceId(), source.getSourceObjectZoneChangeCounter())); if (target.canChoose(source.getSourceId(), controller.getId(), game)) { if (controller.chooseTarget(Outcome.PutCreatureInPlay, target, source, game)) { @@ -182,7 +175,7 @@ class AshiokNightmareWeaverPutIntoPlayEffect extends OneShotEffect { if (permanent != null) { permanent.changeControllerId(source.getControllerId(), game); } - + ContinuousEffectImpl effect = new AshiokNightmareWeaverAddTypeEffect(); effect.setTargetPointer(new FixedTarget(card.getId())); game.addEffect(effect, source); @@ -267,7 +260,7 @@ class AshiokNightmareWeaverExileAllEffect extends OneShotEffect { if (exileId == null) { return false; } - for (UUID opponentId: game.getOpponents(source.getControllerId())) { + for (UUID opponentId : game.getOpponents(source.getControllerId())) { Player opponent = game.getPlayer(opponentId); if (opponent != null) { Cards cards = new CardsImpl(); @@ -280,7 +273,7 @@ class AshiokNightmareWeaverExileAllEffect extends OneShotEffect { } cards.clear(); cards.addAll(opponent.getGraveyard()); - for (UUID cardId :cards) { + for (UUID cardId : cards) { Card card = game.getCard(cardId); if (card != null) { controller.moveCardToExileWithInfo(card, exileId, sourceObject.getIdName(), source.getSourceId(), game, Zone.GRAVEYARD, true); diff --git a/Mage.Sets/src/mage/sets/unlimitededition/VesuvanDoppelganger.java b/Mage.Sets/src/mage/sets/unlimitededition/VesuvanDoppelganger.java index 09cc3484c95..8dd32a04b9e 100644 --- a/Mage.Sets/src/mage/sets/unlimitededition/VesuvanDoppelganger.java +++ b/Mage.Sets/src/mage/sets/unlimitededition/VesuvanDoppelganger.java @@ -108,7 +108,7 @@ class VesuvanDoppelgangerCopyEffect extends OneShotEffect { controller.choose(Outcome.Copy, target, source.getSourceId(), game); Permanent copyFromPermanent = game.getPermanent(target.getFirstTarget()); if (copyFromPermanent != null) { - game.copyPermanent(copyFromPermanent, sourcePermanent, source, new ApplyToPermanent() { + game.copyPermanent(copyFromPermanent, sourcePermanent.getId(), source, new ApplyToPermanent() { @Override public Boolean apply(Game game, Permanent permanent) { permanent.getColor(game).setColor(sourcePermanent.getColor(game)); diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/abilities/enters/ProteanHydraTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/abilities/enters/ProteanHydraTest.java index 6b3a7325312..4fd8c979fab 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/abilities/enters/ProteanHydraTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/abilities/enters/ProteanHydraTest.java @@ -16,7 +16,10 @@ public class ProteanHydraTest extends CardTestPlayerBase { @Test public void testEnteringWithCounters() { addCard(Zone.BATTLEFIELD, playerA, "Forest", 5); - addCard(Zone.HAND, playerA, "Protean Hydra"); + // Protean Hydra enters the battlefield with X +1/+1 counters on it. + // If damage would be dealt to Protean Hydra, prevent that damage and remove that many +1/+1 counters from it. + // Whenever a +1/+1 counter is removed from Protean Hydra, put two +1/+1 counters on it at the beginning of the next end step. + addCard(Zone.HAND, playerA, "Protean Hydra"); // CREATURE - {X}{G} castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Protean Hydra"); diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/abilities/other/MycosynthGolemTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/abilities/other/MycosynthGolemTest.java index f7172974d0a..f77f9d097af 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/abilities/other/MycosynthGolemTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/abilities/other/MycosynthGolemTest.java @@ -51,8 +51,10 @@ public class MycosynthGolemTest extends CardTestPlayerBase { public void testSpellsAffinity() { addCard(Zone.BATTLEFIELD, playerA, "Mountain", 1); addCard(Zone.BATTLEFIELD, playerA, "Forest", 1); + // Affinity for artifacts + // Artifact creature spells you cast have affinity for artifacts. addCard(Zone.BATTLEFIELD, playerA, "Mycosynth Golem"); - addCard(Zone.HAND, playerA, "Alpha Myr"); + addCard(Zone.HAND, playerA, "Alpha Myr"); // Creature - Myr 2/1 castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Alpha Myr"); diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/abilities/other/SoulfireGrandMasterTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/abilities/other/SoulfireGrandMasterTest.java index bce66195698..32387a9896d 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/abilities/other/SoulfireGrandMasterTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/abilities/other/SoulfireGrandMasterTest.java @@ -66,6 +66,9 @@ public class SoulfireGrandMasterTest extends CardTestPlayerBase { @Test public void testSpellsReturnToHand() { addCard(Zone.BATTLEFIELD, playerA, "Mountain", 5); + // Lifelink + // Instant and sorcery spells you control have lifelink. + // {2}{U/R}{U/R}: The next time you cast an instant or sorcery spell from your hand this turn, put that card into your hand instead of your graveyard as it resolves. addCard(Zone.BATTLEFIELD, playerA, "Soulfire Grand Master"); addCard(Zone.HAND, playerA, "Lightning Bolt"); @@ -199,7 +202,6 @@ public class SoulfireGrandMasterTest extends CardTestPlayerBase { * Test that if Soulfire Grand Master has left the battlefield spell has no * longer lifelink */ - @Test public void testSoulfireLeft() { addCard(Zone.BATTLEFIELD, playerA, "Mountain", 1); @@ -231,7 +233,6 @@ public class SoulfireGrandMasterTest extends CardTestPlayerBase { * the elemental, so stoke didnt resolve, but i still got the life from * lifelink. */ - @Test public void testSoulfireStokeTheFlames() { addCard(Zone.BATTLEFIELD, playerA, "Mountain", 8); @@ -296,7 +297,6 @@ public class SoulfireGrandMasterTest extends CardTestPlayerBase { * Constructed. * */ - @Test public void testWithDeflectingPalm() { addCard(Zone.BATTLEFIELD, playerA, "Mountain", 1); diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/conditional/RootwaterMatriarchTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/conditional/RootwaterMatriarchTest.java index 7f74e563818..79a8b996666 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/conditional/RootwaterMatriarchTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/conditional/RootwaterMatriarchTest.java @@ -1,7 +1,3 @@ -/* - * To change this template, choose Tools | Templates - * and open the template in the editor. - */ package org.mage.test.cards.conditional; import mage.constants.PhaseStep; @@ -14,10 +10,10 @@ import org.mage.test.serverside.base.CardTestPlayerBase; * @author jeff */ public class RootwaterMatriarchTest extends CardTestPlayerBase { - + @Test public void testTargetFail() { - + addCard(Zone.BATTLEFIELD, playerA, "Rootwater Matriarch"); addCard(Zone.BATTLEFIELD, playerB, "Memnite"); @@ -25,73 +21,73 @@ public class RootwaterMatriarchTest extends CardTestPlayerBase { setStopAt(1, PhaseStep.BEGIN_COMBAT); execute(); - + assertPermanentCount(playerA, "Rootwater Matriarch", 1); assertPermanentCount(playerB, "Memnite", 1); } - + @Test public void testTargetSuccess() { - + // {T}: Gain control of target creature for as long as that creature is enchanted addCard(Zone.BATTLEFIELD, playerA, "Rootwater Matriarch"); addCard(Zone.BATTLEFIELD, playerA, "Island"); addCard(Zone.BATTLEFIELD, playerB, "Memnite"); - + addCard(Zone.HAND, playerA, "Flight"); - + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Flight", "Memnite"); activateAbility(1, PhaseStep.BEGIN_COMBAT, playerA, "{T}: Gain control of target creature for as long as that creature is enchanted.", "Memnite"); setStopAt(1, PhaseStep.END_COMBAT); execute(); - + assertPermanentCount(playerA, "Rootwater Matriarch", 1); assertPermanentCount(playerA, "Memnite", 1); - + } - + @Test public void testGainControlEnchantedTargetAndRWLeavesPlay() { - + addCard(Zone.BATTLEFIELD, playerA, "Rootwater Matriarch"); addCard(Zone.BATTLEFIELD, playerA, "Island", 2); addCard(Zone.BATTLEFIELD, playerB, "Memnite"); addCard(Zone.HAND, playerA, "Unsummon"); addCard(Zone.HAND, playerA, "Flight"); - + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Flight", "Memnite"); activateAbility(1, PhaseStep.BEGIN_COMBAT, playerA, "{T}: Gain control of target creature for as long as that creature is enchanted.", "Memnite"); - + castSpell(1, PhaseStep.POSTCOMBAT_MAIN, playerA, "Unsummon", "Rootwater Matriarch"); - + setStopAt(1, PhaseStep.END_TURN); execute(); - + assertPermanentCount(playerA, "Rootwater Matriarch", 0); assertPermanentCount(playerA, "Memnite", 1); } - + @Test public void testGainControlEnchantedTargetAndAuraIsDisenchanted() { - + addCard(Zone.BATTLEFIELD, playerA, "Rootwater Matriarch"); addCard(Zone.BATTLEFIELD, playerA, "Island"); addCard(Zone.BATTLEFIELD, playerA, "Plains", 2); addCard(Zone.BATTLEFIELD, playerB, "Memnite"); addCard(Zone.HAND, playerA, "Disenchant"); addCard(Zone.HAND, playerA, "Flight"); - + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Flight", "Memnite"); activateAbility(1, PhaseStep.BEGIN_COMBAT, playerA, "{T}: Gain control of target creature for as long as that creature is enchanted.", "Memnite"); - + castSpell(1, PhaseStep.POSTCOMBAT_MAIN, playerA, "Disenchant", "Flight"); - + setStopAt(1, PhaseStep.END_TURN); execute(); - + assertPermanentCount(playerA, "Rootwater Matriarch", 1); assertPermanentCount(playerB, "Memnite", 1); } diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/copy/PhantasmalImageTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/copy/PhantasmalImageTest.java index 7b1ecd66b1e..7326f3ec5cc 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/copy/PhantasmalImageTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/copy/PhantasmalImageTest.java @@ -202,6 +202,9 @@ public class PhantasmalImageTest extends CardTestPlayerBase { addCard(Zone.BATTLEFIELD, playerA, "Island", 5); addCard(Zone.BATTLEFIELD, playerA, "Llanowar Elves"); addCard(Zone.HAND, playerA, "Phantasmal Image"); + + // As Lurebound Scarecrow enters the battlefield, choose a color. + // When you control no permanents of the chosen color, sacrifice Lurebound Scarecrow. addCard(Zone.HAND, playerA, "Lurebound Scarecrow"); setChoice(playerA, "Green"); @@ -324,7 +327,7 @@ public class PhantasmalImageTest extends CardTestPlayerBase { addCard(Zone.HAND, playerB, "Phantasmal Image"); castSpell(2, PhaseStep.PRECOMBAT_MAIN, playerB, "Phantasmal Image"); // not targeted - castSpell(2, PhaseStep.PRECOMBAT_MAIN, playerA, "Veil of Secrecy", "Frost Titan"); // so it's no longer targetable + castSpell(2, PhaseStep.PRECOMBAT_MAIN, playerA, "Veil of Secrecy", "Frost Titan"); // so it's no longer targetable setChoice(playerB, "Frost Titan"); castSpell(2, PhaseStep.POSTCOMBAT_MAIN, playerA, "Terror", "Frost Titan"); // of player Bs Phantasmal Image copying Frost Titan @@ -346,7 +349,7 @@ public class PhantasmalImageTest extends CardTestPlayerBase { } // I've casted a Phantasmal Image targeting opponent's Wurmcoil Engine - // When my Phantasmal Image died, it didn't triggered the Wurmcoil Engine's last ability + // When my Phantasmal Image died, it didn't triggered the Wurmcoil Engine's last ability // (When Wurmcoil Engine dies, put a 3/3 colorless Wurm artifact creature token with deathtouch and // a 3/3 colorless Wurm artifact creature token with lifelink onto the battlefield.) @Test @@ -418,31 +421,39 @@ public class PhantasmalImageTest extends CardTestPlayerBase { } /** - * Action - * Game State 1 -----------------> Game State 2 - * (On 'field) (Move to GY) (In graveyard) - * - * LTB abilities such as Persist are expceptional in that they trigger based on their existence and - * state of objects before the event (Game State 1, when the card is on the battlefield) rather than - * after (Game State 2, when the card is in the graveyard). It doesn't matter that the LTB ability - * doesn't exist in Game State 2. [CR 603.6d] - * - * 603.6d Normally, objects that exist immediately after an event are checked to see if the event matched any trigger conditions. - * Continuous effects that exist at that time are used to determine what the trigger conditions are and what the objects involved - * in the event look like. However, some triggered abilities must be treated specially. Leaves-the-battlefield abilities, abilities - * that trigger when a permanent phases out, abilities that trigger when an object that all players can see is put into a hand or - * library, abilities that trigger specifically when an object becomes unattached, abilities that trigger when a player loses control - * of an object, and abilities that trigger when a player planeswalks away from a plane will trigger based on their existence, and - * the appearance of objects, prior to the event rather than afterward. The game has to “look back in time” to determine if these abilities trigger. - * - * Example: Two creatures are on the battlefield along with an artifact that has the ability “Whenever a creature dies, you gain 1 life.” - * Someone plays a spell that destroys all artifacts, creatures, and enchantments. The artifact’s ability triggers twice, even though - * the artifact goes to its owner’s graveyard at the same time as the creatures. - * + * Action Game State 1 -----------------> Game State 2 (On 'field) (Move to + * GY) (In graveyard) + * + * LTB abilities such as Persist are expceptional in that they trigger based + * on their existence and state of objects before the event (Game State 1, + * when the card is on the battlefield) rather than after (Game State 2, + * when the card is in the graveyard). It doesn't matter that the LTB + * ability doesn't exist in Game State 2. [CR 603.6d] + * + * 603.6d Normally, objects that exist immediately after an event are + * checked to see if the event matched any trigger conditions. Continuous + * effects that exist at that time are used to determine what the trigger + * conditions are and what the objects involved in the event look like. + * However, some triggered abilities must be treated specially. + * Leaves-the-battlefield abilities, abilities that trigger when a permanent + * phases out, abilities that trigger when an object that all players can + * see is put into a hand or library, abilities that trigger specifically + * when an object becomes unattached, abilities that trigger when a player + * loses control of an object, and abilities that trigger when a player + * planeswalks away from a plane will trigger based on their existence, and + * the appearance of objects, prior to the event rather than afterward. The + * game has to “look back in time” to determine if these abilities trigger. + * + * Example: Two creatures are on the battlefield along with an artifact that + * has the ability “Whenever a creature dies, you gain 1 life.” Someone + * plays a spell that destroys all artifacts, creatures, and enchantments. + * The artifact’s ability triggers twice, even though the artifact goes to + * its owner’s graveyard at the same time as the creatures. + * */ @Test public void testPersist() { - addCard(Zone.BATTLEFIELD, playerA, "Forest", 3); + addCard(Zone.BATTLEFIELD, playerA, "Forest", 3); // When Kitchen Finks enters the battlefield, you gain 2 life. // Persist (When this creature dies, if it had no -1/-1 counters on it, return it to the battlefield under its owner's control with a -1/-1 counter on it.) addCard(Zone.HAND, playerA, "Kitchen Finks"); @@ -452,21 +463,20 @@ public class PhantasmalImageTest extends CardTestPlayerBase { addCard(Zone.BATTLEFIELD, playerA, "Swamp", 6); addCard(Zone.BATTLEFIELD, playerB, "Island", 2); - + // You may have Phantasmal Image enter the battlefield as a copy of any creature // on the battlefield, except it's an Illusion in addition to its other types and - // it gains "When this creature becomes the target of a spell or ability, sacrifice it." + // it gains "When this creature becomes the target of a spell or ability, sacrifice it." addCard(Zone.HAND, playerB, "Phantasmal Image"); - castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Kitchen Finks"); - + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Kitchen Finks"); + castSpell(2, PhaseStep.PRECOMBAT_MAIN, playerB, "Phantasmal Image"); // not targeted setChoice(playerB, "Kitchen Finks"); - castSpell(2, PhaseStep.POSTCOMBAT_MAIN, playerA, "Public Execution", "Kitchen Finks"); setChoice(playerB, "Kitchen Finks"); - + setStopAt(2, PhaseStep.END_TURN); execute(); @@ -480,13 +490,13 @@ public class PhantasmalImageTest extends CardTestPlayerBase { assertHandCount(playerB, "Phantasmal Image", 0); assertGraveyardCount(playerB, "Phantasmal Image", 0); assertPermanentCount(playerB, "Kitchen Finks", 1); - assertPowerToughness(playerB, "Kitchen Finks", 2, 1); + assertPowerToughness(playerB, "Kitchen Finks", 2, 1); } - + @Test public void testUndying() { - addCard(Zone.BATTLEFIELD, playerA, "Swamp", 2); + addCard(Zone.BATTLEFIELD, playerA, "Swamp", 2); // Undying (When this creature dies, if it had no +1/+1 counters on it, return it to the battlefield under its owner's control with a +1/+1 counter on it.) addCard(Zone.HAND, playerA, "Butcher Ghoul"); @@ -495,21 +505,20 @@ public class PhantasmalImageTest extends CardTestPlayerBase { addCard(Zone.BATTLEFIELD, playerA, "Swamp", 6); addCard(Zone.BATTLEFIELD, playerB, "Island", 2); - + // You may have Phantasmal Image enter the battlefield as a copy of any creature // on the battlefield, except it's an Illusion in addition to its other types and - // it gains "When this creature becomes the target of a spell or ability, sacrifice it." + // it gains "When this creature becomes the target of a spell or ability, sacrifice it." addCard(Zone.HAND, playerB, "Phantasmal Image"); - castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Butcher Ghoul"); - + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Butcher Ghoul"); + castSpell(2, PhaseStep.PRECOMBAT_MAIN, playerB, "Phantasmal Image"); // not targeted setChoice(playerB, "Butcher Ghoul"); - castSpell(2, PhaseStep.POSTCOMBAT_MAIN, playerA, "Public Execution", "Butcher Ghoul"); setChoice(playerB, "Butcher Ghoul"); - + setStopAt(2, PhaseStep.END_TURN); execute(); @@ -523,29 +532,25 @@ public class PhantasmalImageTest extends CardTestPlayerBase { assertHandCount(playerB, "Phantasmal Image", 0); assertGraveyardCount(playerB, "Phantasmal Image", 0); assertPermanentCount(playerB, "Butcher Ghoul", 1); - assertPowerToughness(playerB, "Butcher Ghoul", 2, 2); + assertPowerToughness(playerB, "Butcher Ghoul", 2, 2); } /** * 12:29: Attacker: Wurmcoil Engine [466] (6/6) blocked by Wurmcoil Engine - * [4ed] (6/6) - * 12:29: yespair gains 6 life - * 12:29: HipSomHap gains 6 life - * 12:29: Wurmcoil Engine [4ed] died - * 12:29: Ability triggers: Wurmcoil Engine [4ed] - When Wurmcoil Engine [4ed] dies, put a a 3/3 colorless + * [4ed] (6/6) 12:29: yespair gains 6 life 12:29: HipSomHap gains 6 life + * 12:29: Wurmcoil Engine [4ed] died 12:29: Ability triggers: Wurmcoil + * Engine [4ed] - When Wurmcoil Engine [4ed] dies, put a a 3/3 colorless * Wurm artifact creature token with deathtouch onto the battlefield. Put a * a 3/3 colorless Wurm artifact creature token with lifelink onto the - * battlefield. - * 12:29: Phantasmal Image [466] died - * 12:29: HipSomHap puts a Wurm [7d0] token onto the battlefield - * 12:29: HipSomHap puts a Wurm [186] token onto the battlefield + * battlefield. 12:29: Phantasmal Image [466] died 12:29: HipSomHap puts a + * Wurm [7d0] token onto the battlefield 12:29: HipSomHap puts a Wurm [186] + * token onto the battlefield * * To the best of my knowledge, the Phantasmal Image [466], which entered * the battlefield as a Wurmcoil Engine, should grant tokens through the * Dies-trigger as well, right? */ - @Test public void testDiesTriggered2() { addCard(Zone.BATTLEFIELD, playerB, "Wurmcoil Engine"); @@ -570,5 +575,5 @@ public class PhantasmalImageTest extends CardTestPlayerBase { assertPermanentCount(playerA, "Wurm", 2); assertPermanentCount(playerB, "Wurm", 2); - } + } } diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/copy/PhyrexianMetamorphTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/copy/PhyrexianMetamorphTest.java index 460ac83b825..1f3ac8a3242 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/copy/PhyrexianMetamorphTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/copy/PhyrexianMetamorphTest.java @@ -36,10 +36,8 @@ import org.mage.test.serverside.base.CardTestPlayerBase; * * @author LevelX2 */ - public class PhyrexianMetamorphTest extends CardTestPlayerBase { - @Test public void testCopyCreature() { addCard(Zone.BATTLEFIELD, playerA, "Island", 1); @@ -48,7 +46,7 @@ public class PhyrexianMetamorphTest extends CardTestPlayerBase { // You may have Phyrexian Metamorph enter the battlefield as a copy of any artifact or creature on the battlefield, except it's an artifact in addition to its other types. addCard(Zone.HAND, playerA, "Phyrexian Metamorph"); // {3}{UP} addCard(Zone.HAND, playerA, "Cloudshift"); - + //Flying // Vanishing 3 (This permanent enters the battlefield with three time counters on it. At the beginning of your upkeep, remove a time counter from it. When the last is removed, sacrifice it.) // When Aven Riftwatcher enters the battlefield or leaves the battlefield, you gain 2 life. @@ -68,13 +66,13 @@ public class PhyrexianMetamorphTest extends CardTestPlayerBase { assertLife(playerA, 24); assertLife(playerB, 20); - + assertGraveyardCount(playerA, "Cloudshift", 1); - + assertPermanentCount(playerA, "Ponyback Brigade", 1); assertPermanentCount(playerA, "Goblin", 3); - } + } /** * An opponent cast Phyrexian Metamorph and cloned another opponent's @@ -84,7 +82,6 @@ public class PhyrexianMetamorphTest extends CardTestPlayerBase { * to choose a new creature to clone when the Phyrexian Metamorph re-entered * the battlefield. */ - @Test public void testFlickerWithBrago() { addCard(Zone.BATTLEFIELD, playerA, "Island", 4); @@ -93,9 +90,9 @@ public class PhyrexianMetamorphTest extends CardTestPlayerBase { addCard(Zone.HAND, playerA, "Phyrexian Metamorph"); // {3}{UP} // Flying - // When Brago, King Eternal deals combat damage to a player, exile any number of target nonland permanents you control, then return those cards to the battlefield under their owner's control. + // When Brago, King Eternal deals combat damage to a player, exile any number of target nonland permanents you control, then return those cards to the battlefield under their owner's control. addCard(Zone.BATTLEFIELD, playerA, "Brago, King Eternal"); // 2/4 - + // Creatures you control have haste. // Cascade, cascade addCard(Zone.BATTLEFIELD, playerB, "Maelstrom Wanderer"); // 7/5 @@ -106,19 +103,19 @@ public class PhyrexianMetamorphTest extends CardTestPlayerBase { setChoice(playerA, "Maelstrom Wanderer"); attack(3, playerA, "Brago, King Eternal"); - addTarget(playerA, "Maelstrom Wanderer"); + addTarget(playerA, "Maelstrom Wanderer"); setChoice(playerA, "Ponyback Brigade"); - + setStopAt(3, PhaseStep.END_COMBAT); execute(); assertLife(playerA, 20); assertLife(playerB, 18); - + assertPermanentCount(playerA, "Ponyback Brigade", 1); assertPermanentCount(playerA, "Goblin", 3); - } + } /** * I had a Harmonic Sliver, my opponent played Phyrexian Metamorph copying @@ -126,7 +123,7 @@ public class PhyrexianMetamorphTest extends CardTestPlayerBase { * destroying ability, where it should have had two of them and triggered * twice (the Metamorph might have nothing to do with this) */ - @Test + @Test public void testHarmonicSliver() { addCard(Zone.BATTLEFIELD, playerA, "Island", 4); @@ -137,7 +134,7 @@ public class PhyrexianMetamorphTest extends CardTestPlayerBase { addCard(Zone.BATTLEFIELD, playerB, "Kitesail", 1); // All Slivers have "When this permanent enters the battlefield, destroy target artifact or enchantment." addCard(Zone.BATTLEFIELD, playerB, "Harmonic Sliver"); // 2/4 - + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Phyrexian Metamorph"); setChoice(playerA, "Harmonic Sliver"); addTarget(playerA, "Alloy Myr"); @@ -145,66 +142,116 @@ public class PhyrexianMetamorphTest extends CardTestPlayerBase { setStopAt(1, PhaseStep.END_COMBAT); execute(); - + assertPermanentCount(playerA, "Harmonic Sliver", 1); assertGraveyardCount(playerB, "Alloy Myr", 1); assertGraveyardCount(playerB, "Kitesail", 1); - } - + } + /** - * If a Harmonic Sliver enters the battlefield - * the controller has to destroy one artifacts or enchantments + * If a Harmonic Sliver enters the battlefield the controller has to destroy + * one artifacts or enchantments */ @Test public void testHarmonicSliverNative1() { addCard(Zone.BATTLEFIELD, playerA, "Forest", 1); addCard(Zone.BATTLEFIELD, playerA, "Plains", 2); - - // All Slivers have "When this permanent enters the battlefield, destroy target artifact or enchantment." - addCard(Zone.HAND, playerA, "Harmonic Sliver"); - addCard(Zone.BATTLEFIELD, playerB, "Alloy Myr", 2); // 2/2 - + // All Slivers have "When this permanent enters the battlefield, destroy target artifact or enchantment." + addCard(Zone.HAND, playerA, "Harmonic Sliver"); + + addCard(Zone.BATTLEFIELD, playerB, "Alloy Myr", 2); // 2/2 + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Harmonic Sliver"); setStopAt(1, PhaseStep.END_COMBAT); execute(); - + assertPermanentCount(playerA, "Harmonic Sliver", 1); assertGraveyardCount(playerB, "Alloy Myr", 1); - } - + } + /** - * If a Harmonic Sliver enters the battlefield and there is already one on the battlefield - * the controller has to destroy two artifacts or enchantments + * If a Harmonic Sliver enters the battlefield and there is already one on + * the battlefield the controller has to destroy two artifacts or + * enchantments */ @Test public void testHarmonicSliverNative2() { addCard(Zone.BATTLEFIELD, playerA, "Forest", 1); addCard(Zone.BATTLEFIELD, playerA, "Plains", 2); - - addCard(Zone.HAND, playerA, "Harmonic Sliver"); + + addCard(Zone.HAND, playerA, "Harmonic Sliver"); addCard(Zone.BATTLEFIELD, playerB, "Alloy Myr", 1); addCard(Zone.BATTLEFIELD, playerB, "Kitesail", 1); // All Slivers have "When this permanent enters the battlefield, destroy target artifact or enchantment." addCard(Zone.BATTLEFIELD, playerB, "Harmonic Sliver"); // 2/4 - + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Harmonic Sliver"); addTarget(playerA, "Alloy Myr"); addTarget(playerA, "Kitesail"); setStopAt(1, PhaseStep.END_COMBAT); execute(); - + assertPermanentCount(playerA, "Harmonic Sliver", 1); assertGraveyardCount(playerB, "Alloy Myr", 1); assertGraveyardCount(playerB, "Kitesail", 1); - } + } + + /** + * I cast Show and Tell, and put Sheoldred, Whispering One into play and my + * opponent put Phyrexian Metamorph into play and he was able to clone my + * Sheoldred, Whispering One. + * + * 6/1/2011 If Phyrexian Metamorph somehow enters the battlefield at the + * same time as another permanent (due to Mass Polymorph or Liliana Vess's + * third ability, for example), Phyrexian Metamorph can't become a copy of + * that permanent. You may only choose a permanent that's already on the + * battlefield. + * + * 400.6. If an object would move from one zone to another, determine what + * event is moving the object. If the object is moving to a public zone, all + * players look at it to see if it has any abilities that would affect the + * move. Then any appropriate replacement effects, whether they come from + * that object or from elsewhere, are applied to that event. If any effects + * or rules try to do two or more contradictory or mutually exclusive things + * to a particular object, that object's controller -- or its owner if it + * has no controller -- chooses which effect to apply, and what that effect + * does. (Note that multiple instances of the same thing may be mutually + * exclusive; for example, two simultaneous "destroy" effects.) Then the + * event moves the object. + */ + @Test + public void testShowAndTell() { + addCard(Zone.BATTLEFIELD, playerA, "Island", 3); + + // Each player may put an artifact, creature, enchantment, or land card from his or her hand onto the battlefield. + addCard(Zone.HAND, playerA, "Show and Tell"); // SORCERY {2}{U} + + // Swampwalk + // At the beginning of your upkeep, return target creature card from your graveyard to the battlefield. + // At the beginning of each opponent's upkeep, that player sacrifices a creature. + addCard(Zone.HAND, playerA, "Sheoldred, Whispering One"); + + addCard(Zone.HAND, playerB, "Phyrexian Metamorph"); + + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Show and Tell"); + + setStopAt(1, PhaseStep.BEGIN_COMBAT); + execute(); + + assertPermanentCount(playerA, "Sheoldred, Whispering One", 1); + assertPermanentCount(playerB, "Sheoldred, Whispering One", 0); + + assertGraveyardCount(playerB, "Phyrexian Metamorph", 1); + + } } diff --git a/Mage.Tests/src/test/java/org/mage/test/player/TestPlayer.java b/Mage.Tests/src/test/java/org/mage/test/player/TestPlayer.java index f168cd1c3dd..fe231aa0a37 100644 --- a/Mage.Tests/src/test/java/org/mage/test/player/TestPlayer.java +++ b/Mage.Tests/src/test/java/org/mage/test/player/TestPlayer.java @@ -554,7 +554,7 @@ public class TestPlayer implements Player { if (!choices.isEmpty()) { for (String choice : choices) { for (int index = 0; index < rEffects.size(); index++) { - if (choice.equals(rEffects.get(index))) { + if (choice.equals(rEffects.get(Integer.toString(index)))) { choices.remove(choice); return index; } @@ -1951,6 +1951,11 @@ public class TestPlayer implements Player { return computerPlayer.scry(value, source, game); } + @Override + public boolean moveCards(Set cards, Zone toZone, Ability source, Game game, boolean tapped, boolean faceDown, boolean byOwner, ArrayList appliedEffects) { + return computerPlayer.moveCards(cards, toZone, source, game, tapped, faceDown, byOwner, appliedEffects); + } + public void setAIPlayer(boolean AIPlayer) { this.AIPlayer = AIPlayer; } diff --git a/Mage.Tests/src/test/java/org/mage/test/serverside/base/impl/CardTestPlayerAPIImpl.java b/Mage.Tests/src/test/java/org/mage/test/serverside/base/impl/CardTestPlayerAPIImpl.java index bc7f74a40f4..77d726faea7 100644 --- a/Mage.Tests/src/test/java/org/mage/test/serverside/base/impl/CardTestPlayerAPIImpl.java +++ b/Mage.Tests/src/test/java/org/mage/test/serverside/base/impl/CardTestPlayerAPIImpl.java @@ -283,7 +283,7 @@ public abstract class CardTestPlayerAPIImpl extends MageTestPlayerBase implement if (card == null) { throw new IllegalArgumentException("[TEST] Couldn't find a card: " + cardName); } - PermanentCard p = new PermanentCard(card, null, currentGame); + PermanentCard p = new PermanentCard(card, player.getId(), currentGame); p.setTapped(tapped); getBattlefieldCards(player).add(p); } diff --git a/Mage/src/mage/abilities/common/DiesAttachedTriggeredAbility.java b/Mage/src/mage/abilities/common/DiesAttachedTriggeredAbility.java index 83adbea699a..e22e9c56744 100644 --- a/Mage/src/mage/abilities/common/DiesAttachedTriggeredAbility.java +++ b/Mage/src/mage/abilities/common/DiesAttachedTriggeredAbility.java @@ -60,7 +60,7 @@ public class DiesAttachedTriggeredAbility extends TriggeredAbilityImpl { // So check here with the LKI of the enchantment Permanent attachment = game.getPermanentOrLKIBattlefield(getSourceId()); if (attachment != null && attachment.getAttachedTo().equals(zEvent.getTargetId()) - && attachment.getAttachedToZoneChangeCounter() == zEvent.getTarget().getZoneChangeCounter(game)) { + && attachment.getAttachedToZoneChangeCounter() == zEvent.getTarget().getZoneChangeCounter(game) - 1) { triggered = true; } } diff --git a/Mage/src/mage/abilities/condition/common/EnchantedTargetCondition.java b/Mage/src/mage/abilities/condition/common/EnchantedTargetCondition.java index ccdc65b27aa..98cd2632909 100644 --- a/Mage/src/mage/abilities/condition/common/EnchantedTargetCondition.java +++ b/Mage/src/mage/abilities/condition/common/EnchantedTargetCondition.java @@ -1,8 +1,6 @@ - package mage.abilities.condition.common; import java.util.UUID; - import mage.abilities.Ability; import mage.abilities.condition.Condition; import mage.constants.CardType; @@ -15,8 +13,8 @@ import mage.target.Target; * @author Jeff */ public class EnchantedTargetCondition implements Condition { - - private static EnchantedTargetCondition fInstance = new EnchantedTargetCondition(); + + private static final EnchantedTargetCondition fInstance = new EnchantedTargetCondition(); public static Condition getInstance() { return fInstance; diff --git a/Mage/src/mage/abilities/effects/AuraReplacementEffect.java b/Mage/src/mage/abilities/effects/AuraReplacementEffect.java index eabe831a800..116930ba282 100644 --- a/Mage/src/mage/abilities/effects/AuraReplacementEffect.java +++ b/Mage/src/mage/abilities/effects/AuraReplacementEffect.java @@ -36,13 +36,13 @@ import mage.cards.Card; import mage.constants.CardType; import mage.constants.Duration; import mage.constants.Outcome; +import mage.constants.SpellAbilityType; import mage.constants.Zone; import mage.game.Game; import mage.game.events.GameEvent; import mage.game.events.ZoneChangeEvent; import mage.game.permanent.Permanent; import mage.game.permanent.PermanentCard; -import mage.game.stack.Spell; import mage.game.stack.StackAbility; import mage.players.Player; import mage.target.Target; @@ -103,12 +103,12 @@ public class AuraReplacementEffect extends ReplacementEffectImpl { UUID targetId = null; MageObject sourceObject = game.getObject(sourceId); boolean enchantCardInGraveyard = false; - if (sourceObject instanceof Spell) { - if (fromZone.equals(Zone.EXILED)) { - // cast from exile (e.g. Neightveil Spector) -> no replacement - return false; - } - } +// if (sourceObject instanceof Spell) { +// if (fromZone.equals(Zone.EXILED)) { +// // cast from exile (e.g. Neightveil Spector) -> no replacement +// return false; +// } +// } if (sourceObject instanceof StackAbility) { StackAbility stackAbility = (StackAbility) sourceObject; if (!stackAbility.getEffects().isEmpty()) { @@ -118,25 +118,34 @@ public class AuraReplacementEffect extends ReplacementEffectImpl { game.applyEffects(); // So continuousEffects are removed if previous effect of the same ability did move objects that cuase continuous effects if (targetId == null) { - Target target = card.getSpellAbility().getTargets().get(0).copy(); + SpellAbility spellAbility = card.getSpellAbility(); + if (spellAbility.getTargets().isEmpty()) { + for (Ability ability : card.getAbilities(game)) { + if ((ability instanceof SpellAbility) + && SpellAbilityType.BASE_ALTERNATE.equals(((SpellAbility) ability).getSpellAbilityType()) + && !ability.getTargets().isEmpty()) { + spellAbility = (SpellAbility) ability; + break; + } + } + } + if (spellAbility.getTargets().isEmpty()) { + return false; + } + Target target = spellAbility.getTargets().get(0).copy(); + Outcome auraOutcome = Outcome.BoostCreature; + for (Effect effect : spellAbility.getEffects()) { + if (effect instanceof AttachEffect) { + auraOutcome = effect.getOutcome(); + break; + } + } enchantCardInGraveyard = target instanceof TargetCardInGraveyard; if (target != null) { target.setNotTarget(true); // always not target because this way it's not handled targeted target.clearChosen(); // neccessary if e.g. aura is blinked multiple times } Player player = game.getPlayer(card.getOwnerId()); - Outcome auraOutcome = Outcome.BoostCreature; - Ability: - for (Ability ability : card.getAbilities()) { - if (ability instanceof SpellAbility) { - for (Effect effect : ability.getEffects()) { - if (effect instanceof AttachEffect) { - auraOutcome = effect.getOutcome(); - break Ability; - } - } - } - } if (target != null && player != null && player.choose(auraOutcome, target, card.getId(), game)) { targetId = target.getFirstTarget(); } @@ -151,44 +160,27 @@ public class AuraReplacementEffect extends ReplacementEffectImpl { } Player targetPlayer = game.getPlayer(targetId); if (targetCard != null || targetPermanent != null || targetPlayer != null) { - switch (fromZone) { - case EXILED: - game.getExile().removeCard(card, game); - break; - case GRAVEYARD: - game.getPlayer(card.getOwnerId()).removeFromGraveyard(card, game); - break; - case HAND: - game.getPlayer(card.getOwnerId()).removeFromHand(card, game); - break; - case LIBRARY: - game.getPlayer(card.getOwnerId()).removeFromLibrary(card, game); - break; - default: - } - game.rememberLKI(card.getId(), fromZone, card); - + card.removeFromZone(game, fromZone, sourceId); + card.updateZoneChangeCounter(game); PermanentCard permanent = new PermanentCard(card, card.getOwnerId(), game); game.getBattlefield().addPermanent(permanent); card.setZone(Zone.BATTLEFIELD, game); - boolean entered = permanent.entersBattlefield(event.getSourceId(), game, fromZone, true); - game.applyEffects(); - if (!entered) { - return false; - } - game.fireEvent(new ZoneChangeEvent(permanent, controllerId, fromZone, Zone.BATTLEFIELD)); + if (permanent.entersBattlefield(event.getSourceId(), game, fromZone, true)) { + if (targetCard != null) { + permanent.attachTo(targetCard.getId(), game); + } else if (targetPermanent != null) { + targetPermanent.addAttachment(permanent.getId(), game); + } else if (targetPlayer != null) { + targetPlayer.addAttachment(permanent.getId(), game); + } + game.applyEffects(); - if (targetCard != null) { - permanent.attachTo(targetCard.getId(), game); - } - if (targetPermanent != null) { - targetPermanent.addAttachment(permanent.getId(), game); - } - if (targetPlayer != null) { - targetPlayer.addAttachment(permanent.getId(), game); + game.fireEvent(new ZoneChangeEvent(permanent, controllerId, fromZone, Zone.BATTLEFIELD)); + return true; } + } - return true; + return false; } @Override @@ -199,7 +191,7 @@ public class AuraReplacementEffect extends ReplacementEffectImpl { @Override public boolean applies(GameEvent event, Ability source, Game game) { if (((ZoneChangeEvent) event).getToZone().equals(Zone.BATTLEFIELD) - && !(((ZoneChangeEvent) event).getFromZone().equals(Zone.HAND))) { + && !(((ZoneChangeEvent) event).getFromZone().equals(Zone.STACK))) { Card card = game.getCard(event.getTargetId()); if (card != null && card.getCardType().contains(CardType.ENCHANTMENT) && card.hasSubtype("Aura")) { return true; diff --git a/Mage/src/mage/abilities/effects/ContinuousEffects.java b/Mage/src/mage/abilities/effects/ContinuousEffects.java index 3477010296d..241c3de5289 100644 --- a/Mage/src/mage/abilities/effects/ContinuousEffects.java +++ b/Mage/src/mage/abilities/effects/ContinuousEffects.java @@ -1147,18 +1147,18 @@ public class ContinuousEffects implements Serializable { } } - private void setControllerForEffect(ContinuousEffectsList effects, UUID cardId, UUID controllerId) { + private void setControllerForEffect(ContinuousEffectsList effects, UUID sourceId, UUID controllerId) { for (Effect effect : effects) { HashSet abilities = effects.getAbility(effect.getId()); if (abilities != null) { for (Ability ability : abilities) { if (ability.getSourceId() != null) { - if (ability.getSourceId().equals(cardId)) { + if (ability.getSourceId().equals(sourceId)) { ability.setControllerId(controllerId); } } else { if (!ability.getZone().equals(Zone.COMMAND)) { - logger.fatal(new StringBuilder("No sourceId Ability: ").append(ability)); + logger.fatal("Continuous effect for ability with no sourceId Ability: " + ability); } } } diff --git a/Mage/src/mage/abilities/effects/ContinuousEffectsList.java b/Mage/src/mage/abilities/effects/ContinuousEffectsList.java index cbad22a927f..234a30e4564 100644 --- a/Mage/src/mage/abilities/effects/ContinuousEffectsList.java +++ b/Mage/src/mage/abilities/effects/ContinuousEffectsList.java @@ -1,30 +1,30 @@ /* -* Copyright 2012 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 2012 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; import java.util.ArrayList; @@ -46,18 +46,19 @@ import org.apache.log4j.Logger; * @param */ public class ContinuousEffectsList extends ArrayList { - + private static final Logger logger = Logger.getLogger(ContinuousEffectsList.class); // the effectAbilityMap holds for each effect all abilities that are connected (used) with this effect private final Map> effectAbilityMap = new HashMap<>(); - public ContinuousEffectsList() { } + public ContinuousEffectsList() { + } public ContinuousEffectsList(final ContinuousEffectsList effects) { this.ensureCapacity(effects.size()); - for (ContinuousEffect cost: effects) { - this.add((T)cost.copy()); + for (ContinuousEffect cost : effects) { + this.add((T) cost.copy()); } for (Map.Entry> entry : effects.effectAbilityMap.entrySet()) { HashSet newSet = new HashSet<>(); @@ -113,12 +114,12 @@ public class ContinuousEffectsList extends ArrayList Ability ability = it.next(); if (ability == null) { it.remove(); - } else if (ability instanceof MageSingleton) { + } else if (ability instanceof MageSingleton) { return false; - } else if (effect.isDiscarded()) { + } else if (effect.isDiscarded()) { it.remove(); } else { - switch(effect.getDuration()) { + switch (effect.getDuration()) { case WhileOnBattlefield: case WhileInGraveyard: case WhileOnStack: @@ -133,8 +134,8 @@ public class ContinuousEffectsList extends ArrayList break; case Custom: case UntilYourNextTurn: - if (effect.isInactive(ability , game)) { - it.remove(); + if (effect.isInactive(ability, game)) { + it.remove(); } } } @@ -143,9 +144,9 @@ public class ContinuousEffectsList extends ArrayList } /** - * Adds an effect and its connected ability to the list. - * For each effect will be stored, which abilities are connected to the effect. - * So an effect can be connected to multiple abilities. + * Adds an effect and its connected ability to the list. For each effect + * will be stored, which abilities are connected to the effect. So an effect + * can be connected to multiple abilities. * * @param effect - effect to add * @param source - connected ability @@ -153,8 +154,8 @@ public class ContinuousEffectsList extends ArrayList public void addEffect(T effect, Ability source) { if (effectAbilityMap.containsKey(effect.getId())) { HashSet set = effectAbilityMap.get(effect.getId()); - for (Ability ability: set) { - if (ability.getId().equals(source.getId()) && ability.getSourceId().equals(source.getSourceId()) ) { + for (Ability ability : set) { + if (ability.getId().equals(source.getId()) && ability.getSourceId().equals(source.getSourceId())) { return; } } diff --git a/Mage/src/mage/abilities/effects/EntersBattlefieldEffect.java b/Mage/src/mage/abilities/effects/EntersBattlefieldEffect.java index 90bdfaf14c3..5a03cbcf339 100644 --- a/Mage/src/mage/abilities/effects/EntersBattlefieldEffect.java +++ b/Mage/src/mage/abilities/effects/EntersBattlefieldEffect.java @@ -1,42 +1,43 @@ /* -* 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; -import mage.constants.Duration; import mage.MageObject; import mage.abilities.Ability; import mage.abilities.Mode; import mage.abilities.condition.Condition; +import mage.constants.Duration; +import mage.constants.Zone; import mage.game.Game; import mage.game.events.GameEvent; import mage.game.events.GameEvent.EventType; import mage.game.stack.Spell; +import mage.game.stack.StackObject; import mage.players.Player; /** @@ -116,12 +117,17 @@ public class EntersBattlefieldEffect extends ReplacementEffectImpl { } } Spell spell = game.getStack().getSpell(event.getSourceId()); - for (Effect effect: baseEffects) { + if (spell == null) { + StackObject stackObject = (StackObject) game.getLastKnownInformation(event.getSourceId(), Zone.STACK); + if (stackObject instanceof Spell) { + spell = (Spell) stackObject; + } + } + for (Effect effect : baseEffects) { if (source.activate(game, false)) { if (effect instanceof ContinuousEffect) { game.addEffect((ContinuousEffect) effect, source); - } - else { + } else { if (spell != null) { effect.setValue(SOURCE_CAST_SPELL_ABILITY, spell.getSpellAbility()); } diff --git a/Mage/src/mage/abilities/effects/common/CopyPermanentEffect.java b/Mage/src/mage/abilities/effects/common/CopyPermanentEffect.java index 7860911a2dd..f6318632ac6 100644 --- a/Mage/src/mage/abilities/effects/common/CopyPermanentEffect.java +++ b/Mage/src/mage/abilities/effects/common/CopyPermanentEffect.java @@ -1,16 +1,16 @@ /* * Copyright 2011 BetaSteward_at_googlemail.com. All rights reserved. - * + * * Redistribution and use in source and binary forms, with or without modification, are * permitted provided that the following conditions are met: - * + * * 1. Redistributions of source code must retain the above copyright notice, this list of * conditions and the following disclaimer. - * + * * 2. Redistributions in binary form must reproduce the above copyright notice, this list * of conditions and the following disclaimer in the documentation and/or other materials * provided with the distribution. - * + * * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR @@ -20,13 +20,14 @@ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * + * * The views and conclusions contained in the software and documentation are those of the * authors and should not be interpreted as representing official policies, either expressed * or implied, of BetaSteward_at_googlemail.com. */ package mage.abilities.effects.common; +import mage.MageObject; import mage.abilities.Ability; import mage.abilities.effects.OneShotEffect; import mage.constants.Outcome; @@ -66,6 +67,7 @@ public class CopyPermanentEffect extends OneShotEffect { public CopyPermanentEffect(FilterPermanent filter, ApplyToPermanent applier) { this(filter, applier, false); } + public CopyPermanentEffect(FilterPermanent filter, ApplyToPermanent applier, boolean useTarget) { super(Outcome.Copy); this.applier = applier; @@ -85,8 +87,8 @@ public class CopyPermanentEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { Player player = game.getPlayer(source.getControllerId()); - Permanent sourcePermanent = game.getPermanent(source.getSourceId()); - if (player != null && sourcePermanent != null) { + MageObject sourceObject = game.getObject(source.getSourceId()); + if (player != null && sourceObject != null) { Permanent copyFromPermanent = null; if (useTargetOfAbility) { copyFromPermanent = game.getPermanent(getTargetPointer().getFirst(game, source)); @@ -99,7 +101,7 @@ public class CopyPermanentEffect extends OneShotEffect { } } if (copyFromPermanent != null) { - bluePrintPermanent = game.copyPermanent(copyFromPermanent, sourcePermanent, source, applier); + bluePrintPermanent = game.copyPermanent(copyFromPermanent, sourceObject.getId(), source, applier); } return true; } diff --git a/Mage/src/mage/abilities/effects/common/CounterTargetWithReplacementEffect.java b/Mage/src/mage/abilities/effects/common/CounterTargetWithReplacementEffect.java index d23e2c8f2ff..01e36d989b4 100644 --- a/Mage/src/mage/abilities/effects/common/CounterTargetWithReplacementEffect.java +++ b/Mage/src/mage/abilities/effects/common/CounterTargetWithReplacementEffect.java @@ -28,7 +28,6 @@ package mage.abilities.effects.common; import java.util.UUID; -import mage.MageObject; import mage.abilities.Ability; import mage.abilities.Mode; import mage.abilities.effects.OneShotEffect; @@ -56,7 +55,8 @@ public class CounterTargetWithReplacementEffect extends OneShotEffect { /** * * @param targetZone - * @param flag use to specify when moving card to library
  • true = put on top
  • false = put on bottom
+ * @param flag use to specify when moving card to library
  • true = put + * on top
  • false = put on bottom
*/ public CounterTargetWithReplacementEffect(Zone targetZone, boolean flag) { super(Outcome.Detriment); @@ -83,33 +83,14 @@ public class CounterTargetWithReplacementEffect extends OneShotEffect { if (controller != null) { StackObject stackObject = game.getStack().getStackObject(objectId); if (stackObject != null && !game.replaceEvent(GameEvent.getEvent(GameEvent.EventType.COUNTER, objectId, sourceId, stackObject.getControllerId()))) { - boolean spell = false; if (stackObject instanceof Spell) { - game.rememberLKI(objectId, Zone.STACK, stackObject); - spell = true; - } - game.getStack().remove(stackObject); - if (spell && !((Spell) stackObject).isCopiedSpell()) { - MageObject mageObject = game.getObject(stackObject.getSourceId()); - if (mageObject instanceof Card) { - Card card = (Card) mageObject; - switch (targetZone) { - case LIBRARY: - controller.moveCardToLibraryWithInfo(card, sourceId, game, Zone.STACK, flag, true); - break; - case EXILED: - controller.moveCardToExileWithInfo(card, null, "", sourceId, game, Zone.STACK, true); - break; - default: - controller.moveCards(card, Zone.STACK, targetZone, source, game); - } - } else { - return false; - } + controller.moveCards((Card) stackObject, null, targetZone, source, game); + } else { + game.getStack().remove(stackObject); } game.fireEvent(GameEvent.getEvent(GameEvent.EventType.COUNTERED, objectId, sourceId, stackObject.getControllerId())); return true; - } + } } return false; } diff --git a/Mage/src/mage/cards/Card.java b/Mage/src/mage/cards/Card.java index 6e5ec8c1d32..5befb3d3a5f 100644 --- a/Mage/src/mage/cards/Card.java +++ b/Mage/src/mage/cards/Card.java @@ -40,6 +40,7 @@ import mage.constants.Zone; import mage.counters.Counter; import mage.counters.Counters; import mage.game.Game; +import mage.game.permanent.Permanent; public interface Card extends MageObject { @@ -65,6 +66,8 @@ public interface Card extends MageObject { String getTokenSetCode(); + void checkForCountersToAdd(Permanent permanent, Game game); + void setFaceDown(boolean value, Game game); boolean isFaceDown(Game game); @@ -125,6 +128,8 @@ public interface Card extends MageObject { boolean cast(Game game, Zone fromZone, SpellAbility ability, UUID controllerId); + boolean removeFromZone(Game game, Zone fromZone, UUID sourceId); + boolean putOntoBattlefield(Game game, Zone fromZone, UUID sourceId, UUID controllerId); boolean putOntoBattlefield(Game game, Zone fromZone, UUID sourceId, UUID controllerId, boolean tapped); diff --git a/Mage/src/mage/cards/CardImpl.java b/Mage/src/mage/cards/CardImpl.java index ee05eb447bd..d6dc1f58c7d 100644 --- a/Mage/src/mage/cards/CardImpl.java +++ b/Mage/src/mage/cards/CardImpl.java @@ -54,8 +54,6 @@ import static mage.constants.Zone.EXILED; import static mage.constants.Zone.GRAVEYARD; import static mage.constants.Zone.HAND; import static mage.constants.Zone.LIBRARY; -import static mage.constants.Zone.OUTSIDE; -import static mage.constants.Zone.PICK; import static mage.constants.Zone.STACK; import mage.counters.Counter; import mage.counters.Counters; @@ -65,6 +63,7 @@ import mage.game.Game; import mage.game.command.Commander; import mage.game.events.GameEvent; import mage.game.events.ZoneChangeEvent; +import mage.game.permanent.Permanent; import mage.game.permanent.PermanentCard; import mage.game.stack.Spell; import mage.game.stack.StackObject; @@ -342,55 +341,7 @@ public abstract class CardImpl extends MageObjectImpl implements Card { Zone fromZone = game.getState().getZone(objectId); ZoneChangeEvent event = new ZoneChangeEvent(this.objectId, sourceId, ownerId, fromZone, toZone, appliedEffects); if (!game.replaceEvent(event)) { - if (event.getFromZone() != null) { - switch (event.getFromZone()) { - case GRAVEYARD: - game.getPlayer(ownerId).removeFromGraveyard(this, game); - break; - case HAND: - game.getPlayer(ownerId).removeFromHand(this, game); - break; - case LIBRARY: - game.getPlayer(ownerId).removeFromLibrary(this, game); - break; - case EXILED: - game.getExile().removeCard(this, game); - break; - case OUTSIDE: - game.getPlayer(ownerId).getSideboard().remove(this); - break; - case COMMAND: - game.getState().getCommand().remove((Commander) game.getObject(objectId)); - break; - case STACK: - StackObject stackObject = game.getStack().getSpell(getSpellAbility().getId()); - if (stackObject == null && (this instanceof SplitCard)) { // handle if half of Split cast is on the stack - stackObject = game.getStack().getSpell(((SplitCard) this).getLeftHalfCard().getId()); - if (stackObject == null) { - stackObject = game.getStack().getSpell(((SplitCard) this).getRightHalfCard().getId()); - } - } - if (stackObject == null) { - stackObject = game.getStack().getSpell(getId()); - } - if (stackObject != null) { - game.getStack().remove(stackObject); - } - break; - case PICK: - case BATTLEFIELD: // for sacrificing permanents or putting to library - break; - default: - Card sourceCard = game.getCard(sourceId); - logger.fatal(new StringBuilder("Invalid from zone [").append(fromZone) - .append("] for card [").append(this.getName()) - .append("] to zone [").append(toZone) - .append("] source [").append(sourceCard != null ? sourceCard.getName() : "null").append("]").toString()); - break; - } - game.rememberLKI(objectId, event.getFromZone(), this); - } - + removeFromZone(game, fromZone, sourceId); setFaceDown(false, game); updateZoneChangeCounter(game); switch (event.getToZone()) { @@ -454,32 +405,7 @@ public abstract class CardImpl extends MageObjectImpl implements Card { Card mainCard = getMainCard(); ZoneChangeEvent event = new ZoneChangeEvent(mainCard.getId(), ability.getId(), controllerId, fromZone, Zone.STACK); if (!game.replaceEvent(event)) { - if (event.getFromZone() != null) { - switch (event.getFromZone()) { - case GRAVEYARD: - game.getPlayer(ownerId).removeFromGraveyard(mainCard, game); - break; - case HAND: - game.getPlayer(ownerId).removeFromHand(mainCard, game); - break; - case LIBRARY: - game.getPlayer(ownerId).removeFromLibrary(mainCard, game); - break; - case EXILED: - game.getExile().removeCard(mainCard, game); - break; - case OUTSIDE: - game.getPlayer(ownerId).getSideboard().remove(mainCard); - break; - - case COMMAND: - game.getState().getCommand().remove((Commander) game.getObject(mainCard.getId())); - break; - default: - //logger.warning("moveToZone, not fully implemented: from="+event.getFromZone() + ", to="+event.getToZone()); - } - game.rememberLKI(mainCard.getId(), event.getFromZone(), this); - } + mainCard.removeFromZone(game, fromZone, ability.getSourceId()); game.getStack().push(new Spell(this, ability.copy(), controllerId, event.getFromZone())); updateZoneChangeCounter(game); setZone(event.getToZone(), game); @@ -499,36 +425,7 @@ public abstract class CardImpl extends MageObjectImpl implements Card { Zone fromZone = game.getState().getZone(objectId); ZoneChangeEvent event = new ZoneChangeEvent(this.objectId, sourceId, ownerId, fromZone, Zone.EXILED, appliedEffects); if (!game.replaceEvent(event)) { - if (fromZone != null) { - switch (fromZone) { - case GRAVEYARD: - game.getPlayer(ownerId).removeFromGraveyard(this, game); - break; - case HAND: - game.getPlayer(ownerId).removeFromHand(this, game); - break; - case LIBRARY: - game.getPlayer(ownerId).removeFromLibrary(this, game); - break; - case EXILED: - game.getExile().removeCard(this, game); - break; - case STACK: - StackObject stackObject = game.getStack().getSpell(getId()); - if (stackObject != null) { - game.getStack().remove(stackObject); - } - break; - case PICK: - // nothing to do - break; - default: - MageObject object = game.getObject(sourceId); - logger.warn(new StringBuilder("moveToExile, not fully implemented: from = ").append(fromZone).append(" - ").append(object != null ? object.getName() : "null")); - } - game.rememberLKI(objectId, event.getFromZone(), this); - } - + removeFromZone(game, fromZone, sourceId); if (exileId == null) { game.getExile().getPermanentExile().add(this); } else { @@ -568,37 +465,7 @@ public abstract class CardImpl extends MageObjectImpl implements Card { if (facedown) { this.setFaceDown(false, game); } - if (fromZone != null) { - boolean removed = false; - switch (fromZone) { - case GRAVEYARD: - removed = game.getPlayer(ownerId).removeFromGraveyard(this, game); - break; - case HAND: - removed = game.getPlayer(ownerId).removeFromHand(this, game); - break; - case LIBRARY: - removed = game.getPlayer(ownerId).removeFromLibrary(this, game); - break; - case EXILED: - game.getExile().removeCard(this, game); - removed = true; - break; - case COMMAND: - // command object (commander) is only on the stack, so no removing neccessary here - removed = true; - break; - case PICK: - removed = true; - break; - default: - logger.warn("putOntoBattlefield, not fully implemented: fromZone=" + fromZone); - } - game.rememberLKI(objectId, event.getFromZone(), this); - if (!removed) { - logger.warn("Couldn't find card in fromZone, card=" + getName() + ", fromZone=" + fromZone); - } - } + removeFromZone(game, fromZone, sourceId); updateZoneChangeCounter(game); PermanentCard permanent = new PermanentCard(this, event.getPlayerId(), game); // make sure the controller of all continuous effects of this card are switched to the current controller @@ -624,7 +491,76 @@ public abstract class CardImpl extends MageObjectImpl implements Card { return false; } - private void checkForCountersToAdd(PermanentCard permanent, Game game) { + @Override + public boolean removeFromZone(Game game, Zone fromZone, UUID sourceId) { + boolean removed = false; + MageObject lkiObject = null; + switch (fromZone) { + case GRAVEYARD: + removed = game.getPlayer(ownerId).removeFromGraveyard(this, game); + break; + case HAND: + removed = game.getPlayer(ownerId).removeFromHand(this, game); + break; + case LIBRARY: + removed = game.getPlayer(ownerId).removeFromLibrary(this, game); + break; + case EXILED: + if (game.getExile().getCard(getId(), game) != null) { + game.getExile().removeCard(this, game); + removed = true; + } + break; + case STACK: + StackObject stackObject = game.getStack().getSpell(getSpellAbility().getId()); + if (stackObject == null && (this instanceof SplitCard)) { // handle if half of Split cast is on the stack + stackObject = game.getStack().getSpell(((SplitCard) this).getLeftHalfCard().getId()); + if (stackObject == null) { + stackObject = game.getStack().getSpell(((SplitCard) this).getRightHalfCard().getId()); + } + } + if (stackObject == null) { + stackObject = game.getStack().getSpell(getId()); + } + if (stackObject != null) { + removed = game.getStack().remove(stackObject); + lkiObject = stackObject; + } + break; + case COMMAND: + lkiObject = (Commander) game.getObject(objectId); + if (lkiObject != null) { + removed = game.getState().getCommand().remove((Commander) game.getObject(objectId)); + } + break; + case OUTSIDE: + if (isCopy()) { // copied cards have no need to be removed from a previous zone + removed = true; + } else if (game.getPlayer(ownerId).getSideboard().contains(this.getId())) { + game.getPlayer(ownerId).getSideboard().remove(this.getId()); + removed = true; + } + break; + + case PICK: // Pick should no longer be used + case BATTLEFIELD: // for sacrificing permanents or putting to library + removed = true; + break; + default: + MageObject sourceObject = game.getObject(sourceId); + logger.fatal("Invalid from zone [" + fromZone + "] for card [" + this.getIdName() + + "] source [" + (sourceObject != null ? sourceObject.getName() : "null") + "]"); + break; + } + game.rememberLKI(objectId, fromZone, lkiObject != null ? lkiObject : this); + if (!removed) { + logger.warn("Couldn't find card in fromZone, card=" + getIdName() + ", fromZone=" + fromZone); + } + return removed; + } + + @Override + public void checkForCountersToAdd(Permanent permanent, Game game) { Counters countersToAdd = game.getEnterWithCounters(permanent.getId()); if (countersToAdd != null) { for (Counter counter : countersToAdd.values()) { diff --git a/Mage/src/mage/game/CardState.java b/Mage/src/mage/game/CardState.java index 1f471370f0b..cf63e960bb4 100644 --- a/Mage/src/mage/game/CardState.java +++ b/Mage/src/mage/game/CardState.java @@ -7,24 +7,25 @@ import mage.abilities.Abilities; import mage.abilities.AbilitiesImpl; import mage.abilities.Ability; import mage.counters.Counters; + /** * * @author BetaSteward */ public class CardState implements Serializable { - + protected boolean faceDown; protected Map info; protected Counters counters; protected Abilities abilities; - + private static final Map emptyInfo = new HashMap<>(); private static final Abilities emptyAbilities = new AbilitiesImpl<>(); - + public CardState() { counters = new Counters(); } - + public CardState(final CardState state) { this.faceDown = state.faceDown; if (state.info != null) { @@ -34,7 +35,7 @@ public class CardState implements Serializable { counters = state.counters.copy(); if (state.abilities != null) { abilities = new AbilitiesImpl<>(); - for (Ability ability: state.abilities) { + for (Ability ability : state.abilities) { abilities.add(ability.copy()); } } @@ -43,7 +44,7 @@ public class CardState implements Serializable { public CardState copy() { return new CardState(this); } - + public void setFaceDown(boolean value) { faceDown = value; } @@ -66,45 +67,45 @@ public class CardState implements Serializable { info.put(key, value); } } - + public Map getInfo() { if (info == null) { return emptyInfo; } return info; } - + public Abilities getAbilities() { if (abilities == null) { return emptyAbilities; } return abilities; } - + public void addAbility(Ability ability) { if (abilities == null) { abilities = new AbilitiesImpl<>(); } abilities.add(ability); - for (Ability sub: ability.getSubAbilities()) { + for (Ability sub : ability.getSubAbilities()) { abilities.add(sub); } } - + public void clearAbilities() { if (abilities != null) { - for (Ability ability: abilities) { - ability.setSourceId(null); - ability.setControllerId(null); - } +// for (Ability ability: abilities) { // Causes problems if temporary (gained) continuous effects are removed +// ability.setSourceId(null); +// ability.setControllerId(null); +// } abilities = null; } } - + public void clear() { counters.clear(); info = null; clearAbilities(); } - + } diff --git a/Mage/src/mage/game/Game.java b/Mage/src/mage/game/Game.java index 1b19e9d30c5..b75ea6a76e5 100644 --- a/Mage/src/mage/game/Game.java +++ b/Mage/src/mage/game/Game.java @@ -364,14 +364,14 @@ public interface Game extends MageItem, Serializable { * This version supports copying of copies of any depth. * * @param copyFromPermanent - * @param copyToPermanent + * @param copyToPermanentId * @param source * @param applier * @return */ - Permanent copyPermanent(Permanent copyFromPermanent, Permanent copyToPermanent, Ability source, ApplyToPermanent applier); + Permanent copyPermanent(Permanent copyFromPermanent, UUID copyToPermanentId, Ability source, ApplyToPermanent applier); - Permanent copyPermanent(Duration duration, Permanent copyFromPermanent, Permanent copyToPermanent, Ability source, ApplyToPermanent applier); + Permanent copyPermanent(Duration duration, Permanent copyFromPermanent, UUID copyToPermanentId, Ability source, ApplyToPermanent applier); Card copyCard(Card cardToCopy, Ability source, UUID newController); diff --git a/Mage/src/mage/game/GameImpl.java b/Mage/src/mage/game/GameImpl.java index a0b1c225791..27abfa58db1 100644 --- a/Mage/src/mage/game/GameImpl.java +++ b/Mage/src/mage/game/GameImpl.java @@ -49,6 +49,7 @@ import mage.MageObject; import mage.abilities.Ability; import mage.abilities.ActivatedAbility; import mage.abilities.DelayedTriggeredAbility; +import mage.abilities.SpellAbility; import mage.abilities.TriggeredAbility; import mage.abilities.common.ChancellorAbility; import mage.abilities.common.GemstoneCavernsAbility; @@ -77,6 +78,7 @@ import mage.constants.Outcome; import mage.constants.PhaseStep; import mage.constants.PlayerAction; import mage.constants.RangeOfInfluence; +import mage.constants.SpellAbilityType; import mage.constants.Zone; import mage.counters.CounterType; import mage.counters.Counters; @@ -1402,12 +1404,12 @@ public abstract class GameImpl implements Game, Serializable { } @Override - public Permanent copyPermanent(Permanent copyFromPermanent, Permanent copyToPermanent, Ability source, ApplyToPermanent applier) { - return copyPermanent(Duration.Custom, copyFromPermanent, copyToPermanent, source, applier); + public Permanent copyPermanent(Permanent copyFromPermanent, UUID copyToPermanentId, Ability source, ApplyToPermanent applier) { + return copyPermanent(Duration.Custom, copyFromPermanent, copyToPermanentId, source, applier); } @Override - public Permanent copyPermanent(Duration duration, Permanent copyFromPermanent, Permanent copyToPermanent, Ability source, ApplyToPermanent applier) { + public Permanent copyPermanent(Duration duration, Permanent copyFromPermanent, UUID copyToPermanentId, Ability source, ApplyToPermanent applier) { Permanent newBluePrint = null; // handle copies of copies for (Effect effect : getState().getContinuousEffects().getLayeredEffects(this)) { @@ -1440,7 +1442,7 @@ public abstract class GameImpl implements Game, Serializable { applier.apply(this, newBluePrint); } - CopyEffect newEffect = new CopyEffect(duration, newBluePrint, copyToPermanent.getId()); + CopyEffect newEffect = new CopyEffect(duration, newBluePrint, copyToPermanentId); newEffect.newId(); newEffect.setApplier(applier); Ability newAbility = source.copy(); @@ -1686,11 +1688,22 @@ public abstract class GameImpl implements Game, Serializable { } } } else { + SpellAbility spellAbility = perm.getSpellAbility(); if (perm.getSpellAbility().getTargets().isEmpty()) { + for (Ability ability : perm.getAbilities(this)) { + if ((ability instanceof SpellAbility) + && SpellAbilityType.BASE_ALTERNATE.equals(((SpellAbility) ability).getSpellAbilityType()) + && !ability.getTargets().isEmpty()) { + spellAbility = (SpellAbility) ability; + break; + } + } + } + if (spellAbility.getTargets().isEmpty()) { Permanent enchanted = this.getPermanent(perm.getAttachedTo()); logger.error("Aura without target: " + perm.getName() + " attached to " + (enchanted == null ? " null" : enchanted.getName())); } else { - Target target = perm.getSpellAbility().getTargets().get(0); + Target target = spellAbility.getTargets().get(0); if (target instanceof TargetPermanent) { Permanent attachedTo = getPermanent(perm.getAttachedTo()); if (attachedTo == null || !attachedTo.getAttachments().contains(perm.getId())) { @@ -1706,7 +1719,7 @@ public abstract class GameImpl implements Game, Serializable { } } } else { - Filter auraFilter = perm.getSpellAbility().getTargets().get(0).getFilter(); + Filter auraFilter = spellAbility.getTargets().get(0).getFilter(); if (auraFilter instanceof FilterControlledCreaturePermanent) { if (!((FilterControlledCreaturePermanent) auraFilter).match(attachedTo, perm.getId(), perm.getControllerId(), this) || attachedTo.cantBeEnchantedBy(perm, this)) { @@ -1737,7 +1750,7 @@ public abstract class GameImpl implements Game, Serializable { somethingHappened = true; } } else { - Filter auraFilter = perm.getSpellAbility().getTargets().get(0).getFilter(); + Filter auraFilter = spellAbility.getTargets().get(0).getFilter(); if (!auraFilter.match(attachedToPlayer, this) || attachedToPlayer.hasProtectionFrom(perm, this)) { if (movePermanentToGraveyardWithInfo(perm)) { somethingHappened = true; diff --git a/Mage/src/mage/game/GameState.java b/Mage/src/mage/game/GameState.java index 3b1bdd805ad..68f312ad7aa 100644 --- a/Mage/src/mage/game/GameState.java +++ b/Mage/src/mage/game/GameState.java @@ -624,7 +624,7 @@ public class GameState implements Serializable, Copyable { public Permanent getPermanent(UUID permanentId) { if (permanentId != null && battlefield.containsPermanent(permanentId)) { Permanent permanent = battlefield.getPermanent(permanentId); - setZone(permanent.getId(), Zone.BATTLEFIELD); // shouldn't this be set anyway? (LevelX2) + // setZone(permanent.getId(), Zone.BATTLEFIELD); // shouldn't this be set anyway? (LevelX2) return permanent; } return null; diff --git a/Mage/src/mage/game/permanent/PermanentCard.java b/Mage/src/mage/game/permanent/PermanentCard.java index af54c92b1dc..2e87290d9e2 100644 --- a/Mage/src/mage/game/permanent/PermanentCard.java +++ b/Mage/src/mage/game/permanent/PermanentCard.java @@ -1,31 +1,30 @@ /* -* Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. -* -* Redistribution and use in source and binary forms, with or without modification, are -* permitted provided that the following conditions are met: -* -* 1. Redistributions of source code must retain the above copyright notice, this list of -* conditions and the following disclaimer. -* -* 2. Redistributions in binary form must reproduce the above copyright notice, this list -* of conditions and the following disclaimer in the documentation and/or other materials -* provided with the distribution. -* -* THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED -* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND -* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR -* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR -* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON -* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING -* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF -* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -* -* The views and conclusions contained in the software and documentation are those of the -* authors and should not be interpreted as representing official policies, either expressed -* or implied, of BetaSteward_at_googlemail.com. -*/ - + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ package mage.game.permanent; import java.util.ArrayList; @@ -49,20 +48,21 @@ public class PermanentCard extends PermanentImpl { protected int maxLevelCounters; protected Card card; - protected int zoneChangeCounter; + // protected int zoneChangeCounter; public PermanentCard(Card card, UUID controllerId, Game game) { super(card.getId(), card.getOwnerId(), controllerId, card.getName()); - this.card = card.copy(); + // this.card = card.copy(); + this.card = card; init(card, game); } private void init(Card card, Game game) { copyFromCard(card); - this.zoneChangeCounter = card.getZoneChangeCounter(game); + // this.zoneChangeCounter = card.getZoneChangeCounter(game); /*if (card.getCardType().contains(CardType.PLANESWALKER)) { - this.loyalty = new MageInt(card.getLoyalty().getValue()); - }*/ + this.loyalty = new MageInt(card.getLoyalty().getValue()); + }*/ if (card instanceof LevelerCard) { maxLevelCounters = ((LevelerCard) card).getMaxLevelCounters(); } @@ -79,7 +79,6 @@ public class PermanentCard extends PermanentImpl { super(permanent); this.card = permanent.card.copy(); this.maxLevelCounters = permanent.maxLevelCounters; - this.zoneChangeCounter = permanent.zoneChangeCounter; } @Override @@ -94,13 +93,12 @@ public class PermanentCard extends PermanentImpl { this.name = card.getName(); this.abilities.clear(); if (this.faceDown) { - for (Ability ability: card.getAbilities()) { + for (Ability ability : card.getAbilities()) { if (ability.getWorksFaceDown()) { this.abilities.add(ability.copy()); } } - } - else { + } else { this.abilities = card.getAbilities().copy(); } this.abilities.setControllerId(this.controllerId); @@ -135,6 +133,7 @@ public class PermanentCard extends PermanentImpl { public Card getCard() { return card; } + @Override public boolean moveToZone(Zone toZone, UUID sourceId, Game game, boolean flag) { return moveToZone(toZone, sourceId, game, flag, null); @@ -255,20 +254,20 @@ public class PermanentCard extends PermanentImpl { } return super.getManaCost(); } - + @Override public int getZoneChangeCounter(Game game) { - return this.zoneChangeCounter; + return card.getZoneChangeCounter(game); } @Override public void updateZoneChangeCounter(Game game) { - this.zoneChangeCounter++; + card.updateZoneChangeCounter(game); } @Override public void setZoneChangeCounter(int value, Game game) { - this.zoneChangeCounter = value; + card.setZoneChangeCounter(value, game); } } diff --git a/Mage/src/mage/game/stack/Spell.java b/Mage/src/mage/game/stack/Spell.java index b1cf6950138..2972b65d2de 100644 --- a/Mage/src/mage/game/stack/Spell.java +++ b/Mage/src/mage/game/stack/Spell.java @@ -221,14 +221,14 @@ public class Spell extends StackObjImpl implements Card { } else if (this.getCardType().contains(CardType.ENCHANTMENT) && this.getSubtype().contains("Aura")) { if (ability.getTargets().stillLegal(ability, game)) { updateOptionalCosts(0); - boolean bestow = this.getSpellAbility() instanceof BestowAbility; + boolean bestow = ability instanceof BestowAbility; if (bestow) { // Must be removed first time, after that will be removed by continous effect // Otherwise effects like evolve trigger from creature comes into play event card.getCardType().remove(CardType.CREATURE); card.getSubtype().add("Aura"); } - if (card.putOntoBattlefield(game, fromZone, ability.getSourceId(), controllerId)) { + if (card.putOntoBattlefield(game, Zone.STACK, ability.getSourceId(), controllerId)) { if (bestow) { // card will be copied during putOntoBattlefield, so the card of CardPermanent has to be changed // TODO: Find a better way to prevent bestow creatures from being effected by creature affecting abilities @@ -238,8 +238,6 @@ public class Spell extends StackObjImpl implements Card { ((PermanentCard) permanent).getCard().getCardType().add(CardType.CREATURE); ((PermanentCard) permanent).getCard().getSubtype().remove("Aura"); } - card.getCardType().add(CardType.CREATURE); - card.getSubtype().remove("Aura"); } return ability.resolve(game); } @@ -251,7 +249,7 @@ public class Spell extends StackObjImpl implements Card { // Aura has no legal target and its a bestow enchantment -> Add it to battlefield as creature if (this.getSpellAbility() instanceof BestowAbility) { updateOptionalCosts(0); - result = card.putOntoBattlefield(game, fromZone, ability.getSourceId(), controllerId); + result = card.putOntoBattlefield(game, Zone.STACK, ability.getSourceId(), controllerId); return result; } else { //20091005 - 608.2b @@ -263,7 +261,7 @@ public class Spell extends StackObjImpl implements Card { } } else { updateOptionalCosts(0); - result = card.putOntoBattlefield(game, fromZone, ability.getSourceId(), controllerId, false, faceDown); + result = card.putOntoBattlefield(game, Zone.STACK, ability.getSourceId(), controllerId, false, faceDown); return result; } } @@ -646,6 +644,11 @@ public class Spell extends StackObjImpl implements Card { } } + @Override + public boolean removeFromZone(Game game, Zone fromZone, UUID sourceId) { + return card.removeFromZone(game, fromZone, sourceId); + } + @Override public boolean moveToZone(Zone zone, UUID sourceId, Game game, boolean flag) { return moveToZone(zone, sourceId, game, flag, null); @@ -847,4 +850,9 @@ public class Spell extends StackObjImpl implements Card { return countered; } + @Override + public void checkForCountersToAdd(Permanent permanent, Game game) { + throw new UnsupportedOperationException("Not supported for Spell"); + } + } diff --git a/Mage/src/mage/game/stack/SpellStack.java b/Mage/src/mage/game/stack/SpellStack.java index 62ea3bb72ca..c22c449d2b6 100644 --- a/Mage/src/mage/game/stack/SpellStack.java +++ b/Mage/src/mage/game/stack/SpellStack.java @@ -34,6 +34,7 @@ import mage.MageObject; import mage.constants.Zone; import mage.game.Game; import mage.game.events.GameEvent; +import org.apache.log4j.Logger; /** * @@ -41,6 +42,8 @@ import mage.game.events.GameEvent; */ public class SpellStack extends ArrayDeque { + private static final Logger logger = Logger.getLogger(SpellStack.class); + protected Date dateLastAdded; public SpellStack() { @@ -61,18 +64,21 @@ public class SpellStack extends ArrayDeque { top.resolve(game); } finally { if (top != null) { - this.remove(top); + if (contains(top)) { + logger.warn("StackObject was still on the stack after resoving" + top.getName()); + this.remove(top); + } } } } - public void remove(StackObject object) { + public boolean remove(StackObject object) { for (StackObject spell : this) { if (spell.getId().equals(object.getId())) { - super.remove(spell); - return; + return super.remove(spell); } } + return false; } public boolean counter(UUID objectId, UUID sourceId, Game game) { diff --git a/Mage/src/mage/game/stack/StackAbility.java b/Mage/src/mage/game/stack/StackAbility.java index 157dace466c..b23de503454 100644 --- a/Mage/src/mage/game/stack/StackAbility.java +++ b/Mage/src/mage/game/stack/StackAbility.java @@ -104,12 +104,15 @@ public class StackAbility extends StackObjImpl implements Ability { @Override public boolean resolve(Game game) { if (ability.getTargets().stillLegal(ability, game)) { - return ability.resolve(game); + boolean result = ability.resolve(game); + game.getStack().remove(this); + return result; } if (!game.isSimulation()) { game.informPlayers("Ability has been fizzled: " + getRule()); } counter(null, game); + game.getStack().remove(this); return false; } diff --git a/Mage/src/mage/players/Player.java b/Mage/src/mage/players/Player.java index eb3d7d70b2c..fe56815b058 100644 --- a/Mage/src/mage/players/Player.java +++ b/Mage/src/mage/players/Player.java @@ -635,6 +635,20 @@ public interface Player extends MageItem, Copyable { boolean moveCards(Set cards, Zone fromZone, Zone toZone, Ability source, Game game); + /** + * + * @param cards + * @param toZone + * @param source + * @param game + * @param tapped tha cards are tapped on the battlefield + * @param faceDown the cards are face down in the to zone + * @param byOwner the card is moved (or put onto battlefield) by the owner + * of the card (instead of the controller of the source) + * @return + */ + boolean moveCards(Set cards, Zone toZone, Ability source, Game game, boolean tapped, boolean faceDown, boolean byOwner, ArrayList appliedEffects); + boolean moveCardsToExile(Card card, Ability source, Game game, boolean withName, UUID exileId, String exileZoneName); boolean moveCardsToExile(Set cards, Ability source, Game game, boolean withName, UUID exileId, String exileZoneName); diff --git a/Mage/src/mage/players/PlayerImpl.java b/Mage/src/mage/players/PlayerImpl.java index e716270b2e4..f1efe5d3301 100644 --- a/Mage/src/mage/players/PlayerImpl.java +++ b/Mage/src/mage/players/PlayerImpl.java @@ -113,6 +113,7 @@ import mage.game.events.DamagePlayerEvent; import mage.game.events.DamagedPlayerEvent; import mage.game.events.GameEvent; import mage.game.events.GameEvent.EventType; +import mage.game.events.ZoneChangeEvent; import mage.game.events.ZoneChangeGroupEvent; import mage.game.match.MatchPlayer; import mage.game.permanent.Permanent; @@ -671,8 +672,7 @@ public abstract class PlayerImpl implements Player, Serializable { @Override public boolean removeFromHand(Card card, Game game) { - hand.remove(card); - return true; + return hand.remove(card.getId()); } @Override @@ -3000,13 +3000,13 @@ public abstract class PlayerImpl implements Player, Serializable { case HAND: for (Card card : cards) { fromZone = game.getState().getZone(card.getId()); - if (fromZone == Zone.STACK) { - // If a spell is returned to its owner's hand, it's removed from the stack and thus will not resolve - Spell spell = game.getStack().getSpell(card.getId()); - if (spell != null) { - game.getStack().remove(spell); - } - } +// if (fromZone == Zone.STACK) { +// // If a spell is returned to its owner's hand, it's removed from the stack and thus will not resolve +// Spell spell = game.getStack().getSpell(card.getId()); +// if (spell != null) { +// game.getStack().remove(spell); +// } +// } boolean hideCard = fromZone.equals(Zone.LIBRARY) || (card.isFaceDown(game) && !fromZone.equals(Zone.STACK) && !fromZone.equals(Zone.BATTLEFIELD)); if (moveCardToHandWithInfo(card, source == null ? null : source.getSourceId(), game, !hideCard)) { @@ -3038,6 +3038,69 @@ public abstract class PlayerImpl implements Player, Serializable { return successfulMovedCards.size() > 0; } + @Override + public boolean moveCards(Set cards, Zone toZone, Ability source, Game game, boolean tapped, boolean faceDown, boolean byOwner, ArrayList appliedEffects) { + if (cards.isEmpty()) { + return true; + } + Set successfulMovedCards = new LinkedHashSet<>(); + Zone fromZone = null; + switch (toZone) { + case BATTLEFIELD: + List permanents = new ArrayList<>(); + List permanentsEntered = new ArrayList<>(); + for (Card card : cards) { + UUID controllingPlayerId = byOwner ? card.getOwnerId() : source.getControllerId(); + fromZone = game.getState().getZone(card.getId()); + if (faceDown) { + card.setFaceDown(true, game); + } + ZoneChangeEvent event = new ZoneChangeEvent(card.getId(), source.getSourceId(), controllingPlayerId, fromZone, Zone.BATTLEFIELD, appliedEffects, tapped); + if (!game.replaceEvent(event)) { + // get permanent + Permanent permanent = new PermanentCard(card, controllingPlayerId, game); + permanents.add(permanent); + card.checkForCountersToAdd(permanent, game); + permanent.setTapped(tapped); + permanent.setFaceDown(faceDown, game); + } + if (faceDown) { + card.setFaceDown(false, game); + } + } + game.setScopeRelevant(true); + for (Permanent permanent : permanents) { + fromZone = game.getState().getZone(permanent.getId()); + if (permanent.entersBattlefield(source.getSourceId(), game, fromZone, true)) { + permanentsEntered.add(permanent); + } + } + game.setScopeRelevant(false); + game.applyEffects(); + for (Permanent permanent : permanentsEntered) { + fromZone = game.getState().getZone(permanent.getId()); + if (((Card) permanent).removeFromZone(game, fromZone, source.getSourceId())) { + permanent.updateZoneChangeCounter(game); + // make sure the controller of all continuous effects of this card are switched to the current controller + game.getContinuousEffects().setController(permanent.getId(), permanent.getControllerId()); + game.addPermanent(permanent); + permanent.setZone(Zone.BATTLEFIELD, game); + // check if there are counters to add to the permanent (e.g. from non replacement effects like Persist) + + game.setScopeRelevant(true); + successfulMovedCards.add(permanent); + game.addSimultaneousEvent(new ZoneChangeEvent(permanent, permanent.getControllerId(), fromZone, Zone.BATTLEFIELD)); + } + } + break; + default: + throw new UnsupportedOperationException("to Zone not supported yet"); + } + + game.fireEvent(new ZoneChangeGroupEvent(successfulMovedCards, source == null ? null : source.getSourceId(), this.getId(), fromZone, toZone)); + return successfulMovedCards.size() > 0; + } + @Override public boolean moveCardsToExile(Card card, Ability source, Game game, boolean withName, UUID exileId, String exileZoneName) { Set cards = new HashSet<>(); diff --git a/Mage/src/mage/util/CardUtil.java b/Mage/src/mage/util/CardUtil.java index 3af5676fa48..9c6f45db5b8 100644 --- a/Mage/src/mage/util/CardUtil.java +++ b/Mage/src/mage/util/CardUtil.java @@ -483,23 +483,6 @@ public class CardUtil { return getExileZoneId(getCardZoneString(SOURCE_EXILE_ZONE_TEXT, sourceId, game, previous), game); } - public static UUID getObjectExileZoneId(Game game, MageObject mageObject) { - return getObjectExileZoneId(game, mageObject, false); - } - - public static UUID getObjectExileZoneId(Game game, MageObject mageObject, boolean previous) { - int zoneChangeCounter = 0; - if (mageObject instanceof Permanent) { - zoneChangeCounter = ((Permanent) mageObject).getZoneChangeCounter(game); - } else if (mageObject instanceof Card) { - zoneChangeCounter = ((Card) mageObject).getZoneChangeCounter(game); - } - if (zoneChangeCounter > 0 && previous) { - zoneChangeCounter--; - } - return getExileZoneId(getObjectZoneString(SOURCE_EXILE_ZONE_TEXT, mageObject.getId(), game, zoneChangeCounter, false), game); - } - public static UUID getExileZoneId(Game game, UUID objectId, int zoneChangeCounter) { return getExileZoneId(getObjectZoneString(SOURCE_EXILE_ZONE_TEXT, objectId, game, zoneChangeCounter, false), game); } From f4b667650c66a85251cab6b655f7b95c54077219 Mon Sep 17 00:00:00 2001 From: LevelX2 Date: Sun, 11 Oct 2015 03:57:29 +0200 Subject: [PATCH 061/268] * Fixed that enters the battlefield replacement effects of objects entering the battlefield were able to see permanents that entered the battlefield by the same effect (e.g. a Phyrexian Metamorph put onto the battlefield with Show and Tell was able to copy permanents that other players put onto the battlefield with the same Show and Tell.) fixes #594. --- Mage.Sets/src/mage/sets/exodus/Manabond.java | 48 +++++------ .../sets/innistrad/GrimoireOfTheDead.java | 40 +++++---- .../src/mage/sets/magic2010/LilianaVess.java | 31 +++---- .../mage/sets/magic2011/MassPolymorph.java | 84 ++++++++++--------- .../sets/magic2014/RiseOfTheDarkRealms.java | 23 +++-- .../sets/magicorigins/AnimistsAwakening.java | 21 +++-- .../sets/scarsofmirrodin/GenesisWave.java | 6 +- .../src/mage/sets/urzassaga/ShowAndTell.java | 19 +++-- 8 files changed, 149 insertions(+), 123 deletions(-) diff --git a/Mage.Sets/src/mage/sets/exodus/Manabond.java b/Mage.Sets/src/mage/sets/exodus/Manabond.java index 95dcbe4d6c8..b3d4487f70a 100644 --- a/Mage.Sets/src/mage/sets/exodus/Manabond.java +++ b/Mage.Sets/src/mage/sets/exodus/Manabond.java @@ -27,17 +27,19 @@ */ package mage.sets.exodus; +import java.util.LinkedHashSet; +import java.util.Set; import java.util.UUID; -import mage.constants.CardType; -import mage.constants.Outcome; -import mage.constants.Rarity; -import mage.constants.Zone; +import mage.MageObject; import mage.abilities.Ability; import mage.abilities.common.BeginningOfYourEndStepTriggeredAbility; import mage.abilities.effects.OneShotEffect; import mage.cards.Card; import mage.cards.CardImpl; -import mage.cards.Cards; +import mage.constants.CardType; +import mage.constants.Outcome; +import mage.constants.Rarity; +import mage.constants.Zone; import mage.game.Game; import mage.players.Player; @@ -51,8 +53,7 @@ public class Manabond extends CardImpl { super(ownerId, 113, "Manabond", Rarity.RARE, new CardType[]{CardType.ENCHANTMENT}, "{G}"); this.expansionSetCode = "EXO"; - - // At the beginning of your end step, you may reveal your hand and put all land cards from it onto the battlefield. If you do, discard your hand. + // At the beginning of your end step, reveal your hand and put all land cards from it onto the battlefield. If you do, discard your hand. this.addAbility(new BeginningOfYourEndStepTriggeredAbility(new ManabondEffect(), true)); } @@ -66,12 +67,11 @@ public class Manabond extends CardImpl { } } - class ManabondEffect extends OneShotEffect { public ManabondEffect() { super(Outcome.PutCardInPlay); - staticText = "reveal your hand and put all land cards from it onto the battlefield. If you do, discard your hand"; + staticText = "you may reveal your hand and put all land cards from it onto the battlefield. If you do, discard your hand"; } public ManabondEffect(final ManabondEffect effect) { @@ -80,24 +80,22 @@ class ManabondEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { - Player player = game.getPlayer(source.getControllerId()); - if (player != null) { - player.revealCards("Manabond", player.getHand(), game); - - Cards hand = player.getHand().copy(); - for(UUID uuid : hand){ + Player controller = game.getPlayer(source.getControllerId()); + MageObject sourceObject = source.getSourceObject(game); + if (controller != null && sourceObject != null) { + controller.revealCards(sourceObject.getIdName(), controller.getHand(), game); + Set toBattlefield = new LinkedHashSet<>(); + for (UUID uuid : controller.getHand()) { Card card = game.getCard(uuid); - if(card != null){ - if(card.getCardType().contains(CardType.LAND)){ - card.moveToZone(Zone.BATTLEFIELD, source.getSourceId(), game, false); - } - else{ - player.discard(card, source, game); - } + if (card != null && card.getCardType().contains(CardType.LAND)) { + toBattlefield.add(card); } + } - - } + controller.moveCards(toBattlefield, Zone.BATTLEFIELD, source, game, false, false, true, null); + controller.discard(controller.getHand().size(), false, source, game); + return true; + } return false; } @@ -105,4 +103,4 @@ class ManabondEffect extends OneShotEffect { public ManabondEffect copy() { return new ManabondEffect(this); } -} \ No newline at end of file +} diff --git a/Mage.Sets/src/mage/sets/innistrad/GrimoireOfTheDead.java b/Mage.Sets/src/mage/sets/innistrad/GrimoireOfTheDead.java index 84e2bdea4ef..bf41dc6d02b 100644 --- a/Mage.Sets/src/mage/sets/innistrad/GrimoireOfTheDead.java +++ b/Mage.Sets/src/mage/sets/innistrad/GrimoireOfTheDead.java @@ -27,14 +27,9 @@ */ package mage.sets.innistrad; +import java.util.LinkedHashSet; +import java.util.Set; import java.util.UUID; -import mage.constants.CardType; -import mage.constants.Duration; -import mage.constants.Layer; -import mage.constants.Outcome; -import mage.constants.Rarity; -import mage.constants.SubLayer; -import mage.constants.Zone; import mage.abilities.Ability; import mage.abilities.common.SimpleActivatedAbility; import mage.abilities.costs.common.DiscardTargetCost; @@ -47,6 +42,13 @@ import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.counter.AddCountersSourceEffect; import mage.cards.Card; import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.Layer; +import mage.constants.Outcome; +import mage.constants.Rarity; +import mage.constants.SubLayer; +import mage.constants.Zone; import mage.counters.CounterType; import mage.game.Game; import mage.game.permanent.Permanent; @@ -101,15 +103,21 @@ class GrimoireOfTheDeadEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { - for (Player player: game.getPlayers().values()) { - for (Card card: player.getGraveyard().getCards(game)) { - if (card.getCardType().contains(CardType.CREATURE)) { - card.putOntoBattlefield(game, Zone.GRAVEYARD, source.getSourceId(), source.getControllerId()); - game.addEffect(new GrimoireOfTheDeadEffect2(card.getId()), source); + Player controller = game.getPlayer(source.getControllerId()); + if (controller != null) { + Set creatureCards = new LinkedHashSet<>(); + for (Player player : game.getPlayers().values()) { + for (Card card : player.getGraveyard().getCards(game)) { + if (card.getCardType().contains(CardType.CREATURE)) { + creatureCards.add(card); + game.addEffect(new GrimoireOfTheDeadEffect2(card.getId()), source); + } } } + controller.moveCards(creatureCards, Zone.BATTLEFIELD, source, game, false, false, true, null); + return true; } - return true; + return false; } @Override @@ -121,10 +129,10 @@ class GrimoireOfTheDeadEffect extends OneShotEffect { class GrimoireOfTheDeadEffect2 extends ContinuousEffectImpl { - private UUID targetId; + private final UUID targetId; public GrimoireOfTheDeadEffect2(UUID targetId) { - super(Duration.EndOfGame, Outcome.Neutral); + super(Duration.Custom, Outcome.Neutral); this.targetId = targetId; staticText = "Becomes a black Zombie in addition to its other colors and types"; } @@ -170,4 +178,4 @@ class GrimoireOfTheDeadEffect2 extends ContinuousEffectImpl { return layer == Layer.ColorChangingEffects_5 || layer == Layer.TypeChangingEffects_4; } -} \ No newline at end of file +} diff --git a/Mage.Sets/src/mage/sets/magic2010/LilianaVess.java b/Mage.Sets/src/mage/sets/magic2010/LilianaVess.java index d03f79e665a..5f955caa787 100644 --- a/Mage.Sets/src/mage/sets/magic2010/LilianaVess.java +++ b/Mage.Sets/src/mage/sets/magic2010/LilianaVess.java @@ -1,16 +1,16 @@ /* * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. - * + * * Redistribution and use in source and binary forms, with or without modification, are * permitted provided that the following conditions are met: - * + * * 1. Redistributions of source code must retain the above copyright notice, this list of * conditions and the following disclaimer. - * + * * 2. Redistributions in binary form must reproduce the above copyright notice, this list * of conditions and the following disclaimer in the documentation and/or other materials * provided with the distribution. - * + * * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR @@ -20,28 +20,29 @@ * 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.magic2010; +import java.util.LinkedHashSet; +import java.util.Set; import java.util.UUID; -import mage.constants.CardType; -import mage.constants.Outcome; -import mage.constants.Rarity; -import mage.constants.Zone; import mage.abilities.Ability; import mage.abilities.LoyaltyAbility; import mage.abilities.common.EntersBattlefieldAbility; import mage.abilities.effects.OneShotEffect; -import mage.abilities.effects.common.discard.DiscardTargetEffect; import mage.abilities.effects.common.counter.AddCountersSourceEffect; +import mage.abilities.effects.common.discard.DiscardTargetEffect; import mage.abilities.effects.common.search.SearchLibraryPutOnLibraryEffect; import mage.cards.Card; import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.Outcome; +import mage.constants.Rarity; +import mage.constants.Zone; import mage.counters.CounterType; import mage.game.Game; import mage.players.Player; @@ -98,14 +99,16 @@ class LilianaVessEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { Player controller = game.getPlayer(source.getControllerId()); - for (UUID playerId: controller.getInRange()) { + for (UUID playerId : controller.getInRange()) { Player player = game.getPlayer(playerId); if (player != null) { - for (Card card: player.getGraveyard().getCards(game)) { + Set creatureCards = new LinkedHashSet<>(); + for (Card card : player.getGraveyard().getCards(game)) { if (card.getCardType().contains(CardType.CREATURE)) { - card.putOntoBattlefield(game, Zone.GRAVEYARD, source.getSourceId(), source.getControllerId()); + creatureCards.add(card); } } + controller.moveCards(creatureCards, Zone.BATTLEFIELD, source, game, false, false, false, null); } } return true; diff --git a/Mage.Sets/src/mage/sets/magic2011/MassPolymorph.java b/Mage.Sets/src/mage/sets/magic2011/MassPolymorph.java index 9e159d7af75..95bb22a3635 100644 --- a/Mage.Sets/src/mage/sets/magic2011/MassPolymorph.java +++ b/Mage.Sets/src/mage/sets/magic2011/MassPolymorph.java @@ -1,16 +1,16 @@ /* * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. - * + * * Redistribution and use in source and binary forms, with or without modification, are * permitted provided that the following conditions are met: - * + * * 1. Redistributions of source code must retain the above copyright notice, this list of * conditions and the following disclaimer. - * + * * 2. Redistributions in binary form must reproduce the above copyright notice, this list * of conditions and the following disclaimer in the documentation and/or other materials * provided with the distribution. - * + * * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR @@ -20,32 +20,34 @@ * 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.magic2011; -import mage.constants.CardType; -import mage.constants.Outcome; -import mage.constants.Rarity; -import mage.constants.Zone; +import java.util.HashSet; +import java.util.LinkedHashSet; +import java.util.List; +import java.util.Set; +import java.util.UUID; +import mage.MageObject; import mage.abilities.Ability; import mage.abilities.effects.OneShotEffect; 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.common.FilterCreaturePermanent; import mage.game.Game; import mage.game.permanent.Permanent; import mage.players.Player; -import java.util.List; -import java.util.UUID; - /** * * @author BetaSteward_at_googlemail.com @@ -82,34 +84,36 @@ class MassPolymorphEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { - int count; - List creatures = game.getBattlefield().getAllActivePermanents(new FilterCreaturePermanent(), source.getControllerId(), game); - count = creatures.size(); - for (Permanent creature: creatures) { - creature.moveToExile(null, null, source.getSourceId(), game); - } - Cards revealed = new CardsImpl(); - Cards creatureCards = new CardsImpl(); - Cards nonCreatureCards = new CardsImpl(); - Player player = game.getPlayer(source.getControllerId()); - while (creatureCards.size() < count && player.getLibrary().size() > 0) { - Card card = player.getLibrary().removeFromTop(game); - revealed.add(card); - if (card.getCardType().contains(CardType.CREATURE)) { - creatureCards.add(card); - } else { - nonCreatureCards.add(card); + Player controller = game.getPlayer(source.getControllerId()); + MageObject sourceObject = source.getSourceObject(game); + if (controller != null && sourceObject != null) { + int count; + // Cards creatures = new CardsImpl(); + List creatures = game.getBattlefield().getAllActivePermanents(new FilterCreaturePermanent(), source.getControllerId(), game); + Set creaturesToExile = new HashSet<>(); + creaturesToExile.addAll(creatures); + count = creatures.size(); + controller.moveCards(creaturesToExile, null, Zone.HAND, source, game); + + Cards revealed = new CardsImpl(); + Set creatureCards = new LinkedHashSet<>(); + Cards nonCreatureCards = new CardsImpl(); + while (creatureCards.size() < count && controller.getLibrary().size() > 0) { + Card card = controller.getLibrary().removeFromTop(game); + revealed.add(card); + if (card.getCardType().contains(CardType.CREATURE)) { + creatureCards.add(card); + } else { + nonCreatureCards.add(card); + } } + controller.revealCards(sourceObject.getIdName(), revealed, game); + controller.moveCards(creatureCards, Zone.BATTLEFIELD, source, game, false, false, true, null); + controller.putCardsOnTopOfLibrary(nonCreatureCards, game, source, false); + controller.shuffleLibrary(game); + return true; } - player.revealCards("Mass Polymorph", revealed, game); - for (Card creatureCard: creatureCards.getCards(game)) { - creatureCard.putOntoBattlefield(game, Zone.LIBRARY, source.getSourceId(), source.getControllerId()); - } - for (Card card: nonCreatureCards.getCards(game)) { - player.moveCardToLibraryWithInfo(card, source.getSourceId(), game, Zone.GRAVEYARD, true, true); - } - player.shuffleLibrary(game); - return true; + return false; } @Override @@ -117,4 +121,4 @@ class MassPolymorphEffect extends OneShotEffect { return new MassPolymorphEffect(this); } -} \ No newline at end of file +} diff --git a/Mage.Sets/src/mage/sets/magic2014/RiseOfTheDarkRealms.java b/Mage.Sets/src/mage/sets/magic2014/RiseOfTheDarkRealms.java index 8b84ffb6124..4fbe776a8c5 100644 --- a/Mage.Sets/src/mage/sets/magic2014/RiseOfTheDarkRealms.java +++ b/Mage.Sets/src/mage/sets/magic2014/RiseOfTheDarkRealms.java @@ -27,6 +27,8 @@ */ package mage.sets.magic2014; +import java.util.LinkedHashSet; +import java.util.Set; import java.util.UUID; import mage.abilities.Ability; import mage.abilities.effects.OneShotEffect; @@ -49,7 +51,6 @@ public class RiseOfTheDarkRealms extends CardImpl { super(ownerId, 111, "Rise of the Dark Realms", Rarity.MYTHIC, new CardType[]{CardType.SORCERY}, "{7}{B}{B}"); this.expansionSetCode = "M14"; - // Put all creature cards from all graveyards onto the battlefield under your control. this.getSpellAbility().addEffect(new RiseOfTheDarkRealmsEffect()); } @@ -78,17 +79,23 @@ class RiseOfTheDarkRealmsEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { Player controller = game.getPlayer(source.getControllerId()); - for (UUID playerId: controller.getInRange()) { - Player player = game.getPlayer(playerId); - if (player != null) { - for (Card card: player.getGraveyard().getCards(game)) { - if (card.getCardType().contains(CardType.CREATURE)) { - card.putOntoBattlefield(game, Zone.GRAVEYARD, source.getSourceId(), source.getControllerId()); + if (controller != null) { + + Set creatureCards = new LinkedHashSet<>(); + for (UUID playerId : controller.getInRange()) { + Player player = game.getPlayer(playerId); + if (player != null) { + for (Card card : player.getGraveyard().getCards(game)) { + if (card.getCardType().contains(CardType.CREATURE)) { + creatureCards.add(card); + } } } } + controller.moveCards(creatureCards, Zone.BATTLEFIELD, source, game, false, false, true, null); + return true; } - return true; + return false; } @Override diff --git a/Mage.Sets/src/mage/sets/magicorigins/AnimistsAwakening.java b/Mage.Sets/src/mage/sets/magicorigins/AnimistsAwakening.java index 4cbe0168fc4..4ccfccda7a6 100644 --- a/Mage.Sets/src/mage/sets/magicorigins/AnimistsAwakening.java +++ b/Mage.Sets/src/mage/sets/magicorigins/AnimistsAwakening.java @@ -27,8 +27,8 @@ */ package mage.sets.magicorigins; -import java.util.ArrayList; -import java.util.List; +import java.util.LinkedHashSet; +import java.util.Set; import java.util.UUID; import mage.MageObject; import mage.abilities.Ability; @@ -94,23 +94,22 @@ class AnimistsAwakeningEffect extends OneShotEffect { Cards cards = new CardsImpl(Zone.LIBRARY); int xValue = source.getManaCostsToPay().getX(); cards.addAll(controller.getLibrary().getTopCards(game, xValue)); - List lands = new ArrayList<>(); if (cards.size() > 0) { controller.revealCards(sourceObject.getIdName(), cards, game); + Set toBattlefield = new LinkedHashSet<>(); for (Card card : cards.getCards(new FilterLandCard(), source.getSourceId(), source.getControllerId(), game)) { cards.remove(card); - controller.putOntoBattlefieldWithInfo(card, game, Zone.LIBRARY, source.getSourceId(), true); - Permanent land = game.getPermanent(card.getId()); - if (land != null) { - lands.add(land); - } - + toBattlefield.add(card); } + controller.moveCards(toBattlefield, Zone.BATTLEFIELD, source, game, true, false, true, null); controller.putCardsOnBottomOfLibrary(cards, game, source, true); if (SpellMasteryCondition.getInstance().apply(game, source)) { - for (Permanent land : lands) { - land.untap(game); + for (Card card : toBattlefield) { + Permanent land = game.getPermanent(card.getId()); + if (land != null) { + land.untap(game); + } } } } diff --git a/Mage.Sets/src/mage/sets/scarsofmirrodin/GenesisWave.java b/Mage.Sets/src/mage/sets/scarsofmirrodin/GenesisWave.java index b20a7cfe247..c8224d6d27e 100644 --- a/Mage.Sets/src/mage/sets/scarsofmirrodin/GenesisWave.java +++ b/Mage.Sets/src/mage/sets/scarsofmirrodin/GenesisWave.java @@ -27,6 +27,8 @@ */ package mage.sets.scarsofmirrodin; +import java.util.LinkedHashSet; +import java.util.Set; import java.util.UUID; import mage.MageObject; import mage.abilities.Ability; @@ -115,13 +117,15 @@ class GenesisWaveEffect extends OneShotEffect { target1.setRequired(false); controller.choose(Outcome.PutCardInPlay, cards, target1, game); + Set toBattlefield = new LinkedHashSet<>(); for (UUID cardId : target1.getTargets()) { Card card = cards.get(cardId, game); if (card != null) { cards.remove(card); - controller.putOntoBattlefieldWithInfo(card, game, Zone.LIBRARY, source.getSourceId()); + toBattlefield.add(card); } } + controller.moveCards(toBattlefield, Zone.BATTLEFIELD, source, game, false, false, false, null); controller.moveCards(cards, Zone.LIBRARY, Zone.GRAVEYARD, source, game); } return true; diff --git a/Mage.Sets/src/mage/sets/urzassaga/ShowAndTell.java b/Mage.Sets/src/mage/sets/urzassaga/ShowAndTell.java index 856e29d1943..3bbcbbefb1f 100644 --- a/Mage.Sets/src/mage/sets/urzassaga/ShowAndTell.java +++ b/Mage.Sets/src/mage/sets/urzassaga/ShowAndTell.java @@ -28,7 +28,9 @@ package mage.sets.urzassaga; import java.util.ArrayList; +import java.util.LinkedHashSet; import java.util.List; +import java.util.Set; import java.util.UUID; import mage.abilities.Ability; import mage.abilities.effects.OneShotEffect; @@ -102,7 +104,7 @@ class ShowAndTellEffect extends OneShotEffect { if (controller == null) { return false; } - List cardsToPutIntoPlay = new ArrayList<>(); + Set cardsToPutIntoPlay = new LinkedHashSet<>(); TargetCardInHand target = new TargetCardInHand(filter); for (UUID playerId : game.getState().getPlayersInRange(controller.getId(), game)) { @@ -119,12 +121,13 @@ class ShowAndTellEffect extends OneShotEffect { } } } - for (Card card : cardsToPutIntoPlay) { - Player player = game.getPlayer(card.getOwnerId()); - if (player != null) { - player.putOntoBattlefieldWithInfo(card, game, Zone.HAND, source.getSourceId()); - } - } - return true; + return controller.moveCards(cardsToPutIntoPlay, Zone.BATTLEFIELD, source, game, false, false, true, null); +// for (Card card : cardsToPutIntoPlay) { +// Player player = game.getPlayer(card.getOwnerId()); +// if (player != null) { +// player.putOntoBattlefieldWithInfo(card, game, Zone.HAND, source.getSourceId()); +// } +// } + // return true; } } From ad4a75d94b9bd333987ee8a927aefb573c4714ae Mon Sep 17 00:00:00 2001 From: LoneFox Date: Sun, 11 Oct 2015 11:33:59 +0300 Subject: [PATCH 062/268] Implement cards: Armor Thrull, Dwarven Armorer, Dwarven Lieutenant, and Elven Lyre --- .../mage/sets/fallenempires/ArmorThrull1.java | 52 +++++++ .../mage/sets/fallenempires/ArmorThrull2.java | 52 +++++++ .../mage/sets/fallenempires/ArmorThrull3.java | 52 +++++++ .../mage/sets/fallenempires/ArmorThrull4.java | 52 +++++++ .../sets/fallenempires/DwarvenArmorer.java | 128 ++++++++++++++++++ .../sets/fallenempires/DwarvenLieutenant.java | 79 +++++++++++ .../mage/sets/fallenempires/ElvenLyre.java | 54 ++++++++ .../sets/masterseditionii/ArmorThrull.java | 72 ++++++++++ .../mage/sets/masterseditionii/ElvenLyre.java | 71 ++++++++++ Mage/src/mage/counters/CounterType.java | 6 + 10 files changed, 618 insertions(+) create mode 100644 Mage.Sets/src/mage/sets/fallenempires/ArmorThrull1.java create mode 100644 Mage.Sets/src/mage/sets/fallenempires/ArmorThrull2.java create mode 100644 Mage.Sets/src/mage/sets/fallenempires/ArmorThrull3.java create mode 100644 Mage.Sets/src/mage/sets/fallenempires/ArmorThrull4.java create mode 100644 Mage.Sets/src/mage/sets/fallenempires/DwarvenArmorer.java create mode 100644 Mage.Sets/src/mage/sets/fallenempires/DwarvenLieutenant.java create mode 100644 Mage.Sets/src/mage/sets/fallenempires/ElvenLyre.java create mode 100644 Mage.Sets/src/mage/sets/masterseditionii/ArmorThrull.java create mode 100644 Mage.Sets/src/mage/sets/masterseditionii/ElvenLyre.java diff --git a/Mage.Sets/src/mage/sets/fallenempires/ArmorThrull1.java b/Mage.Sets/src/mage/sets/fallenempires/ArmorThrull1.java new file mode 100644 index 00000000000..e543304cf03 --- /dev/null +++ b/Mage.Sets/src/mage/sets/fallenempires/ArmorThrull1.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.fallenempires; + +import java.util.UUID; + +/** + * + * @author LoneFox + */ +public class ArmorThrull1 extends mage.sets.masterseditionii.ArmorThrull { + + public ArmorThrull1(UUID ownerId) { + super(ownerId); + this.cardNumber = 1; + this.expansionSetCode = "FEM"; + } + + public ArmorThrull1(final ArmorThrull1 card) { + super(card); + } + + @Override + public ArmorThrull1 copy() { + return new ArmorThrull1(this); + } +} diff --git a/Mage.Sets/src/mage/sets/fallenempires/ArmorThrull2.java b/Mage.Sets/src/mage/sets/fallenempires/ArmorThrull2.java new file mode 100644 index 00000000000..c39b457788b --- /dev/null +++ b/Mage.Sets/src/mage/sets/fallenempires/ArmorThrull2.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.fallenempires; + +import java.util.UUID; + +/** + * + * @author LoneFox + */ +public class ArmorThrull2 extends mage.sets.masterseditionii.ArmorThrull { + + public ArmorThrull2(UUID ownerId) { + super(ownerId); + this.cardNumber = 2; + this.expansionSetCode = "FEM"; + } + + public ArmorThrull2(final ArmorThrull2 card) { + super(card); + } + + @Override + public ArmorThrull2 copy() { + return new ArmorThrull2(this); + } +} diff --git a/Mage.Sets/src/mage/sets/fallenempires/ArmorThrull3.java b/Mage.Sets/src/mage/sets/fallenempires/ArmorThrull3.java new file mode 100644 index 00000000000..2a16cd7b3fd --- /dev/null +++ b/Mage.Sets/src/mage/sets/fallenempires/ArmorThrull3.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.fallenempires; + +import java.util.UUID; + +/** + * + * @author LoneFox + */ +public class ArmorThrull3 extends mage.sets.masterseditionii.ArmorThrull { + + public ArmorThrull3(UUID ownerId) { + super(ownerId); + this.cardNumber = 3; + this.expansionSetCode = "FEM"; + } + + public ArmorThrull3(final ArmorThrull3 card) { + super(card); + } + + @Override + public ArmorThrull3 copy() { + return new ArmorThrull3(this); + } +} diff --git a/Mage.Sets/src/mage/sets/fallenempires/ArmorThrull4.java b/Mage.Sets/src/mage/sets/fallenempires/ArmorThrull4.java new file mode 100644 index 00000000000..97d46f88982 --- /dev/null +++ b/Mage.Sets/src/mage/sets/fallenempires/ArmorThrull4.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.fallenempires; + +import java.util.UUID; + +/** + * + * @author LoneFox + */ +public class ArmorThrull4 extends mage.sets.masterseditionii.ArmorThrull { + + public ArmorThrull4(UUID ownerId) { + super(ownerId); + this.cardNumber = 4; + this.expansionSetCode = "FEM"; + } + + public ArmorThrull4(final ArmorThrull4 card) { + super(card); + } + + @Override + public ArmorThrull4 copy() { + return new ArmorThrull4(this); + } +} diff --git a/Mage.Sets/src/mage/sets/fallenempires/DwarvenArmorer.java b/Mage.Sets/src/mage/sets/fallenempires/DwarvenArmorer.java new file mode 100644 index 00000000000..b98704b1ec6 --- /dev/null +++ b/Mage.Sets/src/mage/sets/fallenempires/DwarvenArmorer.java @@ -0,0 +1,128 @@ +/* + * 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.fallenempires; + +import java.util.HashSet; +import java.util.UUID; +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.costs.common.DiscardCardCost; +import mage.abilities.costs.common.TapSourceCost; +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.effects.Effect; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.counter.AddCountersTargetEffect; +import mage.cards.CardImpl; +import mage.choices.Choice; +import mage.choices.ChoiceImpl; +import mage.constants.CardType; +import mage.constants.Outcome; +import mage.constants.Rarity; +import mage.constants.Zone; +import mage.counters.Counter; +import mage.counters.CounterType; +import mage.game.Game; +import mage.players.Player; +import mage.target.common.TargetCreaturePermanent; +import mage.target.targetpointer.FixedTarget; + +/** + * + * @author LoneFox + */ +public class DwarvenArmorer extends CardImpl { + + public DwarvenArmorer(UUID ownerId) { + super(ownerId, 104, "Dwarven Armorer", Rarity.RARE, new CardType[]{CardType.CREATURE}, "{R}"); + this.expansionSetCode = "FEM"; + this.subtype.add("Dwarf"); + this.power = new MageInt(0); + this.toughness = new MageInt(2); + + // {R}, {tap}, Discard a card: Put a +0/+1 counter or a +1/+0 counter on target creature. + Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new DwarvenArmorerEffect(), new ManaCostsImpl("{R}")); + ability.addCost(new TapSourceCost()); + ability.addCost(new DiscardCardCost()); + ability.addTarget(new TargetCreaturePermanent()); + this.addAbility(ability); + } + + public DwarvenArmorer(final DwarvenArmorer card) { + super(card); + } + + @Override + public DwarvenArmorer copy() { + return new DwarvenArmorer(this); + } +} + +class DwarvenArmorerEffect extends OneShotEffect { + + private static final HashSet choices = new HashSet<>(); + + static { + choices.add("+0/+1"); + choices.add("+1/+0"); + } + + public DwarvenArmorerEffect() { + super(Outcome.Benefit); + staticText = "Put a +0/+1 counter or a +1/+0 counter on target creature."; + } + + public DwarvenArmorerEffect(final DwarvenArmorerEffect effect) { + super(effect); + } + + @java.lang.Override + public DwarvenArmorerEffect copy() { + return new DwarvenArmorerEffect(this); + } + + @java.lang.Override + public boolean apply(Game game, Ability source) { + Player controller = game.getPlayer(source.getControllerId()); + if(controller != null) { + Choice choice = new ChoiceImpl(true); + choice.setMessage("Choose type of counter to add"); + choice.setChoices(choices); + while(!controller.choose(outcome, choice, game)) { + if(controller.canRespond()) { + return false; + } + } + Counter counter = choice.getChoice().equals("+0/+1") ? CounterType.P0P1.createInstance() : CounterType.P1P0.createInstance(); + Effect effect = new AddCountersTargetEffect(counter); + effect.setTargetPointer(new FixedTarget(this.getTargetPointer().getFirst(game, source))); + return effect.apply(game, source); + } + return false; + } +} diff --git a/Mage.Sets/src/mage/sets/fallenempires/DwarvenLieutenant.java b/Mage.Sets/src/mage/sets/fallenempires/DwarvenLieutenant.java new file mode 100644 index 00000000000..2cc864b9fc7 --- /dev/null +++ b/Mage.Sets/src/mage/sets/fallenempires/DwarvenLieutenant.java @@ -0,0 +1,79 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.sets.fallenempires; + +import java.util.UUID; +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.effects.common.continuous.BoostTargetEffect; +import mage.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.mageobject.SubtypePredicate; +import mage.target.common.TargetCreaturePermanent; + +/** + * + * @author LoneFox + */ +public class DwarvenLieutenant extends CardImpl { + + static FilterCreaturePermanent filter = new FilterCreaturePermanent("Dwarf creature"); + + static { + filter.add(new SubtypePredicate("Dwarf")); + } + + public DwarvenLieutenant(UUID ownerId) { + super(ownerId, 106, "Dwarven Lieutenant", Rarity.UNCOMMON, new CardType[]{CardType.CREATURE}, "{R}{R}"); + this.expansionSetCode = "FEM"; + this.subtype.add("Dwarf"); + this.subtype.add("Soldier"); + this.power = new MageInt(1); + this.toughness = new MageInt(2); + + // {1}{R}: Target Dwarf creature gets +1/+0 until end of turn. + Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new BoostTargetEffect(1, 0, Duration.EndOfTurn), new ManaCostsImpl("{1}{R}")); + ability.addTarget(new TargetCreaturePermanent(filter)); + this.addAbility(ability); + } + + public DwarvenLieutenant(final DwarvenLieutenant card) { + super(card); + } + + @Override + public DwarvenLieutenant copy() { + return new DwarvenLieutenant(this); + } +} diff --git a/Mage.Sets/src/mage/sets/fallenempires/ElvenLyre.java b/Mage.Sets/src/mage/sets/fallenempires/ElvenLyre.java new file mode 100644 index 00000000000..8657136f098 --- /dev/null +++ b/Mage.Sets/src/mage/sets/fallenempires/ElvenLyre.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.fallenempires; + +import java.util.UUID; +import mage.constants.Rarity; + +/** + * + * @author LoneFox + */ +public class ElvenLyre extends mage.sets.masterseditionii.ElvenLyre { + + public ElvenLyre(UUID ownerId) { + super(ownerId); + this.cardNumber = 172; + this.expansionSetCode = "FEM"; + this.rarity = Rarity.RARE; + } + + public ElvenLyre(final ElvenLyre card) { + super(card); + } + + @Override + public ElvenLyre copy() { + return new ElvenLyre(this); + } +} diff --git a/Mage.Sets/src/mage/sets/masterseditionii/ArmorThrull.java b/Mage.Sets/src/mage/sets/masterseditionii/ArmorThrull.java new file mode 100644 index 00000000000..dbd058685b3 --- /dev/null +++ b/Mage.Sets/src/mage/sets/masterseditionii/ArmorThrull.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.masterseditionii; + +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.costs.common.TapSourceCost; +import mage.abilities.effects.common.counter.AddCountersTargetEffect; +import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.Rarity; +import mage.constants.Zone; +import mage.counters.CounterType; +import mage.target.common.TargetCreaturePermanent; + +/** + * + * @author LoneFox + */ +public class ArmorThrull extends CardImpl { + + public ArmorThrull(UUID ownerId) { + super(ownerId, 77, "Armor Thrull", Rarity.COMMON, new CardType[]{CardType.CREATURE}, "{2}{B}"); + this.expansionSetCode = "ME2"; + this.subtype.add("Thrull"); + this.power = new MageInt(1); + this.toughness = new MageInt(3); + + // {T}, Sacrifice Armor Thrull: Put a +1/+2 counter on target creature. + Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new AddCountersTargetEffect(CounterType.P1P2.createInstance()), new TapSourceCost()); + ability.addCost(new SacrificeSourceCost()); + ability.addTarget(new TargetCreaturePermanent()); + this.addAbility(ability); + } + + public ArmorThrull(final ArmorThrull card) { + super(card); + } + + @Override + public ArmorThrull copy() { + return new ArmorThrull(this); + } +} diff --git a/Mage.Sets/src/mage/sets/masterseditionii/ElvenLyre.java b/Mage.Sets/src/mage/sets/masterseditionii/ElvenLyre.java new file mode 100644 index 00000000000..5fd78b1f651 --- /dev/null +++ b/Mage.Sets/src/mage/sets/masterseditionii/ElvenLyre.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.masterseditionii; + +import java.util.UUID; +import mage.abilities.Ability; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.costs.common.SacrificeSourceCost; +import mage.abilities.costs.common.TapSourceCost; +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.effects.common.continuous.BoostTargetEffect; +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 ElvenLyre extends CardImpl { + + public ElvenLyre(UUID ownerId) { + super(ownerId, 208, "Elven Lyre", Rarity.COMMON, new CardType[]{CardType.ARTIFACT}, "{2}"); + this.expansionSetCode = "ME2"; + + // {1}, {tap}, Sacrifice Elven Lyre: Target creature gets +2/+2 until end of turn. + Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new BoostTargetEffect(2, 2, Duration.EndOfTurn), new ManaCostsImpl("{1}")); + ability.addCost(new TapSourceCost()); + ability.addCost(new SacrificeSourceCost()); + ability.addTarget(new TargetCreaturePermanent()); + this.addAbility(ability); + + } + + public ElvenLyre(final ElvenLyre card) { + super(card); + } + + @Override + public ElvenLyre copy() { + return new ElvenLyre(this); + } +} diff --git a/Mage/src/mage/counters/CounterType.java b/Mage/src/mage/counters/CounterType.java index eaf7bde19ef..da70425325e 100644 --- a/Mage/src/mage/counters/CounterType.java +++ b/Mage/src/mage/counters/CounterType.java @@ -75,8 +75,10 @@ public enum CounterType { M2M2(new BoostCounter(-2, -2).name), MINING("mining"), MUSTER("muster"), + P0P1(new BoostCounter(0, 1).name), P1P0(new BoostCounter(1, 0).name), P1P1(new BoostCounter(1, 1).name), + P1P2(new BoostCounter(1, 2).name), P2P2(new BoostCounter(2, 2).name), PAGE("page"), PAIN("pain"), @@ -134,10 +136,14 @@ public enum CounterType { */ public Counter createInstance(int amount) { switch (this) { + case P0P1: + return new BoostCounter(0, 1, amount); case P1P0: return new BoostCounter(1, 0, amount); case P1P1: return new BoostCounter(1, 1, amount); + case P1P2: + return new BoostCounter(1, 2, amount); case P2P2: return new BoostCounter(2, 2, amount); case M1M1: From 673cd6b38a024e9f658a190a78d944f97aace1c2 Mon Sep 17 00:00:00 2001 From: LevelX2 Date: Sun, 11 Oct 2015 11:19:19 +0200 Subject: [PATCH 063/268] * Fixed a bug that if opponent left tournament during a match, get got points for that mathc if he won more games (fixes #1310). --- .../mage/game/tournament/TournamentImpl.java | 63 +++++++++---------- 1 file changed, 30 insertions(+), 33 deletions(-) diff --git a/Mage/src/mage/game/tournament/TournamentImpl.java b/Mage/src/mage/game/tournament/TournamentImpl.java index 2719c4a277d..e326882b29d 100644 --- a/Mage/src/mage/game/tournament/TournamentImpl.java +++ b/Mage/src/mage/game/tournament/TournamentImpl.java @@ -25,7 +25,6 @@ * authors and should not be interpreted as representing official policies, either expressed * or implied, of BetaSteward_at_googlemail.com. */ - package mage.game.tournament; import java.util.ArrayList; @@ -114,7 +113,7 @@ public abstract class TournamentImpl implements Tournament { } synchronized (this) { this.notifyAll(); - } + } } @Override @@ -209,7 +208,7 @@ public abstract class TournamentImpl implements Tournament { } protected void playRound(Round round) { - for (TournamentPairing pair: round.getPairs()) { + for (TournamentPairing pair : round.getPairs()) { playMatch(pair); } updateResults(); // show points from byes @@ -227,7 +226,7 @@ public abstract class TournamentImpl implements Tournament { protected List getActivePlayers() { List activePlayers = new ArrayList<>(); - for (TournamentPlayer player: players.values()) { + for (TournamentPlayer player : players.values()) { if (!player.isEliminated()) { activePlayers.add(player); } @@ -240,13 +239,13 @@ public abstract class TournamentImpl implements Tournament { */ @Override public void updateResults() { - for (TournamentPlayer player: players.values()) { + for (TournamentPlayer player : players.values()) { player.setResults(""); player.setPoints(0); player.setStateInfo(""); } - for (Round round: rounds) { - for (TournamentPairing pair: round.getPairs()) { + for (Round round : rounds) { + for (TournamentPairing pair : round.getPairs()) { Match match = pair.getMatch(); if (match != null && match.hasEnded()) { TournamentPlayer tp1 = pair.getPlayer1(); @@ -276,9 +275,9 @@ public abstract class TournamentImpl implements Tournament { tp2.setResults(addRoundResult(round.getRoundNumber(), pair, tp2, tp1)); // Add points - if (mp2.hasQuit() || mp1.getWins() > mp2.getWins()) { + if ((!mp1.hasQuit() && mp1.getWins() > mp2.getWins()) || mp2.hasQuit()) { tp1.setPoints(tp1.getPoints() + 3); - } else if (mp1.hasQuit() || mp1.getWins() < mp2.getWins()) { + } else if ((!mp2.hasQuit() && mp1.getWins() < mp2.getWins()) || mp1.hasQuit()) { tp2.setPoints(tp2.getPoints() + 3); } else { tp1.setPoints(tp1.getPoints() + 1); @@ -299,7 +298,7 @@ public abstract class TournamentImpl implements Tournament { playerResult.append(getMatchResultString(tournamentPlayer, opponentPlayer, pair.getMatch())); return playerResult.toString(); } - + private static String getMatchResultString(TournamentPlayer p1, TournamentPlayer p2, Match match) { MatchPlayer mp1 = match.getPlayer(p1.getPlayer().getId()); MatchPlayer mp2 = match.getPlayer(p2.getPlayer().getId()); @@ -307,22 +306,22 @@ public abstract class TournamentImpl implements Tournament { matchResult.append(p2.getPlayer().getName()); matchResult.append(" [").append(mp1.getWins()); if (mp1.hasQuit()) { - matchResult.append(mp1.getPlayer().hasIdleTimeout()? "I" :(mp1.getPlayer().hasTimerTimeout()?"T":"Q")); + matchResult.append(mp1.getPlayer().hasIdleTimeout() ? "I" : (mp1.getPlayer().hasTimerTimeout() ? "T" : "Q")); } if (match.getDraws() > 0) { matchResult.append("-").append(match.getDraws()); } matchResult.append("-").append(mp2.getWins()); if (mp2.hasQuit()) { - matchResult.append(mp2.getPlayer().hasIdleTimeout()? "I" :(mp2.getPlayer().hasTimerTimeout()?"T":"Q")); - } + matchResult.append(mp2.getPlayer().hasIdleTimeout() ? "I" : (mp2.getPlayer().hasTimerTimeout() ? "T" : "Q")); + } matchResult.append("] "); return matchResult.toString(); } - + @Override public boolean isDoneConstructing() { - for (TournamentPlayer player: this.players.values()) { + for (TournamentPlayer player : this.players.values()) { if (!player.isDoneConstructing()) { return false; } @@ -332,7 +331,7 @@ public abstract class TournamentImpl implements Tournament { @Override public boolean allJoined() { - for (TournamentPlayer player: this.players.values()) { + for (TournamentPlayer player : this.players.values()) { if (!player.isJoined()) { return false; } @@ -358,27 +357,26 @@ public abstract class TournamentImpl implements Tournament { public void construct() { tableEventSource.fireTableEvent(EventType.CONSTRUCT); if (!isAbort()) { - for (final TournamentPlayer player: players.values()) { + for (final TournamentPlayer player : players.values()) { player.setConstructing(); new Thread( - new Runnable() { - @Override - public void run() { - player.getPlayer().construct(TournamentImpl.this, player.getDeck()); + new Runnable() { + @Override + public void run() { + player.getPlayer().construct(TournamentImpl.this, player.getDeck()); + } } - } ).start(); } // add autosubmit trigger - - - synchronized(this) { + + synchronized (this) { while (!isDoneConstructing()) { try { this.wait(); } catch (InterruptedException ex) { - + } } } @@ -387,7 +385,7 @@ public abstract class TournamentImpl implements Tournament { } protected void openBoosters() { - for (TournamentPlayer player: this.players.values()) { + for (TournamentPlayer player : this.players.values()) { player.setDeck(new Deck()); if (options.getLimitedOptions().getDraftCube() != null) { DraftCube cube = options.getLimitedOptions().getDraftCube(); @@ -395,7 +393,7 @@ public abstract class TournamentImpl implements Tournament { player.getDeck().getSideboard().addAll(cube.createBooster()); } } else { - for (ExpansionSet set: sets) { + for (ExpansionSet set : sets) { player.getDeck().getSideboard().addAll(set.createBooster()); } } @@ -406,7 +404,7 @@ public abstract class TournamentImpl implements Tournament { public void resetBufferedCards() { HashSet setsDone = new HashSet<>(); - for(ExpansionSet set: sets) { + for (ExpansionSet set : sets) { if (!setsDone.contains(set)) { set.removeSavedCards(); setsDone.add(set); @@ -454,7 +452,7 @@ public abstract class TournamentImpl implements Tournament { protected void winners() { List winners = new ArrayList<>(); int pointsWinner = 1; // with less than 1 point you can't win - for(TournamentPlayer tournamentPlayer: this.getPlayers()) { + for (TournamentPlayer tournamentPlayer : this.getPlayers()) { if (pointsWinner < tournamentPlayer.getPoints()) { winners.clear(); winners.add(tournamentPlayer); @@ -464,14 +462,14 @@ public abstract class TournamentImpl implements Tournament { } } // set winner state for the players with the most points > 0 - for (TournamentPlayer tournamentPlayer: winners) { + for (TournamentPlayer tournamentPlayer : winners) { tournamentPlayer.setStateInfo("Winner"); } } @Override public void cleanUpOnTournamentEnd() { - for(TournamentPlayer tournamentPlayer: players.values()) { + for (TournamentPlayer tournamentPlayer : players.values()) { tournamentPlayer.CleanUpOnTournamentEnd(); } } @@ -509,7 +507,6 @@ public abstract class TournamentImpl implements Tournament { this.startTime = new Date(); } - @Override public void setStepStartTime(Date stepStartTime) { this.stepStartTime = stepStartTime; From 8dad1eeb135d45b91308fe64dc30e76c58e00400 Mon Sep 17 00:00:00 2001 From: LevelX2 Date: Sun, 11 Oct 2015 11:19:50 +0200 Subject: [PATCH 064/268] Minor most tooltip related changes. --- .../mage/sets/shadowmoor/AphoticWisps.java | 28 +++--- .../mage/sets/shadowmoor/DrownerInitiate.java | 10 +- .../src/mage/sets/shadowmoor/LeechBonder.java | 2 +- .../sets/shadowmoor/WickerWarcrawler.java | 48 ++------- .../src/mage/sets/urzassaga/ShowAndTell.java | 7 -- .../src/mage/sets/worldwake/FeralContest.java | 7 +- .../src/mage/sets/zendikar/BloodTribute.java | 12 +-- .../AttacksOrBlocksTriggeredAbility.java | 11 ++- .../abilities/costs/AlternativeCost2Impl.java | 33 ++++--- .../mage/abilities/costs/CompositeCost.java | 13 ++- Mage/src/mage/abilities/costs/Cost.java | 62 +++++++----- Mage/src/mage/abilities/costs/CostImpl.java | 54 +++++----- Mage/src/mage/abilities/costs/CostsImpl.java | 99 ++++++++++--------- .../costs/OptionalAdditionalCostImpl.java | 4 +- Mage/src/mage/abilities/costs/OrCost.java | 9 +- .../abilities/costs/VariableCostImpl.java | 5 + .../costs/common/DiscardTargetCost.java | 29 +++--- .../abilities/costs/mana/ManaCostsImpl.java | 9 ++ .../effects/common/DrawCardTargetEffect.java | 15 ++- .../BecomesColorOrColorsTargetEffect.java | 11 ++- .../abilities/keyword/BuybackAbility.java | 4 +- .../abilities/keyword/ConspireAbility.java | 5 +- .../abilities/keyword/EntwineAbility.java | 2 +- .../mage/abilities/keyword/KickerAbility.java | 4 +- .../abilities/keyword/ReplicateAbility.java | 2 +- .../abilities/keyword/RetraceAbility.java | 5 +- 26 files changed, 253 insertions(+), 237 deletions(-) diff --git a/Mage.Sets/src/mage/sets/shadowmoor/AphoticWisps.java b/Mage.Sets/src/mage/sets/shadowmoor/AphoticWisps.java index 20096cb783e..588154614b0 100644 --- a/Mage.Sets/src/mage/sets/shadowmoor/AphoticWisps.java +++ b/Mage.Sets/src/mage/sets/shadowmoor/AphoticWisps.java @@ -25,20 +25,19 @@ * authors and should not be interpreted as representing official policies, either expressed * or implied, of BetaSteward_at_googlemail.com. */ - package mage.sets.shadowmoor; import java.util.UUID; - -import mage.constants.CardType; -import mage.constants.Rarity; import mage.ObjectColor; +import mage.abilities.effects.Effect; import mage.abilities.effects.common.DrawCardSourceControllerEffect; -import mage.abilities.effects.common.continuous.GainAbilityTargetEffect; import mage.abilities.effects.common.continuous.BecomesColorTargetEffect; +import mage.abilities.effects.common.continuous.GainAbilityTargetEffect; import mage.abilities.keyword.FearAbility; import mage.cards.CardImpl; +import mage.constants.CardType; import mage.constants.Duration; +import mage.constants.Rarity; import mage.target.common.TargetCreaturePermanent; /** @@ -47,19 +46,25 @@ import mage.target.common.TargetCreaturePermanent; */ public class AphoticWisps extends CardImpl { - public AphoticWisps (UUID ownerId) { + public AphoticWisps(UUID ownerId) { super(ownerId, 55, "Aphotic Wisps", Rarity.COMMON, new CardType[]{CardType.INSTANT}, "{B}"); this.expansionSetCode = "SHM"; - // Target creature becomes black and gains fear until end of turn. (It can't be blocked except by artifact creatures and/or black creatures.) + // Target creature becomes black and gains fear until end of turn. (It can't be blocked except by artifact creatures and/or black creatures.) this.getSpellAbility().addTarget(new TargetCreaturePermanent()); - this.getSpellAbility().addEffect(new BecomesColorTargetEffect(ObjectColor.BLACK, Duration.EndOfTurn)); - this.getSpellAbility().addEffect(new GainAbilityTargetEffect(FearAbility.getInstance(), Duration.EndOfTurn)); + Effect effect = new BecomesColorTargetEffect(ObjectColor.BLACK, Duration.EndOfTurn); + effect.setText("Target creature becomes black"); + this.getSpellAbility().addEffect(effect); + effect = new GainAbilityTargetEffect(FearAbility.getInstance(), Duration.EndOfTurn); + effect.setText("and gains fear until end of turn"); + this.getSpellAbility().addEffect(effect); // Draw a card. - this.getSpellAbility().addEffect(new DrawCardSourceControllerEffect(1)); + effect = new DrawCardSourceControllerEffect(1); + effect.setText("
Draw a card"); + this.getSpellAbility().addEffect(effect); } - public AphoticWisps (final AphoticWisps card) { + public AphoticWisps(final AphoticWisps card) { super(card); } @@ -69,4 +74,3 @@ public class AphoticWisps extends CardImpl { } } - diff --git a/Mage.Sets/src/mage/sets/shadowmoor/DrownerInitiate.java b/Mage.Sets/src/mage/sets/shadowmoor/DrownerInitiate.java index e2c04a54d62..67b9eda3099 100644 --- a/Mage.Sets/src/mage/sets/shadowmoor/DrownerInitiate.java +++ b/Mage.Sets/src/mage/sets/shadowmoor/DrownerInitiate.java @@ -45,12 +45,12 @@ import mage.target.TargetPlayer; /** * * @author jeffwadsworth - + * */ public class DrownerInitiate extends CardImpl { - + private static final FilterSpell filter = new FilterSpell("a blue spell"); - + static { filter.add(new ColorPredicate(ObjectColor.BLUE)); } @@ -65,10 +65,10 @@ public class DrownerInitiate extends CardImpl { this.toughness = new MageInt(1); // Whenever a player casts a blue spell, you may pay {1}. If you do, target player puts the top two cards of his or her library into his or her graveyard. - Ability ability = new SpellCastAllTriggeredAbility(new DoIfCostPaid(new PutLibraryIntoGraveTargetEffect(2), new ManaCostsImpl("{1}")), filter, true); + Ability ability = new SpellCastAllTriggeredAbility(new DoIfCostPaid(new PutLibraryIntoGraveTargetEffect(2), new ManaCostsImpl("{1}")), filter, false); ability.addTarget(new TargetPlayer()); this.addAbility(ability); - + } public DrownerInitiate(final DrownerInitiate card) { diff --git a/Mage.Sets/src/mage/sets/shadowmoor/LeechBonder.java b/Mage.Sets/src/mage/sets/shadowmoor/LeechBonder.java index 623580db2d0..7e6f922d10d 100644 --- a/Mage.Sets/src/mage/sets/shadowmoor/LeechBonder.java +++ b/Mage.Sets/src/mage/sets/shadowmoor/LeechBonder.java @@ -72,7 +72,7 @@ public class LeechBonder extends CardImpl { // Leech Bonder enters the battlefield with two -1/-1 counters on it. this.addAbility(new EntersBattlefieldAbility(new AddCountersSourceEffect(CounterType.M1M1.createInstance(2)))); - // {U}, {untap}: Move a counter from target creature onto a second target creature. + // {U}, {untap}: Move a counter from target creature onto another target creature. Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new LeechBonderEffect(), new ManaCostsImpl("{U}")); ability.addCost(new UntapSourceCost()); ability.addTarget(new TargetCreaturePermanent(new FilterCreaturePermanent("creature to remove counter from"))); diff --git a/Mage.Sets/src/mage/sets/shadowmoor/WickerWarcrawler.java b/Mage.Sets/src/mage/sets/shadowmoor/WickerWarcrawler.java index 4ea92e72079..597a65871af 100644 --- a/Mage.Sets/src/mage/sets/shadowmoor/WickerWarcrawler.java +++ b/Mage.Sets/src/mage/sets/shadowmoor/WickerWarcrawler.java @@ -29,19 +29,16 @@ package mage.sets.shadowmoor; import java.util.UUID; import mage.MageInt; -import mage.abilities.Ability; +import mage.abilities.DelayedTriggeredAbility; import mage.abilities.common.AttacksOrBlocksTriggeredAbility; import mage.abilities.common.delayed.AtTheEndOfCombatDelayedTriggeredAbility; -import mage.abilities.effects.OneShotEffect; -import mage.abilities.effects.common.counter.AddCountersTargetEffect; +import mage.abilities.effects.Effect; +import mage.abilities.effects.common.CreateDelayedTriggeredAbilityEffect; +import mage.abilities.effects.common.counter.AddCountersSourceEffect; import mage.cards.CardImpl; import mage.constants.CardType; -import mage.constants.Outcome; import mage.constants.Rarity; import mage.counters.CounterType; -import mage.game.Game; -import mage.game.permanent.Permanent; -import mage.target.targetpointer.FixedTarget; /** * @@ -57,7 +54,10 @@ public class WickerWarcrawler extends CardImpl { this.toughness = new MageInt(6); // Whenever Wicker Warcrawler attacks or blocks, put a -1/-1 counter on it at end of combat. - this.addAbility(new AttacksOrBlocksTriggeredAbility(new WickerWarcrawlerEffect(), false)); + Effect effect = new AddCountersSourceEffect(CounterType.M1M1.createInstance(), true); + effect.setText("put a -1/-1 counter on it at end of combat"); + DelayedTriggeredAbility ability = new AtTheEndOfCombatDelayedTriggeredAbility(effect); + this.addAbility(new AttacksOrBlocksTriggeredAbility(new CreateDelayedTriggeredAbilityEffect(ability, false, false), false)); } @@ -70,35 +70,3 @@ public class WickerWarcrawler extends CardImpl { return new WickerWarcrawler(this); } } - -class WickerWarcrawlerEffect extends OneShotEffect { - - WickerWarcrawlerEffect() { - super(Outcome.Detriment); - staticText = "put a -1/-1 counter on {this} at the end of combat"; - } - - WickerWarcrawlerEffect(final WickerWarcrawlerEffect effect) { - super(effect); - } - - @Override - public boolean apply(Game game, Ability source) { - Permanent wickerWarcrawler = game.getPermanent(source.getSourceId()); - if (wickerWarcrawler != null) { - AtTheEndOfCombatDelayedTriggeredAbility delayedAbility = new AtTheEndOfCombatDelayedTriggeredAbility(new AddCountersTargetEffect(CounterType.M1M1.createInstance())); - delayedAbility.setSourceId(source.getSourceId()); - delayedAbility.setControllerId(source.getControllerId()); - delayedAbility.setSourceObject(source.getSourceObject(game), game); - delayedAbility.getEffects().get(0).setTargetPointer(new FixedTarget(source.getSourceId())); - game.addDelayedTriggeredAbility(delayedAbility); - return true; - } - return false; - } - - @Override - public WickerWarcrawlerEffect copy() { - return new WickerWarcrawlerEffect(this); - } -} diff --git a/Mage.Sets/src/mage/sets/urzassaga/ShowAndTell.java b/Mage.Sets/src/mage/sets/urzassaga/ShowAndTell.java index 3bbcbbefb1f..0161b4f0df9 100644 --- a/Mage.Sets/src/mage/sets/urzassaga/ShowAndTell.java +++ b/Mage.Sets/src/mage/sets/urzassaga/ShowAndTell.java @@ -122,12 +122,5 @@ class ShowAndTellEffect extends OneShotEffect { } } return controller.moveCards(cardsToPutIntoPlay, Zone.BATTLEFIELD, source, game, false, false, true, null); -// for (Card card : cardsToPutIntoPlay) { -// Player player = game.getPlayer(card.getOwnerId()); -// if (player != null) { -// player.putOntoBattlefieldWithInfo(card, game, Zone.HAND, source.getSourceId()); -// } -// } - // return true; } } diff --git a/Mage.Sets/src/mage/sets/worldwake/FeralContest.java b/Mage.Sets/src/mage/sets/worldwake/FeralContest.java index f0af7b313e4..b519cab6c9c 100644 --- a/Mage.Sets/src/mage/sets/worldwake/FeralContest.java +++ b/Mage.Sets/src/mage/sets/worldwake/FeralContest.java @@ -32,7 +32,6 @@ import java.util.UUID; import mage.constants.CardType; import mage.constants.Rarity; import mage.abilities.Ability; -import mage.abilities.effects.Effect; import mage.abilities.effects.RequirementEffect; import mage.abilities.effects.common.counter.AddCountersTargetEffect; import mage.cards.CardImpl; @@ -53,8 +52,7 @@ public class FeralContest extends CardImpl { super(ownerId, 100, "Feral Contest", Rarity.COMMON, new CardType[]{CardType.SORCERY}, "{3}{G}"); this.expansionSetCode = "WWK"; - - // Put a +1/+1 counter on target creature you control. + // Put a +1/+1 counter on target creature you control. this.getSpellAbility().addEffect(new AddCountersTargetEffect(CounterType.P1P1.createInstance())); this.getSpellAbility().addTarget(new TargetControlledCreaturePermanent()); // Another target creature blocks it this turn if able. @@ -88,7 +86,7 @@ class FeralContestEffect extends RequirementEffect { } @Override - public boolean applies(Permanent permanent, Ability source, Game game) { + public boolean applies(Permanent permanent, Ability source, Game game) { if (permanent.getId().equals(source.getTargets().get(1).getFirstTarget())) { return permanent.canBlock(source.getFirstTarget(), game); } @@ -116,4 +114,3 @@ class FeralContestEffect extends RequirementEffect { } } - diff --git a/Mage.Sets/src/mage/sets/zendikar/BloodTribute.java b/Mage.Sets/src/mage/sets/zendikar/BloodTribute.java index 43437afc3f2..1335d9f4be9 100644 --- a/Mage.Sets/src/mage/sets/zendikar/BloodTribute.java +++ b/Mage.Sets/src/mage/sets/zendikar/BloodTribute.java @@ -33,8 +33,6 @@ import mage.constants.Outcome; import mage.constants.Rarity; import mage.abilities.Ability; import mage.abilities.condition.common.KickedCondition; -import mage.abilities.costs.OptionalAdditionalCost; -import mage.abilities.costs.OptionalAdditionalCostImpl; import mage.abilities.costs.common.TapTargetCost; import mage.abilities.decorator.ConditionalOneShotEffect; import mage.abilities.effects.Effect; @@ -56,7 +54,7 @@ import mage.target.common.TargetOpponent; */ public class BloodTribute extends CardImpl { - private static final FilterControlledCreaturePermanent filter = new FilterControlledCreaturePermanent("untapped Vampire you control"); + private static final FilterControlledCreaturePermanent filter = new FilterControlledCreaturePermanent("an untapped Vampire you control"); static { filter.add(Predicates.not(new TappedPredicate())); @@ -67,20 +65,18 @@ public class BloodTribute extends CardImpl { super(ownerId, 81, "Blood Tribute", Rarity.RARE, new CardType[]{CardType.SORCERY}, "{4}{B}{B}"); this.expansionSetCode = "ZEN"; - // Kicker - Tap an untapped Vampire you control. - OptionalAdditionalCost cost = new OptionalAdditionalCostImpl("Kicker-","",new TapTargetCost(new TargetControlledCreaturePermanent(1, 1, filter, true))); - this.addAbility(new KickerAbility(cost)); + this.addAbility(new KickerAbility(new TapTargetCost(new TargetControlledCreaturePermanent(1, 1, filter, true)))); // Target opponent loses half his or her life, rounded up. this.getSpellAbility().addTarget(new TargetOpponent()); this.getSpellAbility().addEffect(new BloodTributeLoseLifeEffect()); - + // If Blood Tribute was kicked, you gain life equal to the life lost this way. Effect effect = new ConditionalOneShotEffect( new BloodTributeGainLifeEffect(), KickedCondition.getInstance(), - "If Blood Tribute was kicked, you gain life equal to the life lost this way"); + "If {this} was kicked, you gain life equal to the life lost this way"); this.getSpellAbility().addEffect(effect); } diff --git a/Mage/src/mage/abilities/common/AttacksOrBlocksTriggeredAbility.java b/Mage/src/mage/abilities/common/AttacksOrBlocksTriggeredAbility.java index 7c1bb123487..732e6c59a7b 100644 --- a/Mage/src/mage/abilities/common/AttacksOrBlocksTriggeredAbility.java +++ b/Mage/src/mage/abilities/common/AttacksOrBlocksTriggeredAbility.java @@ -2,17 +2,25 @@ package mage.abilities.common; import mage.abilities.TriggeredAbilityImpl; import mage.abilities.effects.Effect; +import mage.abilities.effects.common.CreateDelayedTriggeredAbilityEffect; import mage.constants.Zone; import mage.game.Game; import mage.game.events.GameEvent; public class AttacksOrBlocksTriggeredAbility extends TriggeredAbilityImpl { + + protected String startText = "Whenever"; + public AttacksOrBlocksTriggeredAbility(Effect effect, boolean optional) { super(Zone.BATTLEFIELD, effect, optional); + if (effect instanceof CreateDelayedTriggeredAbilityEffect) { + startText = "When"; + } } public AttacksOrBlocksTriggeredAbility(final AttacksOrBlocksTriggeredAbility ability) { super(ability); + this.startText = ability.startText; } @Override @@ -22,8 +30,9 @@ public class AttacksOrBlocksTriggeredAbility extends TriggeredAbilityImpl { @Override public String getRule() { - return "When {this} attacks or blocks, " + super.getRule(); + return startText + " {this} attacks or blocks, " + super.getRule(); } + @Override public boolean checkEventType(GameEvent event, Game game) { return event.getType() == GameEvent.EventType.ATTACKER_DECLARED || event.getType() == GameEvent.EventType.BLOCKER_DECLARED; diff --git a/Mage/src/mage/abilities/costs/AlternativeCost2Impl.java b/Mage/src/mage/abilities/costs/AlternativeCost2Impl.java index b6b73034a93..03a0be13f47 100644 --- a/Mage/src/mage/abilities/costs/AlternativeCost2Impl.java +++ b/Mage/src/mage/abilities/costs/AlternativeCost2Impl.java @@ -25,20 +25,18 @@ * authors and should not be interpreted as representing official policies, either expressed * or implied, of BetaSteward_at_googlemail.com. */ - package mage.abilities.costs; import mage.game.Game; /** * Alternative costs - * + * * @author LevelX2 - * + * * @param */ - -public class AlternativeCost2Impl > extends CostsImpl implements AlternativeCost2 { +public class AlternativeCost2Impl> extends CostsImpl implements AlternativeCost2 { protected String name; protected String reminderText; @@ -72,6 +70,7 @@ public class AlternativeCost2Impl > extends Co public String getName() { return this.name; } + /** * Returns the complete text for the addional cost or if onlyCost is true * only the pure text for the included native cost @@ -84,7 +83,7 @@ public class AlternativeCost2Impl > extends Co if (onlyCost) { return getText(); } else { - return new StringBuffer(name != null ? name: "").append(delimiter != null ? delimiter: "").append(getText()).toString(); + return (name != null ? name : "") + (delimiter != null ? delimiter : "") + getText(); } } @@ -103,20 +102,20 @@ public class AlternativeCost2Impl > extends Co } /** - * Returns a text suffix for the game log, that can be added to - * the cast message. + * Returns a text suffix for the game log, that can be added to the cast + * message. * - * @param position - if there are multiple costs, it's the postion the cost is set (starting with 0) + * @param position - if there are multiple costs, it's the postion the cost + * is set (starting with 0) * @return */ @Override public String getCastSuffixMessage(int position) { - StringBuilder sb = new StringBuilder(position > 0 ? " and ":"").append(" with "); + StringBuilder sb = new StringBuilder(position > 0 ? " and " : "").append(" with "); sb.append(name); - return sb.toString(); + return sb.toString(); } - /** * If the player intends to pay the cost, the cost will be activated * @@ -124,7 +123,9 @@ public class AlternativeCost2Impl > extends Co @Override public void activate() { activated = true; - }; + } + + ; /** * Reset the activate and count information @@ -142,9 +143,11 @@ public class AlternativeCost2Impl > extends Co * @return */ @Override - public boolean isActivated(Game game){ + public boolean isActivated(Game game) { return activated; - }; + } + + ; @Override public AlternativeCost2Impl copy() { diff --git a/Mage/src/mage/abilities/costs/CompositeCost.java b/Mage/src/mage/abilities/costs/CompositeCost.java index f76693fb185..1d497d43793 100644 --- a/Mage/src/mage/abilities/costs/CompositeCost.java +++ b/Mage/src/mage/abilities/costs/CompositeCost.java @@ -1,14 +1,14 @@ package mage.abilities.costs; +import java.util.UUID; import mage.abilities.Ability; import mage.game.Game; import mage.target.Targets; -import java.util.UUID; - public class CompositeCost implements Cost { - private Cost firstCost; - private Cost secondCost; + + private final Cost firstCost; + private final Cost secondCost; private String description; public CompositeCost(Cost firstCost, Cost secondCost, String description) { @@ -28,6 +28,11 @@ public class CompositeCost implements Cost { throw new RuntimeException("Not supported method"); } + @Override + public void setText(String text) { + this.description = text; + } + @Override public String getText() { return description; diff --git a/Mage/src/mage/abilities/costs/Cost.java b/Mage/src/mage/abilities/costs/Cost.java index cd8696cd138..885ff8376fd 100644 --- a/Mage/src/mage/abilities/costs/Cost.java +++ b/Mage/src/mage/abilities/costs/Cost.java @@ -1,31 +1,30 @@ /* -* Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. -* -* Redistribution and use in source and binary forms, with or without modification, are -* permitted provided that the following conditions are met: -* -* 1. Redistributions of source code must retain the above copyright notice, this list of -* conditions and the following disclaimer. -* -* 2. Redistributions in binary form must reproduce the above copyright notice, this list -* of conditions and the following disclaimer in the documentation and/or other materials -* provided with the distribution. -* -* THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED -* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND -* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR -* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR -* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON -* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING -* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF -* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -* -* The views and conclusions contained in the software and documentation are those of the -* authors and should not be interpreted as representing official policies, either expressed -* or implied, of BetaSteward_at_googlemail.com. -*/ - + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ package mage.abilities.costs; import java.io.Serializable; @@ -37,12 +36,21 @@ import mage.target.Targets; public interface Cost extends Serializable { UUID getId(); + String getText(); + + void setText(String text); + boolean canPay(Ability ability, UUID sourceId, UUID controllerId, Game game); + boolean pay(Ability ability, Game game, UUID sourceId, UUID controllerId, boolean noMana); + boolean isPaid(); + void clearPaid(); + void setPaid(); + Targets getTargets(); Cost copy(); diff --git a/Mage/src/mage/abilities/costs/CostImpl.java b/Mage/src/mage/abilities/costs/CostImpl.java index e423f30fed4..57f6c5a7471 100644 --- a/Mage/src/mage/abilities/costs/CostImpl.java +++ b/Mage/src/mage/abilities/costs/CostImpl.java @@ -1,31 +1,30 @@ /* -* Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. -* -* Redistribution and use in source and binary forms, with or without modification, are -* permitted provided that the following conditions are met: -* -* 1. Redistributions of source code must retain the above copyright notice, this list of -* conditions and the following disclaimer. -* -* 2. Redistributions in binary form must reproduce the above copyright notice, this list -* of conditions and the following disclaimer in the documentation and/or other materials -* provided with the distribution. -* -* THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED -* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND -* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR -* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR -* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON -* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING -* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF -* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -* -* The views and conclusions contained in the software and documentation are those of the -* authors and should not be interpreted as representing official policies, either expressed -* or implied, of BetaSteward_at_googlemail.com. -*/ - + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ package mage.abilities.costs; import java.util.UUID; @@ -57,6 +56,7 @@ public abstract class CostImpl implements Cost { return text; } + @Override public void setText(String text) { this.text = text; } diff --git a/Mage/src/mage/abilities/costs/CostsImpl.java b/Mage/src/mage/abilities/costs/CostsImpl.java index a2624f3f29d..df64087a373 100644 --- a/Mage/src/mage/abilities/costs/CostsImpl.java +++ b/Mage/src/mage/abilities/costs/CostsImpl.java @@ -1,31 +1,30 @@ /* -* Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. -* -* Redistribution and use in source and binary forms, with or without modification, are -* permitted provided that the following conditions are met: -* -* 1. Redistributions of source code must retain the above copyright notice, this list of -* conditions and the following disclaimer. -* -* 2. Redistributions in binary form must reproduce the above copyright notice, this list -* of conditions and the following disclaimer in the documentation and/or other materials -* provided with the distribution. -* -* THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED -* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND -* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR -* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR -* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON -* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING -* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF -* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -* -* The views and conclusions contained in the software and documentation are those of the -* authors and should not be interpreted as representing official policies, either expressed -* or implied, of BetaSteward_at_googlemail.com. -*/ - + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ package mage.abilities.costs; import java.util.ArrayList; @@ -44,12 +43,16 @@ import mage.target.Targets; */ public class CostsImpl extends ArrayList implements Costs { - public CostsImpl() {} + protected String text = null; + + public CostsImpl() { + } public CostsImpl(final CostsImpl costs) { - for (Cost cost: costs) { - this.add((T)cost.copy()); + for (Cost cost : costs) { + this.add((T) cost.copy()); } + this.text = costs.text; } @Override @@ -57,20 +60,28 @@ public class CostsImpl extends ArrayList implements Costs throw new RuntimeException("Not supported method"); } + @Override + public void setText(String text) { + this.text = text; + } + @Override public String getText() { + if (text != null) { + return text; + } if (this.size() == 0) { return ""; } StringBuilder sbText = new StringBuilder(); - for (T cost: this) { - String text = cost.getText(); - if (text != null && !text.isEmpty()) { - sbText.append(Character.toUpperCase(text.charAt(0))).append(text.substring(1)).append(", "); + for (T cost : this) { + String textCost = cost.getText(); + if (textCost != null && !textCost.isEmpty()) { + sbText.append(Character.toUpperCase(textCost.charAt(0))).append(textCost.substring(1)).append(", "); } } - if (sbText.length() > 1){ + if (sbText.length() > 1) { sbText.setLength(sbText.length() - 2); } return sbText.toString(); @@ -78,7 +89,7 @@ public class CostsImpl extends ArrayList implements Costs @Override public boolean canPay(Ability ability, UUID sourceId, UUID controllerId, Game game) { - for (T cost: this) { + for (T cost : this) { if (!cost.canPay(ability, sourceId, controllerId, game)) { return false; } @@ -101,7 +112,7 @@ public class CostsImpl extends ArrayList implements Costs @Override public boolean isPaid() { - for (T cost: this) { + for (T cost : this) { if (!(cost instanceof VariableManaCost) && !cost.isPaid()) { return false; } @@ -111,14 +122,14 @@ public class CostsImpl extends ArrayList implements Costs @Override public void clearPaid() { - for (T cost: this) { + for (T cost : this) { cost.clearPaid(); } } @Override public void setPaid() { - for (T cost: this) { + for (T cost : this) { cost.setPaid(); } } @@ -126,7 +137,7 @@ public class CostsImpl extends ArrayList implements Costs @Override public Costs getUnpaid() { Costs unpaid = new CostsImpl<>(); - for (T cost: this) { + for (T cost : this) { if (!cost.isPaid()) { unpaid.add(cost); } @@ -140,17 +151,17 @@ public class CostsImpl extends ArrayList implements Costs return unpaid.get(0); } return null; - } + } @Override public List getVariableCosts() { List variableCosts = new ArrayList<>(); - for (T cost: this) { + for (T cost : this) { if (cost instanceof VariableCost) { variableCosts.add((VariableCost) cost); } if (cost instanceof ManaCosts) { - variableCosts.addAll(((ManaCosts)cost).getVariableCosts()); + variableCosts.addAll(((ManaCosts) cost).getVariableCosts()); } } return variableCosts; @@ -159,7 +170,7 @@ public class CostsImpl extends ArrayList implements Costs @Override public Targets getTargets() { Targets targets = new Targets(); - for (T cost: this) { + for (T cost : this) { if (cost.getTargets() != null) { targets.addAll(cost.getTargets()); } diff --git a/Mage/src/mage/abilities/costs/OptionalAdditionalCostImpl.java b/Mage/src/mage/abilities/costs/OptionalAdditionalCostImpl.java index 489d8690ea7..3646a9c3ec0 100644 --- a/Mage/src/mage/abilities/costs/OptionalAdditionalCostImpl.java +++ b/Mage/src/mage/abilities/costs/OptionalAdditionalCostImpl.java @@ -50,7 +50,7 @@ public class OptionalAdditionalCostImpl ex this.activated = false; this.name = name; this.delimiter = delimiter; - this.reminderText = new StringBuilder("").append(reminderText).append("").toString(); + this.reminderText = "(" + reminderText + ")"; this.activatedCounter = 0; this.add((Cost) cost); } @@ -81,7 +81,7 @@ public class OptionalAdditionalCostImpl ex if (onlyCost) { return getText(); } else { - return new StringBuffer(name).append(delimiter).append(getText()).toString(); + return name + delimiter + getText(); } } diff --git a/Mage/src/mage/abilities/costs/OrCost.java b/Mage/src/mage/abilities/costs/OrCost.java index 2c5a7740e7c..0707741244f 100644 --- a/Mage/src/mage/abilities/costs/OrCost.java +++ b/Mage/src/mage/abilities/costs/OrCost.java @@ -37,8 +37,8 @@ import mage.target.Targets; public class OrCost implements Cost { - private Cost firstCost; - private Cost secondCost; + private final Cost firstCost; + private final Cost secondCost; private String description; // which cost was slected to pay private Cost selectedCost; @@ -61,6 +61,11 @@ public class OrCost implements Cost { throw new RuntimeException("Not supported method"); } + @Override + public void setText(String text) { + this.description = text; + } + @Override public String getText() { return description; diff --git a/Mage/src/mage/abilities/costs/VariableCostImpl.java b/Mage/src/mage/abilities/costs/VariableCostImpl.java index 68557546df2..e1002b91eb4 100644 --- a/Mage/src/mage/abilities/costs/VariableCostImpl.java +++ b/Mage/src/mage/abilities/costs/VariableCostImpl.java @@ -77,6 +77,11 @@ public abstract class VariableCostImpl implements Cost, VariableCost { this.amountPaid = cost.amountPaid; } + @Override + public void setText(String text) { + this.text = text; + } + @Override public String getText() { return text; diff --git a/Mage/src/mage/abilities/costs/common/DiscardTargetCost.java b/Mage/src/mage/abilities/costs/common/DiscardTargetCost.java index 69fb9b62298..3cb460452af 100644 --- a/Mage/src/mage/abilities/costs/common/DiscardTargetCost.java +++ b/Mage/src/mage/abilities/costs/common/DiscardTargetCost.java @@ -1,16 +1,16 @@ /* * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. - * + * * Redistribution and use in source and binary forms, with or without modification, are * permitted provided that the following conditions are met: - * + * * 1. Redistributions of source code must retain the above copyright notice, this list of * conditions and the following disclaimer. - * + * * 2. Redistributions in binary form must reproduce the above copyright notice, this list * of conditions and the following disclaimer in the documentation and/or other materials * provided with the distribution. - * + * * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR @@ -20,21 +20,20 @@ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * + * * The views and conclusions contained in the software and documentation are those of the * authors and should not be interpreted as representing official policies, either expressed * or implied, of BetaSteward_at_googlemail.com. */ - package mage.abilities.costs.common; import java.util.ArrayList; import java.util.List; import java.util.UUID; -import mage.constants.Outcome; import mage.abilities.Ability; import mage.abilities.costs.CostImpl; import mage.cards.Card; +import mage.constants.Outcome; import mage.game.Game; import mage.players.Player; import mage.target.common.TargetCardInHand; @@ -44,23 +43,23 @@ import mage.target.common.TargetCardInHand; * @author BetaSteward_at_googlemail.com */ public class DiscardTargetCost extends CostImpl { - + List cards = new ArrayList<>(); protected boolean randomDiscard; public DiscardTargetCost(TargetCardInHand target) { this(target, false); } - + public DiscardTargetCost(TargetCardInHand target, boolean randomDiscard) { this.addTarget(target); this.randomDiscard = randomDiscard; - this.text = "Discard " + target.getTargetName(); + this.text = "discard " + target.getTargetName(); } public DiscardTargetCost(DiscardTargetCost cost) { super(cost); - for (Card card: cost.cards) { + for (Card card : cost.cards) { this.cards.add(card.copy()); } this.randomDiscard = cost.randomDiscard; @@ -74,11 +73,11 @@ public class DiscardTargetCost extends CostImpl { return false; } int amount = this.getTargets().get(0).getNumberOfTargets(); - if (randomDiscard) { + if (randomDiscard) { this.cards.addAll(player.discard(amount, true, ability, game).getCards(game)); } else { - if (targets.choose(Outcome.Discard, controllerId, sourceId, game)) { - for (UUID targetId: targets.get(0).getTargets()) { + if (targets.choose(Outcome.Discard, controllerId, sourceId, game)) { + for (UUID targetId : targets.get(0).getTargets()) { Card card = player.getHand().get(targetId, game); if (card == null) { return false; @@ -94,7 +93,7 @@ public class DiscardTargetCost extends CostImpl { @Override public void clearPaid() { - super.clearPaid(); + super.clearPaid(); cards.clear(); } diff --git a/Mage/src/mage/abilities/costs/mana/ManaCostsImpl.java b/Mage/src/mage/abilities/costs/mana/ManaCostsImpl.java index 5c6cb083be8..ac056ba437a 100644 --- a/Mage/src/mage/abilities/costs/mana/ManaCostsImpl.java +++ b/Mage/src/mage/abilities/costs/mana/ManaCostsImpl.java @@ -51,6 +51,7 @@ import mage.util.ManaUtil; public class ManaCostsImpl extends ArrayList implements ManaCosts { protected UUID id; + protected String text = null; private static Map costs = new HashMap<>(); @@ -372,8 +373,16 @@ public class ManaCostsImpl extends ArrayList implements M return this.id; } + @Override + public void setText(String text) { + this.text = text; + } + @Override public String getText() { + if (text != null) { + return text; + } if (this.size() == 0) { return ""; } diff --git a/Mage/src/mage/abilities/effects/common/DrawCardTargetEffect.java b/Mage/src/mage/abilities/effects/common/DrawCardTargetEffect.java index 6443cc2efbc..7d7556fc7cf 100644 --- a/Mage/src/mage/abilities/effects/common/DrawCardTargetEffect.java +++ b/Mage/src/mage/abilities/effects/common/DrawCardTargetEffect.java @@ -1,16 +1,16 @@ /* * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. - * + * * Redistribution and use in source and binary forms, with or without modification, are * permitted provided that the following conditions are met: - * + * * 1. Redistributions of source code must retain the above copyright notice, this list of * conditions and the following disclaimer. - * + * * 2. Redistributions in binary form must reproduce the above copyright notice, this list * of conditions and the following disclaimer in the documentation and/or other materials * provided with the distribution. - * + * * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR @@ -20,12 +20,11 @@ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * + * * The views and conclusions contained in the software and documentation are those of the * authors and should not be interpreted as representing official policies, either expressed * or implied, of BetaSteward_at_googlemail.com. */ - package mage.abilities.effects.common; import mage.abilities.Ability; @@ -51,6 +50,7 @@ public class DrawCardTargetEffect extends OneShotEffect { public DrawCardTargetEffect(int amount) { this(new StaticValue(amount)); } + public DrawCardTargetEffect(int amount, boolean optional) { this(new StaticValue(amount), optional); } @@ -117,7 +117,7 @@ public class DrawCardTargetEffect extends OneShotEffect { if (upTo) { sb.append("up to "); } - sb.append(CardUtil.numberToText(amount.toString())).append(" card"); + sb.append(CardUtil.numberToText(amount.toString(), "a")).append(" card"); try { if (Integer.parseInt(amount.toString()) > 1) { sb.append("s"); @@ -133,5 +133,4 @@ public class DrawCardTargetEffect extends OneShotEffect { return sb.toString(); } - } diff --git a/Mage/src/mage/abilities/effects/common/continuous/BecomesColorOrColorsTargetEffect.java b/Mage/src/mage/abilities/effects/common/continuous/BecomesColorOrColorsTargetEffect.java index dcdbe3ef9f2..c8fc6e2e6c2 100644 --- a/Mage/src/mage/abilities/effects/common/continuous/BecomesColorOrColorsTargetEffect.java +++ b/Mage/src/mage/abilities/effects/common/continuous/BecomesColorOrColorsTargetEffect.java @@ -44,14 +44,14 @@ import mage.target.targetpointer.FixedTarget; * * @author LevelX2 */ - public class BecomesColorOrColorsTargetEffect extends OneShotEffect { Duration duration; + /** * This effect let the controller choose one or more colors the target will - * become to. - * Use effect.setText() if case you use a targetPointer, otherwise the rule text will be empty. + * become to. Use effect.setText() if case you use a targetPointer, + * otherwise the rule text will be empty. * * @param duration */ @@ -81,8 +81,9 @@ public class BecomesColorOrColorsTargetEffect extends OneShotEffect { if (!controller.canRespond()) { return false; } - if (!game.isSimulation()) + if (!game.isSimulation()) { game.informPlayers(target.getName() + ": " + controller.getLogName() + " has chosen " + choiceColor.getChoice()); + } if (choiceColor.getColor().isBlack()) { sb.append("B"); } else if (choiceColor.getColor().isBlue()) { @@ -119,7 +120,7 @@ public class BecomesColorOrColorsTargetEffect extends OneShotEffect { StringBuilder sb = new StringBuilder(); if (mode.getTargets().size() > 0) { sb.append("target "); - sb.append(mode.getTargets().get(0).getMessage()); + sb.append(mode.getTargets().get(0).getFilter().getMessage()); sb.append(" becomes the color or colors of your choice"); if (duration.toString().length() > 0) { sb.append(" ").append(duration.toString()); diff --git a/Mage/src/mage/abilities/keyword/BuybackAbility.java b/Mage/src/mage/abilities/keyword/BuybackAbility.java index 05059e4e53c..f35c32c874f 100644 --- a/Mage/src/mage/abilities/keyword/BuybackAbility.java +++ b/Mage/src/mage/abilities/keyword/BuybackAbility.java @@ -63,8 +63,8 @@ import mage.players.Player; public class BuybackAbility extends StaticAbility implements OptionalAdditionalSourceCosts { private static final String keywordText = "Buyback"; - private static final String reminderTextCost = "(You may {cost} in addition to any other costs as you cast this spell. If you do, put this card into your hand as it resolves.)"; - private static final String reminderTextMana = "(You may pay an additional {cost} as you cast this spell. If you do, put this card into your hand as it resolves.)"; + private static final String reminderTextCost = "You may {cost} in addition to any other costs as you cast this spell. If you do, put this card into your hand as it resolves."; + private static final String reminderTextMana = "You may pay an additional {cost} as you cast this spell. If you do, put this card into your hand as it resolves."; protected OptionalAdditionalCost buybackCost; public BuybackAbility(String manaString) { diff --git a/Mage/src/mage/abilities/keyword/ConspireAbility.java b/Mage/src/mage/abilities/keyword/ConspireAbility.java index 7d48fe50e04..674505173bb 100644 --- a/Mage/src/mage/abilities/keyword/ConspireAbility.java +++ b/Mage/src/mage/abilities/keyword/ConspireAbility.java @@ -113,8 +113,9 @@ public class ConspireAbility extends StaticAbility implements OptionalAdditional reminderText = "As you cast this spell, you may tap two untapped creatures you control that share a color with it. When you do, copy it and you may choose a new targets for the copy.)"; break; } - conspireCost = new OptionalAdditionalCostImpl(keywordText, "-", reminderText, - new TapTargetCost(new TargetControlledPermanent(2, 2, filter, true))); + Cost cost = new TapTargetCost(new TargetControlledPermanent(2, 2, filter, true)); + cost.setText(""); + conspireCost = new OptionalAdditionalCostImpl(keywordText, " ", reminderText, cost); addSubAbility(new ConspireTriggeredAbility(conspireId)); } diff --git a/Mage/src/mage/abilities/keyword/EntwineAbility.java b/Mage/src/mage/abilities/keyword/EntwineAbility.java index 8448463486c..c81d1cbd955 100644 --- a/Mage/src/mage/abilities/keyword/EntwineAbility.java +++ b/Mage/src/mage/abilities/keyword/EntwineAbility.java @@ -59,7 +59,7 @@ import mage.players.Player; public class EntwineAbility extends StaticAbility implements OptionalAdditionalModeSourceCosts { private static final String keywordText = "Entwine"; - private static final String reminderText = " (Choose both if you pay the entwine cost.)"; + private static final String reminderText = "Choose both if you pay the entwine cost."; protected OptionalAdditionalCost additionalCost; public EntwineAbility(String manaString) { diff --git a/Mage/src/mage/abilities/keyword/KickerAbility.java b/Mage/src/mage/abilities/keyword/KickerAbility.java index d28edb5307c..f7bc6c8ff84 100644 --- a/Mage/src/mage/abilities/keyword/KickerAbility.java +++ b/Mage/src/mage/abilities/keyword/KickerAbility.java @@ -85,8 +85,8 @@ import mage.players.Player; public class KickerAbility extends StaticAbility implements OptionalAdditionalSourceCosts { protected static final String KICKER_KEYWORD = "Kicker"; - protected static final String KICKER_REMINDER_MANA = "(You may pay an additional {cost} as you cast this spell.)"; - protected static final String KICKER_REMINDER_COST = "(You may {cost} in addition to any other costs as you cast this spell.)"; + protected static final String KICKER_REMINDER_MANA = "You may pay an additional {cost} as you cast this spell."; + protected static final String KICKER_REMINDER_COST = "You may {cost} in addition to any other costs as you cast this spell."; protected Map activations = new HashMap<>(); // zoneChangeCounter, activations diff --git a/Mage/src/mage/abilities/keyword/ReplicateAbility.java b/Mage/src/mage/abilities/keyword/ReplicateAbility.java index 8be57a3997e..ed5c34e1a2f 100644 --- a/Mage/src/mage/abilities/keyword/ReplicateAbility.java +++ b/Mage/src/mage/abilities/keyword/ReplicateAbility.java @@ -56,7 +56,7 @@ import mage.players.Player; public class ReplicateAbility extends StaticAbility implements OptionalAdditionalSourceCosts { private static final String keywordText = "Replicate"; - private static final String reminderTextMana = "(When you cast this spell, copy it for each time you paid its replicate cost. You may choose new targets for the copies.)"; + private static final String reminderTextMana = "When you cast this spell, copy it for each time you paid its replicate cost. You may choose new targets for the copies."; protected OptionalAdditionalCost additionalCost; public ReplicateAbility(Card card, String manaString) { diff --git a/Mage/src/mage/abilities/keyword/RetraceAbility.java b/Mage/src/mage/abilities/keyword/RetraceAbility.java index 2ce121fc255..21e6b84d9ed 100644 --- a/Mage/src/mage/abilities/keyword/RetraceAbility.java +++ b/Mage/src/mage/abilities/keyword/RetraceAbility.java @@ -28,6 +28,7 @@ package mage.abilities.keyword; import mage.abilities.SpellAbility; +import mage.abilities.costs.Cost; import mage.abilities.costs.common.DiscardTargetCost; import mage.cards.Card; import mage.constants.SpellAbilityType; @@ -44,7 +45,9 @@ public class RetraceAbility extends SpellAbility { public RetraceAbility(Card card) { super(card.getManaCost(), card.getName() + " with retrace", Zone.GRAVEYARD, SpellAbilityType.BASE_ALTERNATE); this.getCosts().addAll(card.getSpellAbility().getCosts().copy()); - this.addCost(new DiscardTargetCost(new TargetCardInHand(new FilterLandCard()))); + Cost cost = new DiscardTargetCost(new TargetCardInHand(new FilterLandCard())); + cost.setText(""); + this.addCost(cost); this.getEffects().addAll(card.getSpellAbility().getEffects().copy()); this.getTargets().addAll(card.getSpellAbility().getTargets().copy()); this.getChoices().addAll(card.getSpellAbility().getChoices().copy()); From d9da74868ee6fcd37afb5c9af5e92cdf92e45c22 Mon Sep 17 00:00:00 2001 From: LoneFox Date: Sun, 11 Oct 2015 12:28:24 +0300 Subject: [PATCH 065/268] Fix Bloodied Ghost's tooltip text --- Mage.Sets/src/mage/sets/eventide/BloodiedGhost.java | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/Mage.Sets/src/mage/sets/eventide/BloodiedGhost.java b/Mage.Sets/src/mage/sets/eventide/BloodiedGhost.java index 2d046b50dfa..dd8ae7ec4ba 100644 --- a/Mage.Sets/src/mage/sets/eventide/BloodiedGhost.java +++ b/Mage.Sets/src/mage/sets/eventide/BloodiedGhost.java @@ -29,13 +29,13 @@ package mage.sets.eventide; import java.util.UUID; -import mage.constants.CardType; -import mage.constants.Rarity; import mage.MageInt; import mage.abilities.common.EntersBattlefieldAbility; import mage.abilities.effects.common.counter.AddCountersSourceEffect; import mage.abilities.keyword.FlyingAbility; import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.Rarity; import mage.counters.CounterType; /** @@ -48,12 +48,15 @@ public class BloodiedGhost extends CardImpl { super(ownerId, 83, "Bloodied Ghost", Rarity.UNCOMMON, new CardType[]{CardType.CREATURE}, "{1}{W/B}{W/B}"); this.expansionSetCode = "EVE"; this.subtype.add("Spirit"); - - this.power = new MageInt(3); this.toughness = new MageInt(3); + + // Flying this.addAbility(FlyingAbility.getInstance()); - this.addAbility(new EntersBattlefieldAbility(new AddCountersSourceEffect(CounterType.M1M1.createInstance()), "Bloodied Ghost gets a -1/-1 counter")); + + // Bloodied Ghost enters the battlefield with a -1/-1 counter on it. + this.addAbility(new EntersBattlefieldAbility(new AddCountersSourceEffect(CounterType.M1M1.createInstance()), + "with a -1/-1 counter on it.")); } public BloodiedGhost (final BloodiedGhost card) { From 981a27ccbf19acbbc84fc20de1a1503703688537 Mon Sep 17 00:00:00 2001 From: LevelX2 Date: Sun, 11 Oct 2015 18:13:14 +0200 Subject: [PATCH 066/268] * Fate transfer - Fixed that +1/+1 or -1/-1 counters on target permanent were not applied. --- .../mage/sets/shadowmoor/FateTransfer.java | 6 +-- .../oneshot/counter/MovingCounterTest.java | 51 +++++++++++++++---- 2 files changed, 42 insertions(+), 15 deletions(-) diff --git a/Mage.Sets/src/mage/sets/shadowmoor/FateTransfer.java b/Mage.Sets/src/mage/sets/shadowmoor/FateTransfer.java index dcfe9b5a38b..811237a3b48 100644 --- a/Mage.Sets/src/mage/sets/shadowmoor/FateTransfer.java +++ b/Mage.Sets/src/mage/sets/shadowmoor/FateTransfer.java @@ -53,7 +53,6 @@ public class FateTransfer extends CardImpl { super(ownerId, 161, "Fate Transfer", Rarity.COMMON, new CardType[]{CardType.INSTANT}, "{1}{U/B}"); this.expansionSetCode = "SHM"; - // Move all counters from target creature onto another target creature. this.getSpellAbility().addEffect(new FateTransferEffect()); this.getSpellAbility().addTarget(new TargetCreaturePermanent(filter)); @@ -96,9 +95,8 @@ class FateTransferEffect extends OneShotEffect { && creatureToMoveCountersTo != null) { Permanent copyCreature = creatureToMoveCountersFrom.copy(); for (Counter counter : copyCreature.getCounters().values()) { - Counter newCounterTest = new Counter(counter.getName(), counter.getCount()); - creatureToMoveCountersFrom.removeCounters(newCounterTest, game); - creatureToMoveCountersTo.addCounters(newCounterTest, game); + creatureToMoveCountersFrom.removeCounters(counter, game); + creatureToMoveCountersTo.addCounters(counter, game); } return true; } diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/abilities/oneshot/counter/MovingCounterTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/abilities/oneshot/counter/MovingCounterTest.java index 8e687a50e95..a1ef2b75ec5 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/abilities/oneshot/counter/MovingCounterTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/abilities/oneshot/counter/MovingCounterTest.java @@ -36,7 +36,6 @@ import org.mage.test.serverside.base.CardTestPlayerBase; * * @author LevelX2 */ - public class MovingCounterTest extends CardTestPlayerBase { /** @@ -51,12 +50,11 @@ public class MovingCounterTest extends CardTestPlayerBase { // Move any number of +1/+1 counters from target creature onto another target creature with the same controller. addCard(Zone.HAND, playerA, "Bioshift", 1); - - // Protean Hydra enters the battlefield with X +1/+1 counters on it. - // If damage would be dealt to Protean Hydra, prevent that damage and remove that many +1/+1 counters from it. - // Whenever a +1/+1 counter is removed from Protean Hydra, put two +1/+1 counters on it at the beginning of the next end step. - addCard(Zone.HAND, playerA, "Protean Hydra", 1); + // Protean Hydra enters the battlefield with X +1/+1 counters on it. + // If damage would be dealt to Protean Hydra, prevent that damage and remove that many +1/+1 counters from it. + // Whenever a +1/+1 counter is removed from Protean Hydra, put two +1/+1 counters on it at the beginning of the next end step. + addCard(Zone.HAND, playerA, "Protean Hydra", 1); castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Protean Hydra"); setChoice(playerA, "X=4"); @@ -67,14 +65,45 @@ public class MovingCounterTest extends CardTestPlayerBase { execute(); assertGraveyardCount(playerA, "Bioshift", 1); - - assertPermanentCount(playerA, "Silvercoat Lion", 1); + + assertPermanentCount(playerA, "Silvercoat Lion", 1); assertPowerToughness(playerA, "Silvercoat Lion", 4, 4); // added 2 counters - assertPermanentCount(playerA, "Protean Hydra", 1); + assertPermanentCount(playerA, "Protean Hydra", 1); assertPowerToughness(playerA, "Protean Hydra", 6, 6); // started with 4, removed 2, added 4 at end = 6 - } -} \ No newline at end of file + /** + * I'm having an issue when using Bioshift to move only a portion of + * counters to another creature. When I attempt to do this, it moves all of + * the counters (and in some cases with my Simic deck) kills the creature. + */ + @Test + public void testFateTransfer() { + addCard(Zone.BATTLEFIELD, playerA, "Forest", 4); + // Noxious Hatchling enters the battlefield with four -1/-1 counters on it. + // Wither (This deals damage to creatures in the form of -1/-1 counters.) + // Whenever you cast a black spell, remove a -1/-1 counter from Noxious Hatchling. + // Whenever you cast a green spell, remove a -1/-1 counter from Noxious Hatchling. + addCard(Zone.HAND, playerA, "Noxious Hatchling", 1);// 6/6 + addCard(Zone.BATTLEFIELD, playerA, "Ruin Processor", 1); // Creature 7/8 + + addCard(Zone.BATTLEFIELD, playerB, "Swamp", 2); + // Move all counters from target creature onto another target creature. + addCard(Zone.HAND, playerB, "Fate Transfer", 1); + + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Noxious Hatchling"); + castSpell(1, PhaseStep.BEGIN_COMBAT, playerB, "Fate Transfer", "Noxious Hatchling^Ruin Processor"); + + setStopAt(1, PhaseStep.END_COMBAT); + execute(); + + assertGraveyardCount(playerB, "Fate Transfer", 1); + + assertPowerToughness(playerA, "Noxious Hatchling", 6, 6); + + assertPowerToughness(playerA, "Ruin Processor", 3, 4); + + } +} From ef3e4321883f984a98e2aeac649bc6c7faf0e745 Mon Sep 17 00:00:00 2001 From: LevelX2 Date: Sun, 11 Oct 2015 18:32:37 +0200 Subject: [PATCH 067/268] * Domineering Will - Fixed not correctly working effects. --- .../sets/commander2014/DomineeringWill.java | 129 ++---------------- Mage/src/mage/game/combat/Combat.java | 2 +- 2 files changed, 15 insertions(+), 116 deletions(-) diff --git a/Mage.Sets/src/mage/sets/commander2014/DomineeringWill.java b/Mage.Sets/src/mage/sets/commander2014/DomineeringWill.java index df27ae5176b..31497d4ee8a 100644 --- a/Mage.Sets/src/mage/sets/commander2014/DomineeringWill.java +++ b/Mage.Sets/src/mage/sets/commander2014/DomineeringWill.java @@ -30,25 +30,25 @@ package mage.sets.commander2014; import java.util.UUID; import mage.abilities.Ability; import mage.abilities.effects.ContinuousEffect; -import mage.abilities.effects.ContinuousEffectImpl; import mage.abilities.effects.Effect; import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.RequirementEffect; +import mage.abilities.effects.common.UntapTargetEffect; +import mage.abilities.effects.common.combat.BlocksIfAbleTargetEffect; +import mage.abilities.effects.common.continuous.GainControlTargetEffect; import mage.cards.CardImpl; import mage.constants.CardType; import mage.constants.Duration; -import mage.constants.Layer; import mage.constants.Outcome; import mage.constants.Rarity; -import mage.constants.SubLayer; import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.Predicates; import mage.filter.predicate.permanent.AttackingPredicate; import mage.game.Game; -import mage.game.permanent.Permanent; import mage.players.Player; import mage.target.TargetPlayer; import mage.target.common.TargetCreaturePermanent; +import mage.target.targetpointer.SecondTargetPointer; /** * @@ -66,7 +66,6 @@ public class DomineeringWill extends CardImpl { super(ownerId, 13, "Domineering Will", Rarity.RARE, new CardType[]{CardType.INSTANT}, "{3}{U}"); this.expansionSetCode = "C14"; - // Target player gains control of up to three target nonattacking creatures until end of turn. Untap those creatures. They block this turn if able. this.getSpellAbility().addEffect(new DomineeringWillEffect()); this.getSpellAbility().addTarget(new TargetPlayer()); @@ -102,14 +101,20 @@ class DomineeringWillEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { - Player targetPlayer = game.getPlayer(targetPointer.getFirst(game, source)); + Player targetPlayer = game.getPlayer(getTargetPointer().getFirst(game, source)); if (targetPlayer != null) { - ContinuousEffect effect = new DomineeringWillControlEffect(); + ContinuousEffect effect = new GainControlTargetEffect(Duration.EndOfTurn, targetPlayer.getId()); + effect.setTargetPointer(new SecondTargetPointer()); + effect.setText("Target player gains control of up to three target nonattacking creatures until end of turn"); game.addEffect(effect, source); - Effect effect2 = new DomineeringWillUntapTargetEffect(); + + Effect effect2 = new UntapTargetEffect(); + effect2.setTargetPointer(new SecondTargetPointer()); effect2.setText("Untap those creatures"); effect2.apply(game, source); - RequirementEffect effect3 = new DomineeringWillBlocksIfAbleTargetEffect(Duration.EndOfTurn); + + RequirementEffect effect3 = new BlocksIfAbleTargetEffect(Duration.EndOfTurn); + effect3.setTargetPointer(new SecondTargetPointer()); effect3.setText("They block this turn if able"); game.addEffect(effect3, source); return true; @@ -117,109 +122,3 @@ class DomineeringWillEffect extends OneShotEffect { return false; } } - -class DomineeringWillControlEffect extends ContinuousEffectImpl { - - public DomineeringWillControlEffect() { - super(Duration.EndOfTurn, Layer.ControlChangingEffects_2, SubLayer.NA, Outcome.GainControl); - } - - public DomineeringWillControlEffect(final DomineeringWillControlEffect effect) { - super(effect); - } - - @Override - public DomineeringWillControlEffect copy() { - return new DomineeringWillControlEffect(this); - } - - @Override - public boolean apply(Game game, Ability source) { - Player targetPlayer = game.getPlayer(targetPointer.getFirst(game, source)); - if (targetPlayer != null) { - boolean targetStillExists = false; - for (UUID permanentId : source.getTargets().get(1).getTargets()) { - Permanent permanent = game.getPermanent(permanentId); - if (permanent != null) { - targetStillExists = true; - if (targetPlayer != null) { - permanent.changeControllerId(targetPlayer.getId(), game); - permanent.getAbilities().setControllerId(targetPlayer.getId()); - } else { - permanent.changeControllerId(source.getControllerId(), game); - permanent.getAbilities().setControllerId(source.getControllerId()); - } - } - } - if (!targetStillExists) { - // no valid target exists, effect can be discarded - discard(); - } - return true; - } - return false; - } -} - -class DomineeringWillUntapTargetEffect extends OneShotEffect { - - public DomineeringWillUntapTargetEffect() { - super(Outcome.Untap); - } - - public DomineeringWillUntapTargetEffect(final DomineeringWillUntapTargetEffect effect) { - super(effect); - } - - @Override - public DomineeringWillUntapTargetEffect copy() { - return new DomineeringWillUntapTargetEffect(this); - } - - @Override - public boolean apply(Game game, Ability source) { - for (UUID target : source.getTargets().get(1).getTargets()) { - Permanent permanent = game.getPermanent(target); - if (permanent != null) { - permanent.untap(game); - } - } - return true; - } -} - -class DomineeringWillBlocksIfAbleTargetEffect extends RequirementEffect { - - public DomineeringWillBlocksIfAbleTargetEffect(Duration duration) { - super(duration); - } - - public DomineeringWillBlocksIfAbleTargetEffect(final DomineeringWillBlocksIfAbleTargetEffect effect) { - super(effect); - } - - @Override - public DomineeringWillBlocksIfAbleTargetEffect copy() { - return new DomineeringWillBlocksIfAbleTargetEffect(this); - } - - @Override - public boolean applies(Permanent permanent, Ability source, Game game) { - return source.getTargets().get(1).getTargets().contains(permanent.getId()); - } - - @Override - public boolean mustAttack(Game game) { - return false; - } - - @Override - public boolean mustBlock(Game game) { - return false; - } - - @Override - public boolean mustBlockAny(Game game) { - return true; - } -} diff --git a/Mage/src/mage/game/combat/Combat.java b/Mage/src/mage/game/combat/Combat.java index 1aa89433f70..b03625617c6 100644 --- a/Mage/src/mage/game/combat/Combat.java +++ b/Mage/src/mage/game/combat/Combat.java @@ -663,7 +663,7 @@ public class Combat implements Serializable, Copyable { if (mayBlock) { if (controller.isHuman()) { if (!game.isSimulation()) { - game.informPlayer(controller, "Creature should block this turn: " + creature.getLogName()); + game.informPlayer(controller, "Creature should block this turn: " + creature.getIdName()); } } else { Player defender = game.getPlayer(creature.getControllerId()); From 01a14a26653b3df0d450273f33f2d403e56fe957 Mon Sep 17 00:00:00 2001 From: LevelX2 Date: Sun, 11 Oct 2015 19:20:12 +0200 Subject: [PATCH 068/268] * Fixed function and handling of the Ice Age depletion counter lands. --- .../mage/sets/fifthdawn/GoblinBrawler.java | 20 ++--- Mage.Sets/src/mage/sets/iceage/LandCap.java | 9 +- Mage.Sets/src/mage/sets/iceage/LavaTubes.java | 6 +- .../src/mage/sets/iceage/RiverDelta.java | 7 +- .../src/mage/sets/iceage/TimberlineRidge.java | 6 +- Mage.Sets/src/mage/sets/iceage/Veldt.java | 6 +- ...ditionalContinuousRuleModifyingEffect.java | 19 +++- .../ContinuousRuleModifyingEffectImpl.java | 90 +++++++++---------- ...tapInControllersUntapStepSourceEffect.java | 11 ++- 9 files changed, 95 insertions(+), 79 deletions(-) diff --git a/Mage.Sets/src/mage/sets/fifthdawn/GoblinBrawler.java b/Mage.Sets/src/mage/sets/fifthdawn/GoblinBrawler.java index 13b1344e3da..5851db67059 100644 --- a/Mage.Sets/src/mage/sets/fifthdawn/GoblinBrawler.java +++ b/Mage.Sets/src/mage/sets/fifthdawn/GoblinBrawler.java @@ -31,9 +31,7 @@ import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.SimpleStaticAbility; -import mage.abilities.effects.ContinuousEffect; import mage.abilities.effects.ContinuousRuleModifyingEffectImpl; -import mage.abilities.effects.ReplacementEffectImpl; import mage.abilities.keyword.FirstStrikeAbility; import mage.cards.CardImpl; import mage.constants.CardType; @@ -83,12 +81,12 @@ class CantBeEquippedSourceEffect extends ContinuousRuleModifyingEffectImpl { } public CantBeEquippedSourceEffect() { - super(Duration.WhileOnBattlefield, Outcome.Neutral); - staticText = "{this} can't be equipped"; + super(Duration.WhileOnBattlefield, Outcome.Neutral); + staticText = "{this} can't be equipped"; } - + @Override - public ContinuousEffect copy() { + public CantBeEquippedSourceEffect copy() { return new CantBeEquippedSourceEffect(this); } @@ -96,14 +94,14 @@ class CantBeEquippedSourceEffect extends ContinuousRuleModifyingEffectImpl { public boolean checksEventType(GameEvent event, Game game) { return event.getType() == GameEvent.EventType.ATTACH; } - + @Override public boolean applies(GameEvent event, Ability source, Game game) { if (event.getTargetId().equals(source.getSourceId())) { - Permanent permanent = game.getPermanent(event.getSourceId()); - if(permanent != null && permanent.getSubtype().contains("Equipment")){ - return true; - } + Permanent permanent = game.getPermanent(event.getSourceId()); + if (permanent != null && permanent.getSubtype().contains("Equipment")) { + return true; + } } return false; } diff --git a/Mage.Sets/src/mage/sets/iceage/LandCap.java b/Mage.Sets/src/mage/sets/iceage/LandCap.java index c430a5be249..9049711a15e 100644 --- a/Mage.Sets/src/mage/sets/iceage/LandCap.java +++ b/Mage.Sets/src/mage/sets/iceage/LandCap.java @@ -34,7 +34,6 @@ import mage.abilities.common.BeginningOfUpkeepTriggeredAbility; import mage.abilities.common.SimpleStaticAbility; import mage.abilities.condition.common.SourceHasCounterCondition; import mage.abilities.costs.common.TapSourceCost; -import mage.abilities.decorator.ConditionalContinuousEffect; import mage.abilities.decorator.ConditionalContinuousRuleModifyingEffect; import mage.abilities.effects.Effect; import mage.abilities.effects.common.DontUntapInControllersUntapStepSourceEffect; @@ -50,7 +49,7 @@ import mage.counters.CounterType; /** * - * @author anonymous + * @author Luna Skyrise */ public class LandCap extends CardImpl { @@ -59,15 +58,15 @@ public class LandCap extends CardImpl { this.expansionSetCode = "ICE"; // Land Cap doesn't untap during your untap step if it has a depletion counter on it. - Effect effect = new ConditionalContinuousRuleModifyingEffect(new DontUntapInControllersUntapStepSourceEffect(), - new SourceHasCounterCondition(CounterType.DEPLETION, 0)); + Effect effect = new ConditionalContinuousRuleModifyingEffect(new DontUntapInControllersUntapStepSourceEffect(false, true), + new SourceHasCounterCondition(CounterType.DEPLETION, 1, Integer.MAX_VALUE)); effect.setText("{this} doesn't untap during your untap step if it has a depletion counter on it"); Ability ability = new SimpleStaticAbility(Zone.BATTLEFIELD, effect); this.addAbility(ability); // At the beginning of your upkeep, remove a depletion counter from Land Cap. Ability ability2 = new BeginningOfUpkeepTriggeredAbility(new RemoveCounterSourceEffect(CounterType.DEPLETION.createInstance()), TargetController.YOU, false); this.addAbility(ability2); - // {tap}: Add {W} or {U} to your mana pool. Put a depletion counter on Land Cap. + // {T}: Add {W} or {U} to your mana pool. Put a depletion counter on Land Cap. Ability ability3 = new SimpleManaAbility(Zone.BATTLEFIELD, Mana.WhiteMana, new TapSourceCost()); ability3.addEffect(new AddCountersSourceEffect(CounterType.DEPLETION.createInstance())); this.addAbility(ability3); diff --git a/Mage.Sets/src/mage/sets/iceage/LavaTubes.java b/Mage.Sets/src/mage/sets/iceage/LavaTubes.java index 26cd59dc92f..ba645300648 100644 --- a/Mage.Sets/src/mage/sets/iceage/LavaTubes.java +++ b/Mage.Sets/src/mage/sets/iceage/LavaTubes.java @@ -49,7 +49,7 @@ import mage.counters.CounterType; /** * - * @author anonymous + * @author Luna Skyrise */ public class LavaTubes extends CardImpl { @@ -58,8 +58,8 @@ public class LavaTubes extends CardImpl { this.expansionSetCode = "ICE"; // Lava Tubes doesn't untap during your untap step if it has a depletion counter on it. - Effect effect = new ConditionalContinuousRuleModifyingEffect(new DontUntapInControllersUntapStepSourceEffect(), - new SourceHasCounterCondition(CounterType.DEPLETION, 0)); + Effect effect = new ConditionalContinuousRuleModifyingEffect(new DontUntapInControllersUntapStepSourceEffect(false, true), + new SourceHasCounterCondition(CounterType.DEPLETION, 1, Integer.MAX_VALUE)); effect.setText("{this} doesn't untap during your untap step if it has a depletion counter on it"); Ability ability = new SimpleStaticAbility(Zone.BATTLEFIELD, effect); this.addAbility(ability); diff --git a/Mage.Sets/src/mage/sets/iceage/RiverDelta.java b/Mage.Sets/src/mage/sets/iceage/RiverDelta.java index b5f91fff064..008c5d3f159 100644 --- a/Mage.Sets/src/mage/sets/iceage/RiverDelta.java +++ b/Mage.Sets/src/mage/sets/iceage/RiverDelta.java @@ -34,7 +34,6 @@ import mage.abilities.common.BeginningOfUpkeepTriggeredAbility; import mage.abilities.common.SimpleStaticAbility; import mage.abilities.condition.common.SourceHasCounterCondition; import mage.abilities.costs.common.TapSourceCost; -import mage.abilities.decorator.ConditionalContinuousEffect; import mage.abilities.decorator.ConditionalContinuousRuleModifyingEffect; import mage.abilities.effects.Effect; import mage.abilities.effects.common.DontUntapInControllersUntapStepSourceEffect; @@ -50,7 +49,7 @@ import mage.counters.CounterType; /** * - * @author anonymous + * @author Luna Skyrise */ public class RiverDelta extends CardImpl { @@ -59,8 +58,8 @@ public class RiverDelta extends CardImpl { this.expansionSetCode = "ICE"; // River Delta doesn't untap during your untap step if it has a depletion counter on it. - Effect effect = new ConditionalContinuousRuleModifyingEffect(new DontUntapInControllersUntapStepSourceEffect(), - new SourceHasCounterCondition(CounterType.DEPLETION, 0)); + Effect effect = new ConditionalContinuousRuleModifyingEffect(new DontUntapInControllersUntapStepSourceEffect(false, true), + new SourceHasCounterCondition(CounterType.DEPLETION, 1, Integer.MAX_VALUE)); effect.setText("{this} doesn't untap during your untap step if it has a depletion counter on it"); Ability ability = new SimpleStaticAbility(Zone.BATTLEFIELD, effect); this.addAbility(ability); diff --git a/Mage.Sets/src/mage/sets/iceage/TimberlineRidge.java b/Mage.Sets/src/mage/sets/iceage/TimberlineRidge.java index 56a826a8e0a..e10a0009454 100644 --- a/Mage.Sets/src/mage/sets/iceage/TimberlineRidge.java +++ b/Mage.Sets/src/mage/sets/iceage/TimberlineRidge.java @@ -49,7 +49,7 @@ import mage.counters.CounterType; /** * - * @author anonymous + * @author Luna Skyrise */ public class TimberlineRidge extends CardImpl { @@ -58,8 +58,8 @@ public class TimberlineRidge extends CardImpl { this.expansionSetCode = "ICE"; // Timberline Ridge doesn't untap during your untap step if it has a depletion counter on it. - Effect effect = new ConditionalContinuousRuleModifyingEffect(new DontUntapInControllersUntapStepSourceEffect(), - new SourceHasCounterCondition(CounterType.DEPLETION, 0)); + Effect effect = new ConditionalContinuousRuleModifyingEffect(new DontUntapInControllersUntapStepSourceEffect(false, true), + new SourceHasCounterCondition(CounterType.DEPLETION, 1, Integer.MAX_VALUE)); effect.setText("{this} doesn't untap during your untap step if it has a depletion counter on it"); Ability ability = new SimpleStaticAbility(Zone.BATTLEFIELD, effect); this.addAbility(ability); diff --git a/Mage.Sets/src/mage/sets/iceage/Veldt.java b/Mage.Sets/src/mage/sets/iceage/Veldt.java index 437370080e8..29f1e423aa3 100644 --- a/Mage.Sets/src/mage/sets/iceage/Veldt.java +++ b/Mage.Sets/src/mage/sets/iceage/Veldt.java @@ -49,7 +49,7 @@ import mage.counters.CounterType; /** * - * @author anonymous + * @author Luna Skyrise */ public class Veldt extends CardImpl { @@ -58,8 +58,8 @@ public class Veldt extends CardImpl { this.expansionSetCode = "ICE"; // Veldt doesn't untap during your untap step if it has a depletion counter on it. - Effect effect = new ConditionalContinuousRuleModifyingEffect(new DontUntapInControllersUntapStepSourceEffect(), - new SourceHasCounterCondition(CounterType.DEPLETION, 0)); + Effect effect = new ConditionalContinuousRuleModifyingEffect(new DontUntapInControllersUntapStepSourceEffect(false, true), + new SourceHasCounterCondition(CounterType.DEPLETION, 1, Integer.MAX_VALUE)); effect.setText("{this} doesn't untap during your untap step if it has a depletion counter on it"); Ability ability = new SimpleStaticAbility(Zone.BATTLEFIELD, effect); this.addAbility(ability); diff --git a/Mage/src/mage/abilities/decorator/ConditionalContinuousRuleModifyingEffect.java b/Mage/src/mage/abilities/decorator/ConditionalContinuousRuleModifyingEffect.java index 8028e727066..c289550a5ff 100644 --- a/Mage/src/mage/abilities/decorator/ConditionalContinuousRuleModifyingEffect.java +++ b/Mage/src/mage/abilities/decorator/ConditionalContinuousRuleModifyingEffect.java @@ -41,7 +41,7 @@ import mage.game.events.GameEvent; * * @author LevelX2 */ -public class ConditionalContinuousRuleModifyingEffect extends ContinuousRuleModifyingEffectImpl { +public class ConditionalContinuousRuleModifyingEffect extends ContinuousRuleModifyingEffectImpl { protected ContinuousRuleModifyingEffect effect; protected ContinuousRuleModifyingEffect otherwiseEffect; @@ -88,7 +88,6 @@ public class ConditionalContinuousRuleModifyingEffect extends ContinuousRuleModi initDone = true; } - @Override public boolean isDiscarded() { return effect.isDiscarded() || (otherwiseEffect != null && otherwiseEffect.isDiscarded()); @@ -136,4 +135,20 @@ public class ConditionalContinuousRuleModifyingEffect extends ContinuousRuleModi public ConditionalContinuousRuleModifyingEffect copy() { return new ConditionalContinuousRuleModifyingEffect(this); } + + @Override + public boolean sendMessageToGameLog() { + return effect.sendMessageToGameLog(); //To change body of generated methods, choose Tools | Templates. + } + + @Override + public boolean sendMessageToUser() { + return effect.sendMessageToUser(); //To change body of generated methods, choose Tools | Templates. + } + + @Override + public String getInfoMessage(Ability source, GameEvent event, Game game) { + return effect.getInfoMessage(source, event, game); //To change body of generated methods, choose Tools | Templates. + } + } diff --git a/Mage/src/mage/abilities/effects/ContinuousRuleModifyingEffectImpl.java b/Mage/src/mage/abilities/effects/ContinuousRuleModifyingEffectImpl.java index 5dcf58d5e90..541873718fc 100644 --- a/Mage/src/mage/abilities/effects/ContinuousRuleModifyingEffectImpl.java +++ b/Mage/src/mage/abilities/effects/ContinuousRuleModifyingEffectImpl.java @@ -1,31 +1,30 @@ /* -* Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. -* -* Redistribution and use in source and binary forms, with or without modification, are -* permitted provided that the following conditions are met: -* -* 1. Redistributions of source code must retain the above copyright notice, this list of -* conditions and the following disclaimer. -* -* 2. Redistributions in binary form must reproduce the above copyright notice, this list -* of conditions and the following disclaimer in the documentation and/or other materials -* provided with the distribution. -* -* THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED -* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND -* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR -* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR -* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON -* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING -* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF -* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -* -* The views and conclusions contained in the software and documentation are those of the -* authors and should not be interpreted as representing official policies, either expressed -* or implied, of BetaSteward_at_googlemail.com. -*/ - + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ package mage.abilities.effects; import mage.MageObject; @@ -45,20 +44,18 @@ public abstract class ContinuousRuleModifyingEffectImpl extends ContinuousEffect protected final boolean messageToUser; protected final boolean messageToGameLog; protected final String infoMessage; - + // 613.10 - // Some continuous effects affect game rules rather than objects. For example, effects may modify + // Some continuous effects affect game rules rather than objects. For example, effects may modify // a player’s maximum hand size, or say that a creature must attack this turn if able. These effects // are applied after all other continuous effects have been applied. Continuous effects that affect - // the costs of spells or abilities are applied according to the order specified in rule 601.2e. - // All other such effects are applied in timestamp order. See also the rules for timestamp order + // the costs of spells or abilities are applied according to the order specified in rule 601.2e. + // All other such effects are applied in timestamp order. See also the rules for timestamp order // and dependency (rules 613.6 and 613.7). - // Some of this rule modifying effects are implemented as normal CONTINUOUS effects using the Layer.RulesEffects. // But if the rule change can be implemented simply by preventing an event from happening, CONTINUOUS_RULE_MODIFICATION effects can be used. - // They work technical like a replacement effect that replaces the event completely. + // They work technical like a replacement effect that replaces the event completely. // But player isn't asked to choose order of effects if multiple are applied to the same event. - public ContinuousRuleModifyingEffectImpl(Duration duration, Outcome outcome) { this(duration, outcome, true, false); } @@ -67,11 +64,13 @@ public abstract class ContinuousRuleModifyingEffectImpl extends ContinuousEffect * * @param duration * @param outcome - * @param messageToUser - Every time the effect replaces an event, the user gets a message in a dialog window. - * Don't set it to true if the event happens regularly or very often. The message itself can be - * changed by overriding the getInfoMessage method. - * @param messageToLog - Every time the effect replaces an event, a message is posted to the game log. The message - * can be changed by overriding the getInfoMessage method. + * @param messageToUser - Every time the effect replaces an event, the user + * gets a message in a dialog window. Don't set it to true if the event + * happens regularly or very often. The message itself can be changed by + * overriding the getInfoMessage method. + * @param messageToLog - Every time the effect replaces an event, a message + * is posted to the game log. The message can be changed by overriding the + * getInfoMessage method. */ public ContinuousRuleModifyingEffectImpl(Duration duration, Outcome outcome, boolean messageToUser, boolean messageToLog) { super(duration, outcome); @@ -89,9 +88,11 @@ public abstract class ContinuousRuleModifyingEffectImpl extends ContinuousEffect } /** - * An early check for the event types this effect applies to. This check was added - * to speed up event handling. Once all existing ContinuousRuleModifiyingEffects have - * implemented this method, the method should be changed to abstract here or removed. + * An early check for the event types this effect applies to. This check was + * added to speed up event handling. Once all existing + * ContinuousRuleModifiyingEffects have implemented this method, the method + * should be changed to abstract here or removed. + * * @param event * @param game * @return @@ -112,10 +113,10 @@ public abstract class ContinuousRuleModifyingEffectImpl extends ContinuousEffect String message; MageObject object = game.getObject(source.getSourceId()); if (object != null) { - message = source.getRule(object.getLogName()); + message = source.getRule(messageToUser ? object.getIdName() : object.getLogName()); } else { message = source.getRule(); - } + } return message; } else { return infoMessage; @@ -132,5 +133,4 @@ public abstract class ContinuousRuleModifyingEffectImpl extends ContinuousEffect return messageToGameLog; } - } diff --git a/Mage/src/mage/abilities/effects/common/DontUntapInControllersUntapStepSourceEffect.java b/Mage/src/mage/abilities/effects/common/DontUntapInControllersUntapStepSourceEffect.java index 576628205dc..fd5d40ed8ae 100644 --- a/Mage/src/mage/abilities/effects/common/DontUntapInControllersUntapStepSourceEffect.java +++ b/Mage/src/mage/abilities/effects/common/DontUntapInControllersUntapStepSourceEffect.java @@ -27,11 +27,11 @@ */ package mage.abilities.effects.common; +import mage.abilities.Ability; +import mage.abilities.effects.ContinuousRuleModifyingEffectImpl; import mage.constants.Duration; import mage.constants.Outcome; import mage.constants.PhaseStep; -import mage.abilities.Ability; -import mage.abilities.effects.ContinuousRuleModifyingEffectImpl; import mage.game.Game; import mage.game.events.GameEvent; import mage.game.events.GameEvent.EventType; @@ -44,7 +44,11 @@ import mage.game.permanent.Permanent; public class DontUntapInControllersUntapStepSourceEffect extends ContinuousRuleModifyingEffectImpl { public DontUntapInControllersUntapStepSourceEffect() { - super(Duration.WhileOnBattlefield, Outcome.Detriment, false, true); + this(false, true); + } + + public DontUntapInControllersUntapStepSourceEffect(boolean messageToUser, boolean messageToLog) { + super(Duration.WhileOnBattlefield, Outcome.Detriment, messageToUser, messageToLog); staticText = "{this} doesn't untap during your untap step"; } @@ -78,4 +82,5 @@ public class DontUntapInControllersUntapStepSourceEffect extends ContinuousRuleM } return false; } + } From a54843fd260d7c143bd59cb36f663bfe5092e050 Mon Sep 17 00:00:00 2001 From: LevelX2 Date: Sun, 11 Oct 2015 23:55:45 +0200 Subject: [PATCH 069/268] * Fixed that players during elemination tournaments could get multiple byes in a row. --- .../mage/game/tournament/TournamentImpl.java | 45 ++++++++++++++++--- .../mage/game/tournament/TournamentSwiss.java | 17 +++---- 2 files changed, 48 insertions(+), 14 deletions(-) diff --git a/Mage/src/mage/game/tournament/TournamentImpl.java b/Mage/src/mage/game/tournament/TournamentImpl.java index e326882b29d..a578a681107 100644 --- a/Mage/src/mage/game/tournament/TournamentImpl.java +++ b/Mage/src/mage/game/tournament/TournamentImpl.java @@ -32,6 +32,7 @@ import java.util.Collection; import java.util.Date; import java.util.HashMap; import java.util.HashSet; +import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Random; @@ -187,15 +188,16 @@ public abstract class TournamentImpl implements Tournament { Round round = new Round(rounds.size() + 1, this); rounds.add(round); List roundPlayers = getActivePlayers(); + + // search the player with a bye last round + List playerWithByes = getTournamentPlayersWithBye(roundPlayers); + while (roundPlayers.size() > 1) { - int i = rnd.nextInt(roundPlayers.size()); - TournamentPlayer player1 = roundPlayers.get(i); - roundPlayers.remove(i); - i = rnd.nextInt(roundPlayers.size()); - TournamentPlayer player2 = roundPlayers.get(i); - roundPlayers.remove(i); + TournamentPlayer player1 = getNextAvailablePlayer(roundPlayers, playerWithByes); + TournamentPlayer player2 = getNextAvailablePlayer(roundPlayers, playerWithByes); round.addPairing(new TournamentPairing(player1, player2)); } + if (roundPlayers.size() > 0) { // player free round - add to bye players of this round TournamentPlayer player1 = roundPlayers.get(0); @@ -207,6 +209,37 @@ public abstract class TournamentImpl implements Tournament { return round; } + private TournamentPlayer getNextAvailablePlayer(List roundPlayers, List playerWithByes) { + TournamentPlayer nextPlayer; + if (playerWithByes.isEmpty()) { + int i = rnd.nextInt(roundPlayers.size()); + nextPlayer = roundPlayers.get(i); + roundPlayers.remove(i); + } else { // prefer players with byes to pair + Iterator iterator = playerWithByes.iterator(); + nextPlayer = iterator.next(); + iterator.remove(); + roundPlayers.remove(nextPlayer); + } + return nextPlayer; + } + + private List getTournamentPlayersWithBye(List roundPlayers) { + List playersWithBye = new ArrayList<>(); + if (rounds.size() > 1) { + for (int i = rounds.size() - 2; i >= 0; i--) { + Round oldRound = rounds.get(i); + if (oldRound != null && !oldRound.getPlayerByes().isEmpty()) { + TournamentPlayer tournamentPlayerWithBye = oldRound.getPlayerByes().iterator().next(); + if (roundPlayers.contains(tournamentPlayerWithBye)) { + playersWithBye.add(tournamentPlayerWithBye); + } + } + } + } + return playersWithBye; + } + protected void playRound(Round round) { for (TournamentPairing pair : round.getPairs()) { playMatch(pair); diff --git a/Mage/src/mage/game/tournament/TournamentSwiss.java b/Mage/src/mage/game/tournament/TournamentSwiss.java index 9f6c970bd4a..6855e57eb01 100644 --- a/Mage/src/mage/game/tournament/TournamentSwiss.java +++ b/Mage/src/mage/game/tournament/TournamentSwiss.java @@ -46,8 +46,8 @@ public abstract class TournamentSwiss extends TournamentImpl { } @Override - protected void runTournament() { - for (Map.Entry entry: players.entrySet()) { + protected void runTournament() { + for (Map.Entry entry : players.entrySet()) { if (entry.getValue().getPlayer().autoLoseGame()) { entry.getValue().setEliminated(); entry.getValue().setResults("Auto Eliminated"); @@ -57,7 +57,7 @@ public abstract class TournamentSwiss extends TournamentImpl { while (this.getActivePlayers().size() > 1 && this.getNumberRounds() > this.getRounds().size()) { // check if some player got killed / disconnected meanwhile and update their state tableEventSource.fireTableEvent(TableEvent.EventType.CHECK_STATE_PLAYERS); - // Swiss pairing + // Swiss pairing Round round = createRoundSwiss(); playRound(round); } @@ -70,8 +70,9 @@ public abstract class TournamentSwiss extends TournamentImpl { List roundPlayers = getActivePlayers(); // sort players by tournament points Collections.sort(roundPlayers, new Comparator() { - @Override public int compare(TournamentPlayer p1, TournamentPlayer p2) { - return p2.getPoints() - p1.getPoints(); + @Override + public int compare(TournamentPlayer p1, TournamentPlayer p2) { + return p2.getPoints() - p1.getPoints(); } }); @@ -80,9 +81,9 @@ public abstract class TournamentSwiss extends TournamentImpl { TournamentPlayer player1 = roundPlayers.get(0); roundPlayers.remove(0); TournamentPlayer playerForPossibleSecondPairing = null; - for (TournamentPlayer player2: roundPlayers) { + for (TournamentPlayer player2 : roundPlayers) { if (alreadyPaired(player1, player2)) { - // if laready paired but equal ponts -> remember if second pairing is needed + // if already paired but equal points -> remember if second pairing is needed if (playerForPossibleSecondPairing == null) { playerForPossibleSecondPairing = player2; } @@ -126,7 +127,7 @@ public abstract class TournamentSwiss extends TournamentImpl { protected boolean alreadyPaired(TournamentPlayer player1, TournamentPlayer player2) { for (Round round : rounds) { - for (TournamentPairing pairing: round.getPairs()) { + for (TournamentPairing pairing : round.getPairs()) { if (pairing.getPlayer1().equals(player1) || pairing.getPlayer2().equals(player1)) { if (pairing.getPlayer1().equals(player2) || pairing.getPlayer2().equals(player2)) { return true; From 8dd9fbea40ecf327826a494f0b8f411012155b5d Mon Sep 17 00:00:00 2001 From: LevelX2 Date: Sun, 11 Oct 2015 23:56:29 +0200 Subject: [PATCH 070/268] Conspire - The player is now asked to use conspire only if he is able to pay the tap costs. --- .../mage/sets/eventide/MerrowBonegnawer.java | 12 +++++------ .../test/cards/triggers/OblivionRingTest.java | 4 ++-- .../abilities/costs/common/TapTargetCost.java | 2 +- .../common/ExileFromZoneTargetEffect.java | 21 ++++++++----------- .../abilities/keyword/ConspireAbility.java | 5 +++-- 5 files changed, 21 insertions(+), 23 deletions(-) diff --git a/Mage.Sets/src/mage/sets/eventide/MerrowBonegnawer.java b/Mage.Sets/src/mage/sets/eventide/MerrowBonegnawer.java index f8be8da2f87..2273adfe092 100644 --- a/Mage.Sets/src/mage/sets/eventide/MerrowBonegnawer.java +++ b/Mage.Sets/src/mage/sets/eventide/MerrowBonegnawer.java @@ -50,11 +50,11 @@ import mage.target.TargetPlayer; * @author jeffwadsworth */ public class MerrowBonegnawer extends CardImpl { - + private UUID exileId = UUID.randomUUID(); - + private static final FilterSpell filter = new FilterSpell("black spell"); - + static { filter.add(new ColorPredicate(ObjectColor.BLACK)); } @@ -69,13 +69,13 @@ public class MerrowBonegnawer extends CardImpl { this.toughness = new MageInt(1); // {tap}: Target player exiles a card from his or her graveyard. - Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new ExileFromZoneTargetEffect(Zone.GRAVEYARD, exileId, "Merrow Bonegnawer", new FilterCard("a card")), new TapSourceCost()); + Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new ExileFromZoneTargetEffect(Zone.GRAVEYARD, exileId, getIdName(), new FilterCard()), new TapSourceCost()); ability.addTarget(new TargetPlayer()); this.addAbility(ability); - + // Whenever you cast a black spell, you may untap Merrow Bonegnawer. this.addAbility(new SpellCastControllerTriggeredAbility(Zone.BATTLEFIELD, new UntapSourceEffect(), filter, true, false)); - + } public MerrowBonegnawer(final MerrowBonegnawer card) { diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/triggers/OblivionRingTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/triggers/OblivionRingTest.java index 1324dee0596..ef5dc6ae622 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/triggers/OblivionRingTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/triggers/OblivionRingTest.java @@ -92,10 +92,10 @@ public class OblivionRingTest extends CardTestPlayerBase { addCard(Zone.BATTLEFIELD, playerA, "Jace Beleren"); addCard(Zone.HAND, playerA, "Revoke Existence"); - activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "-1: Target player draws one card", playerA); + activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "-1: Target player draws a card", playerA); castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Oblivion Ring"); castSpell(1, PhaseStep.POSTCOMBAT_MAIN, playerA, "Revoke Existence", "Oblivion Ring"); - activateAbility(1, PhaseStep.POSTCOMBAT_MAIN, playerA, "-1: Target player draws one card", playerA); + activateAbility(1, PhaseStep.POSTCOMBAT_MAIN, playerA, "-1: Target player draws a card", playerA); setStopAt(1, PhaseStep.END_TURN); execute(); diff --git a/Mage/src/mage/abilities/costs/common/TapTargetCost.java b/Mage/src/mage/abilities/costs/common/TapTargetCost.java index 749eea7aff5..8f448eaa093 100644 --- a/Mage/src/mage/abilities/costs/common/TapTargetCost.java +++ b/Mage/src/mage/abilities/costs/common/TapTargetCost.java @@ -76,7 +76,7 @@ public class TapTargetCost extends CostImpl { @Override public boolean canPay(Ability ability, UUID sourceId, UUID controllerId, Game game) { - return target.canChoose(controllerId, game); + return target.canChoose(sourceId, controllerId, game); } @Override diff --git a/Mage/src/mage/abilities/effects/common/ExileFromZoneTargetEffect.java b/Mage/src/mage/abilities/effects/common/ExileFromZoneTargetEffect.java index 48be98f6899..028237b01cf 100644 --- a/Mage/src/mage/abilities/effects/common/ExileFromZoneTargetEffect.java +++ b/Mage/src/mage/abilities/effects/common/ExileFromZoneTargetEffect.java @@ -1,16 +1,16 @@ /* * Copyright 2011 BetaSteward_at_googlemail.com. All rights reserved. - * + * * Redistribution and use in source and binary forms, with or without modification, are * permitted provided that the following conditions are met: - * + * * 1. Redistributions of source code must retain the above copyright notice, this list of * conditions and the following disclaimer. - * + * * 2. Redistributions in binary form must reproduce the above copyright notice, this list * of conditions and the following disclaimer in the documentation and/or other materials * provided with the distribution. - * + * * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR @@ -20,7 +20,7 @@ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * + * * The views and conclusions contained in the software and documentation are those of the * authors and should not be interpreted as representing official policies, either expressed * or implied, of BetaSteward_at_googlemail.com. @@ -28,17 +28,18 @@ package mage.abilities.effects.common; import java.util.UUID; -import mage.constants.Outcome; -import mage.constants.Zone; import mage.abilities.Ability; import mage.abilities.effects.OneShotEffect; import mage.cards.Card; +import mage.constants.Outcome; +import mage.constants.Zone; import mage.filter.FilterCard; import mage.game.Game; import mage.players.Player; import mage.target.Target; import mage.target.common.TargetCardInHand; import mage.target.common.TargetCardInYourGraveyard; +import mage.util.CardUtil; /** * @@ -110,10 +111,6 @@ public class ExileFromZoneTargetEffect extends OneShotEffect { } private void setText() { - if (amount == 1) { - staticText = "Target player exiles a " + filter.getMessage() + " from his or her " + zone.toString().toLowerCase(); - } else { - staticText = "Target player exiles " + amount + " " + filter.getMessage() + " from his or her " + zone.toString().toLowerCase(); - } + staticText = "target player exiles " + CardUtil.numberToText(exileName, "a") + filter.getMessage() + " from his or her " + zone.toString().toLowerCase(); } } diff --git a/Mage/src/mage/abilities/keyword/ConspireAbility.java b/Mage/src/mage/abilities/keyword/ConspireAbility.java index 674505173bb..cef23120fe0 100644 --- a/Mage/src/mage/abilities/keyword/ConspireAbility.java +++ b/Mage/src/mage/abilities/keyword/ConspireAbility.java @@ -158,10 +158,11 @@ public class ConspireAbility extends StaticAbility implements OptionalAdditional @Override public void addOptionalAdditionalCosts(Ability ability, Game game) { if (ability instanceof SpellAbility) { - Player player = game.getPlayer(controllerId); + Player player = game.getPlayer(getControllerId()); if (player != null) { resetConspire(ability, game); - if (player.chooseUse(Outcome.Benefit, "Pay " + conspireCost.getText(false) + " ?", ability, game)) { + if (conspireCost.canPay(ability, getSourceId(), getControllerId(), game) + && player.chooseUse(Outcome.Benefit, "Pay " + conspireCost.getText(false) + " ?", ability, game)) { activateConspire(ability, game); for (Iterator it = ((Costs) conspireCost).iterator(); it.hasNext();) { Cost cost = (Cost) it.next(); From dc7dfafe548f321f38f84c1ae18cad97a833d721 Mon Sep 17 00:00:00 2001 From: AlumiuN <> Date: Mon, 12 Oct 2015 14:16:37 +1300 Subject: [PATCH 071/268] Added Infiltrate, Teferi's Response, Surestrike Trident, Chaoslace, Deathlace, Lifelace, Purelace, Thoughlace and Moonlace. --- .../src/mage/sets/coldsnap/BraidOfFire.java | 97 +++++++++ .../sets/darksteel/SurestrikeTrident.java | 139 ++++++++++++ .../mage/sets/fourthedition/Chaoslace.java | 63 ++++++ .../mage/sets/fourthedition/Deathlace.java | 52 +++++ .../src/mage/sets/fourthedition/Lifelace.java | 52 +++++ .../src/mage/sets/fourthedition/Purelace.java | 52 +++++ .../mage/sets/fourthedition/Thoughtlace.java | 52 +++++ .../mage/sets/invasion/TeferisResponse.java | 198 ++++++++++++++++++ .../src/mage/sets/limitedalpha/Chaoslace.java | 52 +++++ .../src/mage/sets/limitedalpha/Deathlace.java | 52 +++++ .../src/mage/sets/limitedalpha/Lifelace.java | 62 ++++++ .../src/mage/sets/limitedalpha/Purelace.java | 52 +++++ .../mage/sets/limitedalpha/Thoughtlace.java | 52 +++++ .../src/mage/sets/limitedbeta/Chaoslace.java | 52 +++++ .../src/mage/sets/limitedbeta/Deathlace.java | 62 ++++++ .../src/mage/sets/limitedbeta/Lifelace.java | 52 +++++ .../src/mage/sets/limitedbeta/Purelace.java | 52 +++++ .../mage/sets/limitedbeta/Thoughtlace.java | 62 ++++++ .../src/mage/sets/nemesis/Infiltrate.java | 60 ++++++ .../mage/sets/revisededition/Chaoslace.java | 52 +++++ .../mage/sets/revisededition/Deathlace.java | 52 +++++ .../mage/sets/revisededition/Lifelace.java | 52 +++++ .../mage/sets/revisededition/Purelace.java | 52 +++++ .../mage/sets/revisededition/Thoughtlace.java | 52 +++++ .../src/mage/sets/timespiral/Moonlace.java | 62 ++++++ .../mage/sets/unlimitededition/Chaoslace.java | 52 +++++ .../mage/sets/unlimitededition/Deathlace.java | 52 +++++ .../mage/sets/unlimitededition/Lifelace.java | 52 +++++ .../mage/sets/unlimitededition/Purelace.java | 62 ++++++ .../sets/unlimitededition/Thoughtlace.java | 52 +++++ 30 files changed, 1907 insertions(+) create mode 100644 Mage.Sets/src/mage/sets/coldsnap/BraidOfFire.java create mode 100644 Mage.Sets/src/mage/sets/darksteel/SurestrikeTrident.java create mode 100644 Mage.Sets/src/mage/sets/fourthedition/Chaoslace.java create mode 100644 Mage.Sets/src/mage/sets/fourthedition/Deathlace.java create mode 100644 Mage.Sets/src/mage/sets/fourthedition/Lifelace.java create mode 100644 Mage.Sets/src/mage/sets/fourthedition/Purelace.java create mode 100644 Mage.Sets/src/mage/sets/fourthedition/Thoughtlace.java create mode 100644 Mage.Sets/src/mage/sets/invasion/TeferisResponse.java create mode 100644 Mage.Sets/src/mage/sets/limitedalpha/Chaoslace.java create mode 100644 Mage.Sets/src/mage/sets/limitedalpha/Deathlace.java create mode 100644 Mage.Sets/src/mage/sets/limitedalpha/Lifelace.java create mode 100644 Mage.Sets/src/mage/sets/limitedalpha/Purelace.java create mode 100644 Mage.Sets/src/mage/sets/limitedalpha/Thoughtlace.java create mode 100644 Mage.Sets/src/mage/sets/limitedbeta/Chaoslace.java create mode 100644 Mage.Sets/src/mage/sets/limitedbeta/Deathlace.java create mode 100644 Mage.Sets/src/mage/sets/limitedbeta/Lifelace.java create mode 100644 Mage.Sets/src/mage/sets/limitedbeta/Purelace.java create mode 100644 Mage.Sets/src/mage/sets/limitedbeta/Thoughtlace.java create mode 100644 Mage.Sets/src/mage/sets/nemesis/Infiltrate.java create mode 100644 Mage.Sets/src/mage/sets/revisededition/Chaoslace.java create mode 100644 Mage.Sets/src/mage/sets/revisededition/Deathlace.java create mode 100644 Mage.Sets/src/mage/sets/revisededition/Lifelace.java create mode 100644 Mage.Sets/src/mage/sets/revisededition/Purelace.java create mode 100644 Mage.Sets/src/mage/sets/revisededition/Thoughtlace.java create mode 100644 Mage.Sets/src/mage/sets/timespiral/Moonlace.java create mode 100644 Mage.Sets/src/mage/sets/unlimitededition/Chaoslace.java create mode 100644 Mage.Sets/src/mage/sets/unlimitededition/Deathlace.java create mode 100644 Mage.Sets/src/mage/sets/unlimitededition/Lifelace.java create mode 100644 Mage.Sets/src/mage/sets/unlimitededition/Purelace.java create mode 100644 Mage.Sets/src/mage/sets/unlimitededition/Thoughtlace.java diff --git a/Mage.Sets/src/mage/sets/coldsnap/BraidOfFire.java b/Mage.Sets/src/mage/sets/coldsnap/BraidOfFire.java new file mode 100644 index 00000000000..7cb6a494524 --- /dev/null +++ b/Mage.Sets/src/mage/sets/coldsnap/BraidOfFire.java @@ -0,0 +1,97 @@ +/* + * 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.Mana; +import mage.abilities.Ability; +import mage.abilities.costs.CostImpl; +import mage.abilities.keyword.CumulativeUpkeepAbility; +import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.Rarity; +import mage.game.Game; +import mage.players.Player; + +/** + * + * @author AlumiuN + */ +public class BraidOfFire extends CardImpl { + + public BraidOfFire(UUID ownerId) { + super(ownerId, 78, "Braid of Fire", Rarity.RARE, new CardType[]{CardType.ENCHANTMENT}, "{1}{R}"); + this.expansionSetCode = "CSP"; + + // Cumulative upkeep-Add {R} to your mana pool. + this.addAbility(new CumulativeUpkeepAbility(new BraidOfFireCost())); + } + + public BraidOfFire(final BraidOfFire card) { + super(card); + } + + @Override + public BraidOfFire copy() { + return new BraidOfFire(this); + } +} + +class BraidOfFireCost extends CostImpl { + + public BraidOfFireCost() { + this.text = "Add {R} to your mana pool"; + } + + public BraidOfFireCost(BraidOfFireCost cost) { + super(cost); + } + + @Override + public boolean pay(Ability ability, Game game, UUID sourceId, UUID controllerId, boolean noMana) { + Player player = game.getPlayer(controllerId); + player.getManaPool().addMana(Mana.RedMana, game, ability); + paid = true; + return true; + } + + @Override + public boolean canPay(Ability ability, UUID sourceId, UUID controllerId, Game game) { + Player player = game.getPlayer(controllerId); + if (player != null) { + return true; + } + return false; + } + + @Override + public BraidOfFireCost copy() { + return new BraidOfFireCost(this); + } + +} \ No newline at end of file diff --git a/Mage.Sets/src/mage/sets/darksteel/SurestrikeTrident.java b/Mage.Sets/src/mage/sets/darksteel/SurestrikeTrident.java new file mode 100644 index 00000000000..761ed72d842 --- /dev/null +++ b/Mage.Sets/src/mage/sets/darksteel/SurestrikeTrident.java @@ -0,0 +1,139 @@ +/* + * 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.darksteel; + +import java.util.UUID; +import mage.abilities.Ability; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.costs.CostImpl; +import mage.abilities.costs.common.TapSourceCost; +import mage.abilities.costs.mana.GenericManaCost; +import mage.abilities.dynamicvalue.DynamicValue; +import mage.abilities.dynamicvalue.common.SourcePermanentPowerCount; +import mage.abilities.effects.common.continuous.GainAbilityAttachedEffect; +import mage.abilities.keyword.EquipAbility; +import mage.abilities.keyword.FirstStrikeAbility; +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.Zone; +import mage.abilities.effects.Effect; +import mage.abilities.effects.common.DamageTargetEffect; +import mage.game.Game; +import mage.game.permanent.Permanent; +import mage.target.TargetPlayer; + +/** + * + * @author AlumiuN + */ +public class SurestrikeTrident extends CardImpl { + + public SurestrikeTrident(UUID ownerId) { + super(ownerId, 147, "Surestrike Trident", Rarity.UNCOMMON, new CardType[]{CardType.ARTIFACT}, "{2}"); + this.expansionSetCode = "DST"; + this.subtype.add("Equipment"); + + // Equipped creature has first strike and "{tap}, Unattach Surestrike Trident: This creature deals damage equal to its power to target player." + this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new GainAbilityAttachedEffect(FirstStrikeAbility.getInstance(), AttachmentType.EQUIPMENT))); + + DynamicValue xValue = new SourcePermanentPowerCount(); + Effect effect = new DamageTargetEffect(xValue); + effect.setText("This creature deals damage equal to its power to target player"); + Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, effect, new TapSourceCost()); + ability.addTarget(new TargetPlayer()); + ability.addCost(new SurestrikeTridentUnattachCost()); + this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new GainAbilityAttachedEffect(ability, AttachmentType.EQUIPMENT, Duration.WhileOnBattlefield))); + + // Equip {4} + this.addAbility(new EquipAbility(Outcome.Benefit, new GenericManaCost(4))); + } + + public SurestrikeTrident(final SurestrikeTrident card) { + super(card); + } + + @Override + public SurestrikeTrident copy() { + return new SurestrikeTrident(this); + } +} + +class SurestrikeTridentUnattachCost extends CostImpl { + + public SurestrikeTridentUnattachCost() { + this.text = "Unattach Surestrike Trident"; + } + + public SurestrikeTridentUnattachCost(final SurestrikeTridentUnattachCost cost) { + super(cost); + } + + @Override + public boolean pay(Ability ability, Game game, UUID sourceId, UUID controllerId, boolean noMana) { + Permanent permanent = game.getPermanent(sourceId); + if (permanent != null) { + for (UUID attachmentId :permanent.getAttachments()) { + Permanent attachment = game.getPermanent(attachmentId); + if (attachment != null && attachment.getName().equals("Surestrike Trident")) { + paid = permanent.removeAttachment(attachmentId, game); + if (paid) { + break; + } + } + } + + } + return paid; + } + + @Override + public boolean canPay(Ability ability, UUID sourceId, UUID controllerId, Game game) { + Permanent permanent = game.getPermanent(sourceId); + if (permanent != null) { + for (UUID attachmentId :permanent.getAttachments()) { + Permanent attachment = game.getPermanent(attachmentId); + if (attachment != null && attachment.getName().equals("Surestrike Trident") ) { + return true; + } + } + + } + return false; + } + + @Override + public SurestrikeTridentUnattachCost copy() { + return new SurestrikeTridentUnattachCost(this); + } + +} \ No newline at end of file diff --git a/Mage.Sets/src/mage/sets/fourthedition/Chaoslace.java b/Mage.Sets/src/mage/sets/fourthedition/Chaoslace.java new file mode 100644 index 00000000000..74d149d3ed6 --- /dev/null +++ b/Mage.Sets/src/mage/sets/fourthedition/Chaoslace.java @@ -0,0 +1,63 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.sets.fourthedition; + +import java.util.UUID; +import mage.abilities.effects.common.continuous.BecomesColorTargetEffect; +import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.Rarity; +import mage.ObjectColor; +import mage.target.common.TargetSpellOrPermanent; + + +/** + * + * @author AlumiuN + */ +public class Chaoslace extends CardImpl { + + public Chaoslace(UUID ownerId) { + super(ownerId, 200, "Chaoslace", Rarity.RARE, new CardType[]{CardType.INSTANT}, "{R}"); + this.expansionSetCode = "4ED"; + + // Target spell or permanent becomes red. + this.getSpellAbility().addTarget(new TargetSpellOrPermanent()); + this.getSpellAbility().addEffect(new BecomesColorTargetEffect(ObjectColor.RED, Duration.Custom)); + } + + public Chaoslace(final Chaoslace card) { + super(card); + } + + @Override + public Chaoslace copy() { + return new Chaoslace(this); + } +} \ No newline at end of file diff --git a/Mage.Sets/src/mage/sets/fourthedition/Deathlace.java b/Mage.Sets/src/mage/sets/fourthedition/Deathlace.java new file mode 100644 index 00000000000..a6d66e70d78 --- /dev/null +++ b/Mage.Sets/src/mage/sets/fourthedition/Deathlace.java @@ -0,0 +1,52 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.sets.fourthedition; + +import java.util.UUID; + +/** + * + * @author AlumiuN + */ +public class Deathlace extends mage.sets.limitedbeta.Deathlace { + + public Deathlace(UUID ownerId) { + super(ownerId); + this.cardNumber = 15; + this.expansionSetCode = "4ED"; + } + + public Deathlace(final Deathlace card) { + super(card); + } + + @Override + public Deathlace copy() { + return new Deathlace(this); + } +} diff --git a/Mage.Sets/src/mage/sets/fourthedition/Lifelace.java b/Mage.Sets/src/mage/sets/fourthedition/Lifelace.java new file mode 100644 index 00000000000..2b9c81b10ef --- /dev/null +++ b/Mage.Sets/src/mage/sets/fourthedition/Lifelace.java @@ -0,0 +1,52 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.sets.fourthedition; + +import java.util.UUID; + +/** + * + * @author AlumiuN + */ +public class Lifelace extends mage.sets.limitedalpha.Lifelace { + + public Lifelace(UUID ownerId) { + super(ownerId); + this.cardNumber = 142; + this.expansionSetCode = "4ED"; + } + + public Lifelace(final Lifelace card) { + super(card); + } + + @Override + public Lifelace copy() { + return new Lifelace(this); + } +} diff --git a/Mage.Sets/src/mage/sets/fourthedition/Purelace.java b/Mage.Sets/src/mage/sets/fourthedition/Purelace.java new file mode 100644 index 00000000000..a25d9f92c2c --- /dev/null +++ b/Mage.Sets/src/mage/sets/fourthedition/Purelace.java @@ -0,0 +1,52 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.sets.fourthedition; + +import java.util.UUID; + +/** + * + * @author AlumiuN + */ +public class Purelace extends mage.sets.unlimitededition.Purelace { + + public Purelace(UUID ownerId) { + super(ownerId); + this.cardNumber = 293; + this.expansionSetCode = "4ED"; + } + + public Purelace(final Purelace card) { + super(card); + } + + @Override + public Purelace copy() { + return new Purelace(this); + } +} diff --git a/Mage.Sets/src/mage/sets/fourthedition/Thoughtlace.java b/Mage.Sets/src/mage/sets/fourthedition/Thoughtlace.java new file mode 100644 index 00000000000..19f9d3bcc34 --- /dev/null +++ b/Mage.Sets/src/mage/sets/fourthedition/Thoughtlace.java @@ -0,0 +1,52 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.sets.fourthedition; + +import java.util.UUID; + +/** + * + * @author AlumiuN + */ +public class Thoughtlace extends mage.sets.limitedbeta.Thoughtlace { + + public Thoughtlace(UUID ownerId) { + super(ownerId); + this.cardNumber = 107; + this.expansionSetCode = "4ED"; + } + + public Thoughtlace(final Thoughtlace card) { + super(card); + } + + @Override + public Thoughtlace copy() { + return new Thoughtlace(this); + } +} diff --git a/Mage.Sets/src/mage/sets/invasion/TeferisResponse.java b/Mage.Sets/src/mage/sets/invasion/TeferisResponse.java new file mode 100644 index 00000000000..f61b1d22bd6 --- /dev/null +++ b/Mage.Sets/src/mage/sets/invasion/TeferisResponse.java @@ -0,0 +1,198 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.sets.invasion; + +import java.util.HashSet; +import java.util.Set; +import java.util.UUID; +import mage.abilities.Ability; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.DrawCardSourceControllerEffect; +import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.Outcome; +import mage.constants.Rarity; +import mage.constants.Zone; +import mage.filter.Filter; +import mage.game.Game; +import mage.game.permanent.Permanent; +import mage.game.stack.Spell; +import mage.game.stack.StackAbility; +import mage.game.stack.StackObject; +import mage.target.Target; +import mage.target.TargetObject; +import mage.target.Targets; + +/** + * + * @author AlumiuN + */ +public class TeferisResponse extends CardImpl { + + public TeferisResponse(UUID ownerId) { + super(ownerId, 78, "Teferi's Response", Rarity.RARE, new CardType[]{CardType.INSTANT}, "{1}{U}"); + this.expansionSetCode = "INV"; + + // Counter target spell or ability an opponent controls that targets a land you control. If a permanent's ability is countered this way, destroy that permanent. + this.getSpellAbility().addEffect(new TeferisResponseEffect()); + this.getSpellAbility().addTarget(new TargetStackObjectTargetingControlledLand()); + + // Draw two cards. + this.getSpellAbility().addEffect(new DrawCardSourceControllerEffect(2)); + } + + public TeferisResponse(final TeferisResponse card) { + super(card); + } + + @Override + public TeferisResponse copy() { + return new TeferisResponse(this); + } +} + +class TargetStackObjectTargetingControlledLand extends TargetObject { + + public TargetStackObjectTargetingControlledLand() { + this.minNumberOfTargets = 1; + this.maxNumberOfTargets = 1; + this.zone = Zone.STACK; + this.targetName = "spell or ability an opponent controls that targets a land you control"; + } + + public TargetStackObjectTargetingControlledLand(final TargetStackObjectTargetingControlledLand target) { + super(target); + } + + @Override + public Filter getFilter() { + throw new UnsupportedOperationException("Not supported."); //To change body of generated methods, choose Tools | Templates. + } + + @Override + public boolean canTarget(UUID id, Ability source, Game game) { + StackObject stackObject = game.getStack().getStackObject(id); + if ((stackObject instanceof Spell) || (stackObject instanceof StackAbility)) { + return true; + } + return false; + } + + @Override + public boolean canChoose(UUID sourceId, UUID sourceControllerId, Game game) { + return canChoose(sourceControllerId, game); + } + + @Override + public boolean canChoose(UUID sourceControllerId, Game game) { + for (StackObject stackObject : game.getStack()) { + if (((stackObject instanceof Spell) || (stackObject instanceof StackAbility)) && stackObject.getControllerId() != sourceControllerId) { + Targets objectTargets = stackObject.getStackAbility().getTargets(); + if(!objectTargets.isEmpty()) { + for (Target target : objectTargets) { + for (UUID targetId : target.getTargets()) { + Permanent targetedPermanent = game.getPermanentOrLKIBattlefield(targetId); + if (targetedPermanent != null && targetedPermanent.getCardType().contains(CardType.LAND) && targetedPermanent.getControllerId().equals(sourceControllerId)) { + return true; + } + } + } + } + } + } + return false; + } + + @Override + public Set possibleTargets(UUID sourceId, UUID sourceControllerId, + Game game) { + return possibleTargets(sourceControllerId, game); + } + + @Override + public Set possibleTargets(UUID sourceControllerId, Game game) { + Set possibleTargets = new HashSet<>(); + for (StackObject stackObject : game.getStack()) { + if (((stackObject instanceof Spell) || (stackObject instanceof StackAbility)) && stackObject.getControllerId() != sourceControllerId) { + Targets objectTargets = stackObject.getStackAbility().getTargets(); + if(!objectTargets.isEmpty()) { + for (Target target : objectTargets) { + for (UUID targetId : target.getTargets()) { + Permanent targetedPermanent = game.getPermanentOrLKIBattlefield(targetId); + if (targetedPermanent != null && targetedPermanent.getCardType().contains(CardType.LAND) && targetedPermanent.getControllerId().equals(sourceControllerId)) { + possibleTargets.add(stackObject.getId()); + } + } + } + } + } + } + return possibleTargets; + } + + @Override + public TargetStackObjectTargetingControlledLand copy() { + return new TargetStackObjectTargetingControlledLand(this); + } + +} + +class TeferisResponseEffect extends OneShotEffect { + + public TeferisResponseEffect() { + super(Outcome.Detriment); + this.staticText = "Counter target spell or ability an opponent controls that targets a land you control. If a permanent's ability is countered this way, destroy that permanent"; + } + + public TeferisResponseEffect(final TeferisResponseEffect effect) { + super(effect); + } + + @Override + public TeferisResponseEffect copy() { + return new TeferisResponseEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + UUID targetId = source.getFirstTarget(); + StackObject stackObject = game.getStack().getStackObject(targetId); + if (targetId != null && game.getStack().counter(targetId, source.getSourceId(), game)) { + UUID permanentId = stackObject.getSourceId(); + if (permanentId != null) { + Permanent usedPermanent = game.getPermanent(permanentId); + if (usedPermanent != null) { + usedPermanent.destroy(source.getSourceId(), game, false); + } + } + return true; + } + + return false; + } +} \ No newline at end of file diff --git a/Mage.Sets/src/mage/sets/limitedalpha/Chaoslace.java b/Mage.Sets/src/mage/sets/limitedalpha/Chaoslace.java new file mode 100644 index 00000000000..0c9258bab69 --- /dev/null +++ b/Mage.Sets/src/mage/sets/limitedalpha/Chaoslace.java @@ -0,0 +1,52 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.sets.limitedalpha; + +import java.util.UUID; + +/** + * + * @author AlumiuN + */ +public class Chaoslace extends mage.sets.fourthedition.Chaoslace { + + public Chaoslace(UUID ownerId) { + super(ownerId); + this.cardNumber = 140; + this.expansionSetCode = "LEA"; + } + + public Chaoslace(final Chaoslace card) { + super(card); + } + + @Override + public Chaoslace copy() { + return new Chaoslace(this); + } +} diff --git a/Mage.Sets/src/mage/sets/limitedalpha/Deathlace.java b/Mage.Sets/src/mage/sets/limitedalpha/Deathlace.java new file mode 100644 index 00000000000..15a9f297430 --- /dev/null +++ b/Mage.Sets/src/mage/sets/limitedalpha/Deathlace.java @@ -0,0 +1,52 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.sets.limitedalpha; + +import java.util.UUID; + +/** + * + * @author AlumiuN + */ +public class Deathlace extends mage.sets.limitedbeta.Deathlace { + + public Deathlace(UUID ownerId) { + super(ownerId); + this.cardNumber = 10; + this.expansionSetCode = "LEA"; + } + + public Deathlace(final Deathlace card) { + super(card); + } + + @Override + public Deathlace copy() { + return new Deathlace(this); + } +} diff --git a/Mage.Sets/src/mage/sets/limitedalpha/Lifelace.java b/Mage.Sets/src/mage/sets/limitedalpha/Lifelace.java new file mode 100644 index 00000000000..f01f6e6ae90 --- /dev/null +++ b/Mage.Sets/src/mage/sets/limitedalpha/Lifelace.java @@ -0,0 +1,62 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.sets.limitedalpha; + +import java.util.UUID; +import mage.ObjectColor; +import mage.abilities.effects.common.continuous.BecomesColorTargetEffect; +import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.Rarity; +import mage.target.common.TargetSpellOrPermanent; + +/** + * + * @author AlumiuN + */ +public class Lifelace extends CardImpl { + + public Lifelace(UUID ownerId) { + super(ownerId, 116, "Lifelace", Rarity.RARE, new CardType[]{CardType.INSTANT}, "{G}"); + this.expansionSetCode = "LEA"; + + // Target spell or permanent becomes green. + this.getSpellAbility().addTarget(new TargetSpellOrPermanent()); + this.getSpellAbility().addEffect(new BecomesColorTargetEffect(ObjectColor.GREEN, Duration.Custom)); + } + + public Lifelace(final Lifelace card) { + super(card); + } + + @Override + public Lifelace copy() { + return new Lifelace(this); + } +} diff --git a/Mage.Sets/src/mage/sets/limitedalpha/Purelace.java b/Mage.Sets/src/mage/sets/limitedalpha/Purelace.java new file mode 100644 index 00000000000..3651a9766cf --- /dev/null +++ b/Mage.Sets/src/mage/sets/limitedalpha/Purelace.java @@ -0,0 +1,52 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.sets.limitedalpha; + +import java.util.UUID; + +/** + * + * @author AlumiuN + */ +public class Purelace extends mage.sets.unlimitededition.Purelace { + + public Purelace(UUID ownerId) { + super(ownerId); + this.cardNumber = 216; + this.expansionSetCode = "LEA"; + } + + public Purelace(final Purelace card) { + super(card); + } + + @Override + public Purelace copy() { + return new Purelace(this); + } +} diff --git a/Mage.Sets/src/mage/sets/limitedalpha/Thoughtlace.java b/Mage.Sets/src/mage/sets/limitedalpha/Thoughtlace.java new file mode 100644 index 00000000000..e426d3ec9fb --- /dev/null +++ b/Mage.Sets/src/mage/sets/limitedalpha/Thoughtlace.java @@ -0,0 +1,52 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.sets.limitedalpha; + +import java.util.UUID; + +/** + * + * @author AlumiuN + */ +public class Thoughtlace extends mage.sets.limitedbeta.Thoughtlace { + + public Thoughtlace(UUID ownerId) { + super(ownerId); + this.cardNumber = 83; + this.expansionSetCode = "LEA"; + } + + public Thoughtlace(final Thoughtlace card) { + super(card); + } + + @Override + public Thoughtlace copy() { + return new Thoughtlace(this); + } +} diff --git a/Mage.Sets/src/mage/sets/limitedbeta/Chaoslace.java b/Mage.Sets/src/mage/sets/limitedbeta/Chaoslace.java new file mode 100644 index 00000000000..5dd7ab9c797 --- /dev/null +++ b/Mage.Sets/src/mage/sets/limitedbeta/Chaoslace.java @@ -0,0 +1,52 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.sets.limitedbeta; + +import java.util.UUID; + +/** + * + * @author AlumiuN + */ +public class Chaoslace extends mage.sets.fourthedition.Chaoslace { + + public Chaoslace(UUID ownerId) { + super(ownerId); + this.cardNumber = 141; + this.expansionSetCode = "LEB"; + } + + public Chaoslace(final Chaoslace card) { + super(card); + } + + @Override + public Chaoslace copy() { + return new Chaoslace(this); + } +} diff --git a/Mage.Sets/src/mage/sets/limitedbeta/Deathlace.java b/Mage.Sets/src/mage/sets/limitedbeta/Deathlace.java new file mode 100644 index 00000000000..568c4641561 --- /dev/null +++ b/Mage.Sets/src/mage/sets/limitedbeta/Deathlace.java @@ -0,0 +1,62 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.sets.limitedbeta; + +import java.util.UUID; +import mage.ObjectColor; +import mage.abilities.effects.common.continuous.BecomesColorTargetEffect; +import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.Rarity; +import mage.target.common.TargetSpellOrPermanent; + +/** + * + * @author AlumiuN + */ +public class Deathlace extends CardImpl { + + public Deathlace(UUID ownerId) { + super(ownerId, 10, "Deathlace", Rarity.RARE, new CardType[]{CardType.INSTANT}, "{B}"); + this.expansionSetCode = "LEB"; + + // Target spell or permanent becomes black. + this.getSpellAbility().addTarget(new TargetSpellOrPermanent()); + this.getSpellAbility().addEffect(new BecomesColorTargetEffect(ObjectColor.BLACK, Duration.Custom)); + } + + public Deathlace(final Deathlace card) { + super(card); + } + + @Override + public Deathlace copy() { + return new Deathlace(this); + } +} diff --git a/Mage.Sets/src/mage/sets/limitedbeta/Lifelace.java b/Mage.Sets/src/mage/sets/limitedbeta/Lifelace.java new file mode 100644 index 00000000000..e19cd0970da --- /dev/null +++ b/Mage.Sets/src/mage/sets/limitedbeta/Lifelace.java @@ -0,0 +1,52 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.sets.limitedbeta; + +import java.util.UUID; + +/** + * + * @author AlumiuN + */ +public class Lifelace extends mage.sets.limitedalpha.Lifelace { + + public Lifelace(UUID ownerId) { + super(ownerId); + this.cardNumber = 116; + this.expansionSetCode = "LEB"; + } + + public Lifelace(final Lifelace card) { + super(card); + } + + @Override + public Lifelace copy() { + return new Lifelace(this); + } +} diff --git a/Mage.Sets/src/mage/sets/limitedbeta/Purelace.java b/Mage.Sets/src/mage/sets/limitedbeta/Purelace.java new file mode 100644 index 00000000000..bc81190443e --- /dev/null +++ b/Mage.Sets/src/mage/sets/limitedbeta/Purelace.java @@ -0,0 +1,52 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.sets.limitedbeta; + +import java.util.UUID; + +/** + * + * @author AlumiuN + */ +public class Purelace extends mage.sets.unlimitededition.Purelace { + + public Purelace(UUID ownerId) { + super(ownerId); + this.cardNumber = 218; + this.expansionSetCode = "LEB"; + } + + public Purelace(final Purelace card) { + super(card); + } + + @Override + public Purelace copy() { + return new Purelace(this); + } +} diff --git a/Mage.Sets/src/mage/sets/limitedbeta/Thoughtlace.java b/Mage.Sets/src/mage/sets/limitedbeta/Thoughtlace.java new file mode 100644 index 00000000000..0b91774b4df --- /dev/null +++ b/Mage.Sets/src/mage/sets/limitedbeta/Thoughtlace.java @@ -0,0 +1,62 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.sets.limitedbeta; + +import java.util.UUID; +import mage.ObjectColor; +import mage.abilities.effects.common.continuous.BecomesColorTargetEffect; +import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.Rarity; +import mage.target.common.TargetSpellOrPermanent; + +/** + * + * @author AlumiuN + */ +public class Thoughtlace extends CardImpl { + + public Thoughtlace(UUID ownerId) { + super(ownerId, 83, "Thoughtlace", Rarity.RARE, new CardType[]{CardType.INSTANT}, "{U}"); + this.expansionSetCode = "LEB"; + + // Target spell or permanent becomes blue. + this.getSpellAbility().addTarget(new TargetSpellOrPermanent()); + this.getSpellAbility().addEffect(new BecomesColorTargetEffect(ObjectColor.BLUE, Duration.Custom)); + } + + public Thoughtlace(final Thoughtlace card) { + super(card); + } + + @Override + public Thoughtlace copy() { + return new Thoughtlace(this); + } +} diff --git a/Mage.Sets/src/mage/sets/nemesis/Infiltrate.java b/Mage.Sets/src/mage/sets/nemesis/Infiltrate.java new file mode 100644 index 00000000000..cb8f7fbc9ea --- /dev/null +++ b/Mage.Sets/src/mage/sets/nemesis/Infiltrate.java @@ -0,0 +1,60 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.sets.nemesis; + +import java.util.UUID; +import mage.abilities.effects.common.combat.CantBeBlockedTargetEffect; +import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.Rarity; +import mage.target.common.TargetCreaturePermanent; + +/** + * + * @author AlumiuN + */ +public class Infiltrate extends CardImpl { + + public Infiltrate(UUID ownerId) { + super(ownerId, 33, "Infiltrate", Rarity.COMMON, new CardType[]{CardType.INSTANT}, "{U}"); + this.expansionSetCode = "NMS"; + + // Target creature is unblockable this turn. + this.getSpellAbility().addEffect(new CantBeBlockedTargetEffect()); + this.getSpellAbility().addTarget(new TargetCreaturePermanent()); + } + + public Infiltrate(final Infiltrate card) { + super(card); + } + + @Override + public Infiltrate copy() { + return new Infiltrate(this); + } +} diff --git a/Mage.Sets/src/mage/sets/revisededition/Chaoslace.java b/Mage.Sets/src/mage/sets/revisededition/Chaoslace.java new file mode 100644 index 00000000000..247ae5fe06d --- /dev/null +++ b/Mage.Sets/src/mage/sets/revisededition/Chaoslace.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.revisededition; + +import java.util.UUID; + +/** + * + * @author AlumiuN + */ +public class Chaoslace extends mage.sets.fourthedition.Chaoslace { + + public Chaoslace(UUID ownerId) { + super(ownerId); + this.cardNumber = 140; + this.expansionSetCode = "3ED"; + } + + public Chaoslace(final Chaoslace card) { + super(card); + } + + @Override + public Chaoslace copy() { + return new Chaoslace(this); + } +} diff --git a/Mage.Sets/src/mage/sets/revisededition/Deathlace.java b/Mage.Sets/src/mage/sets/revisededition/Deathlace.java new file mode 100644 index 00000000000..55e0d3a6a95 --- /dev/null +++ b/Mage.Sets/src/mage/sets/revisededition/Deathlace.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.revisededition; + +import java.util.UUID; + +/** + * + * @author AlumiuN + */ +public class Deathlace extends mage.sets.limitedbeta.Deathlace { + + public Deathlace(UUID ownerId) { + super(ownerId); + this.cardNumber = 10; + this.expansionSetCode = "3ED"; + } + + public Deathlace(final Deathlace card) { + super(card); + } + + @Override + public Deathlace copy() { + return new Deathlace(this); + } +} diff --git a/Mage.Sets/src/mage/sets/revisededition/Lifelace.java b/Mage.Sets/src/mage/sets/revisededition/Lifelace.java new file mode 100644 index 00000000000..3012b263eb7 --- /dev/null +++ b/Mage.Sets/src/mage/sets/revisededition/Lifelace.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.revisededition; + +import java.util.UUID; + +/** + * + * @author AlumiuN + */ +public class Lifelace extends mage.sets.limitedalpha.Lifelace { + + public Lifelace(UUID ownerId) { + super(ownerId); + this.cardNumber = 115; + this.expansionSetCode = "3ED"; + } + + public Lifelace(final Lifelace card) { + super(card); + } + + @Override + public Lifelace copy() { + return new Lifelace(this); + } +} diff --git a/Mage.Sets/src/mage/sets/revisededition/Purelace.java b/Mage.Sets/src/mage/sets/revisededition/Purelace.java new file mode 100644 index 00000000000..35bf375c635 --- /dev/null +++ b/Mage.Sets/src/mage/sets/revisededition/Purelace.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.revisededition; + +import java.util.UUID; + +/** + * + * @author AlumiuN + */ +public class Purelace extends mage.sets.unlimitededition.Purelace { + + public Purelace(UUID ownerId) { + super(ownerId); + this.cardNumber = 216; + this.expansionSetCode = "3ED"; + } + + public Purelace(final Purelace card) { + super(card); + } + + @Override + public Purelace copy() { + return new Purelace(this); + } +} diff --git a/Mage.Sets/src/mage/sets/revisededition/Thoughtlace.java b/Mage.Sets/src/mage/sets/revisededition/Thoughtlace.java new file mode 100644 index 00000000000..a0415d3b7e2 --- /dev/null +++ b/Mage.Sets/src/mage/sets/revisededition/Thoughtlace.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.revisededition; + +import java.util.UUID; + +/** + * + * @author AlumiuN + */ +public class Thoughtlace extends mage.sets.limitedbeta.Thoughtlace { + + public Thoughtlace(UUID ownerId) { + super(ownerId); + this.cardNumber = 85; + this.expansionSetCode = "3ED"; + } + + public Thoughtlace(final Thoughtlace card) { + super(card); + } + + @Override + public Thoughtlace copy() { + return new Thoughtlace(this); + } +} diff --git a/Mage.Sets/src/mage/sets/timespiral/Moonlace.java b/Mage.Sets/src/mage/sets/timespiral/Moonlace.java new file mode 100644 index 00000000000..8babbebfc6b --- /dev/null +++ b/Mage.Sets/src/mage/sets/timespiral/Moonlace.java @@ -0,0 +1,62 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.sets.timespiral; + +import java.util.UUID; +import mage.ObjectColor; +import mage.abilities.effects.common.continuous.BecomesColorTargetEffect; +import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.Rarity; +import mage.target.common.TargetSpellOrPermanent; + +/** + * + * @author AlumiuN + */ +public class Moonlace extends CardImpl { + + public Moonlace(UUID ownerId) { + super(ownerId, 68, "Moonlace", Rarity.RARE, new CardType[]{CardType.INSTANT}, "{U}"); + this.expansionSetCode = "TSP"; + + // Target spell or permanent becomes colorless. + this.getSpellAbility().addTarget(new TargetSpellOrPermanent()); + this.getSpellAbility().addEffect(new BecomesColorTargetEffect(new ObjectColor(), Duration.Custom)); + } + + public Moonlace(final Moonlace card) { + super(card); + } + + @Override + public Moonlace copy() { + return new Moonlace(this); + } +} diff --git a/Mage.Sets/src/mage/sets/unlimitededition/Chaoslace.java b/Mage.Sets/src/mage/sets/unlimitededition/Chaoslace.java new file mode 100644 index 00000000000..b42abd03c4b --- /dev/null +++ b/Mage.Sets/src/mage/sets/unlimitededition/Chaoslace.java @@ -0,0 +1,52 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.sets.unlimitededition; + +import java.util.UUID; + +/** + * + * @author AlumiuN + */ +public class Chaoslace extends mage.sets.fourthedition.Chaoslace { + + public Chaoslace(UUID ownerId) { + super(ownerId); + this.cardNumber = 140; + this.expansionSetCode = "2ED"; + } + + public Chaoslace(final Chaoslace card) { + super(card); + } + + @Override + public Chaoslace copy() { + return new Chaoslace(this); + } +} diff --git a/Mage.Sets/src/mage/sets/unlimitededition/Deathlace.java b/Mage.Sets/src/mage/sets/unlimitededition/Deathlace.java new file mode 100644 index 00000000000..6dd2d54e012 --- /dev/null +++ b/Mage.Sets/src/mage/sets/unlimitededition/Deathlace.java @@ -0,0 +1,52 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.sets.unlimitededition; + +import java.util.UUID; + +/** + * + * @author AlumiuN + */ +public class Deathlace extends mage.sets.limitedbeta.Deathlace { + + public Deathlace(UUID ownerId) { + super(ownerId); + this.cardNumber = 10; + this.expansionSetCode = "2ED"; + } + + public Deathlace(final Deathlace card) { + super(card); + } + + @Override + public Deathlace copy() { + return new Deathlace(this); + } +} diff --git a/Mage.Sets/src/mage/sets/unlimitededition/Lifelace.java b/Mage.Sets/src/mage/sets/unlimitededition/Lifelace.java new file mode 100644 index 00000000000..d96ebdbe10d --- /dev/null +++ b/Mage.Sets/src/mage/sets/unlimitededition/Lifelace.java @@ -0,0 +1,52 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.sets.unlimitededition; + +import java.util.UUID; + +/** + * + * @author AlumiuN + */ +public class Lifelace extends mage.sets.limitedalpha.Lifelace { + + public Lifelace(UUID ownerId) { + super(ownerId); + this.cardNumber = 116; + this.expansionSetCode = "2ED"; + } + + public Lifelace(final Lifelace card) { + super(card); + } + + @Override + public Lifelace copy() { + return new Lifelace(this); + } +} diff --git a/Mage.Sets/src/mage/sets/unlimitededition/Purelace.java b/Mage.Sets/src/mage/sets/unlimitededition/Purelace.java new file mode 100644 index 00000000000..d7fb351bf06 --- /dev/null +++ b/Mage.Sets/src/mage/sets/unlimitededition/Purelace.java @@ -0,0 +1,62 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.sets.unlimitededition; + +import java.util.UUID; +import mage.ObjectColor; +import mage.abilities.effects.common.continuous.BecomesColorTargetEffect; +import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.Rarity; +import mage.target.common.TargetSpellOrPermanent; + +/** + * + * @author AlumiuN + */ +public class Purelace extends CardImpl { + + public Purelace(UUID ownerId) { + super(ownerId, 217, "Purelace", Rarity.RARE, new CardType[]{CardType.INSTANT}, "{W}"); + this.expansionSetCode = "2ED"; + + // Target spell or permanent becomes white. + this.getSpellAbility().addTarget(new TargetSpellOrPermanent()); + this.getSpellAbility().addEffect(new BecomesColorTargetEffect(ObjectColor.WHITE, Duration.Custom)); + } + + public Purelace(final Purelace card) { + super(card); + } + + @Override + public Purelace copy() { + return new Purelace(this); + } +} diff --git a/Mage.Sets/src/mage/sets/unlimitededition/Thoughtlace.java b/Mage.Sets/src/mage/sets/unlimitededition/Thoughtlace.java new file mode 100644 index 00000000000..e7fb6d39082 --- /dev/null +++ b/Mage.Sets/src/mage/sets/unlimitededition/Thoughtlace.java @@ -0,0 +1,52 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.sets.unlimitededition; + +import java.util.UUID; + +/** + * + * @author AlumiuN + */ +public class Thoughtlace extends mage.sets.limitedbeta.Thoughtlace { + + public Thoughtlace(UUID ownerId) { + super(ownerId); + this.cardNumber = 83; + this.expansionSetCode = "2ED"; + } + + public Thoughtlace(final Thoughtlace card) { + super(card); + } + + @Override + public Thoughtlace copy() { + return new Thoughtlace(this); + } +} From 303362fa1246ac2b159f4e428d2673709093b0f0 Mon Sep 17 00:00:00 2001 From: LevelX2 Date: Mon, 12 Oct 2015 17:35:04 +0200 Subject: [PATCH 072/268] * Paradox Haze - Fixed that check if a step is the first upkeep step of a turn did not work always correctly (fixes #1313). --- .../src/mage/sets/tempest/VerdantForce.java | 7 +- .../src/mage/sets/timespiral/ParadoxHaze.java | 39 ++++---- .../cards/enchantments/ParadoxHazeTest.java | 88 +++++++++++++++++++ .../watchers/common/FirstTimeStepWatcher.java | 72 +++++++++++++++ 4 files changed, 183 insertions(+), 23 deletions(-) create mode 100644 Mage.Tests/src/test/java/org/mage/test/cards/enchantments/ParadoxHazeTest.java create mode 100644 Mage/src/mage/watchers/common/FirstTimeStepWatcher.java diff --git a/Mage.Sets/src/mage/sets/tempest/VerdantForce.java b/Mage.Sets/src/mage/sets/tempest/VerdantForce.java index 4377abe9c5b..b383f7df446 100644 --- a/Mage.Sets/src/mage/sets/tempest/VerdantForce.java +++ b/Mage.Sets/src/mage/sets/tempest/VerdantForce.java @@ -28,13 +28,12 @@ package mage.sets.tempest; import java.util.UUID; - -import mage.constants.CardType; -import mage.constants.Rarity; import mage.MageInt; import mage.abilities.common.BeginningOfUpkeepTriggeredAbility; import mage.abilities.effects.common.CreateTokenEffect; import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.Rarity; import mage.constants.TargetController; import mage.game.permanent.token.SaprolingToken; @@ -51,6 +50,8 @@ public class VerdantForce extends CardImpl { this.power = new MageInt(7); this.toughness = new MageInt(7); + + // At the beginning of each upkeep, put a 1/1 green Saproling creature token onto the battlefield. this.addAbility(new BeginningOfUpkeepTriggeredAbility(new CreateTokenEffect(new SaprolingToken()), TargetController.ANY, false)); } diff --git a/Mage.Sets/src/mage/sets/timespiral/ParadoxHaze.java b/Mage.Sets/src/mage/sets/timespiral/ParadoxHaze.java index 40c612225b4..76b84e06c36 100644 --- a/Mage.Sets/src/mage/sets/timespiral/ParadoxHaze.java +++ b/Mage.Sets/src/mage/sets/timespiral/ParadoxHaze.java @@ -47,6 +47,7 @@ import mage.game.turn.UpkeepStep; import mage.players.Player; import mage.target.TargetPlayer; import mage.target.targetpointer.FixedTarget; +import mage.watchers.common.FirstTimeStepWatcher; /** * @@ -59,15 +60,14 @@ public class ParadoxHaze extends CardImpl { this.expansionSetCode = "TSP"; this.subtype.add("Aura"); - // Enchant player TargetPlayer auraTarget = new TargetPlayer(); this.getSpellAbility().addTarget(auraTarget); this.getSpellAbility().addEffect(new AttachEffect(Outcome.Neutral)); this.addAbility(new EnchantAbility(auraTarget.getTargetName())); - + // At the beginning of enchanted player's first upkeep each turn, that player gets an additional upkeep step after this step. - this.addAbility(new ParadoxHazeTriggeredAbility()); + this.addAbility(new ParadoxHazeTriggeredAbility(), new FirstTimeStepWatcher(EventType.UPKEEP_STEP_POST)); } public ParadoxHaze(final ParadoxHaze card) { @@ -81,18 +81,15 @@ public class ParadoxHaze extends CardImpl { } class ParadoxHazeTriggeredAbility extends TriggeredAbilityImpl { - - protected int lastTriggerTurnNumber; - + ParadoxHazeTriggeredAbility() { super(Zone.BATTLEFIELD, new ParadoxHazeEffect(), false); } - + ParadoxHazeTriggeredAbility(final ParadoxHazeTriggeredAbility ability) { super(ability); - lastTriggerTurnNumber = ability.lastTriggerTurnNumber; } - + @Override public ParadoxHazeTriggeredAbility copy() { return new ParadoxHazeTriggeredAbility(this); @@ -102,21 +99,23 @@ class ParadoxHazeTriggeredAbility extends TriggeredAbilityImpl { public boolean checkEventType(GameEvent event, Game game) { return event.getType() == EventType.UPKEEP_STEP_PRE; } - + @Override public boolean checkTrigger(GameEvent event, Game game) { - Permanent permanent = game.getPermanent(this.sourceId); + Permanent permanent = game.getPermanent(getSourceId()); if (permanent != null) { Player player = game.getPlayer(permanent.getAttachedTo()); - if (player != null && game.getActivePlayerId().equals(player.getId()) && lastTriggerTurnNumber != game.getTurnNum()) { - lastTriggerTurnNumber = game.getTurnNum(); - this.getEffects().get(0).setTargetPointer(new FixedTarget(player.getId())); - return true; + if (player != null && game.getActivePlayerId().equals(player.getId())) { + FirstTimeStepWatcher watcher = (FirstTimeStepWatcher) game.getState().getWatchers().get(EventType.UPKEEP_STEP_POST.toString() + FirstTimeStepWatcher.class.getName()); + if (watcher != null && !watcher.conditionMet()) { + this.getEffects().get(0).setTargetPointer(new FixedTarget(player.getId())); + return true; + } } } return false; } - + @Override public String getRule() { return "At the beginning of enchanted player's first upkeep each turn, that player gets an additional upkeep step after this step."; @@ -124,21 +123,21 @@ class ParadoxHazeTriggeredAbility extends TriggeredAbilityImpl { } class ParadoxHazeEffect extends OneShotEffect { - + ParadoxHazeEffect() { super(Outcome.Benefit); this.staticText = "that player gets an additional upkeep step after this step"; } - + ParadoxHazeEffect(final ParadoxHazeEffect effect) { super(effect); } - + @Override public ParadoxHazeEffect copy() { return new ParadoxHazeEffect(this); } - + @Override public boolean apply(Game game, Ability source) { game.getState().getTurnMods().add(new TurnMod(this.getTargetPointer().getFirst(game, source), new UpkeepStep(), null)); diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/enchantments/ParadoxHazeTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/enchantments/ParadoxHazeTest.java new file mode 100644 index 00000000000..917e25519d4 --- /dev/null +++ b/Mage.Tests/src/test/java/org/mage/test/cards/enchantments/ParadoxHazeTest.java @@ -0,0 +1,88 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package org.mage.test.cards.enchantments; + +import mage.constants.PhaseStep; +import mage.constants.Zone; +import org.junit.Test; +import org.mage.test.serverside.base.CardTestPlayerBase; + +/** + * + * @author LevelX2 + */ +public class ParadoxHazeTest extends CardTestPlayerBase { + + @Test + public void testNormal() { + addCard(Zone.BATTLEFIELD, playerA, "Island", 3); + addCard(Zone.BATTLEFIELD, playerA, "Forest", 8); + // Enchant player + // At the beginning of enchanted player's first upkeep each turn, that player gets an additional upkeep step after this step. + addCard(Zone.HAND, playerA, "Paradox Haze", 1); // {2}{U} + // At the beginning of each upkeep, put a 1/1 green Saproling creature token onto the battlefield. + addCard(Zone.HAND, playerA, "Verdant Force", 1); // {5}{G}{G}{G} + + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Paradox Haze", playerA); + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Verdant Force"); + + setStopAt(3, PhaseStep.PRECOMBAT_MAIN); + execute(); + + assertPermanentCount(playerA, "Paradox Haze", 1); + assertPermanentCount(playerA, "Verdant Force", 1); + assertPermanentCount(playerA, "Saproling", 3);// 1 from turn 2 and 2 from turn 3 + } + + @Test + public void testCopied() { + addCard(Zone.BATTLEFIELD, playerA, "Island", 6); + addCard(Zone.BATTLEFIELD, playerA, "Forest", 8); + // Enchant player + // At the beginning of enchanted player's first upkeep each turn, that player gets an additional upkeep step after this step. + addCard(Zone.HAND, playerA, "Paradox Haze", 1); // {2}{U} + + // You may have Copy Enchantment enter the battlefield as a copy of any enchantment on the battlefield. + addCard(Zone.HAND, playerA, "Copy Enchantment", 1); // {2}{U} + + // At the beginning of each upkeep, put a 1/1 green Saproling creature token onto the battlefield. + addCard(Zone.HAND, playerA, "Verdant Force", 1); // {5}{G}{G}{G} + + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Paradox Haze", playerA); + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Copy Enchantment"); + setChoice(playerA, "Paradox Haze"); + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Verdant Force"); + + setStopAt(3, PhaseStep.PRECOMBAT_MAIN); + execute(); + + assertPermanentCount(playerA, "Paradox Haze", 2); + assertPermanentCount(playerA, "Verdant Force", 1); + assertPermanentCount(playerA, "Saproling", 4); // 1 from turn 2 and 3 from turn 3 + } +} diff --git a/Mage/src/mage/watchers/common/FirstTimeStepWatcher.java b/Mage/src/mage/watchers/common/FirstTimeStepWatcher.java new file mode 100644 index 00000000000..911a3ecf93f --- /dev/null +++ b/Mage/src/mage/watchers/common/FirstTimeStepWatcher.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.watchers.common; + +import mage.constants.WatcherScope; +import mage.game.Game; +import mage.game.events.GameEvent; +import mage.game.events.GameEvent.EventType; +import mage.watchers.Watcher; + +/** + * The wachter checks if a specific phase event has already happened during the + * current turn. If not it returns false, otheriwsed true. + * + * @author LevelX2 + */ +public class FirstTimeStepWatcher extends Watcher { + + private final EventType eventType; + + public FirstTimeStepWatcher(EventType eventType) { + super(eventType.toString() + FirstTimeStepWatcher.class.getName(), WatcherScope.GAME); + this.eventType = eventType; + } + + public FirstTimeStepWatcher(final FirstTimeStepWatcher watcher) { + super(watcher); + this.eventType = watcher.eventType; + } + + @Override + public FirstTimeStepWatcher copy() { + return new FirstTimeStepWatcher(this); + } + + @Override + public void watch(GameEvent event, Game game) { + if (event.getType() == eventType) { + condition = true; + } + } + + @Override + public void reset() { + super.reset(); + } +} From f7e92ee885fe1e80dbb1c1c5a4f4ea52154ba9d5 Mon Sep 17 00:00:00 2001 From: LoneFox Date: Mon, 12 Oct 2015 19:18:58 +0300 Subject: [PATCH 073/268] Add RemoveAllCountersSourceEffect and use it for Witherscale Wurm. Implement cards: Homarid and Tidal Influence TODO: The tooltip text of Tidal Infuence's first ability is wrong. The idea is copied from Feast of Blood, which also has the same problem. --- .../src/mage/sets/fallenempires/Homarid1.java | 120 +++++++++++++ .../src/mage/sets/fallenempires/Homarid2.java | 51 ++++++ .../src/mage/sets/fallenempires/Homarid3.java | 51 ++++++ .../src/mage/sets/fallenempires/Homarid4.java | 51 ++++++ .../sets/fallenempires/TidalInfluence.java | 167 ++++++++++++++++++ .../mage/sets/shadowmoor/WitherscaleWurm.java | 37 +--- .../common/RemoveAllCountersSourceEffect.java | 73 ++++++++ Mage/src/mage/counters/CounterType.java | 1 + 8 files changed, 516 insertions(+), 35 deletions(-) create mode 100644 Mage.Sets/src/mage/sets/fallenempires/Homarid1.java create mode 100644 Mage.Sets/src/mage/sets/fallenempires/Homarid2.java create mode 100644 Mage.Sets/src/mage/sets/fallenempires/Homarid3.java create mode 100644 Mage.Sets/src/mage/sets/fallenempires/Homarid4.java create mode 100644 Mage.Sets/src/mage/sets/fallenempires/TidalInfluence.java create mode 100644 Mage/src/mage/abilities/effects/common/RemoveAllCountersSourceEffect.java diff --git a/Mage.Sets/src/mage/sets/fallenempires/Homarid1.java b/Mage.Sets/src/mage/sets/fallenempires/Homarid1.java new file mode 100644 index 00000000000..a69771b1056 --- /dev/null +++ b/Mage.Sets/src/mage/sets/fallenempires/Homarid1.java @@ -0,0 +1,120 @@ +/* + * 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.fallenempires; + +import java.util.UUID; +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.StateTriggeredAbility; +import mage.abilities.common.BeginningOfUpkeepTriggeredAbility; +import mage.abilities.common.EntersBattlefieldAbility; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.condition.common.SourceHasCounterCondition; +import mage.abilities.decorator.ConditionalContinuousEffect; +import mage.abilities.dynamicvalue.common.CountersCount; +import mage.abilities.effects.Effect; +import mage.abilities.effects.common.RemoveAllCountersSourceEffect; +import mage.abilities.effects.common.continuous.BoostSourceEffect; +import mage.abilities.effects.common.counter.AddCountersSourceEffect; +import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.Rarity; +import mage.constants.TargetController; +import mage.constants.Zone; +import mage.counters.CounterType; +import mage.game.Game; +import mage.game.events.GameEvent; + +/** + * + * @author LoneFox + */ +public class Homarid1 extends CardImpl { + + public Homarid1(UUID ownerId) { + super(ownerId, 38, "Homarid", Rarity.COMMON, new CardType[]{CardType.CREATURE}, "{2}{U}"); + this.expansionSetCode = "FEM"; + this.subtype.add("Homarid"); + this.power = new MageInt(2); + this.toughness = new MageInt(2); + + // Homarid enters the battlefield with a tide counter on it. + this.addAbility(new EntersBattlefieldAbility(new AddCountersSourceEffect(CounterType.TIDE.createInstance()), + "with a tide counter on it.")); + // At the beginning of your upkeep, put a tide counter on Homarid. + this.addAbility(new BeginningOfUpkeepTriggeredAbility(new AddCountersSourceEffect(CounterType.TIDE.createInstance()), + TargetController.YOU, false)); + // As long as there is exactly one tide counter on Homarid, it gets -1/-1. + this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new ConditionalContinuousEffect( + new BoostSourceEffect(-1, -1, Duration.WhileOnBattlefield), new SourceHasCounterCondition(CounterType.TIDE, 1, 1), + "As long as there is exactly one tide counter on {this}, it gets -1/-1."))); + // As long as there are exactly three tide counters on Homarid, it gets +1/+1. + this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new ConditionalContinuousEffect( + new BoostSourceEffect(1, 1, Duration.WhileOnBattlefield), new SourceHasCounterCondition(CounterType.TIDE, 3, 3), + "As long as there are exactly three tide counter on {this}, it gets +1/+1."))); + // Whenever there are four tide counters on Homarid, remove all tide counters from it. + this.addAbility(new HomaridTriggeredAbility(new RemoveAllCountersSourceEffect(CounterType.TIDE))); + } + + public Homarid1(final Homarid1 card) { + super(card); + } + + @Override + public Homarid1 copy() { + return new Homarid1(this); + } +} + +class HomaridTriggeredAbility extends StateTriggeredAbility { + + public HomaridTriggeredAbility(Effect effect) { + super(Zone.BATTLEFIELD, effect); + } + + public HomaridTriggeredAbility(final HomaridTriggeredAbility ability) { + super(ability); + } + + @Override + public HomaridTriggeredAbility copy() { + return new HomaridTriggeredAbility(this); + } + + @Override + public boolean checkTrigger(GameEvent event, Game game) { + return new CountersCount(CounterType.TIDE).calculate(game, this, null) == 4; + } + + @Override + public String getRule() { + return "Whenever there are four tide counters on {this}, " + super.getRule(); + } + +} diff --git a/Mage.Sets/src/mage/sets/fallenempires/Homarid2.java b/Mage.Sets/src/mage/sets/fallenempires/Homarid2.java new file mode 100644 index 00000000000..51d33e80bb5 --- /dev/null +++ b/Mage.Sets/src/mage/sets/fallenempires/Homarid2.java @@ -0,0 +1,51 @@ +/* + * 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.fallenempires; + +import java.util.UUID; + +/** + * + * @author LoneFox + */ +public class Homarid2 extends Homarid1 { + + public Homarid2(UUID ownerId) { + super(ownerId); + this.cardNumber = 39; + } + + public Homarid2(final Homarid2 card) { + super(card); + } + + @Override + public Homarid2 copy() { + return new Homarid2(this); + } +} diff --git a/Mage.Sets/src/mage/sets/fallenempires/Homarid3.java b/Mage.Sets/src/mage/sets/fallenempires/Homarid3.java new file mode 100644 index 00000000000..f42970458e1 --- /dev/null +++ b/Mage.Sets/src/mage/sets/fallenempires/Homarid3.java @@ -0,0 +1,51 @@ +/* + * 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.fallenempires; + +import java.util.UUID; + +/** + * + * @author LoneFox + */ +public class Homarid3 extends Homarid1 { + + public Homarid3(UUID ownerId) { + super(ownerId); + this.cardNumber = 40; + } + + public Homarid3(final Homarid3 card) { + super(card); + } + + @Override + public Homarid3 copy() { + return new Homarid3(this); + } +} diff --git a/Mage.Sets/src/mage/sets/fallenempires/Homarid4.java b/Mage.Sets/src/mage/sets/fallenempires/Homarid4.java new file mode 100644 index 00000000000..4ae2066c646 --- /dev/null +++ b/Mage.Sets/src/mage/sets/fallenempires/Homarid4.java @@ -0,0 +1,51 @@ +/* + * 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.fallenempires; + +import java.util.UUID; + +/** + * + * @author LoneFox + */ +public class Homarid4 extends Homarid1 { + + public Homarid4(UUID ownerId) { + super(ownerId); + this.cardNumber = 41; + } + + public Homarid4(final Homarid4 card) { + super(card); + } + + @Override + public Homarid4 copy() { + return new Homarid4(this); + } +} diff --git a/Mage.Sets/src/mage/sets/fallenempires/TidalInfluence.java b/Mage.Sets/src/mage/sets/fallenempires/TidalInfluence.java new file mode 100644 index 00000000000..5de52d6b938 --- /dev/null +++ b/Mage.Sets/src/mage/sets/fallenempires/TidalInfluence.java @@ -0,0 +1,167 @@ +/* + * 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.fallenempires; + +import java.util.UUID; +import mage.ObjectColor; +import mage.abilities.Ability; +import mage.abilities.StateTriggeredAbility; +import mage.abilities.common.BeginningOfUpkeepTriggeredAbility; +import mage.abilities.common.EntersBattlefieldAbility; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.condition.common.SourceHasCounterCondition; +import mage.abilities.costs.CostImpl; +import mage.abilities.decorator.ConditionalContinuousEffect; +import mage.abilities.dynamicvalue.common.CountersCount; +import mage.abilities.effects.Effect; +import mage.abilities.effects.common.RemoveAllCountersSourceEffect; +import mage.abilities.effects.common.continuous.BoostAllEffect; +import mage.abilities.effects.common.counter.AddCountersSourceEffect; +import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.Rarity; +import mage.constants.TargetController; +import mage.constants.Zone; +import mage.counters.CounterType; +import mage.filter.FilterPermanent; +import mage.filter.common.FilterCreaturePermanent; +import mage.filter.predicate.mageobject.ColorPredicate; +import mage.filter.predicate.mageobject.NamePredicate; +import mage.game.Game; +import mage.game.events.GameEvent; + +/** + * + * @author LoneFox + */ +public class TidalInfluence extends CardImpl { + + private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("blue creatures"); + + static { + filter.add(new ColorPredicate(ObjectColor.BLUE)); + } + + public TidalInfluence(UUID ownerId) { + super(ownerId, 57, "Tidal Influence", Rarity.UNCOMMON, new CardType[]{CardType.ENCHANTMENT}, "{2}{U}"); + this.expansionSetCode = "FEM"; + + // Cast Tidal Influence only if no permanents named Tidal Influence are on the battlefield. + this.getSpellAbility().addCost(new TidalInfluenceCost()); + // Tidal Influence enters the battlefield with a tide counter on it. + this.addAbility(new EntersBattlefieldAbility(new AddCountersSourceEffect(CounterType.TIDE.createInstance()), + "with a tide counter on it.")); + // At the beginning of your upkeep, put a tide counter on Tidal Influence. + this.addAbility(new BeginningOfUpkeepTriggeredAbility(new AddCountersSourceEffect(CounterType.TIDE.createInstance()), + TargetController.YOU, false)); + // As long as there is exactly one tide counter on Tidal Influence, all blue creatures get -2/-0. + this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new ConditionalContinuousEffect( + new BoostAllEffect(-2, -0, Duration.WhileOnBattlefield, filter, false), + new SourceHasCounterCondition(CounterType.TIDE, 1, 1), + "As long as there is exactly one tide counter on {this}, all blue creatures get -2/-0."))); + // As long as there are exactly three tide counters on Tidal Influence, all blue creatures get +2/+0. + this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new ConditionalContinuousEffect( + new BoostAllEffect(2, -0, Duration.WhileOnBattlefield, filter, false), + new SourceHasCounterCondition(CounterType.TIDE, 3, 3), + "As long as there are exactly three tide counter on {this}, all blue creatures get +2/-0."))); + // Whenever there are four tide counters on Tidal Influence, remove all tide counters from it. + this.addAbility(new TidalInfluenceTriggeredAbility(new RemoveAllCountersSourceEffect(CounterType.TIDE))); + } + + public TidalInfluence(final TidalInfluence card) { + super(card); + } + + @Override + public TidalInfluence copy() { + return new TidalInfluence(this); + } +} + + +class TidalInfluenceCost extends CostImpl { + + private static final FilterPermanent filter = new FilterPermanent(); + + static { + filter.add(new NamePredicate("Tidal Influence")); + } + + public TidalInfluenceCost() { + this.text = "Cast Tidal Influence only if no permanents named Tidal Influence are on the battlefield"; + } + + public TidalInfluenceCost(final TidalInfluenceCost cost) { + super(cost); + } + + @Override + public boolean canPay(Ability ability, UUID sourceId, UUID controllerId, Game game) { + return !game.getBattlefield().contains(filter, 1, game); + } + + @Override + public boolean pay(Ability ability, Game game, UUID sourceId, UUID controllerId, boolean noMana) { + this.paid = true; + return paid; + } + + @Override + public TidalInfluenceCost copy() { + return new TidalInfluenceCost(this); + } +} + + +class TidalInfluenceTriggeredAbility extends StateTriggeredAbility { + + public TidalInfluenceTriggeredAbility(Effect effect) { + super(Zone.BATTLEFIELD, effect); + } + + public TidalInfluenceTriggeredAbility(final TidalInfluenceTriggeredAbility ability) { + super(ability); + } + + @Override + public TidalInfluenceTriggeredAbility copy() { + return new TidalInfluenceTriggeredAbility(this); + } + + @Override + public boolean checkTrigger(GameEvent event, Game game) { + return new CountersCount(CounterType.TIDE).calculate(game, this, null) == 4; + } + + @Override + public String getRule() { + return "Whenever there are four tide counters on {this}, " + super.getRule(); + } + +} diff --git a/Mage.Sets/src/mage/sets/shadowmoor/WitherscaleWurm.java b/Mage.Sets/src/mage/sets/shadowmoor/WitherscaleWurm.java index bc3e1f3d06c..9f8ba6c97d4 100644 --- a/Mage.Sets/src/mage/sets/shadowmoor/WitherscaleWurm.java +++ b/Mage.Sets/src/mage/sets/shadowmoor/WitherscaleWurm.java @@ -29,21 +29,17 @@ package mage.sets.shadowmoor; import java.util.UUID; import mage.MageInt; -import mage.abilities.Ability; import mage.abilities.common.BlocksOrBecomesBlockedByCreatureTriggeredAbility; import mage.abilities.common.DealsDamageToOpponentTriggeredAbility; import mage.abilities.effects.Effect; -import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.RemoveAllCountersSourceEffect; import mage.abilities.effects.common.continuous.GainAbilityTargetEffect; import mage.abilities.keyword.WitherAbility; import mage.cards.CardImpl; import mage.constants.CardType; import mage.constants.Duration; -import mage.constants.Outcome; import mage.constants.Rarity; import mage.counters.CounterType; -import mage.game.Game; -import mage.game.permanent.Permanent; /** * @@ -65,7 +61,7 @@ public class WitherscaleWurm extends CardImpl { this.addAbility(new BlocksOrBecomesBlockedByCreatureTriggeredAbility(effect, false)); // Whenever Witherscale Wurm deals damage to an opponent, remove all -1/-1 counters from it. - this.addAbility(new DealsDamageToOpponentTriggeredAbility(new WitherscaleWurmEffect(), false)); + this.addAbility(new DealsDamageToOpponentTriggeredAbility(new RemoveAllCountersSourceEffect(CounterType.M1M1), false)); } @@ -78,32 +74,3 @@ public class WitherscaleWurm extends CardImpl { return new WitherscaleWurm(this); } } - -class WitherscaleWurmEffect extends OneShotEffect { - - public WitherscaleWurmEffect() { - super(Outcome.Benefit); - staticText = "remove all -1/-1 counters from it"; - } - - public WitherscaleWurmEffect(WitherscaleWurmEffect effect) { - super(effect); - } - - @Override - public boolean apply(Game game, Ability source) { - Permanent witherscaleWurm = game.getPermanent(source.getSourceId()); - if (witherscaleWurm != null - && witherscaleWurm.getCounters().containsKey(CounterType.M1M1)) { - int M1M1Counters = witherscaleWurm.getCounters().getCount(CounterType.M1M1); - witherscaleWurm.getCounters().removeCounter(CounterType.M1M1, M1M1Counters); - return true; - } - return false; - } - - @Override - public WitherscaleWurmEffect copy() { - return new WitherscaleWurmEffect(this); - } -} diff --git a/Mage/src/mage/abilities/effects/common/RemoveAllCountersSourceEffect.java b/Mage/src/mage/abilities/effects/common/RemoveAllCountersSourceEffect.java new file mode 100644 index 00000000000..abc70475f47 --- /dev/null +++ b/Mage/src/mage/abilities/effects/common/RemoveAllCountersSourceEffect.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.abilities.effects.common; + +import mage.abilities.Ability; +import mage.abilities.effects.OneShotEffect; +import mage.constants.Outcome; +import mage.counters.CounterType; +import mage.game.Game; +import mage.game.permanent.Permanent; + +/** + * + * @author LoneFox + */ +public class RemoveAllCountersSourceEffect extends OneShotEffect { + + private final CounterType counterType; + + public RemoveAllCountersSourceEffect(CounterType counterType) { + super(Outcome.Neutral); + this.counterType = counterType; + staticText = "remove all " + counterType.getName() + " counters from it."; + } + + public RemoveAllCountersSourceEffect(final RemoveAllCountersSourceEffect effect) { + super(effect); + this.counterType = effect.counterType; + } + + @Override + public RemoveAllCountersSourceEffect copy() { + return new RemoveAllCountersSourceEffect(this); + } + + @java.lang.Override + public boolean apply(Game game, Ability source) { + Permanent sourcePermanent = game.getPermanent(source.getSourceId()); + if(sourcePermanent != null) { + int count = sourcePermanent.getCounters().getCount(counterType); + sourcePermanent.getCounters().removeCounter(counterType, count); + return true; + } + return false; + } +} + diff --git a/Mage/src/mage/counters/CounterType.java b/Mage/src/mage/counters/CounterType.java index da70425325e..f7537638758 100644 --- a/Mage/src/mage/counters/CounterType.java +++ b/Mage/src/mage/counters/CounterType.java @@ -96,6 +96,7 @@ public enum CounterType { STRIFE("strife"), STUDY("study"), THEFT("theft"), + TIDE("tide"), TIME("time"), TOWER("tower"), VELOCITY("velocity"), From 41f7b6871b71c49cb64f7428f923669289be30ef Mon Sep 17 00:00:00 2001 From: LoneFox Date: Mon, 12 Oct 2015 20:47:43 +0300 Subject: [PATCH 074/268] Implement cards: Deep Spawn, Homarid Shaman, Homarid Warrior, and Vodalian Mage --- .../mage/sets/fallenempires/DeepSpawn.java | 88 +++++++++++++++++++ .../sets/fallenempires/HomaridShaman.java | 79 +++++++++++++++++ .../sets/fallenempires/HomaridWarrior1.java | 78 ++++++++++++++++ .../sets/fallenempires/HomaridWarrior2.java | 51 +++++++++++ .../sets/fallenempires/HomaridWarrior3.java | 51 +++++++++++ .../sets/fallenempires/VodalianMage1.java | 73 +++++++++++++++ .../sets/fallenempires/VodalianMage2.java | 51 +++++++++++ .../sets/fallenempires/VodalianMage3.java | 51 +++++++++++ .../sets/fifthedition/HomaridWarrior.java | 52 +++++++++++ .../mage/sets/masterseditionii/DeepSpawn.java | 54 ++++++++++++ 10 files changed, 628 insertions(+) create mode 100644 Mage.Sets/src/mage/sets/fallenempires/DeepSpawn.java create mode 100644 Mage.Sets/src/mage/sets/fallenempires/HomaridShaman.java create mode 100644 Mage.Sets/src/mage/sets/fallenempires/HomaridWarrior1.java create mode 100644 Mage.Sets/src/mage/sets/fallenempires/HomaridWarrior2.java create mode 100644 Mage.Sets/src/mage/sets/fallenempires/HomaridWarrior3.java create mode 100644 Mage.Sets/src/mage/sets/fallenempires/VodalianMage1.java create mode 100644 Mage.Sets/src/mage/sets/fallenempires/VodalianMage2.java create mode 100644 Mage.Sets/src/mage/sets/fallenempires/VodalianMage3.java create mode 100644 Mage.Sets/src/mage/sets/fifthedition/HomaridWarrior.java create mode 100644 Mage.Sets/src/mage/sets/masterseditionii/DeepSpawn.java diff --git a/Mage.Sets/src/mage/sets/fallenempires/DeepSpawn.java b/Mage.Sets/src/mage/sets/fallenempires/DeepSpawn.java new file mode 100644 index 00000000000..129e152a1c9 --- /dev/null +++ b/Mage.Sets/src/mage/sets/fallenempires/DeepSpawn.java @@ -0,0 +1,88 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.sets.fallenempires; + +import java.util.UUID; +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.BeginningOfUpkeepTriggeredAbility; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.costs.common.PutTopCardOfYourLibraryToGraveyardCost; +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.effects.Effect; +import mage.abilities.effects.common.DontUntapInControllersNextUntapStepSourceEffect; +import mage.abilities.effects.common.SacrificeSourceUnlessPaysEffect; +import mage.abilities.effects.common.TapSourceEffect; +import mage.abilities.effects.common.continuous.GainAbilitySourceEffect; +import mage.abilities.keyword.ShroudAbility; +import mage.abilities.keyword.TrampleAbility; +import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.Rarity; +import mage.constants.TargetController; +import mage.constants.Zone; + +/** + * + * @author LoneFox + */ +public class DeepSpawn extends CardImpl { + + public DeepSpawn(UUID ownerId) { + super(ownerId, 34, "Deep Spawn", Rarity.UNCOMMON, new CardType[]{CardType.CREATURE}, "{5}{U}{U}{U}"); + this.expansionSetCode = "FEM"; + this.subtype.add("Homarid"); + this.power = new MageInt(6); + this.toughness = new MageInt(6); + + // Trample + this.addAbility(TrampleAbility.getInstance()); + // At the beginning of your upkeep, sacrifice Deep Spawn unless you put the top two cards of your library into your graveyard. + Effect effect = new SacrificeSourceUnlessPaysEffect(new PutTopCardOfYourLibraryToGraveyardCost(2)); + effect.setText("sacrifice {this} unless you put the top two cards of your library into your graveyard"); + this.addAbility(new BeginningOfUpkeepTriggeredAbility(effect, TargetController.YOU, false)); + // {U}: Deep Spawn gains shroud until end of turn and doesn't untap during your next untap step. Tap Deep Spawn. + Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new GainAbilitySourceEffect( + ShroudAbility.getInstance(), Duration.EndOfTurn), new ManaCostsImpl("{U}")); + effect = new DontUntapInControllersNextUntapStepSourceEffect(); + effect.setText("and doesn't untap during your next untap step"); + ability.addEffect(effect); + ability.addEffect(new TapSourceEffect()); + this.addAbility(ability); + } + + public DeepSpawn(final DeepSpawn card) { + super(card); + } + + @Override + public DeepSpawn copy() { + return new DeepSpawn(this); + } +} diff --git a/Mage.Sets/src/mage/sets/fallenempires/HomaridShaman.java b/Mage.Sets/src/mage/sets/fallenempires/HomaridShaman.java new file mode 100644 index 00000000000..e092c8daa75 --- /dev/null +++ b/Mage.Sets/src/mage/sets/fallenempires/HomaridShaman.java @@ -0,0 +1,79 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.sets.fallenempires; + +import java.util.UUID; +import mage.MageInt; +import mage.ObjectColor; +import mage.abilities.Ability; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.effects.common.TapTargetEffect; +import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.Rarity; +import mage.constants.Zone; +import mage.filter.common.FilterCreaturePermanent; +import mage.filter.predicate.mageobject.ColorPredicate; +import mage.target.common.TargetCreaturePermanent; + +/** + * + * @author LoneFox + */ +public class HomaridShaman extends CardImpl { + + private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("green creature"); + + static { + filter.add(new ColorPredicate(ObjectColor.GREEN)); + } + + public HomaridShaman(UUID ownerId) { + super(ownerId, 42, "Homarid Shaman", Rarity.RARE, new CardType[]{CardType.CREATURE}, "{2}{U}{U}"); + this.expansionSetCode = "FEM"; + this.subtype.add("Homarid"); + this.subtype.add("Shaman"); + this.power = new MageInt(2); + this.toughness = new MageInt(1); + + // {U}: Tap target green creature. + Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new TapTargetEffect(), new ManaCostsImpl("{U}")); + ability.addTarget(new TargetCreaturePermanent(filter)); + this.addAbility(ability); + } + + public HomaridShaman(final HomaridShaman card) { + super(card); + } + + @Override + public HomaridShaman copy() { + return new HomaridShaman(this); + } +} diff --git a/Mage.Sets/src/mage/sets/fallenempires/HomaridWarrior1.java b/Mage.Sets/src/mage/sets/fallenempires/HomaridWarrior1.java new file mode 100644 index 00000000000..24114869260 --- /dev/null +++ b/Mage.Sets/src/mage/sets/fallenempires/HomaridWarrior1.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.fallenempires; + +import java.util.UUID; +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.effects.Effect; +import mage.abilities.effects.common.DontUntapInControllersNextUntapStepSourceEffect; +import mage.abilities.effects.common.TapSourceEffect; +import mage.abilities.effects.common.continuous.GainAbilitySourceEffect; +import mage.abilities.keyword.ShroudAbility; +import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.Rarity; +import mage.constants.Zone; + +/** + * + * @author LoneFox + */ +public class HomaridWarrior1 extends CardImpl { + + public HomaridWarrior1(UUID ownerId) { + super(ownerId, 44, "Homarid Warrior", Rarity.COMMON, new CardType[]{CardType.CREATURE}, "{4}{U}"); + this.expansionSetCode = "FEM"; + this.subtype.add("Homarid"); + this.subtype.add("Warrior"); + this.power = new MageInt(3); + this.toughness = new MageInt(3); + + // {U}: Homarid Warrior gains shroud until end of turn and doesn't untap during your next untap step. Tap Homarid Warrior. + Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new GainAbilitySourceEffect( + ShroudAbility.getInstance(), Duration.EndOfTurn), new ManaCostsImpl("{U}")); + Effect effect = new DontUntapInControllersNextUntapStepSourceEffect(); + effect.setText("and doesn't untap during your next untap step"); + ability.addEffect(effect); + ability.addEffect(new TapSourceEffect()); + this.addAbility(ability); + } + + public HomaridWarrior1(final HomaridWarrior1 card) { + super(card); + } + + @Override + public HomaridWarrior1 copy() { + return new HomaridWarrior1(this); + } +} diff --git a/Mage.Sets/src/mage/sets/fallenempires/HomaridWarrior2.java b/Mage.Sets/src/mage/sets/fallenempires/HomaridWarrior2.java new file mode 100644 index 00000000000..f927b68c666 --- /dev/null +++ b/Mage.Sets/src/mage/sets/fallenempires/HomaridWarrior2.java @@ -0,0 +1,51 @@ +/* + * 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.fallenempires; + +import java.util.UUID; + +/** + * + * @author LoneFox + */ +public class HomaridWarrior2 extends HomaridWarrior1 { + + public HomaridWarrior2(UUID ownerId) { + super(ownerId); + this.cardNumber = 45; + } + + public HomaridWarrior2(final HomaridWarrior2 card) { + super(card); + } + + @Override + public HomaridWarrior2 copy() { + return new HomaridWarrior2(this); + } +} diff --git a/Mage.Sets/src/mage/sets/fallenempires/HomaridWarrior3.java b/Mage.Sets/src/mage/sets/fallenempires/HomaridWarrior3.java new file mode 100644 index 00000000000..92ba080f52c --- /dev/null +++ b/Mage.Sets/src/mage/sets/fallenempires/HomaridWarrior3.java @@ -0,0 +1,51 @@ +/* + * 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.fallenempires; + +import java.util.UUID; + +/** + * + * @author LoneFox + */ +public class HomaridWarrior3 extends HomaridWarrior1 { + + public HomaridWarrior3(UUID ownerId) { + super(ownerId); + this.cardNumber = 46; + } + + public HomaridWarrior3(final HomaridWarrior3 card) { + super(card); + } + + @Override + public HomaridWarrior3 copy() { + return new HomaridWarrior3(this); + } +} diff --git a/Mage.Sets/src/mage/sets/fallenempires/VodalianMage1.java b/Mage.Sets/src/mage/sets/fallenempires/VodalianMage1.java new file mode 100644 index 00000000000..ec3c12ddde3 --- /dev/null +++ b/Mage.Sets/src/mage/sets/fallenempires/VodalianMage1.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.fallenempires; + +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.costs.mana.ManaCostsImpl; +import mage.abilities.effects.common.CounterUnlessPaysEffect; +import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.Rarity; +import mage.constants.Zone; +import mage.target.TargetSpell; + +/** + * + * @author LoneFox + */ +public class VodalianMage1 extends CardImpl { + + public VodalianMage1(UUID ownerId) { + super(ownerId, 59, "Vodalian Mage", Rarity.COMMON, new CardType[]{CardType.CREATURE}, "{2}{U}"); + this.expansionSetCode = "FEM"; + this.subtype.add("Merfolk"); + this.subtype.add("Wizard"); + this.power = new MageInt(1); + this.toughness = new MageInt(1); + + // {U}, {tap}: Counter target spell unless its controller pays {1}. + Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new CounterUnlessPaysEffect(new ManaCostsImpl("{1}")), + new ManaCostsImpl("{U}")); + ability.addCost(new TapSourceCost()); + ability.addTarget(new TargetSpell()); + this.addAbility(ability); + } + + public VodalianMage1(final VodalianMage1 card) { + super(card); + } + + @Override + public VodalianMage1 copy() { + return new VodalianMage1(this); + } +} diff --git a/Mage.Sets/src/mage/sets/fallenempires/VodalianMage2.java b/Mage.Sets/src/mage/sets/fallenempires/VodalianMage2.java new file mode 100644 index 00000000000..c1d98f22070 --- /dev/null +++ b/Mage.Sets/src/mage/sets/fallenempires/VodalianMage2.java @@ -0,0 +1,51 @@ +/* + * 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.fallenempires; + +import java.util.UUID; + +/** + * + * @author LoneFox + */ +public class VodalianMage2 extends VodalianMage1 { + + public VodalianMage2(UUID ownerId) { + super(ownerId); + this.cardNumber = 60; + } + + public VodalianMage2(final VodalianMage2 card) { + super(card); + } + + @Override + public VodalianMage2 copy() { + return new VodalianMage2(this); + } +} diff --git a/Mage.Sets/src/mage/sets/fallenempires/VodalianMage3.java b/Mage.Sets/src/mage/sets/fallenempires/VodalianMage3.java new file mode 100644 index 00000000000..c7d1789e17f --- /dev/null +++ b/Mage.Sets/src/mage/sets/fallenempires/VodalianMage3.java @@ -0,0 +1,51 @@ +/* + * 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.fallenempires; + +import java.util.UUID; + +/** + * + * @author LoneFox + */ +public class VodalianMage3 extends VodalianMage1 { + + public VodalianMage3(UUID ownerId) { + super(ownerId); + this.cardNumber = 61; + } + + public VodalianMage3(final VodalianMage3 card) { + super(card); + } + + @Override + public VodalianMage3 copy() { + return new VodalianMage3(this); + } +} diff --git a/Mage.Sets/src/mage/sets/fifthedition/HomaridWarrior.java b/Mage.Sets/src/mage/sets/fifthedition/HomaridWarrior.java new file mode 100644 index 00000000000..a5498872d0b --- /dev/null +++ b/Mage.Sets/src/mage/sets/fifthedition/HomaridWarrior.java @@ -0,0 +1,52 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.sets.fifthedition; + +import java.util.UUID; + +/** + * + * @author LoneFox + */ +public class HomaridWarrior extends mage.sets.fallenempires.HomaridWarrior1 { + + public HomaridWarrior(UUID ownerId) { + super(ownerId); + this.cardNumber = 92; + this.expansionSetCode = "5ED"; + } + + public HomaridWarrior(final HomaridWarrior card) { + super(card); + } + + @Override + public HomaridWarrior copy() { + return new HomaridWarrior(this); + } +} diff --git a/Mage.Sets/src/mage/sets/masterseditionii/DeepSpawn.java b/Mage.Sets/src/mage/sets/masterseditionii/DeepSpawn.java new file mode 100644 index 00000000000..f990a1afa13 --- /dev/null +++ b/Mage.Sets/src/mage/sets/masterseditionii/DeepSpawn.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.masterseditionii; + +import java.util.UUID; +import mage.constants.Rarity; + +/** + * + * @author LoneFox + */ +public class DeepSpawn extends mage.sets.fallenempires.DeepSpawn { + + public DeepSpawn(UUID ownerId) { + super(ownerId); + this.cardNumber = 45; + this.expansionSetCode = "ME2"; + this.rarity = Rarity.RARE; + } + + public DeepSpawn(final DeepSpawn card) { + super(card); + } + + @Override + public DeepSpawn copy() { + return new DeepSpawn(this); + } +} From 05aba24b9a84b67a4215cc13024aeda4595c9faf Mon Sep 17 00:00:00 2001 From: LoneFox Date: Mon, 12 Oct 2015 21:42:42 +0300 Subject: [PATCH 075/268] Implement cards: Basal Thrull, Combat Medic, Elven Fortress, and Ring of Renewal --- .../mage/sets/fallenempires/BasalThrull1.java | 70 ++++++++++++++++++ .../mage/sets/fallenempires/BasalThrull2.java | 51 +++++++++++++ .../mage/sets/fallenempires/BasalThrull3.java | 51 +++++++++++++ .../mage/sets/fallenempires/BasalThrull4.java | 51 +++++++++++++ .../mage/sets/fallenempires/CombatMedic1.java | 52 ++++++++++++++ .../mage/sets/fallenempires/CombatMedic2.java | 52 ++++++++++++++ .../mage/sets/fallenempires/CombatMedic3.java | 52 ++++++++++++++ .../mage/sets/fallenempires/CombatMedic4.java | 52 ++++++++++++++ .../sets/fallenempires/ElvenFortress1.java | 67 +++++++++++++++++ .../sets/fallenempires/ElvenFortress2.java | 51 +++++++++++++ .../sets/fallenempires/ElvenFortress3.java | 51 +++++++++++++ .../sets/fallenempires/ElvenFortress4.java | 51 +++++++++++++ .../sets/fallenempires/RingOfRenewal.java | 52 ++++++++++++++ .../mage/sets/mastersedition/BasalThrull.java | 52 ++++++++++++++ .../sets/masterseditionii/CombatMedic.java | 72 +++++++++++++++++++ .../sets/masterseditioniv/RingOfRenewal.java | 70 ++++++++++++++++++ 16 files changed, 897 insertions(+) create mode 100644 Mage.Sets/src/mage/sets/fallenempires/BasalThrull1.java create mode 100644 Mage.Sets/src/mage/sets/fallenempires/BasalThrull2.java create mode 100644 Mage.Sets/src/mage/sets/fallenempires/BasalThrull3.java create mode 100644 Mage.Sets/src/mage/sets/fallenempires/BasalThrull4.java create mode 100644 Mage.Sets/src/mage/sets/fallenempires/CombatMedic1.java create mode 100644 Mage.Sets/src/mage/sets/fallenempires/CombatMedic2.java create mode 100644 Mage.Sets/src/mage/sets/fallenempires/CombatMedic3.java create mode 100644 Mage.Sets/src/mage/sets/fallenempires/CombatMedic4.java create mode 100644 Mage.Sets/src/mage/sets/fallenempires/ElvenFortress1.java create mode 100644 Mage.Sets/src/mage/sets/fallenempires/ElvenFortress2.java create mode 100644 Mage.Sets/src/mage/sets/fallenempires/ElvenFortress3.java create mode 100644 Mage.Sets/src/mage/sets/fallenempires/ElvenFortress4.java create mode 100644 Mage.Sets/src/mage/sets/fallenempires/RingOfRenewal.java create mode 100644 Mage.Sets/src/mage/sets/mastersedition/BasalThrull.java create mode 100644 Mage.Sets/src/mage/sets/masterseditionii/CombatMedic.java create mode 100644 Mage.Sets/src/mage/sets/masterseditioniv/RingOfRenewal.java diff --git a/Mage.Sets/src/mage/sets/fallenempires/BasalThrull1.java b/Mage.Sets/src/mage/sets/fallenempires/BasalThrull1.java new file mode 100644 index 00000000000..efef91c76aa --- /dev/null +++ b/Mage.Sets/src/mage/sets/fallenempires/BasalThrull1.java @@ -0,0 +1,70 @@ +/* + * 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.fallenempires; + +import java.util.UUID; +import mage.MageInt; +import mage.Mana; +import mage.abilities.Ability; +import mage.abilities.costs.common.SacrificeSourceCost; +import mage.abilities.costs.common.TapSourceCost; +import mage.abilities.effects.common.BasicManaEffect; +import mage.abilities.mana.SimpleManaAbility; +import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.Rarity; +import mage.constants.Zone; + +/** + * + * @author LoneFox + */ +public class BasalThrull1 extends CardImpl { + + public BasalThrull1(UUID ownerId) { + super(ownerId, 5, "Basal Thrull", Rarity.COMMON, new CardType[]{CardType.CREATURE}, "{B}{B}"); + this.expansionSetCode = "FEM"; + this.subtype.add("Thrull"); + this.power = new MageInt(1); + this.toughness = new MageInt(2); + + // {T}, Sacrifice Basal Thrull: Add {B}{B} to your mana pool. + Ability ability = new SimpleManaAbility(Zone.BATTLEFIELD, new BasicManaEffect(new Mana(0, 0, 0, 0, 2, 0, 0)), new TapSourceCost()); + ability.addCost(new SacrificeSourceCost()); + this.addAbility(ability); + } + + public BasalThrull1(final BasalThrull1 card) { + super(card); + } + + @Override + public BasalThrull1 copy() { + return new BasalThrull1(this); + } +} diff --git a/Mage.Sets/src/mage/sets/fallenempires/BasalThrull2.java b/Mage.Sets/src/mage/sets/fallenempires/BasalThrull2.java new file mode 100644 index 00000000000..93ab2baea70 --- /dev/null +++ b/Mage.Sets/src/mage/sets/fallenempires/BasalThrull2.java @@ -0,0 +1,51 @@ +/* + * 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.fallenempires; + +import java.util.UUID; + +/** + * + * @author LoneFox + */ +public class BasalThrull2 extends BasalThrull1 { + + public BasalThrull2(UUID ownerId) { + super(ownerId); + this.cardNumber = 6; + } + + public BasalThrull2(final BasalThrull2 card) { + super(card); + } + + @Override + public BasalThrull2 copy() { + return new BasalThrull2(this); + } +} diff --git a/Mage.Sets/src/mage/sets/fallenempires/BasalThrull3.java b/Mage.Sets/src/mage/sets/fallenempires/BasalThrull3.java new file mode 100644 index 00000000000..27a36274d83 --- /dev/null +++ b/Mage.Sets/src/mage/sets/fallenempires/BasalThrull3.java @@ -0,0 +1,51 @@ +/* + * 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.fallenempires; + +import java.util.UUID; + +/** + * + * @author LoneFox + */ +public class BasalThrull3 extends BasalThrull1 { + + public BasalThrull3(UUID ownerId) { + super(ownerId); + this.cardNumber = 7; + } + + public BasalThrull3(final BasalThrull3 card) { + super(card); + } + + @Override + public BasalThrull3 copy() { + return new BasalThrull3(this); + } +} diff --git a/Mage.Sets/src/mage/sets/fallenempires/BasalThrull4.java b/Mage.Sets/src/mage/sets/fallenempires/BasalThrull4.java new file mode 100644 index 00000000000..d2441b5dc52 --- /dev/null +++ b/Mage.Sets/src/mage/sets/fallenempires/BasalThrull4.java @@ -0,0 +1,51 @@ +/* + * 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.fallenempires; + +import java.util.UUID; + +/** + * + * @author LoneFox + */ +public class BasalThrull4 extends BasalThrull1 { + + public BasalThrull4(UUID ownerId) { + super(ownerId); + this.cardNumber = 8; + } + + public BasalThrull4(final BasalThrull4 card) { + super(card); + } + + @Override + public BasalThrull4 copy() { + return new BasalThrull4(this); + } +} diff --git a/Mage.Sets/src/mage/sets/fallenempires/CombatMedic1.java b/Mage.Sets/src/mage/sets/fallenempires/CombatMedic1.java new file mode 100644 index 00000000000..c564b342fa9 --- /dev/null +++ b/Mage.Sets/src/mage/sets/fallenempires/CombatMedic1.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.fallenempires; + +import java.util.UUID; + +/** + * + * @author LoneFox + */ +public class CombatMedic1 extends mage.sets.masterseditionii.CombatMedic { + + public CombatMedic1(UUID ownerId) { + super(ownerId); + this.cardNumber = 133; + this.expansionSetCode = "FEM"; + } + + public CombatMedic1(final CombatMedic1 card) { + super(card); + } + + @Override + public CombatMedic1 copy() { + return new CombatMedic1(this); + } +} diff --git a/Mage.Sets/src/mage/sets/fallenempires/CombatMedic2.java b/Mage.Sets/src/mage/sets/fallenempires/CombatMedic2.java new file mode 100644 index 00000000000..9234cc19515 --- /dev/null +++ b/Mage.Sets/src/mage/sets/fallenempires/CombatMedic2.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.fallenempires; + +import java.util.UUID; + +/** + * + * @author LoneFox + */ +public class CombatMedic2 extends mage.sets.masterseditionii.CombatMedic { + + public CombatMedic2(UUID ownerId) { + super(ownerId); + this.cardNumber = 134; + this.expansionSetCode = "FEM"; + } + + public CombatMedic2(final CombatMedic2 card) { + super(card); + } + + @Override + public CombatMedic2 copy() { + return new CombatMedic2(this); + } +} diff --git a/Mage.Sets/src/mage/sets/fallenempires/CombatMedic3.java b/Mage.Sets/src/mage/sets/fallenempires/CombatMedic3.java new file mode 100644 index 00000000000..d6efe570e65 --- /dev/null +++ b/Mage.Sets/src/mage/sets/fallenempires/CombatMedic3.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.fallenempires; + +import java.util.UUID; + +/** + * + * @author LoneFox + */ +public class CombatMedic3 extends mage.sets.masterseditionii.CombatMedic { + + public CombatMedic3(UUID ownerId) { + super(ownerId); + this.cardNumber = 135; + this.expansionSetCode = "FEM"; + } + + public CombatMedic3(final CombatMedic3 card) { + super(card); + } + + @Override + public CombatMedic3 copy() { + return new CombatMedic3(this); + } +} diff --git a/Mage.Sets/src/mage/sets/fallenempires/CombatMedic4.java b/Mage.Sets/src/mage/sets/fallenempires/CombatMedic4.java new file mode 100644 index 00000000000..33028ae3b51 --- /dev/null +++ b/Mage.Sets/src/mage/sets/fallenempires/CombatMedic4.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.fallenempires; + +import java.util.UUID; + +/** + * + * @author LoneFox + */ +public class CombatMedic4 extends mage.sets.masterseditionii.CombatMedic { + + public CombatMedic4(UUID ownerId) { + super(ownerId); + this.cardNumber = 136; + this.expansionSetCode = "FEM"; + } + + public CombatMedic4(final CombatMedic4 card) { + super(card); + } + + @Override + public CombatMedic4 copy() { + return new CombatMedic4(this); + } +} diff --git a/Mage.Sets/src/mage/sets/fallenempires/ElvenFortress1.java b/Mage.Sets/src/mage/sets/fallenempires/ElvenFortress1.java new file mode 100644 index 00000000000..2e5618016c8 --- /dev/null +++ b/Mage.Sets/src/mage/sets/fallenempires/ElvenFortress1.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.fallenempires; + +import java.util.UUID; +import mage.abilities.Ability; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.costs.mana.ManaCostsImpl; +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.constants.Zone; +import mage.filter.common.FilterBlockingCreature; +import mage.target.common.TargetCreaturePermanent; + +/** + * + * @author LoneFox + */ +public class ElvenFortress1 extends CardImpl { + + public ElvenFortress1(UUID ownerId) { + super(ownerId, 67, "Elven Fortress", Rarity.COMMON, new CardType[]{CardType.ENCHANTMENT}, "{G}"); + this.expansionSetCode = "FEM"; + + // {1}{G}: Target blocking creature gets +0/+1 until end of turn. + Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new BoostTargetEffect(0, 1, Duration.EndOfTurn), new ManaCostsImpl("{1}{G}")); + ability.addTarget(new TargetCreaturePermanent(new FilterBlockingCreature())); + this.addAbility(ability); + } + + public ElvenFortress1(final ElvenFortress1 card) { + super(card); + } + + @Override + public ElvenFortress1 copy() { + return new ElvenFortress1(this); + } +} diff --git a/Mage.Sets/src/mage/sets/fallenempires/ElvenFortress2.java b/Mage.Sets/src/mage/sets/fallenempires/ElvenFortress2.java new file mode 100644 index 00000000000..c454d76e92c --- /dev/null +++ b/Mage.Sets/src/mage/sets/fallenempires/ElvenFortress2.java @@ -0,0 +1,51 @@ +/* + * 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.fallenempires; + +import java.util.UUID; + +/** + * + * @author LoneFox + */ +public class ElvenFortress2 extends ElvenFortress1 { + + public ElvenFortress2(UUID ownerId) { + super(ownerId); + this.cardNumber = 68; + } + + public ElvenFortress2(final ElvenFortress2 card) { + super(card); + } + + @Override + public ElvenFortress2 copy() { + return new ElvenFortress2(this); + } +} diff --git a/Mage.Sets/src/mage/sets/fallenempires/ElvenFortress3.java b/Mage.Sets/src/mage/sets/fallenempires/ElvenFortress3.java new file mode 100644 index 00000000000..2af6a0b26af --- /dev/null +++ b/Mage.Sets/src/mage/sets/fallenempires/ElvenFortress3.java @@ -0,0 +1,51 @@ +/* + * 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.fallenempires; + +import java.util.UUID; + +/** + * + * @author LoneFox + */ +public class ElvenFortress3 extends ElvenFortress1 { + + public ElvenFortress3(UUID ownerId) { + super(ownerId); + this.cardNumber = 69; + } + + public ElvenFortress3(final ElvenFortress3 card) { + super(card); + } + + @Override + public ElvenFortress3 copy() { + return new ElvenFortress3(this); + } +} diff --git a/Mage.Sets/src/mage/sets/fallenempires/ElvenFortress4.java b/Mage.Sets/src/mage/sets/fallenempires/ElvenFortress4.java new file mode 100644 index 00000000000..70e5a5e6ac7 --- /dev/null +++ b/Mage.Sets/src/mage/sets/fallenempires/ElvenFortress4.java @@ -0,0 +1,51 @@ +/* + * 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.fallenempires; + +import java.util.UUID; + +/** + * + * @author LoneFox + */ +public class ElvenFortress4 extends ElvenFortress1 { + + public ElvenFortress4(UUID ownerId) { + super(ownerId); + this.cardNumber = 70; + } + + public ElvenFortress4(final ElvenFortress4 card) { + super(card); + } + + @Override + public ElvenFortress4 copy() { + return new ElvenFortress4(this); + } +} diff --git a/Mage.Sets/src/mage/sets/fallenempires/RingOfRenewal.java b/Mage.Sets/src/mage/sets/fallenempires/RingOfRenewal.java new file mode 100644 index 00000000000..4d9b13c8182 --- /dev/null +++ b/Mage.Sets/src/mage/sets/fallenempires/RingOfRenewal.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.fallenempires; + +import java.util.UUID; + +/** + * + * @author LoneFox + */ +public class RingOfRenewal extends mage.sets.masterseditioniv.RingOfRenewal { + + public RingOfRenewal(UUID ownerId) { + super(ownerId); + this.cardNumber = 174; + this.expansionSetCode = "FEM"; + } + + public RingOfRenewal(final RingOfRenewal card) { + super(card); + } + + @Override + public RingOfRenewal copy() { + return new RingOfRenewal(this); + } +} diff --git a/Mage.Sets/src/mage/sets/mastersedition/BasalThrull.java b/Mage.Sets/src/mage/sets/mastersedition/BasalThrull.java new file mode 100644 index 00000000000..a2cc39602c0 --- /dev/null +++ b/Mage.Sets/src/mage/sets/mastersedition/BasalThrull.java @@ -0,0 +1,52 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.sets.mastersedition; + +import java.util.UUID; + +/** + * + * @author LoneFox + */ +public class BasalThrull extends mage.sets.fallenempires.BasalThrull1 { + + public BasalThrull(UUID ownerId) { + super(ownerId); + this.cardNumber = 59; + this.expansionSetCode = "MED"; + } + + public BasalThrull(final BasalThrull card) { + super(card); + } + + @Override + public BasalThrull copy() { + return new BasalThrull(this); + } +} diff --git a/Mage.Sets/src/mage/sets/masterseditionii/CombatMedic.java b/Mage.Sets/src/mage/sets/masterseditionii/CombatMedic.java new file mode 100644 index 00000000000..6708aa9d2c7 --- /dev/null +++ b/Mage.Sets/src/mage/sets/masterseditionii/CombatMedic.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.masterseditionii; + +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.PreventDamageToTargetEffect; +import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.Rarity; +import mage.constants.Zone; +import mage.target.common.TargetCreatureOrPlayer; + +/** + * + * @author LoneFox + */ +public class CombatMedic extends CardImpl { + + public CombatMedic(UUID ownerId) { + super(ownerId, 9, "Combat Medic", Rarity.COMMON, new CardType[]{CardType.CREATURE}, "{2}{W}"); + this.expansionSetCode = "ME2"; + this.subtype.add("Human"); + this.subtype.add("Cleric"); + this.subtype.add("Soldier"); + this.power = new MageInt(0); + this.toughness = new MageInt(2); + + // {1}{W}: Prevent the next 1 damage that would be dealt to target creature or player this turn. + Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new PreventDamageToTargetEffect(Duration.EndOfTurn, 1), new ManaCostsImpl("{1}{W}")); + ability.addTarget(new TargetCreatureOrPlayer()); + this.addAbility(ability); + } + + public CombatMedic(final CombatMedic card) { + super(card); + } + + @Override + public CombatMedic copy() { + return new CombatMedic(this); + } +} diff --git a/Mage.Sets/src/mage/sets/masterseditioniv/RingOfRenewal.java b/Mage.Sets/src/mage/sets/masterseditioniv/RingOfRenewal.java new file mode 100644 index 00000000000..61ac07d1299 --- /dev/null +++ b/Mage.Sets/src/mage/sets/masterseditioniv/RingOfRenewal.java @@ -0,0 +1,70 @@ +/* + * 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.masterseditioniv; + +import java.util.UUID; +import mage.abilities.Ability; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.costs.common.TapSourceCost; +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.effects.Effect; +import mage.abilities.effects.common.DrawCardSourceControllerEffect; +import mage.abilities.effects.common.discard.DiscardControllerEffect; +import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.Rarity; +import mage.constants.Zone; + +/** + * + * @author LoneFox + */ +public class RingOfRenewal extends CardImpl { + + public RingOfRenewal(UUID ownerId) { + super(ownerId, 224, "Ring of Renewal", Rarity.RARE, new CardType[]{CardType.ARTIFACT}, "{5}"); + this.expansionSetCode = "ME4"; + + // {5}, {tap}: Discard a card at random, then draw two cards. + Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new DiscardControllerEffect(1, true), new ManaCostsImpl("{5}")); + ability.addCost(new TapSourceCost()); + Effect effect = new DrawCardSourceControllerEffect(2); + effect.setText(", then draw two cards"); + ability.addEffect(effect); + this.addAbility(ability); + } + + public RingOfRenewal(final RingOfRenewal card) { + super(card); + } + + @Override + public RingOfRenewal copy() { + return new RingOfRenewal(this); + } +} From 0d634ebf09990fb31ce01b3cf8d064dd67224a5f Mon Sep 17 00:00:00 2001 From: LoneFox Date: Mon, 12 Oct 2015 22:19:13 +0300 Subject: [PATCH 076/268] Kill a few DamageTargetControllerEffect implementations --- .../riseoftheeldrazi/GrotagSiegeRunner.java | 47 +++------------- .../sets/scarsofmirrodin/MeltTerrain.java | 52 +++--------------- .../mage/sets/shadowmoor/PoisonTheWell.java | 45 +++------------ .../sets/shadowmoor/SmashToSmithereens.java | 51 +++-------------- .../src/mage/sets/tenthedition/Cryoclasm.java | 55 +++---------------- .../src/mage/sets/theros/PeakEruption.java | 53 +++--------------- 6 files changed, 47 insertions(+), 256 deletions(-) diff --git a/Mage.Sets/src/mage/sets/riseoftheeldrazi/GrotagSiegeRunner.java b/Mage.Sets/src/mage/sets/riseoftheeldrazi/GrotagSiegeRunner.java index 4c8578d6096..e3407fb0dec 100644 --- a/Mage.Sets/src/mage/sets/riseoftheeldrazi/GrotagSiegeRunner.java +++ b/Mage.Sets/src/mage/sets/riseoftheeldrazi/GrotagSiegeRunner.java @@ -28,24 +28,21 @@ package mage.sets.riseoftheeldrazi; import java.util.UUID; -import mage.constants.CardType; -import mage.constants.Outcome; -import mage.constants.Rarity; -import mage.constants.Zone; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.SimpleActivatedAbility; import mage.abilities.costs.common.SacrificeSourceCost; import mage.abilities.costs.mana.ManaCostsImpl; -import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.Effect; +import mage.abilities.effects.common.DamageTargetControllerEffect; import mage.abilities.effects.common.DestroyTargetEffect; import mage.abilities.keyword.DefenderAbility; import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.Rarity; +import mage.constants.Zone; import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.mageobject.AbilityPredicate; -import mage.game.Game; -import mage.game.permanent.Permanent; -import mage.players.Player; import mage.target.common.TargetCreaturePermanent; /** @@ -70,10 +67,12 @@ public class GrotagSiegeRunner extends CardImpl { this.toughness = new MageInt(1); // {R}, Sacrifice Grotag Siege-Runner: Destroy target creature with defender. Grotag Siege-Runner deals 2 damage to that creature's controller. - SimpleActivatedAbility ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new DestroyTargetEffect(), new ManaCostsImpl("{R}")); + Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new DestroyTargetEffect(), new ManaCostsImpl("{R}")); ability.addCost(new SacrificeSourceCost()); + Effect effect = new DamageTargetControllerEffect(2); + effect.setText("{this} deals 2 damage to that creature's controller"); + ability.addEffect(effect); ability.addTarget(new TargetCreaturePermanent(filter)); - ability.addEffect(new GrotageSiegeRunnerEffect()); this.addAbility(ability); } @@ -86,31 +85,3 @@ public class GrotagSiegeRunner extends CardImpl { return new GrotagSiegeRunner(this); } } - -class GrotageSiegeRunnerEffect extends OneShotEffect { - - public GrotageSiegeRunnerEffect() { - super(Outcome.Damage); - this.staticText = "{this} deals 2 damage to that creature's controller"; - } - - public GrotageSiegeRunnerEffect(final GrotageSiegeRunnerEffect effect) { - super(effect); - } - - @Override - public GrotageSiegeRunnerEffect copy() { - return new GrotageSiegeRunnerEffect(this); - } - - @Override - public boolean apply(Game game, Ability source) { - Permanent permanent = (Permanent) game.getLastKnownInformation(source.getFirstTarget(), Zone.BATTLEFIELD); - if (permanent != null) { - Player controller = game.getPlayer(permanent.getControllerId()); - controller.damage(2, source.getSourceId(), game, false, true); - return true; - } - return false; - } -} diff --git a/Mage.Sets/src/mage/sets/scarsofmirrodin/MeltTerrain.java b/Mage.Sets/src/mage/sets/scarsofmirrodin/MeltTerrain.java index 8c95d5de0b3..0524d95acd6 100644 --- a/Mage.Sets/src/mage/sets/scarsofmirrodin/MeltTerrain.java +++ b/Mage.Sets/src/mage/sets/scarsofmirrodin/MeltTerrain.java @@ -29,18 +29,12 @@ package mage.sets.scarsofmirrodin; import java.util.UUID; - -import mage.constants.CardType; -import mage.constants.Rarity; -import mage.constants.Zone; -import mage.abilities.Ability; -import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.Effect; +import mage.abilities.effects.common.DamageTargetControllerEffect; import mage.abilities.effects.common.DestroyTargetEffect; import mage.cards.CardImpl; -import mage.constants.Outcome; -import mage.game.Game; -import mage.game.permanent.Permanent; -import mage.players.Player; +import mage.constants.CardType; +import mage.constants.Rarity; import mage.target.common.TargetLandPermanent; /** @@ -53,8 +47,11 @@ public class MeltTerrain extends CardImpl { super(ownerId, 97, "Melt Terrain", Rarity.COMMON, new CardType[]{CardType.SORCERY}, "{2}{R}{R}"); this.expansionSetCode = "SOM"; + // Destroy target land. Melt Terrain deals 2 damage to that land's controller. this.getSpellAbility().addEffect(new DestroyTargetEffect()); - this.getSpellAbility().addEffect(new MeltTerrainEffect()); + Effect effect = new DamageTargetControllerEffect(2); + effect.setText("{this} deals 2 damage to that land's controller"); + this.getSpellAbility().addEffect(effect); this.getSpellAbility().addTarget(new TargetLandPermanent()); } @@ -66,37 +63,4 @@ public class MeltTerrain extends CardImpl { public MeltTerrain copy() { return new MeltTerrain(this); } - } - -class MeltTerrainEffect extends OneShotEffect { - MeltTerrainEffect() { - super(Outcome.Damage); - staticText = "{this} deals 2 damage to that land's controller"; - } - - MeltTerrainEffect(final MeltTerrainEffect effect) { - super(effect); - } - - @Override - public boolean apply(Game game, Ability source) { - Permanent p = game.getBattlefield().getPermanent(source.getFirstTarget()); - if (p == null) { - p = (Permanent) game.getLastKnownInformation(source.getFirstTarget(), Zone.BATTLEFIELD); - } - if (p != null) { - Player player = game.getPlayer(p.getControllerId()); - if (player != null) { - player.damage(2, source.getSourceId(), game, false, true); - } - } - return false; - } - - @Override - public MeltTerrainEffect copy() { - return new MeltTerrainEffect(this); - } - -} \ No newline at end of file diff --git a/Mage.Sets/src/mage/sets/shadowmoor/PoisonTheWell.java b/Mage.Sets/src/mage/sets/shadowmoor/PoisonTheWell.java index cb515b66693..1b8d897cfed 100644 --- a/Mage.Sets/src/mage/sets/shadowmoor/PoisonTheWell.java +++ b/Mage.Sets/src/mage/sets/shadowmoor/PoisonTheWell.java @@ -28,15 +28,12 @@ package mage.sets.shadowmoor; import java.util.UUID; -import mage.abilities.Ability; -import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.Effect; +import mage.abilities.effects.common.DamageTargetControllerEffect; +import mage.abilities.effects.common.DestroyTargetEffect; 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.players.Player; import mage.target.common.TargetLandPermanent; /** @@ -50,7 +47,10 @@ public class PoisonTheWell extends CardImpl { this.expansionSetCode = "SHM"; // Destroy target land. Poison the Well deals 2 damage to that land's controller. - this.getSpellAbility().addEffect(new PoisonTheWellEffect()); + this.getSpellAbility().addEffect(new DestroyTargetEffect()); + Effect effect = new DamageTargetControllerEffect(2); + effect.setText("{this} deals 2 damage to that land's controller"); + this.getSpellAbility().addEffect(effect); this.getSpellAbility().addTarget(new TargetLandPermanent()); } @@ -63,34 +63,3 @@ public class PoisonTheWell extends CardImpl { return new PoisonTheWell(this); } } - -class PoisonTheWellEffect extends OneShotEffect { - - public PoisonTheWellEffect() { - super(Outcome.DestroyPermanent); - this.staticText = "Destroy target land. {this} deals 2 damage to that land's controller"; - } - - public PoisonTheWellEffect(final PoisonTheWellEffect effect) { - super(effect); - } - - @Override - public PoisonTheWellEffect copy() { - return new PoisonTheWellEffect(this); - } - - @Override - public boolean apply(Game game, Ability source) { - Permanent targetedLand = game.getPermanent(source.getFirstTarget()); - if (targetedLand != null) { - targetedLand.destroy(source.getSourceId(), game, true); - Player controller = game.getPlayer(targetedLand.getControllerId()); - if (controller != null) { - controller.damage(2, source.getSourceId(), game, false, true); - } - return true; - } - return false; - } -} diff --git a/Mage.Sets/src/mage/sets/shadowmoor/SmashToSmithereens.java b/Mage.Sets/src/mage/sets/shadowmoor/SmashToSmithereens.java index 98ff75dc2bc..113b83d9f7e 100644 --- a/Mage.Sets/src/mage/sets/shadowmoor/SmashToSmithereens.java +++ b/Mage.Sets/src/mage/sets/shadowmoor/SmashToSmithereens.java @@ -28,17 +28,12 @@ package mage.sets.shadowmoor; import java.util.UUID; -import mage.constants.CardType; -import mage.constants.Outcome; -import mage.constants.Rarity; -import mage.constants.Zone; -import mage.abilities.Ability; -import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.Effect; +import mage.abilities.effects.common.DamageTargetControllerEffect; import mage.abilities.effects.common.DestroyTargetEffect; import mage.cards.CardImpl; -import mage.game.Game; -import mage.game.permanent.Permanent; -import mage.players.Player; +import mage.constants.CardType; +import mage.constants.Rarity; import mage.target.common.TargetArtifactPermanent; /** @@ -52,9 +47,11 @@ public class SmashToSmithereens extends CardImpl { this.expansionSetCode = "SHM"; // Destroy target artifact. Smash to Smithereens deals 3 damage to that artifact's controller. - this.getSpellAbility().addTarget(new TargetArtifactPermanent()); this.getSpellAbility().addEffect(new DestroyTargetEffect()); - this.getSpellAbility().addEffect(new SmashToSmithereensEffect()); + Effect effect = new DamageTargetControllerEffect(3); + effect.setText("{this} deals 3 damage to that artifact's controller"); + this.getSpellAbility().addEffect(effect); + this.getSpellAbility().addTarget(new TargetArtifactPermanent()); } public SmashToSmithereens(final SmashToSmithereens card) { @@ -66,35 +63,3 @@ public class SmashToSmithereens extends CardImpl { return new SmashToSmithereens(this); } } - -class SmashToSmithereensEffect extends OneShotEffect { - - SmashToSmithereensEffect() { - super(Outcome.Damage); - staticText = "{this} deals 3 damage to that artifact's controller"; - } - - SmashToSmithereensEffect(final SmashToSmithereensEffect effect) { - super(effect); - } - - @Override - public boolean apply(Game game, Ability source) { - Permanent permanent = game.getBattlefield().getPermanent(source.getFirstTarget()); - if (permanent == null) { - permanent = (Permanent) game.getLastKnownInformation(source.getFirstTarget(), Zone.BATTLEFIELD); - } - if (permanent != null) { - Player player = game.getPlayer(permanent.getControllerId()); - if (player != null) { - player.damage(3, source.getSourceId(), game, false, true); - } - } - return false; - } - - @Override - public SmashToSmithereensEffect copy() { - return new SmashToSmithereensEffect(this); - } -} diff --git a/Mage.Sets/src/mage/sets/tenthedition/Cryoclasm.java b/Mage.Sets/src/mage/sets/tenthedition/Cryoclasm.java index f76c044baa2..c9c1cff99b5 100644 --- a/Mage.Sets/src/mage/sets/tenthedition/Cryoclasm.java +++ b/Mage.Sets/src/mage/sets/tenthedition/Cryoclasm.java @@ -28,23 +28,15 @@ package mage.sets.tenthedition; import java.util.UUID; - -import mage.MageObject; -import mage.abilities.Ability; -import mage.abilities.effects.OneShotEffect; -import mage.abilities.effects.common.DamageTargetEffect; +import mage.abilities.effects.Effect; +import mage.abilities.effects.common.DamageTargetControllerEffect; import mage.abilities.effects.common.DestroyTargetEffect; import mage.cards.CardImpl; import mage.constants.CardType; -import mage.constants.Outcome; import mage.constants.Rarity; -import mage.constants.Zone; import mage.filter.common.FilterLandPermanent; import mage.filter.predicate.Predicates; import mage.filter.predicate.mageobject.SubtypePredicate; -import mage.game.Game; -import mage.game.permanent.Permanent; -import mage.players.Player; import mage.target.common.TargetLandPermanent; /** @@ -54,20 +46,20 @@ import mage.target.common.TargetLandPermanent; public class Cryoclasm extends CardImpl { private static final FilterLandPermanent filter = new FilterLandPermanent("Plains or Island"); + static { - filter.add(Predicates.or( - new SubtypePredicate("Plains"), - new SubtypePredicate("Island"))); + filter.add(Predicates.or(new SubtypePredicate("Plains"), new SubtypePredicate("Island"))); } public Cryoclasm(UUID ownerId) { super(ownerId, 195, "Cryoclasm", Rarity.UNCOMMON, new CardType[]{CardType.SORCERY}, "{2}{R}"); this.expansionSetCode = "10E"; - // Destroy target Plains or Island. Cryoclasm deals 3 damage to that land's controller. this.getSpellAbility().addEffect(new DestroyTargetEffect()); - this.getSpellAbility().addEffect(new CryoclasmEffect()); + Effect effect = new DamageTargetControllerEffect(3); + effect.setText("{this} deals 3 damage to that land's controller"); + this.getSpellAbility().addEffect(effect); this.getSpellAbility().addTarget(new TargetLandPermanent(filter)); } @@ -81,36 +73,3 @@ public class Cryoclasm extends CardImpl { return new Cryoclasm(this); } } - -class CryoclasmEffect extends OneShotEffect { - - public CryoclasmEffect() { - super(Outcome.Damage); - this.staticText = "{this} deals 3 damage to that land's controller"; - } - - public CryoclasmEffect(final CryoclasmEffect effect) { - super(effect); - } - - @Override - public CryoclasmEffect copy() { - return new CryoclasmEffect(this); - } - - @Override - public boolean apply(Game game, Ability source) { - UUID targetId = getTargetPointer().getFirst(game, source); - if (targetId != null) { - Permanent permanent = game.getPermanentOrLKIBattlefield(targetId); - if (permanent != null) { - Player controller = game.getPlayer(permanent.getControllerId()); - if (controller != null) { - controller.damage(3, source.getSourceId(), game, false, false); - return true; - } - } - } - return false; - } -} \ No newline at end of file diff --git a/Mage.Sets/src/mage/sets/theros/PeakEruption.java b/Mage.Sets/src/mage/sets/theros/PeakEruption.java index 4aa27c573a4..0b8e9796eb1 100644 --- a/Mage.Sets/src/mage/sets/theros/PeakEruption.java +++ b/Mage.Sets/src/mage/sets/theros/PeakEruption.java @@ -28,19 +28,14 @@ package mage.sets.theros; import java.util.UUID; -import mage.abilities.Ability; -import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.Effect; +import mage.abilities.effects.common.DamageTargetControllerEffect; import mage.abilities.effects.common.DestroyTargetEffect; import mage.cards.CardImpl; import mage.constants.CardType; -import mage.constants.Outcome; import mage.constants.Rarity; -import mage.constants.Zone; import mage.filter.common.FilterLandPermanent; import mage.filter.predicate.mageobject.SubtypePredicate; -import mage.game.Game; -import mage.game.permanent.Permanent; -import mage.players.Player; import mage.target.common.TargetLandPermanent; /** @@ -50,20 +45,21 @@ import mage.target.common.TargetLandPermanent; public class PeakEruption extends CardImpl { private static final FilterLandPermanent filter = new FilterLandPermanent("Mountain"); + static{ filter.add(new SubtypePredicate(("Mountain"))); } - - + public PeakEruption(UUID ownerId) { super(ownerId, 132, "Peak Eruption", Rarity.UNCOMMON, new CardType[]{CardType.SORCERY}, "{2}{R}"); this.expansionSetCode = "THS"; - // Destroy target Mountain. Peak Eruption deals 3 damage to that land's controller. - this.getSpellAbility().addTarget(new TargetLandPermanent(filter)); this.getSpellAbility().addEffect(new DestroyTargetEffect()); - this.getSpellAbility().addEffect(new PeakEruptionEffect()); + Effect effect = new DamageTargetControllerEffect(3); + effect.setText("{this} deals 3 damage to that land's controller"); + this.getSpellAbility().addEffect(effect); + this.getSpellAbility().addTarget(new TargetLandPermanent(filter)); } public PeakEruption(final PeakEruption card) { @@ -75,36 +71,3 @@ public class PeakEruption extends CardImpl { return new PeakEruption(this); } } - - -class PeakEruptionEffect extends OneShotEffect { - - PeakEruptionEffect() { - super(Outcome.Damage); - staticText = "{this} deals 3 damage to that land's controller"; - } - - PeakEruptionEffect(final PeakEruptionEffect effect) { - super(effect); - } - - @Override - public boolean apply(Game game, Ability source) { - Permanent permanent = game.getBattlefield().getPermanent(source.getFirstTarget()); - if (permanent == null) { - permanent = (Permanent) game.getLastKnownInformation(source.getFirstTarget(), Zone.BATTLEFIELD); - } - if (permanent != null) { - Player player = game.getPlayer(permanent.getControllerId()); - if (player != null) { - player.damage(3, source.getSourceId(), game, false, true); - } - } - return false; - } - - @Override - public PeakEruptionEffect copy() { - return new PeakEruptionEffect(this); - } -} From 5b5798b7580bf1074631fddd237dad0d676d3060 Mon Sep 17 00:00:00 2001 From: Jeff Date: Mon, 12 Oct 2015 15:15:29 -0500 Subject: [PATCH 077/268] - Simple text fixes. --- Mage/src/mage/abilities/keyword/ConspireAbility.java | 2 +- Mage/src/mage/watchers/common/FirstTimeStepWatcher.java | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Mage/src/mage/abilities/keyword/ConspireAbility.java b/Mage/src/mage/abilities/keyword/ConspireAbility.java index cef23120fe0..a655b31721d 100644 --- a/Mage/src/mage/abilities/keyword/ConspireAbility.java +++ b/Mage/src/mage/abilities/keyword/ConspireAbility.java @@ -68,7 +68,7 @@ import mage.target.common.TargetControlledPermanent; * 702.77b If a spell has multiple instances of conspire, each is paid separately and triggers * based on its own payment, not any other instance of conspire. * * - * @author jeffwadsworth heavily based off the replicate keyword by LevelX + * @author LevelX */ public class ConspireAbility extends StaticAbility implements OptionalAdditionalSourceCosts { diff --git a/Mage/src/mage/watchers/common/FirstTimeStepWatcher.java b/Mage/src/mage/watchers/common/FirstTimeStepWatcher.java index 911a3ecf93f..028e77e1209 100644 --- a/Mage/src/mage/watchers/common/FirstTimeStepWatcher.java +++ b/Mage/src/mage/watchers/common/FirstTimeStepWatcher.java @@ -34,8 +34,8 @@ import mage.game.events.GameEvent.EventType; import mage.watchers.Watcher; /** - * The wachter checks if a specific phase event has already happened during the - * current turn. If not it returns false, otheriwsed true. + * The watcher checks if a specific phase event has already happened during the + * current turn. If not it returns false, otherwise true. * * @author LevelX2 */ From 288a1ec02cd2b3c26b261936a2a883345bd1e064 Mon Sep 17 00:00:00 2001 From: LevelX2 Date: Mon, 12 Oct 2015 23:10:16 +0200 Subject: [PATCH 078/268] * Oath of Lieges - Fixed target handling (fixes #1312). --- .../src/mage/sets/exodus/OathOfLieges.java | 22 ++-- .../cards/enchantments/OathOfLiegesTest.java | 124 ++++++++++++++++++ .../java/org/mage/test/player/TestPlayer.java | 29 +++- Mage/src/mage/game/GameImpl.java | 2 +- 4 files changed, 163 insertions(+), 14 deletions(-) create mode 100644 Mage.Tests/src/test/java/org/mage/test/cards/enchantments/OathOfLiegesTest.java diff --git a/Mage.Sets/src/mage/sets/exodus/OathOfLieges.java b/Mage.Sets/src/mage/sets/exodus/OathOfLieges.java index b7a8d637588..f11e6b7823e 100644 --- a/Mage.Sets/src/mage/sets/exodus/OathOfLieges.java +++ b/Mage.Sets/src/mage/sets/exodus/OathOfLieges.java @@ -31,7 +31,7 @@ import java.util.UUID; import mage.abilities.Ability; import mage.abilities.common.BeginningOfUpkeepTriggeredAbility; import mage.abilities.effects.Effect; -import mage.abilities.effects.common.search.SearchLibraryPutInPlayEffect; +import mage.abilities.effects.common.search.SearchLibraryPutInPlayTargetPlayerEffect; import mage.cards.CardImpl; import mage.constants.CardType; import mage.constants.Outcome; @@ -46,14 +46,16 @@ import mage.game.Game; import mage.players.Player; import mage.target.TargetPlayer; import mage.target.common.TargetCardInLibrary; +import mage.target.targetpointer.FixedTarget; /** * * @author emerald000 */ public class OathOfLieges extends CardImpl { - - private static final FilterPlayer filter = new FilterPlayer(); + + private static final FilterPlayer filter = new FilterPlayer("player who controls more lands than you do and is his your opponent"); + static { filter.add(new OathOfLiegesPredicate()); } @@ -62,9 +64,8 @@ public class OathOfLieges extends CardImpl { super(ownerId, 11, "Oath of Lieges", Rarity.RARE, new CardType[]{CardType.ENCHANTMENT}, "{1}{W}"); this.expansionSetCode = "EXO"; - // At the beginning of each player's upkeep, that player chooses target player who controls more lands than he or she does and is his or her opponent. The first player may search his or her library for a basic land card, put that card onto the battlefield, then shuffle his or her library. - Effect effect = new SearchLibraryPutInPlayEffect(new TargetCardInLibrary(new FilterBasicLandCard()), false, Outcome.PutLandInPlay); + Effect effect = new SearchLibraryPutInPlayTargetPlayerEffect(new TargetCardInLibrary(new FilterBasicLandCard()), false, Outcome.PutLandInPlay); effect.setText("that player chooses target player who controls more lands than he or she does and is his or her opponent. The first player may search his or her library for a basic land card, put that card onto the battlefield, then shuffle his or her library"); Ability ability = new BeginningOfUpkeepTriggeredAbility(effect, TargetController.ANY, true); ability.addTarget(new TargetPlayer(1, 1, false, filter)); @@ -74,16 +75,21 @@ public class OathOfLieges extends CardImpl { public OathOfLieges(final OathOfLieges card) { super(card); } - + @Override public void adjustTargets(Ability ability, Game game) { if (ability instanceof BeginningOfUpkeepTriggeredAbility) { Player activePlayer = game.getPlayer(game.getActivePlayerId()); if (activePlayer != null) { - ability.setControllerId(activePlayer.getId()); ability.getTargets().clear(); TargetPlayer target = new TargetPlayer(1, 1, false, filter); + target.setTargetController(activePlayer.getId()); ability.getTargets().add(target); + for (Effect effect : ability.getEffects()) { + if (effect instanceof SearchLibraryPutInPlayTargetPlayerEffect) { + effect.setTargetPointer(new FixedTarget(activePlayer.getId())); + } + } } } } @@ -119,4 +125,4 @@ class OathOfLiegesPredicate implements ObjectSourcePlayerPredicate abilities, Game game) { if (!choices.isEmpty()) { @@ -1891,11 +1915,6 @@ public class TestPlayer implements Player { return computerPlayer.choose(outcome, cards, target, game); } - @Override - public boolean chooseTarget(Outcome outcome, Cards cards, TargetCard target, Ability source, Game game) { - return computerPlayer.chooseTarget(outcome, cards, target, source, game); - } - @Override public boolean chooseTargetAmount(Outcome outcome, TargetAmount target, Ability source, Game game) { return computerPlayer.chooseTargetAmount(outcome, target, source, game); diff --git a/Mage/src/mage/game/GameImpl.java b/Mage/src/mage/game/GameImpl.java index 27abfa58db1..f67b6387437 100644 --- a/Mage/src/mage/game/GameImpl.java +++ b/Mage/src/mage/game/GameImpl.java @@ -1467,7 +1467,7 @@ public abstract class GameImpl implements Game, Serializable { } else { TriggeredAbility newAbility = ability.copy(); newAbility.newId(); - // Too early, becuase no targets set yet !!!!!!!!!!! + // Too early, because no targets set yet !!!!!!!!!!! for (Effect effect : newAbility.getEffects()) { effect.getTargetPointer().init(this, newAbility); } From 00f48b005d5e9772456fc78aa4d073b1cb23108c Mon Sep 17 00:00:00 2001 From: LevelX2 Date: Mon, 12 Oct 2015 23:50:29 +0200 Subject: [PATCH 079/268] Added test. --- .../sets/avacynrestored/DevastationTide.java | 27 ++++--- .../abilities/other/DevastationTideTest.java | 77 +++++++++++++++++++ 2 files changed, 95 insertions(+), 9 deletions(-) create mode 100644 Mage.Tests/src/test/java/org/mage/test/cards/abilities/other/DevastationTideTest.java diff --git a/Mage.Sets/src/mage/sets/avacynrestored/DevastationTide.java b/Mage.Sets/src/mage/sets/avacynrestored/DevastationTide.java index 2a13b1ecf80..126fc303e65 100644 --- a/Mage.Sets/src/mage/sets/avacynrestored/DevastationTide.java +++ b/Mage.Sets/src/mage/sets/avacynrestored/DevastationTide.java @@ -27,20 +27,23 @@ */ package mage.sets.avacynrestored; +import java.util.LinkedHashSet; +import java.util.Set; import java.util.UUID; -import mage.constants.CardType; -import mage.constants.Outcome; -import mage.constants.Rarity; -import mage.constants.Zone; import mage.abilities.Ability; import mage.abilities.costs.mana.ManaCostsImpl; import mage.abilities.effects.OneShotEffect; import mage.abilities.keyword.MiracleAbility; +import mage.cards.Card; import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.Outcome; +import mage.constants.Rarity; +import mage.constants.Zone; import mage.filter.common.FilterNonlandPermanent; import mage.game.Game; import mage.game.permanent.Permanent; - +import mage.players.Player; /** * @@ -52,7 +55,6 @@ public class DevastationTide extends CardImpl { super(ownerId, 48, "Devastation Tide", Rarity.RARE, new CardType[]{CardType.SORCERY}, "{3}{U}{U}"); this.expansionSetCode = "AVR"; - // Return all nonland permanents to their owners' hands. this.getSpellAbility().addEffect(new DevastationTideEffect()); @@ -83,10 +85,17 @@ class DevastationTideEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { - for (Permanent creature : game.getBattlefield().getActivePermanents(new FilterNonlandPermanent(), source.getControllerId(), source.getSourceId(), game)) { - creature.moveToZone(Zone.HAND, source.getSourceId(), game, true); + Player controller = game.getPlayer(source.getControllerId()); + if (controller != null) { + Set cardsToHand = new LinkedHashSet<>(); + for (Permanent permanent : game.getBattlefield().getActivePermanents(new FilterNonlandPermanent(), source.getControllerId(), source.getSourceId(), game)) { + cardsToHand.add((Card) permanent); + } + controller.moveCards(cardsToHand, null, Zone.HAND, source, game); + return true; + } - return true; + return false; } @Override diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/abilities/other/DevastationTideTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/abilities/other/DevastationTideTest.java new file mode 100644 index 00000000000..e9ddc239d89 --- /dev/null +++ b/Mage.Tests/src/test/java/org/mage/test/cards/abilities/other/DevastationTideTest.java @@ -0,0 +1,77 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package org.mage.test.cards.abilities.other; + +import mage.constants.PhaseStep; +import mage.constants.Zone; +import org.junit.Test; +import org.mage.test.serverside.base.CardTestPlayerBase; + +/** + * + * @author LevelX2 + */ +public class DevastationTideTest extends CardTestPlayerBase { + + @Test + public void testReturnNonLandPermanents() { + addCard(Zone.BATTLEFIELD, playerA, "Island", 4); + addCard(Zone.HAND, playerA, "Devastation Tide"); // {3}{U}{U} + + addCard(Zone.BATTLEFIELD, playerA, "Silvercoat Lion"); // Creature + addCard(Zone.BATTLEFIELD, playerA, "Vampiric Rites"); // Enchantment + addCard(Zone.BATTLEFIELD, playerA, "Hedron Archive"); // Artifact + addCard(Zone.BATTLEFIELD, playerA, "Karn Liberated"); // Planeswalker + addCard(Zone.BATTLEFIELD, playerA, "Nimbus Maze", 1); // Land + + addCard(Zone.BATTLEFIELD, playerB, "Silvercoat Lion"); // Creature + addCard(Zone.BATTLEFIELD, playerB, "Vampiric Rites"); // Enchantment + addCard(Zone.BATTLEFIELD, playerB, "Hedron Archive"); // Artifact + addCard(Zone.BATTLEFIELD, playerB, "Karn Liberated"); // Planeswalker + addCard(Zone.BATTLEFIELD, playerB, "Nimbus Maze", 1); // Land + + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Devastation Tide"); + + setStopAt(1, PhaseStep.BEGIN_COMBAT); + execute(); + + assertHandCount(playerA, "Silvercoat Lion", 1); + assertHandCount(playerA, "Vampiric Rites", 1); + assertHandCount(playerA, "Hedron Archive", 1); + assertHandCount(playerA, "Karn Liberated", 1); + assertHandCount(playerA, "Nimbus Maze", 0); + + assertHandCount(playerB, "Silvercoat Lion", 1); + assertHandCount(playerB, "Vampiric Rites", 1); + assertHandCount(playerB, "Hedron Archive", 1); + assertHandCount(playerB, "Karn Liberated", 1); + assertHandCount(playerB, "Nimbus Maze", 0); + + } + +} From f9a70d287118e73a423ea9cb684fb4ccca97b689 Mon Sep 17 00:00:00 2001 From: LevelX2 Date: Tue, 13 Oct 2015 00:28:05 +0200 Subject: [PATCH 080/268] Added Hostility card. --- .../anthologyjacevschandra/Hostility.java | 52 +++++++ .../mage/sets/jacevschandra/Hostility.java | 145 ++++++++++++++++++ Mage.Sets/src/mage/sets/lorwyn/Hostility.java | 52 +++++++ 3 files changed, 249 insertions(+) create mode 100644 Mage.Sets/src/mage/sets/anthologyjacevschandra/Hostility.java create mode 100644 Mage.Sets/src/mage/sets/jacevschandra/Hostility.java create mode 100644 Mage.Sets/src/mage/sets/lorwyn/Hostility.java diff --git a/Mage.Sets/src/mage/sets/anthologyjacevschandra/Hostility.java b/Mage.Sets/src/mage/sets/anthologyjacevschandra/Hostility.java new file mode 100644 index 00000000000..3c8621e98e7 --- /dev/null +++ b/Mage.Sets/src/mage/sets/anthologyjacevschandra/Hostility.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.anthologyjacevschandra; + +import java.util.UUID; + +/** + * + * @author LevelX2 + */ +public class Hostility extends mage.sets.jacevschandra.Hostility { + + public Hostility(UUID ownerId) { + super(ownerId); + this.cardNumber = 48; + this.expansionSetCode = "DD3"; + } + + public Hostility(final Hostility card) { + super(card); + } + + @Override + public Hostility copy() { + return new Hostility(this); + } +} diff --git a/Mage.Sets/src/mage/sets/jacevschandra/Hostility.java b/Mage.Sets/src/mage/sets/jacevschandra/Hostility.java new file mode 100644 index 00000000000..a4e68652263 --- /dev/null +++ b/Mage.Sets/src/mage/sets/jacevschandra/Hostility.java @@ -0,0 +1,145 @@ +/* + * 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.jacevschandra; + +import java.util.Arrays; +import java.util.UUID; +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.PutIntoGraveFromAnywhereSourceTriggeredAbility; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.effects.PreventionEffectData; +import mage.abilities.effects.PreventionEffectImpl; +import mage.abilities.effects.common.CreateTokenEffect; +import mage.abilities.effects.common.ShuffleIntoLibrarySourceEffect; +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.game.Game; +import mage.game.events.GameEvent; +import mage.game.permanent.token.Token; + +/** + * + * @author LevelX2 + */ +public class Hostility extends CardImpl { + + public Hostility(UUID ownerId) { + super(ownerId, 48, "Hostility", Rarity.RARE, new CardType[]{CardType.CREATURE}, "{3}{R}{R}{R}"); + this.expansionSetCode = "DD2"; + this.subtype.add("Elemental"); + this.subtype.add("Incarnation"); + this.power = new MageInt(6); + this.toughness = new MageInt(6); + + // Haste + this.addAbility(HasteAbility.getInstance()); + + // If a spell you control would deal damage to an opponent, prevent that damage. + // Put a 3/1 red Elemental Shaman creature token with haste onto the battlefield for each 1 damage prevented this way. + this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new HostilityEffect())); + + // When Hostility is put into a graveyard from anywhere, shuffle it into its owner's library. + this.addAbility(new PutIntoGraveFromAnywhereSourceTriggeredAbility(new ShuffleIntoLibrarySourceEffect())); + } + + public Hostility(final Hostility card) { + super(card); + } + + @Override + public Hostility copy() { + return new Hostility(this); + } +} + +class HostilityEffect extends PreventionEffectImpl { + + public HostilityEffect() { + super(Duration.WhileOnBattlefield, Integer.MAX_VALUE, false, false); + staticText = "If a spell you control would deal damage to an opponent, prevent that damage. Put a 3/1 red Elemental Shaman creature token with haste onto the battlefield for each 1 damage prevented this way."; + } + + public HostilityEffect(final HostilityEffect effect) { + super(effect); + } + + @Override + public HostilityEffect copy() { + return new HostilityEffect(this); + } + + @Override + public boolean checksEventType(GameEvent event, Game game) { + switch (event.getType()) { + case DAMAGE_PLAYER: + return true; + } + return false; + } + + @Override + public boolean applies(GameEvent event, Ability source, Game game) { + if (super.applies(event, source, game)) { + if (game.getOpponents(source.getControllerId()).contains(event.getTargetId())) { + return true; + } + } + return false; + } + + @Override + public boolean replaceEvent(GameEvent event, Ability source, Game game) { + PreventionEffectData preventionEffectData = preventDamageAction(event, source, game); + if (preventionEffectData.getPreventedDamage() > 0) { + new CreateTokenEffect(new HostilityElementalToken(), preventionEffectData.getPreventedDamage()).apply(game, source); + } + return true; + } +} + +class HostilityElementalToken extends Token { + + public HostilityElementalToken() { + super("Elemental Shaman", "3/1 red Elemental Shaman creature token with haste"); + availableImageSetCodes.addAll(Arrays.asList("LRW", "DD2")); + cardType.add(CardType.CREATURE); + color.setRed(true); + subtype.add("Elemental"); + subtype.add("Shaman"); + power = new MageInt(3); + toughness = new MageInt(1); + + addAbility(HasteAbility.getInstance()); + } + +} diff --git a/Mage.Sets/src/mage/sets/lorwyn/Hostility.java b/Mage.Sets/src/mage/sets/lorwyn/Hostility.java new file mode 100644 index 00000000000..b309e8f73ad --- /dev/null +++ b/Mage.Sets/src/mage/sets/lorwyn/Hostility.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.lorwyn; + +import java.util.UUID; + +/** + * + * @author LevelX2 + */ +public class Hostility extends mage.sets.jacevschandra.Hostility { + + public Hostility(UUID ownerId) { + super(ownerId); + this.cardNumber = 176; + this.expansionSetCode = "LRW"; + } + + public Hostility(final Hostility card) { + super(card); + } + + @Override + public Hostility copy() { + return new Hostility(this); + } +} From c73e080264b28d3191381bc844dc6fe5af46b725 Mon Sep 17 00:00:00 2001 From: LoneFox Date: Tue, 13 Oct 2015 08:03:39 +0300 Subject: [PATCH 081/268] Fix ExileFromZoneTargetEffect text generation --- .../abilities/effects/common/ExileFromZoneTargetEffect.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Mage/src/mage/abilities/effects/common/ExileFromZoneTargetEffect.java b/Mage/src/mage/abilities/effects/common/ExileFromZoneTargetEffect.java index 028237b01cf..654c49ea41e 100644 --- a/Mage/src/mage/abilities/effects/common/ExileFromZoneTargetEffect.java +++ b/Mage/src/mage/abilities/effects/common/ExileFromZoneTargetEffect.java @@ -111,6 +111,6 @@ public class ExileFromZoneTargetEffect extends OneShotEffect { } private void setText() { - staticText = "target player exiles " + CardUtil.numberToText(exileName, "a") + filter.getMessage() + " from his or her " + zone.toString().toLowerCase(); + staticText = "target player exiles " + CardUtil.numberToText(amount, "a") + " " + filter.getMessage() + " from his or her " + zone.toString().toLowerCase(); } } From 83c2882613a8466264b2a9ce66b2188672e9b799 Mon Sep 17 00:00:00 2001 From: LoneFox Date: Tue, 13 Oct 2015 08:03:56 +0300 Subject: [PATCH 082/268] Fix a couple of incorrect set codes --- Mage.Sets/src/mage/sets/anthologyjacevschandra/Hostility.java | 2 +- Mage.Sets/src/mage/sets/anthologyjacevschandra/Ophidian.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Mage.Sets/src/mage/sets/anthologyjacevschandra/Hostility.java b/Mage.Sets/src/mage/sets/anthologyjacevschandra/Hostility.java index 3c8621e98e7..4769a6c8b3b 100644 --- a/Mage.Sets/src/mage/sets/anthologyjacevschandra/Hostility.java +++ b/Mage.Sets/src/mage/sets/anthologyjacevschandra/Hostility.java @@ -38,7 +38,7 @@ public class Hostility extends mage.sets.jacevschandra.Hostility { public Hostility(UUID ownerId) { super(ownerId); this.cardNumber = 48; - this.expansionSetCode = "DD3"; + this.expansionSetCode = "DD3D"; } public Hostility(final Hostility card) { diff --git a/Mage.Sets/src/mage/sets/anthologyjacevschandra/Ophidian.java b/Mage.Sets/src/mage/sets/anthologyjacevschandra/Ophidian.java index 3816fda1c85..bf513964994 100644 --- a/Mage.Sets/src/mage/sets/anthologyjacevschandra/Ophidian.java +++ b/Mage.Sets/src/mage/sets/anthologyjacevschandra/Ophidian.java @@ -38,7 +38,7 @@ public class Ophidian extends mage.sets.vintagemasters.Ophidian { public Ophidian(UUID ownerId) { super(ownerId); this.cardNumber = 9; - this.expansionSetCode = "DD3"; + this.expansionSetCode = "DD3D"; } public Ophidian(final Ophidian card) { From 9ba29218ba761b6da26e505619e542cf93d00f28 Mon Sep 17 00:00:00 2001 From: LoneFox Date: Tue, 13 Oct 2015 10:02:42 +0300 Subject: [PATCH 083/268] Implement cards: Quicksilver Wall, Ribbon Snake, Vintara Elephant, and Zerapa Minotaur --- .../mage/sets/prophecy/QuicksilverWall.java | 75 +++++++++++++++++++ .../src/mage/sets/prophecy/RibbonSnake.java | 75 +++++++++++++++++++ .../mage/sets/prophecy/VintaraElephant.java | 75 +++++++++++++++++++ .../mage/sets/prophecy/ZerapaMinotaur.java | 75 +++++++++++++++++++ .../continuous/LoseAbilitySourceEffect.java | 16 ++-- 5 files changed, 308 insertions(+), 8 deletions(-) create mode 100644 Mage.Sets/src/mage/sets/prophecy/QuicksilverWall.java create mode 100644 Mage.Sets/src/mage/sets/prophecy/RibbonSnake.java create mode 100644 Mage.Sets/src/mage/sets/prophecy/VintaraElephant.java create mode 100644 Mage.Sets/src/mage/sets/prophecy/ZerapaMinotaur.java diff --git a/Mage.Sets/src/mage/sets/prophecy/QuicksilverWall.java b/Mage.Sets/src/mage/sets/prophecy/QuicksilverWall.java new file mode 100644 index 00000000000..21a43d9f3c0 --- /dev/null +++ b/Mage.Sets/src/mage/sets/prophecy/QuicksilverWall.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.prophecy; + +import java.util.UUID; +import mage.MageInt; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.effects.common.InfoEffect; +import mage.abilities.effects.common.ReturnToHandSourceEffect; +import mage.abilities.keyword.DefenderAbility; +import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.Rarity; +import mage.constants.TargetController; +import mage.constants.Zone; + +/** + * + * @author LoneFox + */ +public class QuicksilverWall extends CardImpl { + + public QuicksilverWall(UUID ownerId) { + super(ownerId, 41, "Quicksilver Wall", Rarity.UNCOMMON, new CardType[]{CardType.CREATURE}, "{2}{U}"); + this.expansionSetCode = "PCY"; + this.subtype.add("Wall"); + this.power = new MageInt(1); + this.toughness = new MageInt(6); + + // Defender + this.addAbility(DefenderAbility.getInstance()); + // {4}: Return Quicksilver Wall to its owner's hand. Any player may activate this ability. + SimpleActivatedAbility ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, + new ReturnToHandSourceEffect(true), new ManaCostsImpl("{4}")); + ability.setMayActivate(TargetController.ANY); + ability.addEffect(new InfoEffect("Any player may activate this ability")); + this.addAbility(ability); + } + + public QuicksilverWall(final QuicksilverWall card) { + super(card); + } + + @Override + public QuicksilverWall copy() { + return new QuicksilverWall(this); + } +} diff --git a/Mage.Sets/src/mage/sets/prophecy/RibbonSnake.java b/Mage.Sets/src/mage/sets/prophecy/RibbonSnake.java new file mode 100644 index 00000000000..4e4829f4dc6 --- /dev/null +++ b/Mage.Sets/src/mage/sets/prophecy/RibbonSnake.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.prophecy; + +import java.util.UUID; +import mage.MageInt; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.effects.common.InfoEffect; +import mage.abilities.effects.common.continuous.LoseAbilitySourceEffect; +import mage.abilities.keyword.FlyingAbility; +import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.Rarity; +import mage.constants.TargetController; +import mage.constants.Zone; + +/** + * + * @author LoneFox + */ +public class RibbonSnake extends CardImpl { + + public RibbonSnake(UUID ownerId) { + super(ownerId, 46, "Ribbon Snake", Rarity.COMMON, new CardType[]{CardType.CREATURE}, "{1}{U}{U}"); + this.expansionSetCode = "PCY"; + this.subtype.add("Snake"); + this.power = new MageInt(2); + this.toughness = new MageInt(3); + + // Flying + this.addAbility(FlyingAbility.getInstance()); + // {2}: Ribbon Snake loses flying until end of turn. Any player may activate this ability. + SimpleActivatedAbility ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new LoseAbilitySourceEffect( + FlyingAbility.getInstance(), Duration.EndOfTurn), new ManaCostsImpl("{2}")); + ability.setMayActivate(TargetController.ANY); + ability.addEffect(new InfoEffect("Any player may activate this ability")); + this.addAbility(ability); + } + + public RibbonSnake(final RibbonSnake card) { + super(card); + } + + @Override + public RibbonSnake copy() { + return new RibbonSnake(this); + } +} diff --git a/Mage.Sets/src/mage/sets/prophecy/VintaraElephant.java b/Mage.Sets/src/mage/sets/prophecy/VintaraElephant.java new file mode 100644 index 00000000000..1e70c6836b7 --- /dev/null +++ b/Mage.Sets/src/mage/sets/prophecy/VintaraElephant.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.prophecy; + +import java.util.UUID; +import mage.MageInt; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.effects.common.InfoEffect; +import mage.abilities.effects.common.continuous.LoseAbilitySourceEffect; +import mage.abilities.keyword.TrampleAbility; +import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.Rarity; +import mage.constants.TargetController; +import mage.constants.Zone; + +/** + * + * @author LoneFox + */ +public class VintaraElephant extends CardImpl { + + public VintaraElephant(UUID ownerId) { + super(ownerId, 131, "Vintara Elephant", Rarity.COMMON, new CardType[]{CardType.CREATURE}, "{4}{G}"); + this.expansionSetCode = "PCY"; + this.subtype.add("Elephant"); + this.power = new MageInt(4); + this.toughness = new MageInt(3); + + // Trample + this.addAbility(TrampleAbility.getInstance()); + // {3}: Vintara Elephant loses trample until end of turn. Any player may activate this ability. + SimpleActivatedAbility ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new LoseAbilitySourceEffect( + TrampleAbility.getInstance(), Duration.EndOfTurn), new ManaCostsImpl("{3}")); + ability.setMayActivate(TargetController.ANY); + ability.addEffect(new InfoEffect("Any player may activate this ability")); + this.addAbility(ability); + } + + public VintaraElephant(final VintaraElephant card) { + super(card); + } + + @Override + public VintaraElephant copy() { + return new VintaraElephant(this); + } +} diff --git a/Mage.Sets/src/mage/sets/prophecy/ZerapaMinotaur.java b/Mage.Sets/src/mage/sets/prophecy/ZerapaMinotaur.java new file mode 100644 index 00000000000..6000fde3df3 --- /dev/null +++ b/Mage.Sets/src/mage/sets/prophecy/ZerapaMinotaur.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.prophecy; + +import java.util.UUID; +import mage.MageInt; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.effects.common.InfoEffect; +import mage.abilities.effects.common.continuous.LoseAbilitySourceEffect; +import mage.abilities.keyword.FirstStrikeAbility; +import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.Rarity; +import mage.constants.TargetController; +import mage.constants.Zone; + +/** + * + * @author LoneFox + */ +public class ZerapaMinotaur extends CardImpl { + + public ZerapaMinotaur(UUID ownerId) { + super(ownerId, 108, "Zerapa Minotaur", Rarity.COMMON, new CardType[]{CardType.CREATURE}, "{2}{R}{R}"); + this.expansionSetCode = "PCY"; + this.subtype.add("Minotaur"); + this.power = new MageInt(3); + this.toughness = new MageInt(3); + + // First strike + this.addAbility(FirstStrikeAbility.getInstance()); + // {2}: Zerapa Minotaur loses first strike until end of turn. Any player may activate this ability. + SimpleActivatedAbility ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new LoseAbilitySourceEffect( + FirstStrikeAbility.getInstance(), Duration.EndOfTurn), new ManaCostsImpl("{2}")); + ability.setMayActivate(TargetController.ANY); + ability.addEffect(new InfoEffect("Any player may activate this ability")); + this.addAbility(ability); + } + + public ZerapaMinotaur(final ZerapaMinotaur card) { + super(card); + } + + @Override + public ZerapaMinotaur copy() { + return new ZerapaMinotaur(this); + } +} diff --git a/Mage/src/mage/abilities/effects/common/continuous/LoseAbilitySourceEffect.java b/Mage/src/mage/abilities/effects/common/continuous/LoseAbilitySourceEffect.java index 2c898399a06..785420e329c 100644 --- a/Mage/src/mage/abilities/effects/common/continuous/LoseAbilitySourceEffect.java +++ b/Mage/src/mage/abilities/effects/common/continuous/LoseAbilitySourceEffect.java @@ -17,36 +17,36 @@ import mage.game.permanent.Permanent; * @author Noahsark */ public class LoseAbilitySourceEffect extends ContinuousEffectImpl{ - + protected Ability ability; - + public LoseAbilitySourceEffect(Ability ability){ this(ability, Duration.WhileOnBattlefield); } - + public LoseAbilitySourceEffect(Ability ability, Duration duration){ super(duration, Layer.AbilityAddingRemovingEffects_6, SubLayer.NA, Outcome.LoseAbility); this.ability = ability; - staticText = "{this} loses " + ability.getRule() + duration.toString(); + staticText = "{this} loses " + ability.getRule() + " " + duration.toString(); } - + public LoseAbilitySourceEffect(final LoseAbilitySourceEffect effect){ super(effect); this.ability = effect.ability.copy(); } - + @Override public LoseAbilitySourceEffect copy(){ return new LoseAbilitySourceEffect(this); } - + @Override public boolean apply(Game game, Ability source){ Permanent permanent = game.getPermanent(source.getSourceId()); if (permanent != null){ // 112.10 while (permanent.getAbilities().remove(ability)) { - + } } return true; From 534ad5eb9d154ef8b992ba08ab5207fb0233eae2 Mon Sep 17 00:00:00 2001 From: LoneFox Date: Tue, 13 Oct 2015 10:29:08 +0300 Subject: [PATCH 084/268] Implement cards: Fen Stalker, Scoria Cat, Spur Grappler, and Vintara Snapper --- .../src/mage/sets/prophecy/FenStalker.java | 81 +++++++++++++++++++ .../src/mage/sets/prophecy/ScoriaCat.java | 80 ++++++++++++++++++ .../src/mage/sets/prophecy/SpurGrappler.java | 80 ++++++++++++++++++ .../mage/sets/prophecy/VintaraSnapper.java | 81 +++++++++++++++++++ 4 files changed, 322 insertions(+) create mode 100644 Mage.Sets/src/mage/sets/prophecy/FenStalker.java create mode 100644 Mage.Sets/src/mage/sets/prophecy/ScoriaCat.java create mode 100644 Mage.Sets/src/mage/sets/prophecy/SpurGrappler.java create mode 100644 Mage.Sets/src/mage/sets/prophecy/VintaraSnapper.java diff --git a/Mage.Sets/src/mage/sets/prophecy/FenStalker.java b/Mage.Sets/src/mage/sets/prophecy/FenStalker.java new file mode 100644 index 00000000000..9a573268b67 --- /dev/null +++ b/Mage.Sets/src/mage/sets/prophecy/FenStalker.java @@ -0,0 +1,81 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.sets.prophecy; + +import java.util.UUID; +import mage.MageInt; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.condition.InvertCondition; +import mage.abilities.condition.common.PermanentsOnTheBattlefieldCondition; +import mage.abilities.decorator.ConditionalContinuousEffect; +import mage.abilities.effects.common.continuous.GainAbilitySourceEffect; +import mage.abilities.keyword.FearAbility; +import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.Rarity; +import mage.constants.Zone; +import mage.filter.common.FilterControlledLandPermanent; +import mage.filter.predicate.Predicates; +import mage.filter.predicate.permanent.TappedPredicate; + +/** + * + * @author LoneFox + */ +public class FenStalker extends CardImpl { + + private static final FilterControlledLandPermanent filter = new FilterControlledLandPermanent(); + + static { + filter.add(Predicates.not(new TappedPredicate())); + } + + public FenStalker(UUID ownerId) { + super(ownerId, 64, "Fen Stalker", Rarity.COMMON, new CardType[]{CardType.CREATURE}, "{3}{B}"); + this.expansionSetCode = "PCY"; + this.subtype.add("Nightstalker"); + this.power = new MageInt(3); + this.toughness = new MageInt(2); + + // Fen Stalker has fear as long as you control no untapped lands. + this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, + new ConditionalContinuousEffect(new GainAbilitySourceEffect(FearAbility.getInstance(), + Duration.WhileOnBattlefield), new InvertCondition(new PermanentsOnTheBattlefieldCondition(filter)), + "{this} has fear as long as you control no untapped lands"))); + } + + public FenStalker(final FenStalker card) { + super(card); + } + + @Override + public FenStalker copy() { + return new FenStalker(this); + } +} diff --git a/Mage.Sets/src/mage/sets/prophecy/ScoriaCat.java b/Mage.Sets/src/mage/sets/prophecy/ScoriaCat.java new file mode 100644 index 00000000000..1d7e4438ddf --- /dev/null +++ b/Mage.Sets/src/mage/sets/prophecy/ScoriaCat.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.prophecy; + +import java.util.UUID; +import mage.MageInt; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.condition.InvertCondition; +import mage.abilities.condition.common.PermanentsOnTheBattlefieldCondition; +import mage.abilities.decorator.ConditionalContinuousEffect; +import mage.abilities.effects.common.continuous.BoostSourceEffect; +import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.Rarity; +import mage.constants.Zone; +import mage.filter.common.FilterControlledLandPermanent; +import mage.filter.predicate.Predicates; +import mage.filter.predicate.permanent.TappedPredicate; + +/** + * + * @author LoneFox + */ +public class ScoriaCat extends CardImpl { + + private static final FilterControlledLandPermanent filter = new FilterControlledLandPermanent(); + + static { + filter.add(Predicates.not(new TappedPredicate())); + } + + public ScoriaCat(UUID ownerId) { + super(ownerId, 101, "Scoria Cat", Rarity.UNCOMMON, new CardType[]{CardType.CREATURE}, "{3}{R}{R}"); + this.expansionSetCode = "PCY"; + this.subtype.add("Cat"); + this.power = new MageInt(3); + this.toughness = new MageInt(3); + + // Scoria Cat gets +3/+3 as long as you control no untapped lands. + this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, + new ConditionalContinuousEffect(new BoostSourceEffect(3, 3, Duration.WhileOnBattlefield), + new InvertCondition(new PermanentsOnTheBattlefieldCondition(filter)), + "{this} gets +3/+3 as long as you control no untapped lands"))); + } + + public ScoriaCat(final ScoriaCat card) { + super(card); + } + + @Override + public ScoriaCat copy() { + return new ScoriaCat(this); + } +} diff --git a/Mage.Sets/src/mage/sets/prophecy/SpurGrappler.java b/Mage.Sets/src/mage/sets/prophecy/SpurGrappler.java new file mode 100644 index 00000000000..204a883999c --- /dev/null +++ b/Mage.Sets/src/mage/sets/prophecy/SpurGrappler.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.prophecy; + +import java.util.UUID; +import mage.MageInt; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.condition.InvertCondition; +import mage.abilities.condition.common.PermanentsOnTheBattlefieldCondition; +import mage.abilities.decorator.ConditionalContinuousEffect; +import mage.abilities.effects.common.continuous.BoostSourceEffect; +import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.Rarity; +import mage.constants.Zone; +import mage.filter.common.FilterControlledLandPermanent; +import mage.filter.predicate.Predicates; +import mage.filter.predicate.permanent.TappedPredicate; + +/** + * + * @author LoneFox + */ +public class SpurGrappler extends CardImpl { + + private static final FilterControlledLandPermanent filter = new FilterControlledLandPermanent(); + + static { + filter.add(Predicates.not(new TappedPredicate())); + } + + public SpurGrappler(UUID ownerId) { + super(ownerId, 104, "Spur Grappler", Rarity.COMMON, new CardType[]{CardType.CREATURE}, "{2}{R}"); + this.expansionSetCode = "PCY"; + this.subtype.add("Beast"); + this.power = new MageInt(2); + this.toughness = new MageInt(1); + + // Spur Grappler gets +2/+1 as long as you control no untapped lands. + this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, + new ConditionalContinuousEffect(new BoostSourceEffect(2, 1, Duration.WhileOnBattlefield), + new InvertCondition(new PermanentsOnTheBattlefieldCondition(filter)), + "{this} gets +2/+1 as long as you control no untapped lands"))); + } + + public SpurGrappler(final SpurGrappler card) { + super(card); + } + + @Override + public SpurGrappler copy() { + return new SpurGrappler(this); + } +} diff --git a/Mage.Sets/src/mage/sets/prophecy/VintaraSnapper.java b/Mage.Sets/src/mage/sets/prophecy/VintaraSnapper.java new file mode 100644 index 00000000000..ba9f95908b0 --- /dev/null +++ b/Mage.Sets/src/mage/sets/prophecy/VintaraSnapper.java @@ -0,0 +1,81 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.sets.prophecy; + +import java.util.UUID; +import mage.MageInt; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.condition.InvertCondition; +import mage.abilities.condition.common.PermanentsOnTheBattlefieldCondition; +import mage.abilities.decorator.ConditionalContinuousEffect; +import mage.abilities.effects.common.continuous.GainAbilitySourceEffect; +import mage.abilities.keyword.ShroudAbility; +import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.Rarity; +import mage.constants.Zone; +import mage.filter.common.FilterControlledLandPermanent; +import mage.filter.predicate.Predicates; +import mage.filter.predicate.permanent.TappedPredicate; + +/** + * + * @author LoneFox + */ +public class VintaraSnapper extends CardImpl { + + private static final FilterControlledLandPermanent filter = new FilterControlledLandPermanent(); + + static { + filter.add(Predicates.not(new TappedPredicate())); + } + + public VintaraSnapper(UUID ownerId) { + super(ownerId, 132, "Vintara Snapper", Rarity.UNCOMMON, new CardType[]{CardType.CREATURE}, "{G}{G}"); + this.expansionSetCode = "PCY"; + this.subtype.add("Turtle"); + this.power = new MageInt(2); + this.toughness = new MageInt(2); + + // Vintara Snapper has shroud as long as you control no untapped lands. + this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, + new ConditionalContinuousEffect(new GainAbilitySourceEffect(ShroudAbility.getInstance(), + Duration.WhileOnBattlefield), new InvertCondition(new PermanentsOnTheBattlefieldCondition(filter)), + "{this} has shroud as long as you control no untapped lands"))); + } + + public VintaraSnapper(final VintaraSnapper card) { + super(card); + } + + @Override + public VintaraSnapper copy() { + return new VintaraSnapper(this); + } +} From 8ed807fbc39d8c8c8ac320b58d38df983a764150 Mon Sep 17 00:00:00 2001 From: LoneFox Date: Tue, 13 Oct 2015 11:07:23 +0300 Subject: [PATCH 085/268] Implement cards: Devastate, Noxious Field, Silt Crawler, and Troublesome Spirit --- .../src/mage/sets/prophecy/Devastate.java | 62 ++++++++++++++ .../src/mage/sets/prophecy/NoxiousField.java | 82 +++++++++++++++++++ .../src/mage/sets/prophecy/SiltCrawler.java | 64 +++++++++++++++ .../mage/sets/prophecy/TroublesomeSpirit.java | 68 +++++++++++++++ 4 files changed, 276 insertions(+) create mode 100644 Mage.Sets/src/mage/sets/prophecy/Devastate.java create mode 100644 Mage.Sets/src/mage/sets/prophecy/NoxiousField.java create mode 100644 Mage.Sets/src/mage/sets/prophecy/SiltCrawler.java create mode 100644 Mage.Sets/src/mage/sets/prophecy/TroublesomeSpirit.java diff --git a/Mage.Sets/src/mage/sets/prophecy/Devastate.java b/Mage.Sets/src/mage/sets/prophecy/Devastate.java new file mode 100644 index 00000000000..20068f5e1bd --- /dev/null +++ b/Mage.Sets/src/mage/sets/prophecy/Devastate.java @@ -0,0 +1,62 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.sets.prophecy; + +import java.util.UUID; +import mage.abilities.effects.common.DamageEverythingEffect; +import mage.abilities.effects.common.DestroyTargetEffect; +import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.Rarity; +import mage.target.common.TargetLandPermanent; + +/** + * + * @author LoneFox + */ +public class Devastate extends CardImpl { + + public Devastate(UUID ownerId) { + super(ownerId, 87, "Devastate", Rarity.COMMON, new CardType[]{CardType.SORCERY}, "{3}{R}{R}"); + this.expansionSetCode = "PCY"; + + // Destroy target land. Devastate deals 1 damage to each creature and each player. + this.getSpellAbility().addEffect(new DestroyTargetEffect()); + this.getSpellAbility().addEffect(new DamageEverythingEffect(1)); + this.getSpellAbility().addTarget(new TargetLandPermanent()); + } + + public Devastate(final Devastate card) { + super(card); + } + + @Override + public Devastate copy() { + return new Devastate(this); + } +} diff --git a/Mage.Sets/src/mage/sets/prophecy/NoxiousField.java b/Mage.Sets/src/mage/sets/prophecy/NoxiousField.java new file mode 100644 index 00000000000..e3aa9bf82c0 --- /dev/null +++ b/Mage.Sets/src/mage/sets/prophecy/NoxiousField.java @@ -0,0 +1,82 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.sets.prophecy; + +import java.util.UUID; +import mage.abilities.Ability; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.costs.common.TapSourceCost; +import mage.abilities.effects.Effect; +import mage.abilities.effects.common.AttachEffect; +import mage.abilities.effects.common.DamageEverythingEffect; +import mage.abilities.effects.common.continuous.GainAbilityAttachedEffect; +import mage.abilities.keyword.EnchantAbility; +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.Zone; +import mage.target.TargetPermanent; +import mage.target.common.TargetLandPermanent; + +/** + * + * @author LoneFox + */ +public class NoxiousField extends CardImpl { + + public NoxiousField(UUID ownerId) { + super(ownerId, 70, "Noxious Field", Rarity.UNCOMMON, new CardType[]{CardType.ENCHANTMENT}, "{1}{B}{B}"); + this.expansionSetCode = "PCY"; + this.subtype.add("Aura"); + + // Enchant land + TargetPermanent auraTarget = new TargetLandPermanent(); + this.getSpellAbility().addTarget(auraTarget); + this.getSpellAbility().addEffect(new AttachEffect(Outcome.AddAbility)); + Ability ability = new EnchantAbility(auraTarget.getTargetName()); + this.addAbility(ability); + // Enchanted land has "{tap}: This land deals 1 damage to each creature and each player." + ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new DamageEverythingEffect(1), new TapSourceCost()); + Effect effect = new GainAbilityAttachedEffect(ability, AttachmentType.AURA); + effect.setText("Enchanted land has \"{T}: This land deals 1 damage to each creature and each player.\""); + this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, effect)); + } + + public NoxiousField(final NoxiousField card) { + super(card); + } + + @Override + public NoxiousField copy() { + return new NoxiousField(this); + } +} diff --git a/Mage.Sets/src/mage/sets/prophecy/SiltCrawler.java b/Mage.Sets/src/mage/sets/prophecy/SiltCrawler.java new file mode 100644 index 00000000000..177b90a0871 --- /dev/null +++ b/Mage.Sets/src/mage/sets/prophecy/SiltCrawler.java @@ -0,0 +1,64 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.sets.prophecy; + +import java.util.UUID; +import mage.MageInt; +import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.effects.common.TapAllEffect; +import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.Rarity; +import mage.filter.common.FilterControlledLandPermanent; + +/** + * + * @author LoneFox + */ +public class SiltCrawler extends CardImpl { + + public SiltCrawler(UUID ownerId) { + super(ownerId, 123, "Silt Crawler", Rarity.COMMON, new CardType[]{CardType.CREATURE}, "{2}{G}"); + this.expansionSetCode = "PCY"; + this.subtype.add("Beast"); + this.power = new MageInt(3); + this.toughness = new MageInt(3); + + // When Silt Crawler enters the battlefield, tap all lands you control. + this.addAbility(new EntersBattlefieldTriggeredAbility(new TapAllEffect(new FilterControlledLandPermanent("lands you control")), false)); + } + + public SiltCrawler(final SiltCrawler card) { + super(card); + } + + @Override + public SiltCrawler copy() { + return new SiltCrawler(this); + } +} diff --git a/Mage.Sets/src/mage/sets/prophecy/TroublesomeSpirit.java b/Mage.Sets/src/mage/sets/prophecy/TroublesomeSpirit.java new file mode 100644 index 00000000000..f3a6f6c58ce --- /dev/null +++ b/Mage.Sets/src/mage/sets/prophecy/TroublesomeSpirit.java @@ -0,0 +1,68 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.sets.prophecy; + +import java.util.UUID; +import mage.MageInt; +import mage.abilities.common.BeginningOfEndStepTriggeredAbility; +import mage.abilities.effects.common.TapAllEffect; +import mage.abilities.keyword.FlyingAbility; +import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.Rarity; +import mage.constants.TargetController; +import mage.filter.common.FilterControlledLandPermanent; + +/** + * + * @author LoneFox + */ +public class TroublesomeSpirit extends CardImpl { + + public TroublesomeSpirit(UUID ownerId) { + super(ownerId, 52, "Troublesome Spirit", Rarity.RARE, new CardType[]{CardType.CREATURE}, "{2}{U}{U}"); + this.expansionSetCode = "PCY"; + this.subtype.add("Spirit"); + this.power = new MageInt(3); + this.toughness = new MageInt(4); + + // Flying + this.addAbility(FlyingAbility.getInstance()); + // At the beginning of your end step, tap all lands you control. + this.addAbility(new BeginningOfEndStepTriggeredAbility(new TapAllEffect(new FilterControlledLandPermanent("lands you control")), TargetController.YOU, false)); + } + + public TroublesomeSpirit(final TroublesomeSpirit card) { + super(card); + } + + @Override + public TroublesomeSpirit copy() { + return new TroublesomeSpirit(this); + } +} From 86cd15476227bfbe92724e180032ad89999b6baa Mon Sep 17 00:00:00 2001 From: LoneFox Date: Tue, 13 Oct 2015 11:58:12 +0300 Subject: [PATCH 086/268] Implement cards: Mine Bearer, Sunken Field, Well of Discovery, and Well of Life --- .../src/mage/sets/prophecy/MineBearer.java | 72 ++++++++++++++++ .../src/mage/sets/prophecy/SunkenField.java | 85 +++++++++++++++++++ .../mage/sets/prophecy/WellOfDiscovery.java | 75 ++++++++++++++++ .../src/mage/sets/prophecy/WellOfLife.java | 74 ++++++++++++++++ 4 files changed, 306 insertions(+) create mode 100644 Mage.Sets/src/mage/sets/prophecy/MineBearer.java create mode 100644 Mage.Sets/src/mage/sets/prophecy/SunkenField.java create mode 100644 Mage.Sets/src/mage/sets/prophecy/WellOfDiscovery.java create mode 100644 Mage.Sets/src/mage/sets/prophecy/WellOfLife.java diff --git a/Mage.Sets/src/mage/sets/prophecy/MineBearer.java b/Mage.Sets/src/mage/sets/prophecy/MineBearer.java new file mode 100644 index 00000000000..f74f6b1f0b3 --- /dev/null +++ b/Mage.Sets/src/mage/sets/prophecy/MineBearer.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.prophecy; + +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.costs.common.TapSourceCost; +import mage.abilities.effects.common.DestroyTargetEffect; +import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.Rarity; +import mage.constants.Zone; +import mage.target.common.TargetAttackingCreature; + +/** + * + * @author LoneFox + */ +public class MineBearer extends CardImpl { + + public MineBearer(UUID ownerId) { + super(ownerId, 16, "Mine Bearer", Rarity.COMMON, new CardType[]{CardType.CREATURE}, "{2}{W}"); + this.expansionSetCode = "PCY"; + this.subtype.add("Human"); + this.subtype.add("Soldier"); + this.power = new MageInt(1); + this.toughness = new MageInt(1); + + // {tap}, Sacrifice Mine Bearer: Destroy target attacking creature. + Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new DestroyTargetEffect(), new TapSourceCost()); + ability.addCost(new SacrificeSourceCost()); + ability.addTarget(new TargetAttackingCreature()); + this.addAbility(ability); + } + + public MineBearer(final MineBearer card) { + super(card); + } + + @Override + public MineBearer copy() { + return new MineBearer(this); + } +} diff --git a/Mage.Sets/src/mage/sets/prophecy/SunkenField.java b/Mage.Sets/src/mage/sets/prophecy/SunkenField.java new file mode 100644 index 00000000000..fca2a0bc868 --- /dev/null +++ b/Mage.Sets/src/mage/sets/prophecy/SunkenField.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.prophecy; + +import java.util.UUID; +import mage.abilities.Ability; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.costs.common.TapSourceCost; +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.effects.Effect; +import mage.abilities.effects.common.AttachEffect; +import mage.abilities.effects.common.CounterUnlessPaysEffect; +import mage.abilities.effects.common.continuous.GainAbilityAttachedEffect; +import mage.abilities.keyword.EnchantAbility; +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.Zone; +import mage.target.TargetPermanent; +import mage.target.TargetSpell; +import mage.target.common.TargetLandPermanent; + +/** + * + * @author LoneFox + */ +public class SunkenField extends CardImpl { + + public SunkenField(UUID ownerId) { + super(ownerId, 51, "Sunken Field", Rarity.UNCOMMON, new CardType[]{CardType.ENCHANTMENT}, "{1}{U}"); + this.expansionSetCode = "PCY"; + this.subtype.add("Aura"); + + // Enchant land + TargetPermanent auraTarget = new TargetLandPermanent(); + this.getSpellAbility().addTarget(auraTarget); + this.getSpellAbility().addEffect(new AttachEffect(Outcome.AddAbility)); + Ability ability = new EnchantAbility(auraTarget.getTargetName()); + this.addAbility(ability); + // Enchanted land has "{T}: Counter target spell unless its controller pays {1}." + ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new CounterUnlessPaysEffect(new ManaCostsImpl("{1}")), new TapSourceCost()); + ability.addTarget(new TargetSpell()); + Effect effect = new GainAbilityAttachedEffect(ability, AttachmentType.AURA); + effect.setText("Enchanted land has \"{T}: Counter target spell unless its controller pays {1}.\""); + this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, effect)); + } + + public SunkenField(final SunkenField card) { + super(card); + } + + @Override + public SunkenField copy() { + return new SunkenField(this); + } +} diff --git a/Mage.Sets/src/mage/sets/prophecy/WellOfDiscovery.java b/Mage.Sets/src/mage/sets/prophecy/WellOfDiscovery.java new file mode 100644 index 00000000000..d13f785e997 --- /dev/null +++ b/Mage.Sets/src/mage/sets/prophecy/WellOfDiscovery.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.prophecy; + +import java.util.UUID; +import mage.abilities.common.BeginningOfEndStepTriggeredAbility; +import mage.abilities.condition.InvertCondition; +import mage.abilities.condition.common.PermanentsOnTheBattlefieldCondition; +import mage.abilities.decorator.ConditionalTriggeredAbility; +import mage.abilities.effects.common.DrawCardSourceControllerEffect; +import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.Rarity; +import mage.constants.TargetController; +import mage.filter.common.FilterControlledLandPermanent; +import mage.filter.predicate.Predicates; +import mage.filter.predicate.permanent.TappedPredicate; + +/** + * + * @author LoneFox + */ +public class WellOfDiscovery extends CardImpl { + + private static final FilterControlledLandPermanent filter = new FilterControlledLandPermanent(); + + static { + filter.add(Predicates.not(new TappedPredicate())); + } + + public WellOfDiscovery(UUID ownerId) { + super(ownerId, 140, "Well of Discovery", Rarity.RARE, new CardType[]{CardType.ARTIFACT}, "{6}"); + this.expansionSetCode = "PCY"; + + // At the beginning of your end step, if you control no untapped lands, draw a card. + this.addAbility(new ConditionalTriggeredAbility(new BeginningOfEndStepTriggeredAbility( + new DrawCardSourceControllerEffect(1), TargetController.YOU, false), + new InvertCondition(new PermanentsOnTheBattlefieldCondition(filter)), + "At the beginning of your end step, if you control no untapped lands, draw a card.")); + } + + public WellOfDiscovery(final WellOfDiscovery card) { + super(card); + } + + @Override + public WellOfDiscovery copy() { + return new WellOfDiscovery(this); + } +} diff --git a/Mage.Sets/src/mage/sets/prophecy/WellOfLife.java b/Mage.Sets/src/mage/sets/prophecy/WellOfLife.java new file mode 100644 index 00000000000..82a2e24ad43 --- /dev/null +++ b/Mage.Sets/src/mage/sets/prophecy/WellOfLife.java @@ -0,0 +1,74 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.sets.prophecy; + +import java.util.UUID; +import mage.abilities.common.BeginningOfEndStepTriggeredAbility; +import mage.abilities.condition.InvertCondition; +import mage.abilities.condition.common.PermanentsOnTheBattlefieldCondition; +import mage.abilities.decorator.ConditionalTriggeredAbility; +import mage.abilities.effects.common.GainLifeEffect; +import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.Rarity; +import mage.constants.TargetController; +import mage.filter.common.FilterControlledLandPermanent; +import mage.filter.predicate.Predicates; +import mage.filter.predicate.permanent.TappedPredicate; + +/** + * + * @author LoneFox + */ +public class WellOfLife extends CardImpl { + + private static final FilterControlledLandPermanent filter = new FilterControlledLandPermanent(); + + static { + filter.add(Predicates.not(new TappedPredicate())); + } + + public WellOfLife(UUID ownerId) { + super(ownerId, 141, "Well of Life", Rarity.UNCOMMON, new CardType[]{CardType.ARTIFACT}, "{4}"); + this.expansionSetCode = "PCY"; + + // At the beginning of your end step, if you control no untapped lands, you gain 2 life. + this.addAbility(new ConditionalTriggeredAbility(new BeginningOfEndStepTriggeredAbility( + new GainLifeEffect(2), TargetController.YOU, false), new InvertCondition(new PermanentsOnTheBattlefieldCondition(filter)), + "At the beginning of your end step, if you control no untapped lands, you gain 2 life.")); + } + + public WellOfLife(final WellOfLife card) { + super(card); + } + + @Override + public WellOfLife copy() { + return new WellOfLife(this); + } +} From c239cefc7a8df4e1a24271cb590abd4e48f36f3a Mon Sep 17 00:00:00 2001 From: LevelX2 Date: Tue, 13 Oct 2015 17:11:10 +0200 Subject: [PATCH 087/268] Added 5 older cards. --- .../mage/sets/planarchaos/BrainGorgers.java | 114 ++++++++++++++++ .../src/mage/sets/planarchaos/DashHopes.java | 110 ++++++++++++++++ .../sets/planarchaos/Phantasmagorian.java | 19 +-- .../sets/planarchaos/TemporalExtortion.java | 104 +++++++++++++++ .../src/mage/sets/prophecy/AvatarOfMight.java | 122 ++++++++++++++++++ .../src/mage/sets/prophecy/AvatarOfWill.java | 120 +++++++++++++++++ .../mage/sets/tenthedition/AvatarOfMight.java | 52 ++++++++ 7 files changed, 633 insertions(+), 8 deletions(-) create mode 100644 Mage.Sets/src/mage/sets/planarchaos/BrainGorgers.java create mode 100644 Mage.Sets/src/mage/sets/planarchaos/DashHopes.java create mode 100644 Mage.Sets/src/mage/sets/planarchaos/TemporalExtortion.java create mode 100644 Mage.Sets/src/mage/sets/prophecy/AvatarOfMight.java create mode 100644 Mage.Sets/src/mage/sets/prophecy/AvatarOfWill.java create mode 100644 Mage.Sets/src/mage/sets/tenthedition/AvatarOfMight.java diff --git a/Mage.Sets/src/mage/sets/planarchaos/BrainGorgers.java b/Mage.Sets/src/mage/sets/planarchaos/BrainGorgers.java new file mode 100644 index 00000000000..9ba3c089df2 --- /dev/null +++ b/Mage.Sets/src/mage/sets/planarchaos/BrainGorgers.java @@ -0,0 +1,114 @@ +/* + * 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.planarchaos; + +import java.util.UUID; +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.costs.common.SacrificeTargetCost; +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.CastSourceTriggeredAbility; +import mage.abilities.keyword.MadnessAbility; +import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.Outcome; +import mage.constants.Rarity; +import mage.game.Game; +import mage.game.stack.Spell; +import mage.players.Player; +import mage.target.common.TargetControlledCreaturePermanent; + +/** + * + * @author LevelX2 + */ +public class BrainGorgers extends CardImpl { + + public BrainGorgers(UUID ownerId) { + super(ownerId, 65, "Brain Gorgers", Rarity.COMMON, new CardType[]{CardType.CREATURE}, "{3}{B}"); + this.expansionSetCode = "PLC"; + this.subtype.add("Zombie"); + this.power = new MageInt(4); + this.toughness = new MageInt(2); + + // When you cast Brain Gorgers, any player may sacrifice a creature. If a player does, counter Brain Gorgers. + this.addAbility(new CastSourceTriggeredAbility(new BrainGorgersCounterSourceEffect())); + + // Madness {1}{B} + this.addAbility(new MadnessAbility(this, new ManaCostsImpl<>("{1}{B}"))); + } + + public BrainGorgers(final BrainGorgers card) { + super(card); + } + + @Override + public BrainGorgers copy() { + return new BrainGorgers(this); + } +} + +class BrainGorgersCounterSourceEffect extends OneShotEffect { + + public BrainGorgersCounterSourceEffect() { + super(Outcome.AIDontUseIt); + staticText = "any player may sacrifice a creature. If a player does, counter {source}"; + } + + public BrainGorgersCounterSourceEffect(final BrainGorgersCounterSourceEffect effect) { + super(effect); + } + + @Override + public BrainGorgersCounterSourceEffect copy() { + return new BrainGorgersCounterSourceEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Spell spell = game.getStack().getSpell(source.getSourceId()); + if (spell != null) { + SacrificeTargetCost cost = new SacrificeTargetCost(new TargetControlledCreaturePermanent()); + for (UUID playerId : game.getState().getPlayerList(source.getControllerId())) { + cost.clearPaid(); + Player player = game.getPlayer(playerId); + if (cost.canPay(source, source.getSourceId(), player.getId(), game) + && player.chooseUse(outcome, "Sacrifice a creature to counter " + spell.getIdName() + "?", source, game)) { + if (cost.pay(source, game, source.getSourceId(), player.getId(), false)) { + game.informPlayers(player.getLogName() + " sacrifices a creature to counter " + spell.getIdName() + "."); + game.getStack().counter(spell.getId(), source.getSourceId(), game); + } + } + } + return true; + } + return false; + } + +} diff --git a/Mage.Sets/src/mage/sets/planarchaos/DashHopes.java b/Mage.Sets/src/mage/sets/planarchaos/DashHopes.java new file mode 100644 index 00000000000..561fbbc9e8b --- /dev/null +++ b/Mage.Sets/src/mage/sets/planarchaos/DashHopes.java @@ -0,0 +1,110 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.sets.planarchaos; + +import java.util.UUID; +import mage.abilities.Ability; +import mage.abilities.costs.common.PayLifeCost; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.CastSourceTriggeredAbility; +import mage.abilities.effects.common.CounterTargetEffect; +import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.Outcome; +import mage.constants.Rarity; +import mage.game.Game; +import mage.game.stack.Spell; +import mage.players.Player; +import mage.target.TargetSpell; + +/** + * + * @author LevelX2 + */ +public class DashHopes extends CardImpl { + + public DashHopes(UUID ownerId) { + super(ownerId, 68, "Dash Hopes", Rarity.COMMON, new CardType[]{CardType.INSTANT}, "{B}{B}"); + this.expansionSetCode = "PLC"; + + // When you cast Dash Hopes, any player may pay 5 life. If a player does, counter Dash Hopes. + this.addAbility(new CastSourceTriggeredAbility(new DashHopesCounterSourceEffect())); + + // Counter target spell. + this.getSpellAbility().addEffect(new CounterTargetEffect()); + this.getSpellAbility().addTarget(new TargetSpell()); + } + + public DashHopes(final DashHopes card) { + super(card); + } + + @Override + public DashHopes copy() { + return new DashHopes(this); + } +} + +class DashHopesCounterSourceEffect extends OneShotEffect { + + public DashHopesCounterSourceEffect() { + super(Outcome.AIDontUseIt); + staticText = "any player may pay 5 life. If a player does, counter {source}"; + } + + public DashHopesCounterSourceEffect(final DashHopesCounterSourceEffect effect) { + super(effect); + } + + @Override + public DashHopesCounterSourceEffect copy() { + return new DashHopesCounterSourceEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Spell spell = game.getStack().getSpell(source.getSourceId()); + if (spell != null) { + PayLifeCost cost = new PayLifeCost(5); + for (UUID playerId : game.getState().getPlayerList(source.getControllerId())) { + Player player = game.getPlayer(playerId); + cost.clearPaid(); + if (cost.canPay(source, source.getSourceId(), player.getId(), game) + && player.chooseUse(outcome, "Pay 5 life to counter " + spell.getIdName() + "?", source, game)) { + if (cost.pay(source, game, source.getSourceId(), player.getId(), false)) { + game.informPlayers(player.getLogName() + " pays 5 life to counter " + spell.getIdName() + "."); + game.getStack().counter(spell.getId(), source.getSourceId(), game); + } + } + } + return true; + } + return false; + } + +} diff --git a/Mage.Sets/src/mage/sets/planarchaos/Phantasmagorian.java b/Mage.Sets/src/mage/sets/planarchaos/Phantasmagorian.java index e8e99f9eb63..966f1d2a126 100644 --- a/Mage.Sets/src/mage/sets/planarchaos/Phantasmagorian.java +++ b/Mage.Sets/src/mage/sets/planarchaos/Phantasmagorian.java @@ -95,19 +95,22 @@ class CounterSourceEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { - + StackObject spell = null; - for(StackObject objet : game.getStack()){ - if(objet instanceof Spell && objet.getSourceId().equals(source.getSourceId())){ + for (StackObject objet : game.getStack()) { + if (objet instanceof Spell && objet.getSourceId().equals(source.getSourceId())) { spell = objet; } } - if(spell != null){ - for(UUID uuid : game.getPlayerList()){ + if (spell != null) { + DiscardTargetCost cost = new DiscardTargetCost(new TargetCardInHand(3, 3, new FilterCard())); + for (UUID uuid : game.getPlayerList()) { Player player = game.getPlayer(uuid); - if(player.chooseUse(Outcome.Detriment, "Discard three cards to counter " + spell.getName() + "?", source, game)){ - DiscardTargetCost cost = new DiscardTargetCost(new TargetCardInHand(3, 3, new FilterCard())); - if(cost.pay(source, game, source.getSourceId(), uuid, false)){ + cost.clearPaid(); + if (cost.canPay(source, source.getSourceId(), player.getId(), game) + && player.chooseUse(Outcome.Detriment, "Discard three cards to counter " + spell.getName() + "?", source, game)) { + + if (cost.pay(source, game, source.getSourceId(), uuid, false)) { game.informPlayers(player.getLogName() + " discards 3 cards to counter " + spell.getName() + "."); game.getStack().counter(spell.getId(), source.getSourceId(), game); return true; diff --git a/Mage.Sets/src/mage/sets/planarchaos/TemporalExtortion.java b/Mage.Sets/src/mage/sets/planarchaos/TemporalExtortion.java new file mode 100644 index 00000000000..ea806b61981 --- /dev/null +++ b/Mage.Sets/src/mage/sets/planarchaos/TemporalExtortion.java @@ -0,0 +1,104 @@ +/* + * 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.planarchaos; + +import java.util.UUID; +import mage.abilities.Ability; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.CastSourceTriggeredAbility; +import mage.abilities.effects.common.turn.AddExtraTurnControllerEffect; +import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.Outcome; +import mage.constants.Rarity; +import mage.game.Game; +import mage.game.stack.Spell; +import mage.players.Player; + +/** + * + * @author LevelX2 + */ +public class TemporalExtortion extends CardImpl { + + public TemporalExtortion(UUID ownerId) { + super(ownerId, 81, "Temporal Extortion", Rarity.RARE, new CardType[]{CardType.SORCERY}, "{B}{B}{B}{B}"); + this.expansionSetCode = "PLC"; + + // When you cast Temporal Extortion, any player may pay half his or her life, rounded up. If a player does, counter Temporal Extortion. + this.addAbility(new CastSourceTriggeredAbility(new TemporalExtortionCounterSourceEffect())); + + // Take an extra turn after this one. + this.getSpellAbility().addEffect(new AddExtraTurnControllerEffect()); + } + + public TemporalExtortion(final TemporalExtortion card) { + super(card); + } + + @Override + public TemporalExtortion copy() { + return new TemporalExtortion(this); + } +} + +class TemporalExtortionCounterSourceEffect extends OneShotEffect { + + public TemporalExtortionCounterSourceEffect() { + super(Outcome.AIDontUseIt); + staticText = "any player may pay half his or her life, rounded up. If a player does, counter {source}"; + } + + public TemporalExtortionCounterSourceEffect(final TemporalExtortionCounterSourceEffect effect) { + super(effect); + } + + @Override + public TemporalExtortionCounterSourceEffect copy() { + return new TemporalExtortionCounterSourceEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Spell spell = game.getStack().getSpell(source.getSourceId()); + if (spell != null) { + for (UUID playerId : game.getState().getPlayerList(source.getControllerId())) { + Player player = game.getPlayer(playerId); + if (player.chooseUse(outcome, "Pay half your life, rounded up to counter " + spell.getIdName() + "?", source, game)) { + Integer amount = (int) Math.ceil(player.getLife() / 2f); + player.loseLife(amount, game); + game.informPlayers(player.getLogName() + " pays half his or her life, rounded up to counter " + spell.getIdName() + "."); + game.getStack().counter(spell.getId(), source.getSourceId(), game); + } + } + return true; + } + return false; + } + +} diff --git a/Mage.Sets/src/mage/sets/prophecy/AvatarOfMight.java b/Mage.Sets/src/mage/sets/prophecy/AvatarOfMight.java new file mode 100644 index 00000000000..8008f96f3df --- /dev/null +++ b/Mage.Sets/src/mage/sets/prophecy/AvatarOfMight.java @@ -0,0 +1,122 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.sets.prophecy; + +import java.util.UUID; +import mage.MageInt; +import mage.Mana; +import mage.abilities.Ability; +import mage.abilities.SpellAbility; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.effects.common.cost.CostModificationEffectImpl; +import mage.abilities.keyword.TrampleAbility; +import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.CostModificationType; +import mage.constants.Duration; +import mage.constants.Outcome; +import mage.constants.Rarity; +import mage.constants.Zone; +import mage.filter.common.FilterCreaturePermanent; +import mage.game.Game; +import mage.players.Player; + +/** + * + * @author LevelX2 + */ +public class AvatarOfMight extends CardImpl { + + public AvatarOfMight(UUID ownerId) { + super(ownerId, 109, "Avatar of Might", Rarity.RARE, new CardType[]{CardType.CREATURE}, "{6}{G}{G}"); + this.expansionSetCode = "PCY"; + this.subtype.add("Avatar"); + this.power = new MageInt(8); + this.toughness = new MageInt(8); + + // If an opponent controls at least four more creatures than you, Avatar of Might costs {6} less to cast. + this.addAbility(new SimpleStaticAbility(Zone.STACK, new AvatarOfMightCostReductionEffect())); + + // Trample + this.addAbility(TrampleAbility.getInstance()); + } + + public AvatarOfMight(final AvatarOfMight card) { + super(card); + } + + @Override + public AvatarOfMight copy() { + return new AvatarOfMight(this); + } +} + +class AvatarOfMightCostReductionEffect extends CostModificationEffectImpl { + + AvatarOfMightCostReductionEffect() { + super(Duration.Custom, Outcome.Benefit, CostModificationType.REDUCE_COST); + staticText = "If an opponent controls at least four more creatures than you, {this} will costs {6} less to cast"; + } + + AvatarOfMightCostReductionEffect(final AvatarOfMightCostReductionEffect effect) { + super(effect); + } + + @Override + public boolean apply(Game game, Ability source, Ability abilityToModify) { + SpellAbility spellAbility = (SpellAbility) abilityToModify; + Mana mana = spellAbility.getManaCostsToPay().getMana(); + if (mana.getColorless() > 0) { + int newCount = mana.getColorless() - 6; + if (newCount < 0) { + newCount = 0; + } + mana.setColorless(newCount); + spellAbility.getManaCostsToPay().load(mana.toString()); + return true; + } + return false; + } + + @Override + public boolean applies(Ability abilityToModify, Ability source, Game game) { + int creatures = game.getBattlefield().countAll(new FilterCreaturePermanent(), source.getControllerId(), game); + for (UUID playerId : game.getOpponents(source.getControllerId())) { + Player opponent = game.getPlayer(playerId); + if (opponent != null && game.getBattlefield().countAll(new FilterCreaturePermanent(), opponent.getId(), game) >= creatures + 4) { + return true; + } + } + return false; + } + + @Override + public AvatarOfMightCostReductionEffect copy() { + return new AvatarOfMightCostReductionEffect(this); + } +} diff --git a/Mage.Sets/src/mage/sets/prophecy/AvatarOfWill.java b/Mage.Sets/src/mage/sets/prophecy/AvatarOfWill.java new file mode 100644 index 00000000000..2dbd76b18b1 --- /dev/null +++ b/Mage.Sets/src/mage/sets/prophecy/AvatarOfWill.java @@ -0,0 +1,120 @@ +/* + * 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.Mana; +import mage.abilities.Ability; +import mage.abilities.SpellAbility; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.effects.common.cost.CostModificationEffectImpl; +import mage.abilities.keyword.FlyingAbility; +import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.CostModificationType; +import mage.constants.Duration; +import mage.constants.Outcome; +import mage.constants.Rarity; +import mage.constants.Zone; +import mage.game.Game; +import mage.players.Player; + +/** + * + * @author LevelX2 + */ +public class AvatarOfWill extends CardImpl { + + public AvatarOfWill(UUID ownerId) { + super(ownerId, 30, "Avatar of Will", Rarity.RARE, new CardType[]{CardType.CREATURE}, "{6}{U}{U}"); + this.expansionSetCode = "PCY"; + this.subtype.add("Avatar"); + this.power = new MageInt(5); + this.toughness = new MageInt(6); + + // If an opponent has no cards in hand, Avatar of Will costs {6} less to cast. + this.addAbility(new SimpleStaticAbility(Zone.STACK, new AvatarOfWillCostReductionEffect())); + + // Flying + this.addAbility(FlyingAbility.getInstance()); + } + + public AvatarOfWill(final AvatarOfWill card) { + super(card); + } + + @Override + public AvatarOfWill copy() { + return new AvatarOfWill(this); + } +} + +class AvatarOfWillCostReductionEffect extends CostModificationEffectImpl { + + AvatarOfWillCostReductionEffect() { + super(Duration.Custom, Outcome.Benefit, CostModificationType.REDUCE_COST); + staticText = "If an opponent has no cards in hand, {this} will costs {6} less to cast"; + } + + AvatarOfWillCostReductionEffect(final AvatarOfWillCostReductionEffect effect) { + super(effect); + } + + @Override + public boolean apply(Game game, Ability source, Ability abilityToModify) { + SpellAbility spellAbility = (SpellAbility) abilityToModify; + Mana mana = spellAbility.getManaCostsToPay().getMana(); + if (mana.getColorless() > 0) { + int newCount = mana.getColorless() - 6; + if (newCount < 0) { + newCount = 0; + } + mana.setColorless(newCount); + spellAbility.getManaCostsToPay().load(mana.toString()); + return true; + } + return false; + } + + @Override + public boolean applies(Ability abilityToModify, Ability source, Game game) { + for (UUID playerId : game.getOpponents(source.getControllerId())) { + Player opponent = game.getPlayer(playerId); + if (opponent != null && opponent.getHand().isEmpty()) { + return true; + } + } + return false; + } + + @Override + public AvatarOfWillCostReductionEffect copy() { + return new AvatarOfWillCostReductionEffect(this); + } +} diff --git a/Mage.Sets/src/mage/sets/tenthedition/AvatarOfMight.java b/Mage.Sets/src/mage/sets/tenthedition/AvatarOfMight.java new file mode 100644 index 00000000000..3fb391e2810 --- /dev/null +++ b/Mage.Sets/src/mage/sets/tenthedition/AvatarOfMight.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.tenthedition; + +import java.util.UUID; + +/** + * + * @author LevelX2 + */ +public class AvatarOfMight extends mage.sets.prophecy.AvatarOfMight { + + public AvatarOfMight(UUID ownerId) { + super(ownerId); + this.cardNumber = 251; + this.expansionSetCode = "10E"; + } + + public AvatarOfMight(final AvatarOfMight card) { + super(card); + } + + @Override + public AvatarOfMight copy() { + return new AvatarOfMight(this); + } +} From e1660180277739fb7d424ff82cc325e7001fc5b0 Mon Sep 17 00:00:00 2001 From: LevelX2 Date: Tue, 13 Oct 2015 22:35:50 +0200 Subject: [PATCH 088/268] * Fixed that continuous effects were not yet applied to lands entering the battlefield (preventing Prismatic Omen and Valakut the Molten Pinnacle combo to work). --- .../mage/sets/shadowmoor/PrismaticOmen.java | 21 ++++--- .../enters/ValakutTheMoltenPinnacleTest.java | 56 +++++++++++++------ .../mage/game/permanent/PermanentImpl.java | 6 +- 3 files changed, 51 insertions(+), 32 deletions(-) diff --git a/Mage.Sets/src/mage/sets/shadowmoor/PrismaticOmen.java b/Mage.Sets/src/mage/sets/shadowmoor/PrismaticOmen.java index f3e7e5bc716..73b5b6ee1b3 100644 --- a/Mage.Sets/src/mage/sets/shadowmoor/PrismaticOmen.java +++ b/Mage.Sets/src/mage/sets/shadowmoor/PrismaticOmen.java @@ -30,13 +30,6 @@ package mage.sets.shadowmoor; import java.util.ArrayList; import java.util.Arrays; import java.util.UUID; -import mage.constants.CardType; -import mage.constants.Duration; -import mage.constants.Layer; -import mage.constants.Outcome; -import mage.constants.Rarity; -import mage.constants.SubLayer; -import mage.constants.Zone; import mage.Mana; import mage.abilities.Ability; import mage.abilities.common.SimpleStaticAbility; @@ -48,6 +41,13 @@ import mage.abilities.mana.GreenManaAbility; import mage.abilities.mana.RedManaAbility; import mage.abilities.mana.WhiteManaAbility; import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.Layer; +import mage.constants.Outcome; +import mage.constants.Rarity; +import mage.constants.SubLayer; +import mage.constants.Zone; import mage.filter.common.FilterLandPermanent; import mage.game.Game; import mage.game.permanent.Permanent; @@ -62,7 +62,6 @@ public class PrismaticOmen extends CardImpl { super(ownerId, 126, "Prismatic Omen", Rarity.RARE, new CardType[]{CardType.ENCHANTMENT}, "{1}{G}"); this.expansionSetCode = "SHM"; - // Lands you control are every basic land type in addition to their other types. this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new BecomesBasicLandTypeAllEffect("Swamp", "Mountain", "Forest", "Island", "Plains"))); } @@ -109,11 +108,11 @@ class BecomesBasicLandTypeAllEffect extends ContinuousEffectImpl { switch (layer) { case AbilityAddingRemovingEffects_6: Mana mana = new Mana(); - for (Ability ability : land.getAbilities()){ + for (Ability ability : land.getAbilities()) { if (ability instanceof BasicManaAbility) { - for (Mana netMana: ((BasicManaAbility)ability ).getNetMana(game)) { + for (Mana netMana : ((BasicManaAbility) ability).getNetMana(game)) { mana.add(netMana); - } + } } } if (mana.getGreen() == 0 && landTypes.contains("Forest")) { diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/abilities/enters/ValakutTheMoltenPinnacleTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/abilities/enters/ValakutTheMoltenPinnacleTest.java index c29cd7a736b..141e9951328 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/abilities/enters/ValakutTheMoltenPinnacleTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/abilities/enters/ValakutTheMoltenPinnacleTest.java @@ -26,13 +26,10 @@ * authors and should not be interpreted as representing official policies, either expressed * or implied, of BetaSteward_at_googlemail.com. */ - package org.mage.test.cards.abilities.enters; import mage.constants.PhaseStep; import mage.constants.Zone; -import mage.game.permanent.Permanent; -import org.junit.Assert; import org.junit.Test; import org.mage.test.serverside.base.CardTestPlayerBase; @@ -40,17 +37,15 @@ import org.mage.test.serverside.base.CardTestPlayerBase; * * @author LevelX2 */ - public class ValakutTheMoltenPinnacleTest extends CardTestPlayerBase { /** - * Valakut, the Molten Pinnacle - * Land - * Valakut, the Molten Pinnacle enters the battlefield tapped. - * Whenever a Mountain enters the battlefield under your control, if you control at least five other Mountains, you may have Valakut, the Molten Pinnacle deal 3 damage to target creature or player. - * {T}: Add {R} to your mana pool. + * Valakut, the Molten Pinnacle Land Valakut, the Molten Pinnacle enters the + * battlefield tapped. Whenever a Mountain enters the battlefield under your + * control, if you control at least five other Mountains, you may have + * Valakut, the Molten Pinnacle deal 3 damage to target creature or player. + * {T}: Add {R} to your mana pool. */ - @Test public void onlyFourMountainsNoDamage() { @@ -85,13 +80,11 @@ public class ValakutTheMoltenPinnacleTest extends CardTestPlayerBase { assertLife(playerA, 20); assertLife(playerB, 17); - } - // Scapeshift {2}{G}{G} - // Sorcery - // Sacrifice any number of lands. Search your library for that many land cards, put them onto the battlefield tapped, then shuffle your library. - + // Scapeshift {2}{G}{G} + // Sorcery + // Sacrifice any number of lands. Search your library for that many land cards, put them onto the battlefield tapped, then shuffle your library. @Test public void sixEnterWithScapeshiftDamageToPlayerB() { @@ -113,7 +106,6 @@ public class ValakutTheMoltenPinnacleTest extends CardTestPlayerBase { assertLife(playerA, 20); assertLife(playerB, 2); // 6 * 3 damage = 18 - } @Test @@ -166,4 +158,36 @@ public class ValakutTheMoltenPinnacleTest extends CardTestPlayerBase { assertLife(playerB, 2); // 6 * 3 damage = 18 } + + /** + * Some lands aren't triggering Valakut, the Molten Pinnacle with Prismatic + * Omen and 6+ lands in play. So far I've noticed that Misty Rainforest and + * basic Island did not trigger Valakut, but an additional copy of Valakut + * did. + */ + @Test + public void withPrismaticOmen() { + // Valakut, the Molten Pinnacle enters the battlefield tapped. + // Whenever a Mountain enters the battlefield under your control, if you control at least five other Mountains, + // you may have Valakut, the Molten Pinnacle deal 3 damage to target creature or player. + // {T}: Add {R} to your mana pool. + addCard(Zone.BATTLEFIELD, playerA, "Valakut, the Molten Pinnacle"); + addCard(Zone.BATTLEFIELD, playerA, "Forest", 4); + + addCard(Zone.HAND, playerA, "Forest", 1); + + // Lands you control are every basic land type in addition to their other types. + addCard(Zone.BATTLEFIELD, playerA, "Prismatic Omen"); + + playLand(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Forest"); + addTarget(playerA, playerB); + + setStopAt(1, PhaseStep.BEGIN_COMBAT); + execute(); + + assertLife(playerA, 20); + assertLife(playerB, 17); + + } + } diff --git a/Mage/src/mage/game/permanent/PermanentImpl.java b/Mage/src/mage/game/permanent/PermanentImpl.java index f5be69ff35f..783801dc7f2 100644 --- a/Mage/src/mage/game/permanent/PermanentImpl.java +++ b/Mage/src/mage/game/permanent/PermanentImpl.java @@ -916,11 +916,7 @@ public abstract class PermanentImpl extends CardImpl implements Permanent { EntersTheBattlefieldEvent event = new EntersTheBattlefieldEvent(this, sourceId, getControllerId(), fromZone); if (!game.replaceEvent(event)) { if (fireEvent) { - if (sourceId == null) { // play lands - game.fireEvent(event); - } else { // from effects - game.addSimultaneousEvent(event); - } + game.addSimultaneousEvent(event); } return true; } From 12500464bed37dd453fe50c8f3ac3f8ded93f85c Mon Sep 17 00:00:00 2001 From: LevelX2 Date: Tue, 13 Oct 2015 23:16:42 +0200 Subject: [PATCH 089/268] * Fixed some handling problems of all players asked to pay a cost to counter the spell with this ability. --- .../mage/sets/planarchaos/BrainGorgers.java | 16 ++++++---- .../src/mage/sets/planarchaos/DashHopes.java | 14 ++++++--- .../sets/planarchaos/Phantasmagorian.java | 31 ++++++++----------- .../sets/planarchaos/TemporalExtortion.java | 14 ++++++--- .../costs/common/DiscardTargetCost.java | 4 ++- 5 files changed, 44 insertions(+), 35 deletions(-) diff --git a/Mage.Sets/src/mage/sets/planarchaos/BrainGorgers.java b/Mage.Sets/src/mage/sets/planarchaos/BrainGorgers.java index 9ba3c089df2..53fd0d565b6 100644 --- a/Mage.Sets/src/mage/sets/planarchaos/BrainGorgers.java +++ b/Mage.Sets/src/mage/sets/planarchaos/BrainGorgers.java @@ -29,6 +29,7 @@ package mage.sets.planarchaos; import java.util.UUID; import mage.MageInt; +import mage.MageObject; import mage.abilities.Ability; import mage.abilities.costs.common.SacrificeTargetCost; import mage.abilities.costs.mana.ManaCostsImpl; @@ -92,23 +93,26 @@ class BrainGorgersCounterSourceEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { - Spell spell = game.getStack().getSpell(source.getSourceId()); - if (spell != null) { + MageObject sourceObject = source.getSourceObject(game); + if (sourceObject != null) { SacrificeTargetCost cost = new SacrificeTargetCost(new TargetControlledCreaturePermanent()); for (UUID playerId : game.getState().getPlayerList(source.getControllerId())) { cost.clearPaid(); Player player = game.getPlayer(playerId); if (cost.canPay(source, source.getSourceId(), player.getId(), game) - && player.chooseUse(outcome, "Sacrifice a creature to counter " + spell.getIdName() + "?", source, game)) { + && player.chooseUse(outcome, "Sacrifice a creature to counter " + sourceObject.getIdName() + "?", source, game)) { if (cost.pay(source, game, source.getSourceId(), player.getId(), false)) { - game.informPlayers(player.getLogName() + " sacrifices a creature to counter " + spell.getIdName() + "."); - game.getStack().counter(spell.getId(), source.getSourceId(), game); + game.informPlayers(player.getLogName() + " sacrifices a creature to counter " + sourceObject.getIdName() + "."); + Spell spell = game.getStack().getSpell(source.getSourceId()); + if (spell != null) { + game.getStack().counter(spell.getId(), source.getSourceId(), game); + } } } } return true; } return false; - } + } } diff --git a/Mage.Sets/src/mage/sets/planarchaos/DashHopes.java b/Mage.Sets/src/mage/sets/planarchaos/DashHopes.java index 561fbbc9e8b..d061e582a98 100644 --- a/Mage.Sets/src/mage/sets/planarchaos/DashHopes.java +++ b/Mage.Sets/src/mage/sets/planarchaos/DashHopes.java @@ -28,6 +28,7 @@ package mage.sets.planarchaos; import java.util.UUID; +import mage.MageObject; import mage.abilities.Ability; import mage.abilities.costs.common.PayLifeCost; import mage.abilities.effects.OneShotEffect; @@ -88,17 +89,20 @@ class DashHopesCounterSourceEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { - Spell spell = game.getStack().getSpell(source.getSourceId()); - if (spell != null) { + MageObject sourceObject = source.getSourceObject(game); + if (sourceObject != null) { PayLifeCost cost = new PayLifeCost(5); for (UUID playerId : game.getState().getPlayerList(source.getControllerId())) { Player player = game.getPlayer(playerId); cost.clearPaid(); if (cost.canPay(source, source.getSourceId(), player.getId(), game) - && player.chooseUse(outcome, "Pay 5 life to counter " + spell.getIdName() + "?", source, game)) { + && player.chooseUse(outcome, "Pay 5 life to counter " + sourceObject.getIdName() + "?", source, game)) { if (cost.pay(source, game, source.getSourceId(), player.getId(), false)) { - game.informPlayers(player.getLogName() + " pays 5 life to counter " + spell.getIdName() + "."); - game.getStack().counter(spell.getId(), source.getSourceId(), game); + game.informPlayers(player.getLogName() + " pays 5 life to counter " + sourceObject.getIdName() + "."); + Spell spell = game.getStack().getSpell(source.getSourceId()); + if (spell != null) { + game.getStack().counter(spell.getId(), source.getSourceId(), game); + } } } } diff --git a/Mage.Sets/src/mage/sets/planarchaos/Phantasmagorian.java b/Mage.Sets/src/mage/sets/planarchaos/Phantasmagorian.java index 966f1d2a126..31778c36699 100644 --- a/Mage.Sets/src/mage/sets/planarchaos/Phantasmagorian.java +++ b/Mage.Sets/src/mage/sets/planarchaos/Phantasmagorian.java @@ -29,6 +29,7 @@ package mage.sets.planarchaos; import java.util.UUID; import mage.MageInt; +import mage.MageObject; import mage.abilities.Ability; import mage.abilities.Mode; import mage.abilities.common.SimpleActivatedAbility; @@ -44,7 +45,6 @@ import mage.constants.Zone; import mage.filter.FilterCard; import mage.game.Game; import mage.game.stack.Spell; -import mage.game.stack.StackObject; import mage.players.Player; import mage.target.common.TargetCardInHand; @@ -81,7 +81,7 @@ public class Phantasmagorian extends CardImpl { class CounterSourceEffect extends OneShotEffect { public CounterSourceEffect() { - super(Outcome.Detriment); + super(Outcome.AIDontUseIt); } public CounterSourceEffect(final CounterSourceEffect effect) { @@ -95,25 +95,20 @@ class CounterSourceEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { - - StackObject spell = null; - for (StackObject objet : game.getStack()) { - if (objet instanceof Spell && objet.getSourceId().equals(source.getSourceId())) { - spell = objet; - } - } - if (spell != null) { + MageObject sourceObject = source.getSourceObject(game); + if (sourceObject != null) { DiscardTargetCost cost = new DiscardTargetCost(new TargetCardInHand(3, 3, new FilterCard())); - for (UUID uuid : game.getPlayerList()) { - Player player = game.getPlayer(uuid); + for (UUID playerId : game.getState().getPlayerList(source.getControllerId())) { + Player player = game.getPlayer(playerId); cost.clearPaid(); if (cost.canPay(source, source.getSourceId(), player.getId(), game) - && player.chooseUse(Outcome.Detriment, "Discard three cards to counter " + spell.getName() + "?", source, game)) { - - if (cost.pay(source, game, source.getSourceId(), uuid, false)) { - game.informPlayers(player.getLogName() + " discards 3 cards to counter " + spell.getName() + "."); - game.getStack().counter(spell.getId(), source.getSourceId(), game); - return true; + && player.chooseUse(outcome, "Discard three cards to counter " + sourceObject.getIdName() + "?", source, game)) { + if (cost.pay(source, game, source.getSourceId(), playerId, false)) { + game.informPlayers(player.getLogName() + " discards 3 cards to counter " + sourceObject.getIdName() + "."); + Spell spell = game.getStack().getSpell(source.getSourceId()); + if (spell != null) { + game.getStack().counter(spell.getId(), source.getSourceId(), game); + } } } } diff --git a/Mage.Sets/src/mage/sets/planarchaos/TemporalExtortion.java b/Mage.Sets/src/mage/sets/planarchaos/TemporalExtortion.java index ea806b61981..c1a25134a5a 100644 --- a/Mage.Sets/src/mage/sets/planarchaos/TemporalExtortion.java +++ b/Mage.Sets/src/mage/sets/planarchaos/TemporalExtortion.java @@ -28,6 +28,7 @@ package mage.sets.planarchaos; import java.util.UUID; +import mage.MageObject; import mage.abilities.Ability; import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.CastSourceTriggeredAbility; @@ -85,15 +86,18 @@ class TemporalExtortionCounterSourceEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { - Spell spell = game.getStack().getSpell(source.getSourceId()); - if (spell != null) { + MageObject sourceObject = source.getSourceObject(game); + if (sourceObject != null) { for (UUID playerId : game.getState().getPlayerList(source.getControllerId())) { Player player = game.getPlayer(playerId); - if (player.chooseUse(outcome, "Pay half your life, rounded up to counter " + spell.getIdName() + "?", source, game)) { + if (player.chooseUse(outcome, "Pay half your life, rounded up to counter " + sourceObject.getIdName() + "?", source, game)) { Integer amount = (int) Math.ceil(player.getLife() / 2f); player.loseLife(amount, game); - game.informPlayers(player.getLogName() + " pays half his or her life, rounded up to counter " + spell.getIdName() + "."); - game.getStack().counter(spell.getId(), source.getSourceId(), game); + game.informPlayers(player.getLogName() + " pays half his or her life, rounded up to counter " + sourceObject.getIdName() + "."); + Spell spell = game.getStack().getSpell(source.getSourceId()); + if (spell != null) { + game.getStack().counter(spell.getId(), source.getSourceId(), game); + } } } return true; diff --git a/Mage/src/mage/abilities/costs/common/DiscardTargetCost.java b/Mage/src/mage/abilities/costs/common/DiscardTargetCost.java index 3cb460452af..5ba87b81916 100644 --- a/Mage/src/mage/abilities/costs/common/DiscardTargetCost.java +++ b/Mage/src/mage/abilities/costs/common/DiscardTargetCost.java @@ -68,6 +68,7 @@ public class DiscardTargetCost extends CostImpl { @Override public boolean pay(Ability ability, Game game, UUID sourceId, UUID controllerId, boolean noMana) { this.cards.clear(); + this.targets.clear(); Player player = game.getPlayer(controllerId); if (player == null) { return false; @@ -94,7 +95,8 @@ public class DiscardTargetCost extends CostImpl { @Override public void clearPaid() { super.clearPaid(); - cards.clear(); + this.cards.clear(); + this.targets.clear(); } @Override From fccf277a66ec1a87a53e3b5d5608a147253c1cd0 Mon Sep 17 00:00:00 2001 From: LevelX2 Date: Tue, 13 Oct 2015 23:34:03 +0200 Subject: [PATCH 090/268] * Fixed possible null pointer exception of DiesAttachedTriggerAbility. --- .../src/mage/sets/conflux/MartialCoup.java | 71 ++++++++++--------- .../common/DiesAttachedTriggeredAbility.java | 3 +- 2 files changed, 39 insertions(+), 35 deletions(-) diff --git a/Mage.Sets/src/mage/sets/conflux/MartialCoup.java b/Mage.Sets/src/mage/sets/conflux/MartialCoup.java index 3344214c170..2b856325231 100644 --- a/Mage.Sets/src/mage/sets/conflux/MartialCoup.java +++ b/Mage.Sets/src/mage/sets/conflux/MartialCoup.java @@ -1,46 +1,45 @@ /* -* 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.sets.conflux; +import java.util.List; import java.util.UUID; -import mage.constants.CardType; -import mage.constants.Outcome; -import mage.constants.Rarity; import mage.abilities.Ability; import mage.abilities.effects.OneShotEffect; import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.Outcome; +import mage.constants.Rarity; import mage.filter.common.FilterCreaturePermanent; import mage.game.Game; import mage.game.permanent.Permanent; import mage.game.permanent.token.SoldierToken; - /** * * @author BetaSteward_at_googlemail.com @@ -51,6 +50,7 @@ public class MartialCoup extends CardImpl { super(ownerId, 11, "Martial Coup", Rarity.RARE, new CardType[]{CardType.SORCERY}, "{X}{W}{W}"); this.expansionSetCode = "CON"; + // Put X 1/1 white Soldier creature tokens onto the battlefield. If X is 5 or more, destroy all other creatures. this.getSpellAbility().addEffect(new MartialCoupEffect()); } @@ -85,12 +85,15 @@ class MartialCoupEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { int amount = source.getManaCostsToPay().getX(); + token.putOntoBattlefield(amount, game, source.getSourceId(), source.getControllerId()); + List tokens = token.getLastAddedTokenIds(); if (amount > 4) { - for (Permanent permanent: game.getBattlefield().getActivePermanents(new FilterCreaturePermanent(), source.getControllerId(), game)) { - permanent.destroy(source.getSourceId(), game, false); + for (Permanent permanent : game.getBattlefield().getActivePermanents(new FilterCreaturePermanent(), source.getControllerId(), game)) { + if (!tokens.contains(permanent.getId())) { + permanent.destroy(source.getSourceId(), game, false); + } } } - token.putOntoBattlefield(amount, game, source.getSourceId(), source.getControllerId()); return true; } diff --git a/Mage/src/mage/abilities/common/DiesAttachedTriggeredAbility.java b/Mage/src/mage/abilities/common/DiesAttachedTriggeredAbility.java index e22e9c56744..70113a4564a 100644 --- a/Mage/src/mage/abilities/common/DiesAttachedTriggeredAbility.java +++ b/Mage/src/mage/abilities/common/DiesAttachedTriggeredAbility.java @@ -59,7 +59,8 @@ public class DiesAttachedTriggeredAbility extends TriggeredAbilityImpl { // If both (attachment and attached went to graveyard at the same time, the attachemnets can be already removed from the attached object.) // So check here with the LKI of the enchantment Permanent attachment = game.getPermanentOrLKIBattlefield(getSourceId()); - if (attachment != null && attachment.getAttachedTo().equals(zEvent.getTargetId()) + if (attachment != null + && zEvent.getTargetId().equals(attachment.getAttachedTo()) && attachment.getAttachedToZoneChangeCounter() == zEvent.getTarget().getZoneChangeCounter(game) - 1) { triggered = true; } From 21437efe847f556d8b12ab1ab8eac925b1c4d3b4 Mon Sep 17 00:00:00 2001 From: LevelX2 Date: Wed, 14 Oct 2015 00:13:57 +0200 Subject: [PATCH 091/268] * Blinding Powder - Fixed check for source object. --- .../betrayersofkamigawa/BlindingPowder.java | 20 +++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/Mage.Sets/src/mage/sets/betrayersofkamigawa/BlindingPowder.java b/Mage.Sets/src/mage/sets/betrayersofkamigawa/BlindingPowder.java index d1030fbd9c8..727a67b0c6f 100644 --- a/Mage.Sets/src/mage/sets/betrayersofkamigawa/BlindingPowder.java +++ b/Mage.Sets/src/mage/sets/betrayersofkamigawa/BlindingPowder.java @@ -61,7 +61,7 @@ public class BlindingPowder extends CardImpl { // Equipped creature has "Unattach Blinding Powder: Prevent all combat damage that would be dealt to this creature this turn." Effect effect = new PreventCombatDamageToSourceEffect(Duration.EndOfTurn); effect.setText("Prevent all combat damage that would be dealt to this creature this turn"); - Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, effect, new BlindingPowderUnattachCost()); + Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, effect, new BlindingPowderUnattachCost(getName(), getId())); this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new GainAbilityAttachedEffect(ability, AttachmentType.EQUIPMENT, Duration.WhileOnBattlefield))); // Equip {2} this.addAbility(new EquipAbility(Outcome.PreventDamage, new GenericManaCost(2))); @@ -79,28 +79,32 @@ public class BlindingPowder extends CardImpl { class BlindingPowderUnattachCost extends CostImpl { - public BlindingPowderUnattachCost() { - this.text = "Unattach Blinding Powder"; + protected UUID sourceEquipmentId; + + public BlindingPowderUnattachCost(String name, UUID sourceId) { + this.text = "Unattach " + name; + this.sourceEquipmentId = sourceId; } public BlindingPowderUnattachCost(final BlindingPowderUnattachCost cost) { super(cost); + this.sourceEquipmentId = cost.sourceEquipmentId; } @Override public boolean pay(Ability ability, Game game, UUID sourceId, UUID controllerId, boolean noMana) { Permanent permanent = game.getPermanent(sourceId); if (permanent != null) { - for (UUID attachmentId :permanent.getAttachments()) { + for (UUID attachmentId : permanent.getAttachments()) { Permanent attachment = game.getPermanent(attachmentId); - if (attachment != null && attachment.getName().equals("Blinding Powder")) { + if (attachment != null && attachment.getId().equals(sourceEquipmentId)) { paid = permanent.removeAttachment(attachmentId, game); if (paid) { break; } } } - + } return paid; } @@ -109,9 +113,9 @@ class BlindingPowderUnattachCost extends CostImpl { public boolean canPay(Ability ability, UUID sourceId, UUID controllerId, Game game) { Permanent permanent = game.getPermanent(sourceId); if (permanent != null) { - for (UUID attachmentId :permanent.getAttachments()) { + for (UUID attachmentId : permanent.getAttachments()) { Permanent attachment = game.getPermanent(attachmentId); - if (attachment != null && attachment.getName().equals("Blinding Powder")) { + if (attachment != null && attachment.getId().equals(sourceEquipmentId)) { return true; } } From 2da4fdf72ab4166bbaa65c70b7b1d998333c7513 Mon Sep 17 00:00:00 2001 From: LevelX2 Date: Wed, 14 Oct 2015 08:30:29 +0200 Subject: [PATCH 092/268] * Some fixed to card movement. --- ...LeaveReturnExiledToBattlefieldAbility.java | 19 ++++--------------- .../ReturnFromExileForSourceEffect.java | 12 +----------- Mage/src/mage/players/Player.java | 3 ++- Mage/src/mage/players/PlayerImpl.java | 8 +------- 4 files changed, 8 insertions(+), 34 deletions(-) diff --git a/Mage/src/mage/abilities/common/delayed/OnLeaveReturnExiledToBattlefieldAbility.java b/Mage/src/mage/abilities/common/delayed/OnLeaveReturnExiledToBattlefieldAbility.java index 62e94044571..e632bc96f7c 100644 --- a/Mage/src/mage/abilities/common/delayed/OnLeaveReturnExiledToBattlefieldAbility.java +++ b/Mage/src/mage/abilities/common/delayed/OnLeaveReturnExiledToBattlefieldAbility.java @@ -27,13 +27,12 @@ */ package mage.abilities.common.delayed; -import java.util.LinkedList; +import java.util.LinkedHashSet; import java.util.UUID; import mage.MageObject; import mage.abilities.Ability; import mage.abilities.DelayedTriggeredAbility; import mage.abilities.effects.OneShotEffect; -import mage.cards.Card; import mage.constants.Duration; import mage.constants.Outcome; import mage.constants.Zone; @@ -50,9 +49,9 @@ import mage.util.CardUtil; * Returns the exiled cards/permanents as source leaves battlefield * * Uses no stack + * * @author LevelX2 */ - public class OnLeaveReturnExiledToBattlefieldAbility extends DelayedTriggeredAbility { public OnLeaveReturnExiledToBattlefieldAbility() { @@ -108,22 +107,12 @@ class ReturnExiledPermanentsEffect extends OneShotEffect { Player controller = game.getPlayer(source.getControllerId()); MageObject sourceObject = source.getSourceObject(game); if (sourceObject != null && controller != null) { - int zoneChangeCounter = (sourceObject instanceof PermanentToken) ? source.getSourceObjectZoneChangeCounter() : source.getSourceObjectZoneChangeCounter() -1; + int zoneChangeCounter = (sourceObject instanceof PermanentToken) ? source.getSourceObjectZoneChangeCounter() : source.getSourceObjectZoneChangeCounter() - 1; UUID exileZone = CardUtil.getExileZoneId(game, source.getSourceId(), zoneChangeCounter); if (exileZone != null) { ExileZone exile = game.getExile().getExileZone(exileZone); if (exile != null) { - LinkedList cards = new LinkedList<>(exile); - for (UUID cardId : cards) { - Card card = game.getCard(cardId); - if (card != null) { - Player owner = game.getPlayer(card.getOwnerId()); - if (owner != null && owner.isInGame()) { - owner.putOntoBattlefieldWithInfo(card, game, Zone.EXILED, source.getSourceId()); - } - } - } - exile.clear(); + controller.moveCards(new LinkedHashSet<>(exile.getCards(game)), Zone.EXILED, source, game, false, false, true, null); } return true; } diff --git a/Mage/src/mage/abilities/effects/common/ReturnFromExileForSourceEffect.java b/Mage/src/mage/abilities/effects/common/ReturnFromExileForSourceEffect.java index 181bb35f94c..8d7b8a7c2be 100644 --- a/Mage/src/mage/abilities/effects/common/ReturnFromExileForSourceEffect.java +++ b/Mage/src/mage/abilities/effects/common/ReturnFromExileForSourceEffect.java @@ -30,7 +30,6 @@ package mage.abilities.effects.common; import mage.MageObject; import mage.abilities.Ability; import mage.abilities.effects.OneShotEffect; -import mage.cards.Card; import mage.constants.Outcome; import mage.constants.Zone; import static mage.constants.Zone.BATTLEFIELD; @@ -102,16 +101,7 @@ public class ReturnFromExileForSourceEffect extends OneShotEffect { } ExileZone exile = game.getExile().getExileZone(CardUtil.getExileZoneId(game, source.getSourceId(), zoneChangeCounter)); if (exile != null) { // null is valid if source left battlefield before enters the battlefield effect resolved - if (returnToZone.equals(Zone.BATTLEFIELD)) { - for (Card card : exile.getCards(game)) { - Player owner = game.getPlayer(card.getOwnerId()); - if (owner != null) { - owner.putOntoBattlefieldWithInfo(card, game, Zone.EXILED, source.getSourceId()); - } - } - } else { - controller.moveCards(exile, Zone.EXILED, returnToZone, source, game); - } + controller.moveCards(exile, null, returnToZone, source, game); } return true; } diff --git a/Mage/src/mage/players/Player.java b/Mage/src/mage/players/Player.java index fe56815b058..d00471867c3 100644 --- a/Mage/src/mage/players/Player.java +++ b/Mage/src/mage/players/Player.java @@ -644,7 +644,8 @@ public interface Player extends MageItem, Copyable { * @param tapped tha cards are tapped on the battlefield * @param faceDown the cards are face down in the to zone * @param byOwner the card is moved (or put onto battlefield) by the owner - * of the card (instead of the controller of the source) + * of the card and if target zone is battlefield controlls the permanent + * (instead of the controller of the source) * @return */ boolean moveCards(Set cards, Zone toZone, Ability source, Game game, boolean tapped, boolean faceDown, boolean byOwner, ArrayList appliedEffects); diff --git a/Mage/src/mage/players/PlayerImpl.java b/Mage/src/mage/players/PlayerImpl.java index f1efe5d3301..49e8ffb656a 100644 --- a/Mage/src/mage/players/PlayerImpl.java +++ b/Mage/src/mage/players/PlayerImpl.java @@ -3015,13 +3015,7 @@ public abstract class PlayerImpl implements Player, Serializable { } break; case BATTLEFIELD: - for (Card card : cards) { - fromZone = game.getState().getZone(card.getId()); - if (putOntoBattlefieldWithInfo(card, game, fromZone, source == null ? null : source.getSourceId(), false, card.isFaceDown(game))) { - successfulMovedCards.add(card); - } - } - break; + return moveCards(cards, toZone, source, game, false, false, false, null); case LIBRARY: for (Card card : cards) { fromZone = game.getState().getZone(card.getId()); From 4d8263ff82e9888e82382840229b8a4c57757953 Mon Sep 17 00:00:00 2001 From: LevelX2 Date: Wed, 14 Oct 2015 14:23:13 +0200 Subject: [PATCH 093/268] Fixed wrong target zone. --- .../common/delayed/OnLeaveReturnExiledToBattlefieldAbility.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Mage/src/mage/abilities/common/delayed/OnLeaveReturnExiledToBattlefieldAbility.java b/Mage/src/mage/abilities/common/delayed/OnLeaveReturnExiledToBattlefieldAbility.java index e632bc96f7c..3d61104c9ad 100644 --- a/Mage/src/mage/abilities/common/delayed/OnLeaveReturnExiledToBattlefieldAbility.java +++ b/Mage/src/mage/abilities/common/delayed/OnLeaveReturnExiledToBattlefieldAbility.java @@ -112,7 +112,7 @@ class ReturnExiledPermanentsEffect extends OneShotEffect { if (exileZone != null) { ExileZone exile = game.getExile().getExileZone(exileZone); if (exile != null) { - controller.moveCards(new LinkedHashSet<>(exile.getCards(game)), Zone.EXILED, source, game, false, false, true, null); + controller.moveCards(new LinkedHashSet<>(exile.getCards(game)), Zone.BATTLEFIELD, source, game, false, false, true, null); } return true; } From 52d0adcac10c2a9aaae4b5cfd83679acba565c96 Mon Sep 17 00:00:00 2001 From: LevelX2 Date: Wed, 14 Oct 2015 17:54:55 +0200 Subject: [PATCH 094/268] Fixed some problems with UUID comparing and some problems with card moving. --- .gitignore | 7 +- Mage.Common/src/mage/view/GameView.java | 2 +- .../mage/sets/alarareborn/Thraximundar.java | 8 +- .../mage/sets/apocalypse/DesolationAngel.java | 14 +-- .../UlamogTheCeaselessHunger.java | 22 ++-- .../sets/bornofthegods/SpitefulReturned.java | 5 +- .../HallOfTheBanditLord.java | 31 ++--- .../championsofkamigawa/NightDealings.java | 27 ++--- .../championsofkamigawa/SiftThroughSands.java | 8 +- .../mage/sets/coldsnap/HibernationsEnd.java | 7 +- .../sets/commander/ChorusOfTheConclave.java | 2 +- .../sets/commander2013/RubiniaSoulsinger.java | 6 +- .../sets/commander2014/InfernalOffering.java | 21 ++-- .../src/mage/sets/darksteel/LichsTomb.java | 14 +-- .../src/mage/sets/eventide/DreamThief.java | 7 +- .../mage/sets/eventide/EndlessHorizons.java | 50 +++++---- .../mage/sets/eventide/HotheadedGiant.java | 7 +- .../src/mage/sets/eventide/SoulReap.java | 16 ++- .../mage/sets/eventide/TalarasBattalion.java | 3 +- .../mage/sets/exodus/SoltariVisionary.java | 2 +- .../sets/fatereforged/MarduWoeReaper.java | 10 +- .../sets/fatereforged/WardscaleDragon.java | 7 +- .../mage/sets/fifthedition/InstillEnergy.java | 3 +- .../src/mage/sets/limitedalpha/Fastbond.java | 14 +-- .../mage/sets/magic2015/GeneratorServant.java | 20 ++-- .../mage/sets/magicorigins/SigilOfValor.java | 4 +- .../sets/masterseditionii/ThoughtLash.java | 26 ++--- .../src/mage/sets/planeshift/OrimsChant.java | 60 +++++----- .../sets/returntoravnica/VraskaTheUnseen.java | 16 ++- .../sets/scarsofmirrodin/RevokeExistence.java | 14 +-- .../mage/sets/shadowmoor/MossbridgeTroll.java | 14 +-- .../sets/shadowmoor/ThoughtweftGambit.java | 3 +- .../sets/shardsofalara/GatherSpecimens.java | 6 +- .../mage/sets/tempest/HelmOfPossession.java | 10 +- .../mage/sets/worldwake/TuktukScrapper.java | 2 +- .../sets/worldwake/WrexialTheRisenDeep.java | 28 ++--- .../test/cards/triggers/OblivionRingTest.java | 4 + .../common/EntersBattlefieldAbility.java | 90 ++++++++------- .../costs/common/DiscardTargetCost.java | 2 +- .../abilities/effects/ContinuousEffects.java | 4 +- .../ReturnFromExileForSourceEffect.java | 6 +- .../abilities/keyword/ReboundAbility.java | 106 +++++++++--------- Mage/src/mage/cards/CardImpl.java | 9 +- Mage/src/mage/game/Exile.java | 5 +- Mage/src/mage/players/PlayerImpl.java | 2 +- 45 files changed, 364 insertions(+), 360 deletions(-) diff --git a/.gitignore b/.gitignore index b129f38e3cb..ca85c840055 100644 --- a/.gitignore +++ b/.gitignore @@ -50,7 +50,7 @@ Mage.Updater/target mage.updater.client/target releases -Utils/author.txt +Utils/author.txt .DS_Store .metadata .project @@ -88,5 +88,6 @@ Mage.Server.Plugins/Mage.Draft.8PlayerBooster/target /Utils/*_unimplemented.txt *.netbeans_automatic_build *.txt -Mage.Client/serverlist.txt -/bin/ +Mage.Client/serverlist.txt +/bin/ +/target/ \ No newline at end of file diff --git a/Mage.Common/src/mage/view/GameView.java b/Mage.Common/src/mage/view/GameView.java index 80ce4867c59..15731967b2c 100644 --- a/Mage.Common/src/mage/view/GameView.java +++ b/Mage.Common/src/mage/view/GameView.java @@ -184,7 +184,7 @@ public class GameView implements Serializable { } if (isPlayer) { // has only to be set for active palyer with priority (e.g. pay mana by delve or Quenchable Fire special action) - if (state.getPriorityPlayerId() == createdForPlayerId && createdForPlayer != null) { + if (createdForPlayer != null && createdForPlayerId.equals(state.getPriorityPlayerId())) { this.special = state.getSpecialActions().getControlledBy(state.getPriorityPlayerId(), createdForPlayer.isInPayManaMode()).size() > 0; } } else { diff --git a/Mage.Sets/src/mage/sets/alarareborn/Thraximundar.java b/Mage.Sets/src/mage/sets/alarareborn/Thraximundar.java index 9fe05560f06..08898a2dcce 100644 --- a/Mage.Sets/src/mage/sets/alarareborn/Thraximundar.java +++ b/Mage.Sets/src/mage/sets/alarareborn/Thraximundar.java @@ -60,9 +60,6 @@ public class Thraximundar extends CardImpl { this.subtype.add("Zombie"); this.subtype.add("Assassin"); - - - this.power = new MageInt(6); this.toughness = new MageInt(6); @@ -116,7 +113,8 @@ class ThraximundarTriggeredAbility extends TriggeredAbilityImpl { @Override public boolean checkTrigger(GameEvent event, Game game) { - if (event.getSourceId() == this.getSourceId()) { + if (event.getSourceId() != null + && event.getSourceId().equals(this.getSourceId())) { UUID defender = game.getCombat().getDefendingPlayerId(this.getSourceId(), game); this.getEffects().get(0).setTargetPointer(new FixedTarget(defender)); return true; @@ -160,4 +158,4 @@ class PlayerSacrificesCreatureTriggeredAbility extends TriggeredAbilityImpl { public PlayerSacrificesCreatureTriggeredAbility copy() { return new PlayerSacrificesCreatureTriggeredAbility(this); } -} \ No newline at end of file +} diff --git a/Mage.Sets/src/mage/sets/apocalypse/DesolationAngel.java b/Mage.Sets/src/mage/sets/apocalypse/DesolationAngel.java index 4c32f5136e9..dd1b5db3a32 100644 --- a/Mage.Sets/src/mage/sets/apocalypse/DesolationAngel.java +++ b/Mage.Sets/src/mage/sets/apocalypse/DesolationAngel.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.apocalypse; import java.util.UUID; -import mage.constants.CardType; -import mage.constants.Outcome; -import mage.constants.Rarity; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.EntersBattlefieldTriggeredAbility; @@ -41,6 +37,9 @@ import mage.abilities.keyword.FlyingAbility; import mage.abilities.keyword.KickerAbility; import mage.cards.Card; import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.Outcome; +import mage.constants.Rarity; import mage.filter.common.FilterLandPermanent; import mage.game.Game; import mage.game.permanent.Permanent; @@ -79,6 +78,7 @@ public class DesolationAngel extends CardImpl { } class DesolationAngelEntersBattlefieldEffect extends OneShotEffect { + DesolationAngelEntersBattlefieldEffect() { super(Outcome.DestroyPermanent); staticText = "destroy all lands you control. If it was kicked, destroy all lands instead"; @@ -93,8 +93,8 @@ class DesolationAngelEntersBattlefieldEffect extends OneShotEffect { Card p = game.getCard(source.getSourceId()); boolean kicked = KickedCondition.getInstance().apply(game, source); for (Permanent permanent : game.getBattlefield().getActivePermanents(new FilterLandPermanent(), source.getControllerId(), source.getSourceId(), game)) { - if ((!kicked && permanent.getControllerId() == source.getControllerId()) - || kicked) { + if ((!kicked && permanent.getControllerId().equals(source.getControllerId())) + || kicked) { permanent.destroy(source.getSourceId(), game, false); } } @@ -106,4 +106,4 @@ class DesolationAngelEntersBattlefieldEffect extends OneShotEffect { return new DesolationAngelEntersBattlefieldEffect(this); } -} \ No newline at end of file +} diff --git a/Mage.Sets/src/mage/sets/battleforzendikar/UlamogTheCeaselessHunger.java b/Mage.Sets/src/mage/sets/battleforzendikar/UlamogTheCeaselessHunger.java index 5b6d8c45eb9..038df1a77e9 100644 --- a/Mage.Sets/src/mage/sets/battleforzendikar/UlamogTheCeaselessHunger.java +++ b/Mage.Sets/src/mage/sets/battleforzendikar/UlamogTheCeaselessHunger.java @@ -67,10 +67,10 @@ public class UlamogTheCeaselessHunger extends CardImpl { // When you cast Ulamog, the Ceaseless Hunger, exile two target permanents. this.addAbility(new UlamogExilePermanentsOnCastAbility()); - + // Indestructible this.addAbility(IndestructibleAbility.getInstance()); - + // Whenever Ulamog attacks, defending player exiles the top twenty cards of his or her library. Effect effect = new UlamogExileLibraryEffect(); effect.setText("defending player exiles the top twenty cards of his or her library"); @@ -139,18 +139,20 @@ class UlamogAttackTriggeredAbility extends TriggeredAbilityImpl { public boolean checkEventType(GameEvent event, Game game) { return event.getType() == EventType.ATTACKER_DECLARED; } - + @Override public boolean checkTrigger(GameEvent event, Game game) { Permanent sourcePermanent = game.getPermanent(this.getSourceId()); - if (sourcePermanent != null && event.getSourceId() == this.getSourceId()) { + if (sourcePermanent != null + && event.getSourceId() != null + && event.getSourceId().equals(this.getSourceId())) { UUID defender = game.getCombat().getDefendingPlayerId(this.getSourceId(), game); this.getEffects().get(0).setTargetPointer(new FixedTarget(defender)); return true; - } - return false; } - + return false; + } + @Override public String getRule() { return new StringBuilder("Whenever {this} attacks, ").append(super.getRule()).toString(); @@ -184,8 +186,8 @@ class UlamogExileLibraryEffect extends OneShotEffect { card.moveToExile(null, null, source.getSourceId(), game); } } - return true; + return true; } - return false; + return false; } -} \ No newline at end of file +} diff --git a/Mage.Sets/src/mage/sets/bornofthegods/SpitefulReturned.java b/Mage.Sets/src/mage/sets/bornofthegods/SpitefulReturned.java index 3f132ca5074..93a3d82a419 100644 --- a/Mage.Sets/src/mage/sets/bornofthegods/SpitefulReturned.java +++ b/Mage.Sets/src/mage/sets/bornofthegods/SpitefulReturned.java @@ -67,7 +67,7 @@ public class SpitefulReturned extends CardImpl { effect.setText("defending player loses 2 life"); this.addAbility(new SpitefulReturnedTriggeredAbility(effect)); // Enchanted creature gets +1/+1. - this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new BoostEnchantedEffect(1,1, Duration.WhileOnBattlefield))); + this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new BoostEnchantedEffect(1, 1, Duration.WhileOnBattlefield))); } public SpitefulReturned(final SpitefulReturned card) { @@ -105,7 +105,8 @@ class SpitefulReturnedTriggeredAbility extends TriggeredAbilityImpl { Permanent sourcePermanent = game.getPermanent(this.getSourceId()); if (sourcePermanent != null) { if (sourcePermanent.getCardType().contains(CardType.CREATURE)) { - if (event.getSourceId() == this.getSourceId()) { + if (event.getSourceId() != null + && event.getSourceId().equals(this.getSourceId())) { UUID defender = game.getCombat().getDefendingPlayerId(this.getSourceId(), game); this.getEffects().get(0).setTargetPointer(new FixedTarget(defender)); return true; diff --git a/Mage.Sets/src/mage/sets/championsofkamigawa/HallOfTheBanditLord.java b/Mage.Sets/src/mage/sets/championsofkamigawa/HallOfTheBanditLord.java index b07a5806979..a23e783906b 100644 --- a/Mage.Sets/src/mage/sets/championsofkamigawa/HallOfTheBanditLord.java +++ b/Mage.Sets/src/mage/sets/championsofkamigawa/HallOfTheBanditLord.java @@ -69,7 +69,7 @@ public class HallOfTheBanditLord extends CardImpl { // Hall of the Bandit Lord enters the battlefield tapped. this.addAbility(new EntersBattlefieldTappedAbility()); - + // {T}, Pay 3 life: Add {1} to your mana pool. If that mana is spent on a creature spell, it gains haste. Mana mana = Mana.ColorlessMana; mana.setFlag(true); @@ -94,12 +94,12 @@ class HallOfTheBanditLordWatcher extends Watcher { private final Ability source; private final List creatures = new ArrayList<>(); - + HallOfTheBanditLordWatcher(Ability source) { super("HallOfTheBanditLordWatcher", WatcherScope.CARD); this.source = source; } - + HallOfTheBanditLordWatcher(final HallOfTheBanditLordWatcher watcher) { super(watcher); this.creatures.addAll(watcher.creatures); @@ -110,22 +110,25 @@ class HallOfTheBanditLordWatcher extends Watcher { public HallOfTheBanditLordWatcher copy() { return new HallOfTheBanditLordWatcher(this); } - + @Override public void watch(GameEvent event, Game game) { if (event.getType() == EventType.MANA_PAYED) { MageObject target = game.getObject(event.getTargetId()); - if (event.getSourceId() == this.getSourceId() && target != null && target.getCardType().contains(CardType.CREATURE) && event.getFlag()) { + if (event.getSourceId() != null + && event.getSourceId().equals(this.getSourceId()) + && target != null && target.getCardType().contains(CardType.CREATURE) + && event.getFlag()) { if (target instanceof Spell) { this.creatures.add(((Spell) target).getCard().getId()); } } } if (event.getType() == EventType.COUNTERED) { - if (creatures.contains(event.getTargetId())) { + if (creatures.contains(event.getTargetId())) { creatures.remove(event.getSourceId()); - } - } + } + } if (event.getType() == EventType.ZONE_CHANGE) { if (creatures.contains(event.getSourceId())) { ZoneChangeEvent zEvent = (ZoneChangeEvent) event; @@ -133,22 +136,22 @@ class HallOfTheBanditLordWatcher extends Watcher { if (zEvent.getToZone() == Zone.STACK) { creatures.remove(event.getSourceId()); } - } - } + } + } if (event.getType() == EventType.ENTERS_THE_BATTLEFIELD) { - if (creatures.contains(event.getSourceId())) { + if (creatures.contains(event.getSourceId())) { ContinuousEffect effect = new GainAbilityTargetEffect(HasteAbility.getInstance(), Duration.Custom); effect.setTargetPointer(new FixedTarget(event.getSourceId())); game.addEffect(effect, source); creatures.remove(event.getSourceId()); - } + } } } - + @Override public void reset() { super.reset(); creatures.clear(); } - + } diff --git a/Mage.Sets/src/mage/sets/championsofkamigawa/NightDealings.java b/Mage.Sets/src/mage/sets/championsofkamigawa/NightDealings.java index 2a9ee7434df..79ca6d3680c 100644 --- a/Mage.Sets/src/mage/sets/championsofkamigawa/NightDealings.java +++ b/Mage.Sets/src/mage/sets/championsofkamigawa/NightDealings.java @@ -25,14 +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.constants.Zone; import mage.abilities.Ability; import mage.abilities.TriggeredAbilityImpl; import mage.abilities.common.SimpleActivatedAbility; @@ -44,7 +39,10 @@ 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.counters.CounterType; import mage.filter.Filter; import mage.filter.common.FilterNonlandCard; @@ -61,7 +59,7 @@ import mage.target.common.TargetCardInLibrary; */ public class NightDealings extends CardImpl { - public NightDealings (UUID ownerId) { + public NightDealings(UUID ownerId) { super(ownerId, 132, "Night Dealings", Rarity.RARE, new CardType[]{CardType.ENCHANTMENT}, "{2}{B}{B}"); this.expansionSetCode = "CHK"; @@ -74,7 +72,7 @@ public class NightDealings extends CardImpl { this.addAbility(ability); } - public NightDealings (final NightDealings card) { + public NightDealings(final NightDealings card) { super(card); } @@ -83,7 +81,6 @@ public class NightDealings extends CardImpl { return new NightDealings(this); } - private class NightDealingsTriggeredAbility extends TriggeredAbilityImpl { public NightDealingsTriggeredAbility() { @@ -106,17 +103,17 @@ public class NightDealings extends CardImpl { @Override public boolean checkTrigger(GameEvent event, Game game) { - // to another player + // to another player if (this.getControllerId() != event.getTargetId()) { // a source you control UUID sourceControllerId = game.getControllerId(event.getSourceId()); - if (sourceControllerId != null && sourceControllerId == this.getControllerId()) { + if (sourceControllerId != null && sourceControllerId.equals(this.getControllerId())) { // save amount of damage to effect this.getEffects().get(0).setValue("damageAmount", event.getAmount()); return true; } } - return false; + return false; } @Override @@ -181,9 +178,9 @@ public class NightDealings extends CardImpl { int cmc = 0; for (Cost cost : source.getCosts()) { if (cost instanceof RemoveVariableCountersSourceCost) { - cmc = ((RemoveVariableCountersSourceCost)cost).getAmount(); + cmc = ((RemoveVariableCountersSourceCost) cost).getAmount(); } - } + } FilterNonlandCard filter = new FilterNonlandCard("nonland card with converted mana cost X = " + cmc); filter.add(new ConvertedManaCostPredicate(Filter.ComparisonType.Equal, cmc)); @@ -192,8 +189,8 @@ public class NightDealings extends CardImpl { if (player.searchLibrary(target, game)) { Card card = player.getLibrary().getCard(target.getFirstTarget(), game); if (card != null) { - card.moveToZone(Zone.HAND, source.getSourceId(), game, false); - + card.moveToZone(Zone.HAND, source.getSourceId(), game, false); + String name = "Reveal"; Cards cards = new CardsImpl(); cards.add(card); diff --git a/Mage.Sets/src/mage/sets/championsofkamigawa/SiftThroughSands.java b/Mage.Sets/src/mage/sets/championsofkamigawa/SiftThroughSands.java index 58e84d068ab..2e2206feef0 100644 --- a/Mage.Sets/src/mage/sets/championsofkamigawa/SiftThroughSands.java +++ b/Mage.Sets/src/mage/sets/championsofkamigawa/SiftThroughSands.java @@ -32,8 +32,8 @@ import mage.abilities.Ability; import mage.abilities.condition.Condition; import mage.abilities.decorator.ConditionalOneShotEffect; import mage.abilities.effects.Effect; -import mage.abilities.effects.common.discard.DiscardControllerEffect; import mage.abilities.effects.common.DrawCardSourceControllerEffect; +import mage.abilities.effects.common.discard.DiscardControllerEffect; import mage.abilities.effects.common.search.SearchLibraryPutInPlayEffect; import mage.cards.CardImpl; import mage.constants.CardType; @@ -56,6 +56,7 @@ public class SiftThroughSands extends CardImpl { private static final String rule = "If you've cast a spell named Peer Through Depths and a spell named Reach Through Mists this turn, you may search your library for a card named The Unspeakable, put it onto the battlefield, then shuffle your library"; private static final FilterCreatureCard filter = new FilterCreatureCard("a card named The Unspeakable"); + static { filter.add(new NamePredicate("The Unspeakable")); } @@ -65,13 +66,12 @@ public class SiftThroughSands extends CardImpl { this.expansionSetCode = "CHK"; this.subtype.add("Arcane"); - // Draw two cards, then discard a card. this.getSpellAbility().addEffect(new DrawCardSourceControllerEffect(2)); Effect effect = new DiscardControllerEffect(1); effect.setText(", then discard a card"); this.getSpellAbility().addEffect(effect); - + // If you've cast a spell named Peer Through Depths and a spell named Reach Through Mists this turn, you may search your library for a card named The Unspeakable, put it onto the battlefield, then shuffle your library. this.getSpellAbility().addEffect(new ConditionalOneShotEffect(new SearchLibraryPutInPlayEffect(new TargetCardInLibrary(filter), false, true), new SiftThroughSandsCondition(), rule)); this.getSpellAbility().addWatcher(new SiftThroughSandsWatcher()); @@ -125,7 +125,7 @@ class SiftThroughSandsWatcher extends Watcher { return; } if (event.getType() == EventType.SPELL_CAST - && controllerId == event.getPlayerId()) { + && controllerId.equals(event.getPlayerId())) { Spell spell = game.getStack().getSpell(event.getTargetId()); if (spell.getCard().getName().equals("Peer Through Depths")) { castPeerThroughDepths = true; diff --git a/Mage.Sets/src/mage/sets/coldsnap/HibernationsEnd.java b/Mage.Sets/src/mage/sets/coldsnap/HibernationsEnd.java index e62a91d9b36..09d46b4974c 100644 --- a/Mage.Sets/src/mage/sets/coldsnap/HibernationsEnd.java +++ b/Mage.Sets/src/mage/sets/coldsnap/HibernationsEnd.java @@ -44,8 +44,8 @@ import mage.filter.FilterCard; import mage.filter.predicate.mageobject.CardTypePredicate; import mage.filter.predicate.mageobject.ConvertedManaCostPredicate; import mage.game.Game; -import mage.game.events.GameEvent.EventType; import mage.game.events.GameEvent; +import mage.game.events.GameEvent.EventType; import mage.game.permanent.Permanent; import mage.players.Player; import mage.target.common.TargetCardInLibrary; @@ -98,7 +98,7 @@ class HibernationsEndAbility extends TriggeredAbilityImpl { @Override public boolean checkTrigger(GameEvent event, Game game) { - return event.getSourceId() == this.getSourceId(); + return event.getSourceId() != null && event.getSourceId().equals(this.getSourceId()); } @Override @@ -127,7 +127,7 @@ class HibernationsEndEffect extends OneShotEffect { public boolean apply(Game game, Ability source) { Player player = game.getPlayer(source.getControllerId()); Permanent sourcePermanent = game.getPermanentOrLKIBattlefield(source.getSourceId()); - if(sourcePermanent != null && player != null) { + if (sourcePermanent != null && player != null) { int newConvertedCost = sourcePermanent.getCounters().getCount("age"); FilterCard filter = new FilterCard("creature card with converted mana cost " + newConvertedCost); filter.add(new ConvertedManaCostPredicate(Filter.ComparisonType.Equal, newConvertedCost)); @@ -138,4 +138,3 @@ class HibernationsEndEffect extends OneShotEffect { return false; } } - diff --git a/Mage.Sets/src/mage/sets/commander/ChorusOfTheConclave.java b/Mage.Sets/src/mage/sets/commander/ChorusOfTheConclave.java index 83774981509..70fc31b6951 100644 --- a/Mage.Sets/src/mage/sets/commander/ChorusOfTheConclave.java +++ b/Mage.Sets/src/mage/sets/commander/ChorusOfTheConclave.java @@ -135,7 +135,7 @@ class ChorusOfTheConclaveReplacementEffect extends ReplacementEffectImpl { @Override public boolean applies(GameEvent event, Ability source, Game game) { - if (event.getPlayerId() == source.getControllerId()) { + if (event.getPlayerId().equals(source.getControllerId())) { MageObject spellObject = game.getObject(event.getSourceId()); if (spellObject != null) { return spellObject.getCardType().contains(CardType.CREATURE); diff --git a/Mage.Sets/src/mage/sets/commander2013/RubiniaSoulsinger.java b/Mage.Sets/src/mage/sets/commander2013/RubiniaSoulsinger.java index 0580c020d38..26b8c62ebfa 100644 --- a/Mage.Sets/src/mage/sets/commander2013/RubiniaSoulsinger.java +++ b/Mage.Sets/src/mage/sets/commander2013/RubiniaSoulsinger.java @@ -92,9 +92,9 @@ class RubiniaSoulsingerCondition implements Condition { controllerId = source.getControllerId(); } Permanent permanent = game.getBattlefield().getPermanent(source.getSourceId()); - if (permanent != null){ - if (permanent.isTapped()){ - return controllerId == source.getControllerId(); + if (permanent != null) { + if (permanent.isTapped()) { + return controllerId.equals(source.getControllerId()); } } return false; diff --git a/Mage.Sets/src/mage/sets/commander2014/InfernalOffering.java b/Mage.Sets/src/mage/sets/commander2014/InfernalOffering.java index f0bb1741adc..18a0fef42cb 100644 --- a/Mage.Sets/src/mage/sets/commander2014/InfernalOffering.java +++ b/Mage.Sets/src/mage/sets/commander2014/InfernalOffering.java @@ -61,10 +61,9 @@ public class InfernalOffering extends CardImpl { super(ownerId, 24, "Infernal Offering", Rarity.RARE, new CardType[]{CardType.SORCERY}, "{4}{B}"); this.expansionSetCode = "C14"; - // Choose an opponent. You and that player each sacrifice a creature. Each player who sacrificed a creature this way draws two cards. this.getSpellAbility().addEffect(new InfernalOfferingSacrificeEffect()); - + // Choose an opponent. Return a creature card from your graveyard to the battlefield, then that player returns a creature card from his or her graveyard to the battlefield. this.getSpellAbility().addEffect(new InfernalOfferingReturnEffect()); } @@ -80,21 +79,21 @@ public class InfernalOffering extends CardImpl { } class InfernalOfferingSacrificeEffect extends OneShotEffect { - + InfernalOfferingSacrificeEffect() { super(Outcome.Sacrifice); this.staticText = "Choose an opponent. You and that player each sacrifice a creature. Each player who sacrificed a creature this way draws two cards"; } - + InfernalOfferingSacrificeEffect(final InfernalOfferingSacrificeEffect effect) { super(effect); } - + @Override public InfernalOfferingSacrificeEffect copy() { return new InfernalOfferingSacrificeEffect(this); } - + @Override public boolean apply(Game game, Ability source) { Player player = game.getPlayer(source.getControllerId()); @@ -106,7 +105,7 @@ class InfernalOfferingSacrificeEffect extends OneShotEffect { //Choose creatures to sacrifice Map toSacrifice = new HashMap<>(2); for (UUID playerId : player.getInRange()) { - if (playerId == player.getId() || playerId == opponent.getId()) { + if (playerId.equals(player.getId()) || playerId.equals(opponent.getId())) { target = new TargetControlledCreaturePermanent(1, 1, new FilterControlledCreaturePermanent(), true); if (target.choose(Outcome.Sacrifice, playerId, source.getControllerId(), game)) { toSacrifice.put(playerId, target.getFirstTarget()); @@ -138,21 +137,21 @@ class InfernalOfferingSacrificeEffect extends OneShotEffect { } class InfernalOfferingReturnEffect extends OneShotEffect { - + InfernalOfferingReturnEffect() { super(Outcome.PutCreatureInPlay); this.staticText = "Choose an opponent. Return a creature card from your graveyard to the battlefield, then that player returns a creature card from his or her graveyard to the battlefield"; } - + InfernalOfferingReturnEffect(final InfernalOfferingReturnEffect effect) { super(effect); } - + @Override public InfernalOfferingReturnEffect copy() { return new InfernalOfferingReturnEffect(this); } - + @Override public boolean apply(Game game, Ability source) { Player player = game.getPlayer(source.getControllerId()); diff --git a/Mage.Sets/src/mage/sets/darksteel/LichsTomb.java b/Mage.Sets/src/mage/sets/darksteel/LichsTomb.java index 3ec918d0114..33a0f45d56e 100644 --- a/Mage.Sets/src/mage/sets/darksteel/LichsTomb.java +++ b/Mage.Sets/src/mage/sets/darksteel/LichsTomb.java @@ -56,7 +56,7 @@ public class LichsTomb extends CardImpl { // You don't lose the game for having 0 or less life. this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new DontLoseByZeroOrLessLifeEffect(Duration.WhileOnBattlefield))); - + // Whenever you lose life, sacrifice a permanent for each 1 life you lost. this.addAbility(new LichsTombTriggeredAbility()); } @@ -72,15 +72,15 @@ public class LichsTomb extends CardImpl { } class LichsTombTriggeredAbility extends TriggeredAbilityImpl { - + LichsTombTriggeredAbility() { super(Zone.BATTLEFIELD, new SacrificeControllerEffect(new FilterPermanent(), 0, ""), false); } - + LichsTombTriggeredAbility(final LichsTombTriggeredAbility ability) { super(ability); } - + @Override public LichsTombTriggeredAbility copy() { return new LichsTombTriggeredAbility(this); @@ -90,16 +90,16 @@ class LichsTombTriggeredAbility extends TriggeredAbilityImpl { public boolean checkEventType(GameEvent event, Game game) { return event.getType() == EventType.LOST_LIFE; } - + @Override public boolean checkTrigger(GameEvent event, Game game) { - if (event.getPlayerId() == this.getControllerId()) { + if (event.getPlayerId().equals(this.getControllerId())) { ((SacrificeEffect) this.getEffects().get(0)).setAmount(new StaticValue(event.getAmount())); return true; } return false; } - + @Override public String getRule() { return "Whenever you lose life, sacrifice a permanent for each 1 life you lost."; diff --git a/Mage.Sets/src/mage/sets/eventide/DreamThief.java b/Mage.Sets/src/mage/sets/eventide/DreamThief.java index f0373c53ccf..a3dc86a47d3 100644 --- a/Mage.Sets/src/mage/sets/eventide/DreamThief.java +++ b/Mage.Sets/src/mage/sets/eventide/DreamThief.java @@ -53,7 +53,7 @@ import mage.watchers.Watcher; * @author jeffwadsworth */ public class DreamThief extends CardImpl { - + private static final String rule = "draw a card if you've cast another blue spell this turn"; public DreamThief(UUID ownerId) { @@ -70,7 +70,7 @@ public class DreamThief extends CardImpl { // When Dream Thief enters the battlefield, draw a card if you've cast another blue spell this turn. this.addAbility(new EntersBattlefieldTriggeredAbility(new ConditionalOneShotEffect(new DrawCardSourceControllerEffect(1), new CastBlueSpellThisTurnCondition(), rule)), new DreamThiefWatcher(this.getId())); - + } public DreamThief(final DreamThief card) { @@ -98,6 +98,7 @@ class CastBlueSpellThisTurnCondition implements Condition { class DreamThiefWatcher extends Watcher { private static final FilterSpell filter = new FilterSpell(); + static { filter.add(new ColorPredicate(ObjectColor.BLUE)); } @@ -125,7 +126,7 @@ class DreamThiefWatcher extends Watcher { return; } if (event.getType() == EventType.SPELL_CAST - && controllerId == event.getPlayerId()) { + && controllerId.equals(event.getPlayerId())) { Spell spell = game.getStack().getSpell(event.getTargetId()); if (!spell.getSourceId().equals(cardId) && filter.match(spell, game)) { condition = true; diff --git a/Mage.Sets/src/mage/sets/eventide/EndlessHorizons.java b/Mage.Sets/src/mage/sets/eventide/EndlessHorizons.java index 240c94a0218..17af8a3fdcf 100644 --- a/Mage.Sets/src/mage/sets/eventide/EndlessHorizons.java +++ b/Mage.Sets/src/mage/sets/eventide/EndlessHorizons.java @@ -40,11 +40,13 @@ import mage.constants.Outcome; import mage.constants.Rarity; import mage.constants.TargetController; import mage.constants.Zone; +import mage.filter.FilterCard; import mage.filter.common.FilterLandCard; import mage.filter.predicate.mageobject.SubtypePredicate; import mage.game.ExileZone; import mage.game.Game; import mage.players.Player; +import mage.target.TargetCard; import mage.target.common.TargetCardInLibrary; import mage.util.CardUtil; @@ -58,7 +60,6 @@ public class EndlessHorizons extends CardImpl { super(ownerId, 4, "Endless Horizons", Rarity.RARE, new CardType[]{CardType.ENCHANTMENT}, "{3}{W}"); this.expansionSetCode = "EVE"; - // When Endless Horizons enters the battlefield, search your library for any number of Plains cards and exile them. Then shuffle your library. this.addAbility(new EntersBattlefieldTriggeredAbility(new EndlessHorizonsEffect(), false)); @@ -122,34 +123,41 @@ class EndlessHorizonsEffect extends SearchEffect { } } - class EndlessHorizonsEffect2 extends OneShotEffect { +class EndlessHorizonsEffect2 extends OneShotEffect { - public EndlessHorizonsEffect2() { - super(Outcome.ReturnToHand); - this.staticText = "you may put a card you own exiled with {this} into your hand"; - } + public EndlessHorizonsEffect2() { + super(Outcome.ReturnToHand); + this.staticText = "you may put a card you own exiled with {this} into your hand"; + } - public EndlessHorizonsEffect2(final EndlessHorizonsEffect2 effect) { - super(effect); - } + public EndlessHorizonsEffect2(final EndlessHorizonsEffect2 effect) { + super(effect); + } - @Override - public EndlessHorizonsEffect2 copy() { - return new EndlessHorizonsEffect2(this); - } + @Override + public EndlessHorizonsEffect2 copy() { + return new EndlessHorizonsEffect2(this); + } - @Override - public boolean apply(Game game, Ability source) { + @Override + public boolean apply(Game game, Ability source) { + Player controller = game.getPlayer(source.getControllerId()); + if (controller != null) { ExileZone exZone = game.getExile().getExileZone(CardUtil.getCardExileZoneId(game, source)); if (exZone != null) { - for (Card card : exZone.getCards(game)) { - if (card.getOwnerId() == source.getControllerId()) { - card.moveToZone(Zone.HAND, source.getSourceId(), game, false); - break; // only one - } + Card card = null; + if (exZone.size() > 1) { + TargetCard target = new TargetCard(Zone.EXILED, new FilterCard()); + controller.choose(outcome, exZone, target, game); + card = game.getCard(target.getFirstTarget()); + } else { + card = exZone.getRandom(game); } + controller.moveCards(card, null, Zone.HAND, source, game); } return true; } - + return false; + } + } diff --git a/Mage.Sets/src/mage/sets/eventide/HotheadedGiant.java b/Mage.Sets/src/mage/sets/eventide/HotheadedGiant.java index 41c797b735b..1e099413f2b 100644 --- a/Mage.Sets/src/mage/sets/eventide/HotheadedGiant.java +++ b/Mage.Sets/src/mage/sets/eventide/HotheadedGiant.java @@ -67,11 +67,11 @@ public class HotheadedGiant extends CardImpl { // Haste this.addAbility(HasteAbility.getInstance()); - + // Hotheaded Giant enters the battlefield with two -1/-1 counters on it unless you've cast another red spell this turn. Condition condition = new CastRedSpellThisTurnCondition(); this.addAbility(new EntersBattlefieldAbility(new ConditionalOneShotEffect(new AddCountersSourceEffect(CounterType.M1M1.createInstance(2)), new InvertCondition(condition), ""), "with two -1/-1 counters on it unless you've cast another red spell this turn"), new HotHeadedGiantWatcher(this.getId())); - + } public HotheadedGiant(final HotheadedGiant card) { @@ -99,6 +99,7 @@ class CastRedSpellThisTurnCondition implements Condition { class HotHeadedGiantWatcher extends Watcher { private static final FilterSpell filter = new FilterSpell(); + static { filter.add(new ColorPredicate(ObjectColor.RED)); } @@ -126,7 +127,7 @@ class HotHeadedGiantWatcher extends Watcher { return; } if (event.getType() == EventType.SPELL_CAST - && controllerId == event.getPlayerId()) { + && controllerId.equals(event.getPlayerId())) { Spell spell = game.getStack().getSpell(event.getTargetId()); if (!spell.getSourceId().equals(cardId) && filter.match(spell, game)) { condition = true; diff --git a/Mage.Sets/src/mage/sets/eventide/SoulReap.java b/Mage.Sets/src/mage/sets/eventide/SoulReap.java index 8c47750a966..3bb073a7dbf 100644 --- a/Mage.Sets/src/mage/sets/eventide/SoulReap.java +++ b/Mage.Sets/src/mage/sets/eventide/SoulReap.java @@ -32,7 +32,6 @@ import mage.ObjectColor; import mage.abilities.Ability; import mage.abilities.condition.Condition; import mage.abilities.decorator.ConditionalOneShotEffect; -import mage.abilities.effects.Effect; import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.DestroyTargetEffect; import mage.cards.CardImpl; @@ -59,26 +58,25 @@ import mage.watchers.Watcher; * @author jeffwadsworth */ public class SoulReap extends CardImpl { - + private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("nongreen creature"); - + static { filter.add(Predicates.not(new ColorPredicate(ObjectColor.GREEN))); } - + private String rule = "Its controller loses 3 life if you've cast another black spell this turn"; public SoulReap(UUID ownerId) { super(ownerId, 44, "Soul Reap", Rarity.COMMON, new CardType[]{CardType.SORCERY}, "{1}{B}"); this.expansionSetCode = "EVE"; - // Destroy target nongreen creature. Its controller loses 3 life if you've cast another black spell this turn. this.getSpellAbility().addEffect(new DestroyTargetEffect()); this.getSpellAbility().addTarget(new TargetCreaturePermanent(filter)); this.getSpellAbility().addEffect(new ConditionalOneShotEffect(new SoulReapEffect(), new CastBlackSpellThisTurnCondition(), rule)); this.getSpellAbility().addWatcher(new SoulReapWatcher(this.getId())); - + } public SoulReap(final SoulReap card) { @@ -106,7 +104,7 @@ class CastBlackSpellThisTurnCondition implements Condition { class SoulReapWatcher extends Watcher { private static final FilterSpell filter = new FilterSpell(); - + static { filter.add(new ColorPredicate(ObjectColor.BLACK)); } @@ -134,7 +132,7 @@ class SoulReapWatcher extends Watcher { return; } if (event.getType() == EventType.SPELL_CAST - && controllerId == event.getPlayerId()) { + && controllerId.equals(event.getPlayerId())) { Spell spell = game.getStack().getSpell(event.getTargetId()); if (!spell.getSourceId().equals(cardId) && filter.match(spell, game)) { condition = true; @@ -177,4 +175,4 @@ class SoulReapEffect extends OneShotEffect { } return false; } -} \ No newline at end of file +} diff --git a/Mage.Sets/src/mage/sets/eventide/TalarasBattalion.java b/Mage.Sets/src/mage/sets/eventide/TalarasBattalion.java index 3220bda751d..190a6d3f5b8 100644 --- a/Mage.Sets/src/mage/sets/eventide/TalarasBattalion.java +++ b/Mage.Sets/src/mage/sets/eventide/TalarasBattalion.java @@ -34,7 +34,6 @@ import mage.abilities.Ability; import mage.abilities.common.SimpleStaticAbility; import mage.abilities.condition.Condition; import mage.abilities.effects.ContinuousRuleModifyingEffectImpl; -import mage.abilities.effects.ReplacementEffectImpl; import mage.abilities.keyword.TrampleAbility; import mage.cards.CardImpl; import mage.constants.CardType; @@ -159,7 +158,7 @@ class TalarasBattalionWatcher extends Watcher { return; } if (event.getType() == EventType.SPELL_CAST - && controllerId == event.getPlayerId()) { + && controllerId.equals(event.getPlayerId())) { Spell spell = game.getStack().getSpell(event.getTargetId()); if (!spell.getSourceId().equals(cardId) && filter.match(spell, game)) { condition = true; diff --git a/Mage.Sets/src/mage/sets/exodus/SoltariVisionary.java b/Mage.Sets/src/mage/sets/exodus/SoltariVisionary.java index 4e07f51447c..99d614dd6a5 100644 --- a/Mage.Sets/src/mage/sets/exodus/SoltariVisionary.java +++ b/Mage.Sets/src/mage/sets/exodus/SoltariVisionary.java @@ -99,7 +99,7 @@ class SoltariVisionaryTriggeredAbility extends TriggeredAbilityImpl { @Override public boolean checkTrigger(GameEvent event, Game game) { Permanent soltari = game.getPermanent(event.getSourceId()); - if (soltari != null && soltari.getId() == this.getSourceId()) { + if (soltari != null && soltari.getId().equals(this.getSourceId())) { FilterEnchantmentPermanent filter = new FilterEnchantmentPermanent("enchantment that player controls."); filter.add(new ControllerIdPredicate(event.getPlayerId())); filter.setMessage("enchantment controlled by " + game.getPlayer(event.getTargetId()).getLogName()); diff --git a/Mage.Sets/src/mage/sets/fatereforged/MarduWoeReaper.java b/Mage.Sets/src/mage/sets/fatereforged/MarduWoeReaper.java index 15a433d0ea6..4b594d31ca4 100644 --- a/Mage.Sets/src/mage/sets/fatereforged/MarduWoeReaper.java +++ b/Mage.Sets/src/mage/sets/fatereforged/MarduWoeReaper.java @@ -99,7 +99,7 @@ class MarduWoeReaperTriggeredAbility extends TriggeredAbilityImpl { public boolean checkTrigger(GameEvent event, Game game) { if (event.getPlayerId().equals(this.getControllerId())) { Permanent permanent = game.getPermanent(event.getTargetId()); - if (permanent != null && (permanent.getId() == this.getSourceId() || permanent.hasSubtype("Warrior"))) { + if (permanent != null && (permanent.getId().equals(this.getSourceId()) || permanent.hasSubtype("Warrior"))) { return true; } } @@ -113,21 +113,21 @@ class MarduWoeReaperTriggeredAbility extends TriggeredAbilityImpl { } class MarduWoeReaperEffect extends OneShotEffect { - + MarduWoeReaperEffect() { super(Outcome.GainLife); this.staticText = "you may exile target creature card from a graveyard. If you do, you gain 1 life"; } - + MarduWoeReaperEffect(final MarduWoeReaperEffect effect) { super(effect); } - + @Override public MarduWoeReaperEffect copy() { return new MarduWoeReaperEffect(this); } - + @Override public boolean apply(Game game, Ability source) { Player player = game.getPlayer(source.getControllerId()); diff --git a/Mage.Sets/src/mage/sets/fatereforged/WardscaleDragon.java b/Mage.Sets/src/mage/sets/fatereforged/WardscaleDragon.java index fadb7c5a883..61869d47454 100644 --- a/Mage.Sets/src/mage/sets/fatereforged/WardscaleDragon.java +++ b/Mage.Sets/src/mage/sets/fatereforged/WardscaleDragon.java @@ -58,11 +58,10 @@ public class WardscaleDragon extends CardImpl { // Flying this.addAbility(FlyingAbility.getInstance()); - + // As long as Wardscale Dragon is attacking, defending player can't cast spells. this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new WardscaleDragonRuleEffect())); - - + } public WardscaleDragon(final WardscaleDragon card) { @@ -105,7 +104,7 @@ class WardscaleDragonRuleEffect extends ContinuousRuleModifyingEffectImpl { public boolean applies(GameEvent event, Ability source, Game game) { Permanent sourcePermanent = game.getPermanent(source.getSourceId()); if (sourcePermanent != null && sourcePermanent.isAttacking()) { - return event.getPlayerId() == game.getCombat().getDefendingPlayerId(sourcePermanent.getId(), game); + return event.getPlayerId().equals(game.getCombat().getDefendingPlayerId(sourcePermanent.getId(), game)); } return false; } diff --git a/Mage.Sets/src/mage/sets/fifthedition/InstillEnergy.java b/Mage.Sets/src/mage/sets/fifthedition/InstillEnergy.java index 5c82efdeba2..9c0b8691038 100644 --- a/Mage.Sets/src/mage/sets/fifthedition/InstillEnergy.java +++ b/Mage.Sets/src/mage/sets/fifthedition/InstillEnergy.java @@ -92,6 +92,7 @@ public class InstillEnergy extends CardImpl { } class CanAttackAsThoughItHadHasteEnchantedEffect extends AsThoughEffectImpl { + public CanAttackAsThoughItHadHasteEnchantedEffect(Duration duration) { super(AsThoughEffectType.ATTACK, duration, Outcome.Benefit); staticText = "Enchanted creature can attack as though it had haste"; @@ -114,7 +115,7 @@ class CanAttackAsThoughItHadHasteEnchantedEffect extends AsThoughEffectImpl { @Override public boolean applies(UUID objectId, Ability source, UUID affectedControllerId, Game game) { Permanent enchantment = game.getPermanent(source.getSourceId()); - return enchantment != null && enchantment.getAttachedTo() != null && enchantment.getAttachedTo() == objectId; + return enchantment != null && enchantment.getAttachedTo() != null && enchantment.getAttachedTo().equals(objectId); } } diff --git a/Mage.Sets/src/mage/sets/limitedalpha/Fastbond.java b/Mage.Sets/src/mage/sets/limitedalpha/Fastbond.java index 3be02bbc3d2..ddcdabe0e99 100644 --- a/Mage.Sets/src/mage/sets/limitedalpha/Fastbond.java +++ b/Mage.Sets/src/mage/sets/limitedalpha/Fastbond.java @@ -52,13 +52,11 @@ public class Fastbond extends CardImpl { super(ownerId, 101, "Fastbond", Rarity.RARE, new CardType[]{CardType.ENCHANTMENT}, "{G}"); this.expansionSetCode = "LEA"; - // You may play any number of additional lands on each of your turns. this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new PlayAdditionalLandsControllerEffect(Integer.MAX_VALUE, Duration.WhileOnBattlefield))); // Whenever you play a land, if it wasn't the first land you played this turn, Fastbond deals 1 damage to you. this.addAbility(new PlayALandTriggeredAbility()); } - public Fastbond(final Fastbond card) { super(card); @@ -70,7 +68,6 @@ public class Fastbond extends CardImpl { } } - class PlayALandTriggeredAbility extends TriggeredAbilityImpl { public PlayALandTriggeredAbility() { @@ -88,14 +85,14 @@ class PlayALandTriggeredAbility extends TriggeredAbilityImpl { @Override public boolean checkTrigger(GameEvent event, Game game) { - return event.getPlayerId() == this.getControllerId(); + return event.getPlayerId().equals(this.getControllerId()); } @Override public boolean checkInterveningIfClause(Game game) { Player player = game.getPlayer(this.getControllerId()); - if (player != null){ - if (player.getLandsPlayed() != 1){ + if (player != null) { + if (player.getLandsPlayed() != 1) { return true; } } @@ -111,8 +108,5 @@ class PlayALandTriggeredAbility extends TriggeredAbilityImpl { public String getRule() { return "Whenever you play a land, if it wasn't the first land you played this turn, {source} deals 1 damage to you"; } - - + } - - diff --git a/Mage.Sets/src/mage/sets/magic2015/GeneratorServant.java b/Mage.Sets/src/mage/sets/magic2015/GeneratorServant.java index 1bda0be0091..898e79c6943 100644 --- a/Mage.Sets/src/mage/sets/magic2015/GeneratorServant.java +++ b/Mage.Sets/src/mage/sets/magic2015/GeneratorServant.java @@ -77,7 +77,7 @@ public class GeneratorServant extends CardImpl { ability.addCost(new SacrificeSourceCost()); ability.getEffects().get(0).setText("Add {2} to your mana pool. If that mana is spent on a creature spell, it gains haste until end of turn."); this.addAbility(ability); - + this.addAbility(new SimpleStaticAbility(Zone.ALL, new GeneratorServantHasteEffect()), new GeneratorServantWatcher()); } @@ -94,11 +94,11 @@ public class GeneratorServant extends CardImpl { class GeneratorServantWatcher extends Watcher { public List creatures = new ArrayList<>(); - + public GeneratorServantWatcher() { super("GeneratorServantWatcher", WatcherScope.CARD); } - + public GeneratorServantWatcher(final GeneratorServantWatcher watcher) { super(watcher); this.creatures.addAll(watcher.creatures); @@ -108,13 +108,13 @@ class GeneratorServantWatcher extends Watcher { public GeneratorServantWatcher copy() { return new GeneratorServantWatcher(this); } - + @Override public void watch(GameEvent event, Game game) { if (event.getType() == GameEvent.EventType.MANA_PAYED) { MageObject target = game.getObject(event.getTargetId()); - MageObject source = game.getObject(this.getSourceId()); - if (event.getSourceId() == this.getSourceId() && target != null && target.getCardType().contains(CardType.CREATURE) && event.getFlag()) { + if (event.getSourceId() != null + && event.getSourceId().equals(this.getSourceId()) && target != null && target.getCardType().contains(CardType.CREATURE) && event.getFlag()) { if (target instanceof Spell) { this.creatures.add(((Spell) target).getCard().getId()); } @@ -127,7 +127,7 @@ class GeneratorServantWatcher extends Watcher { super.reset(); creatures.clear(); } - + } class GeneratorServantHasteEffect extends ContinuousEffectImpl { @@ -135,7 +135,7 @@ class GeneratorServantHasteEffect extends ContinuousEffectImpl { public GeneratorServantHasteEffect() { super(Duration.EndOfGame, Layer.AbilityAddingRemovingEffects_6, SubLayer.NA, Outcome.AddAbility); } - + public GeneratorServantHasteEffect(final GeneratorServantHasteEffect effect) { super(effect); } @@ -144,7 +144,7 @@ class GeneratorServantHasteEffect extends ContinuousEffectImpl { public ContinuousEffect copy() { return new GeneratorServantHasteEffect(this); } - + @Override public boolean apply(Game game, Ability source) { GeneratorServantWatcher watcher = (GeneratorServantWatcher) game.getState().getWatchers().get("GeneratorServantWatcher", source.getSourceId()); @@ -158,5 +158,5 @@ class GeneratorServantHasteEffect extends ContinuousEffectImpl { } return false; } - + } diff --git a/Mage.Sets/src/mage/sets/magicorigins/SigilOfValor.java b/Mage.Sets/src/mage/sets/magicorigins/SigilOfValor.java index bc849bbcf50..be8c354a8ee 100644 --- a/Mage.Sets/src/mage/sets/magicorigins/SigilOfValor.java +++ b/Mage.Sets/src/mage/sets/magicorigins/SigilOfValor.java @@ -105,7 +105,9 @@ class SigilOfValorTriggeredAbility extends TriggeredAbilityImpl { if (game.getCombat().attacksAlone()) { Permanent equipment = game.getPermanent(getSourceId()); UUID attackerId = game.getCombat().getAttackers().get(0); - if (equipment != null && equipment.getAttachedTo() == attackerId) { + if (equipment != null + && equipment.getAttachedTo() != null + && equipment.getAttachedTo().equals(attackerId)) { this.getEffects().get(0).setTargetPointer(new FixedTarget(attackerId)); return true; } diff --git a/Mage.Sets/src/mage/sets/masterseditionii/ThoughtLash.java b/Mage.Sets/src/mage/sets/masterseditionii/ThoughtLash.java index e8a28e8196f..65a48ed577a 100644 --- a/Mage.Sets/src/mage/sets/masterseditionii/ThoughtLash.java +++ b/Mage.Sets/src/mage/sets/masterseditionii/ThoughtLash.java @@ -60,10 +60,10 @@ public class ThoughtLash extends CardImpl { // Cumulative upkeep - Exile the top card of your library. this.addAbility(new CumulativeUpkeepAbility(new ExileFromTopOfLibraryCost(1))); - + // When a player doesn't pay Thought Lash's cumulative upkeep, that player exiles all cards from his or her library. this.addAbility(new ThoughtLashTriggeredAbility()); - + // Exile the top card of your library: Prevent the next 1 damage that would be dealt to you this turn. this.addAbility(new SimpleActivatedAbility(Zone.BATTLEFIELD, new ThoughtLashPreventionEffect(), new ExileFromTopOfLibraryCost(1))); } @@ -79,30 +79,30 @@ public class ThoughtLash extends CardImpl { } class ThoughtLashTriggeredAbility extends TriggeredAbilityImpl { - + ThoughtLashTriggeredAbility() { super(Zone.BATTLEFIELD, new ThoughtLashExileLibraryEffect(), false); } - + ThoughtLashTriggeredAbility(final ThoughtLashTriggeredAbility ability) { super(ability); } - + @Override public ThoughtLashTriggeredAbility copy() { return new ThoughtLashTriggeredAbility(this); } - + @Override public boolean checkEventType(GameEvent event, Game game) { return event.getType() == EventType.DIDNT_PAY_CUMULATIVE_UPKEEP; } - + @Override public boolean checkTrigger(GameEvent event, Game game) { - return event.getSourceId() == this.getSourceId(); + return event.getSourceId() != null && event.getSourceId().equals(this.getSourceId()); } - + @Override public String getRule() { return "When a player doesn't pay {this}'s cumulative upkeep, that player exiles all cards from his or her library."; @@ -110,21 +110,21 @@ class ThoughtLashTriggeredAbility extends TriggeredAbilityImpl { } class ThoughtLashExileLibraryEffect extends OneShotEffect { - + ThoughtLashExileLibraryEffect() { super(Outcome.Detriment); this.staticText = "that player exiles all cards from his or her library"; } - + ThoughtLashExileLibraryEffect(final ThoughtLashExileLibraryEffect effect) { super(effect); } - + @Override public ThoughtLashExileLibraryEffect copy() { return new ThoughtLashExileLibraryEffect(this); } - + @Override public boolean apply(Game game, Ability source) { Player controller = game.getPlayer(source.getControllerId()); diff --git a/Mage.Sets/src/mage/sets/planeshift/OrimsChant.java b/Mage.Sets/src/mage/sets/planeshift/OrimsChant.java index 6c87841a9ef..5a35bbde4f3 100644 --- a/Mage.Sets/src/mage/sets/planeshift/OrimsChant.java +++ b/Mage.Sets/src/mage/sets/planeshift/OrimsChant.java @@ -1,31 +1,30 @@ /* -* Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. -* -* Redistribution and use in source and binary forms, with or without modification, are -* permitted provided that the following conditions are met: -* -* 1. Redistributions of source code must retain the above copyright notice, this list of -* conditions and the following disclaimer. -* -* 2. Redistributions in binary form must reproduce the above copyright notice, this list -* of conditions and the following disclaimer in the documentation and/or other materials -* provided with the distribution. -* -* THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED -* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND -* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR -* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR -* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON -* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING -* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF -* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -* -* The views and conclusions contained in the software and documentation are those of the -* authors and should not be interpreted as representing official policies, either expressed -* or implied, of BetaSteward_at_googlemail.com. -*/ - + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ package mage.sets.planeshift; import java.util.UUID; @@ -56,7 +55,6 @@ public class OrimsChant extends CardImpl { super(ownerId, 11, "Orim's Chant", Rarity.RARE, new CardType[]{CardType.INSTANT}, "{W}"); this.expansionSetCode = "PLS"; - // Kicker {W} (You may pay an additional {W} as you cast this spell.) this.addAbility(new KickerAbility("{W}")); @@ -81,7 +79,7 @@ public class OrimsChant extends CardImpl { class OrimsChantCantCastEffect extends ContinuousRuleModifyingEffectImpl { - public OrimsChantCantCastEffect() { + public OrimsChantCantCastEffect() { super(Duration.EndOfTurn, Outcome.Benefit); staticText = "Target player can't cast spells this turn"; } @@ -97,12 +95,12 @@ class OrimsChantCantCastEffect extends ContinuousRuleModifyingEffectImpl { @Override public boolean checksEventType(GameEvent event, Game game) { - return event.getType() == GameEvent.EventType.CAST_SPELL; + return GameEvent.EventType.CAST_SPELL.equals(event.getType()); } @Override public boolean applies(GameEvent event, Ability source, Game game) { - return event.getPlayerId() == getTargetPointer().getFirst(game, source); + return event.getPlayerId().equals(getTargetPointer().getFirst(game, source)); } } diff --git a/Mage.Sets/src/mage/sets/returntoravnica/VraskaTheUnseen.java b/Mage.Sets/src/mage/sets/returntoravnica/VraskaTheUnseen.java index e04c58658c0..3c890808dd2 100644 --- a/Mage.Sets/src/mage/sets/returntoravnica/VraskaTheUnseen.java +++ b/Mage.Sets/src/mage/sets/returntoravnica/VraskaTheUnseen.java @@ -66,7 +66,7 @@ import mage.target.targetpointer.FixedTarget; * Each Assassin token's triggered ability will trigger whenever it deals combat * damage to any player, including you. * - * + * * @author LevelX2 */ public class VraskaTheUnseen extends CardImpl { @@ -76,11 +76,10 @@ public class VraskaTheUnseen extends CardImpl { this.expansionSetCode = "RTR"; this.subtype.add("Vraska"); - this.addAbility(new EntersBattlefieldAbility(new AddCountersSourceEffect(CounterType.LOYALTY.createInstance(5)), false)); // +1: Until your next turn, whenever a creature deals combat damage to Vraska the Unseen, destroy that creature. - this.addAbility(new LoyaltyAbility(new VraskaTheUnseenGainAbilityEffect(new VraskaTheUnseenTriggeredAbility()),1)); + this.addAbility(new LoyaltyAbility(new VraskaTheUnseenGainAbilityEffect(new VraskaTheUnseenTriggeredAbility()), 1)); // -3: Destroy target nonland permanent. LoyaltyAbility ability = new LoyaltyAbility(new DestroyTargetEffect(), -3); @@ -101,7 +100,6 @@ public class VraskaTheUnseen extends CardImpl { } } - class VraskaTheUnseenGainAbilityEffect extends ContinuousEffectImpl { protected Ability ability; @@ -142,8 +140,7 @@ class VraskaTheUnseenGainAbilityEffect extends ContinuousEffectImpl { @Override public boolean isInactive(Ability source, Game game) { - if (startingTurn != 0 && game.getTurnNum() != startingTurn) - { + if (startingTurn != 0 && game.getTurnNum() != startingTurn) { if (game.getActivePlayerId().equals(source.getControllerId())) { return true; } @@ -153,6 +150,7 @@ class VraskaTheUnseenGainAbilityEffect extends ContinuousEffectImpl { } class AssassinToken extends Token { + AssassinToken() { super("Assassin", "1/1 black Assassin creature tokens with \"Whenever this creature deals combat damage to a player, that player loses the game.\""); cardType.add(CardType.CREATURE); @@ -160,7 +158,7 @@ class AssassinToken extends Token { subtype.add("Assassin"); power = new MageInt(1); toughness = new MageInt(1); - addAbility(new DealsCombatDamageToAPlayerTriggeredAbility(new LoseGameTargetPlayerEffect(),false, true)); + addAbility(new DealsCombatDamageToAPlayerTriggeredAbility(new LoseGameTargetPlayerEffect(), false, true)); } } @@ -186,7 +184,7 @@ class VraskaTheUnseenTriggeredAbility extends TriggeredAbilityImpl { @Override public boolean checkTrigger(GameEvent event, Game game) { - if (((DamagedPlaneswalkerEvent) event).isCombatDamage() && event.getTargetId() == sourceId) { + if (((DamagedPlaneswalkerEvent) event).isCombatDamage() && getSourceId().equals(event.getTargetId())) { Permanent sourceOfDamage = game.getPermanent(event.getSourceId()); if (sourceOfDamage != null && sourceOfDamage.getCardType().contains(CardType.CREATURE)) { Effect effect = this.getEffects().get(0); @@ -202,4 +200,4 @@ class VraskaTheUnseenTriggeredAbility extends TriggeredAbilityImpl { return "Until your next turn, whenever a creature deals combat damage to {this}, destroy that creature"; } -} \ No newline at end of file +} diff --git a/Mage.Sets/src/mage/sets/scarsofmirrodin/RevokeExistence.java b/Mage.Sets/src/mage/sets/scarsofmirrodin/RevokeExistence.java index 554cefc08b4..1186f719aec 100644 --- a/Mage.Sets/src/mage/sets/scarsofmirrodin/RevokeExistence.java +++ b/Mage.Sets/src/mage/sets/scarsofmirrodin/RevokeExistence.java @@ -25,25 +25,24 @@ * authors and should not be interpreted as representing official policies, either expressed * or implied, of BetaSteward_at_googlemail.com. */ - package mage.sets.scarsofmirrodin; -import mage.constants.CardType; -import mage.constants.Rarity; +import java.util.UUID; import mage.abilities.effects.common.ExileTargetEffect; 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; -import java.util.UUID; - /** * * @author Loki */ public class RevokeExistence extends CardImpl { + private static final FilterPermanent filter = new FilterPermanent("artifact or enchantment"); static { @@ -52,15 +51,16 @@ public class RevokeExistence extends CardImpl { new CardTypePredicate(CardType.ENCHANTMENT))); } - public RevokeExistence (UUID ownerId) { + public RevokeExistence(UUID ownerId) { super(ownerId, 18, "Revoke Existence", Rarity.COMMON, new CardType[]{CardType.SORCERY}, "{1}{W}"); this.expansionSetCode = "SOM"; + // Exile target artifact or enchantment. this.getSpellAbility().addEffect(new ExileTargetEffect()); this.getSpellAbility().addTarget(new TargetPermanent(filter)); } - public RevokeExistence (final RevokeExistence card) { + public RevokeExistence(final RevokeExistence card) { super(card); } diff --git a/Mage.Sets/src/mage/sets/shadowmoor/MossbridgeTroll.java b/Mage.Sets/src/mage/sets/shadowmoor/MossbridgeTroll.java index 539b8f9d3d0..bc44a0a95d4 100644 --- a/Mage.Sets/src/mage/sets/shadowmoor/MossbridgeTroll.java +++ b/Mage.Sets/src/mage/sets/shadowmoor/MossbridgeTroll.java @@ -56,7 +56,7 @@ import mage.target.common.TargetControlledCreaturePermanent; * @author jeffwadsworth */ public class MossbridgeTroll extends CardImpl { - + private static final FilterControlledCreaturePermanent filter = new FilterControlledCreaturePermanent("untapped creatures you control"); static { @@ -78,7 +78,7 @@ public class MossbridgeTroll extends CardImpl { Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new BoostSourceEffect(20, 20, Duration.EndOfTurn), new MossbridgeTrollCost()); ability.setAdditionalCostsRuleVisible(false); this.addAbility(ability); - + } public MossbridgeTroll(final MossbridgeTroll card) { @@ -115,10 +115,11 @@ class MossbridgeTrollReplacementEffect extends ReplacementEffectImpl { public boolean checksEventType(GameEvent event, Game game) { return event.getType() == GameEvent.EventType.DESTROY_PERMANENT; } - + @Override public boolean applies(GameEvent event, Ability source, Game game) { - return event.getTargetId() == source.getSourceId(); + return event.getTargetId() != null + && event.getTargetId().equals(source.getSourceId()); } @Override @@ -150,7 +151,7 @@ class MossbridgeTrollCost extends CostImpl { public boolean pay(Ability ability, Game game, UUID sourceId, UUID controllerId, boolean noMana) { int sumPower = 0; if (targets.choose(Outcome.Tap, controllerId, sourceId, game)) { - for (UUID targetId: targets.get(0).getTargets()) { + for (UUID targetId : targets.get(0).getTargets()) { Permanent permanent = game.getPermanent(targetId); if (permanent != null && permanent.tap(game)) { sumPower += permanent.getPower().getValue(); @@ -165,7 +166,7 @@ class MossbridgeTrollCost extends CostImpl { @Override public boolean canPay(Ability ability, UUID sourceId, UUID controllerId, Game game) { int sumPower = 0; - for (Permanent permanent :game.getBattlefield().getAllActivePermanents(new FilterCreaturePermanent(), controllerId, game)) { + for (Permanent permanent : game.getBattlefield().getAllActivePermanents(new FilterCreaturePermanent(), controllerId, game)) { if (!permanent.getId().equals(sourceId)) { sumPower += permanent.getPower().getValue(); } @@ -178,4 +179,3 @@ class MossbridgeTrollCost extends CostImpl { return new MossbridgeTrollCost(this); } } - diff --git a/Mage.Sets/src/mage/sets/shadowmoor/ThoughtweftGambit.java b/Mage.Sets/src/mage/sets/shadowmoor/ThoughtweftGambit.java index f6c0b113a1d..5246fd44592 100644 --- a/Mage.Sets/src/mage/sets/shadowmoor/ThoughtweftGambit.java +++ b/Mage.Sets/src/mage/sets/shadowmoor/ThoughtweftGambit.java @@ -50,7 +50,6 @@ public class ThoughtweftGambit extends CardImpl { super(ownerId, 154, "Thoughtweft Gambit", Rarity.UNCOMMON, new CardType[]{CardType.INSTANT}, "{4}{W/U}{W/U}"); this.expansionSetCode = "SHM"; - // Tap all creatures your opponents control and untap all creatures you control. this.getSpellAbility().addEffect(new ThoughtweftGambitEffect()); @@ -94,7 +93,7 @@ class ThoughtweftGambitEffect extends OneShotEffect { } if (controller != null) { for (Permanent creature : game.getBattlefield().getActivePermanents(filter, source.getControllerId(), game)) { - if (controller.getId() == creature.getControllerId()) { + if (controller.getId().equals(creature.getControllerId())) { creature.untap(game); } } diff --git a/Mage.Sets/src/mage/sets/shardsofalara/GatherSpecimens.java b/Mage.Sets/src/mage/sets/shardsofalara/GatherSpecimens.java index 1287b0fc327..f33ff12365e 100644 --- a/Mage.Sets/src/mage/sets/shardsofalara/GatherSpecimens.java +++ b/Mage.Sets/src/mage/sets/shardsofalara/GatherSpecimens.java @@ -52,10 +52,8 @@ public class GatherSpecimens extends CardImpl { super(ownerId, 45, "Gather Specimens", Rarity.RARE, new CardType[]{CardType.INSTANT}, "{3}{U}{U}{U}"); this.expansionSetCode = "ALA"; - // If a creature would enter the battlefield under an opponent's control this turn, it enters the battlefield under your control instead. this.getSpellAbility().addEffect(new GatherSpecimensReplacementEffect()); - } public GatherSpecimens(final GatherSpecimens card) { @@ -114,7 +112,7 @@ class GatherSpecimensReplacementEffect extends ReplacementEffectImpl { } return false; } - + @Override public boolean replaceEvent(GameEvent event, Ability source, Game game) { Player controller = game.getPlayer(source.getControllerId()); @@ -122,5 +120,5 @@ class GatherSpecimensReplacementEffect extends ReplacementEffectImpl { event.setPlayerId(controller.getId()); } return false; - } + } } diff --git a/Mage.Sets/src/mage/sets/tempest/HelmOfPossession.java b/Mage.Sets/src/mage/sets/tempest/HelmOfPossession.java index f80c7843013..b20810eabfc 100644 --- a/Mage.Sets/src/mage/sets/tempest/HelmOfPossession.java +++ b/Mage.Sets/src/mage/sets/tempest/HelmOfPossession.java @@ -59,7 +59,7 @@ public class HelmOfPossession extends CardImpl { // You may choose not to untap Helm of Possession during your untap step. this.addAbility(new SkipUntapOptionalAbility()); - + // {2}, {tap}, Sacrifice a creature: Gain control of target creature for as long as you control Helm of Possession and Helm of Possession remains tapped. ConditionalContinuousEffect effect = new ConditionalContinuousEffect( new GainControlTargetEffect(Duration.Custom), @@ -92,11 +92,11 @@ class HelmOfPossessionCondition implements Condition { controllerId = source.getControllerId(); } Permanent permanent = game.getBattlefield().getPermanent(source.getSourceId()); - if (permanent != null){ - if (permanent.isTapped()){ - return controllerId == source.getControllerId(); + if (permanent != null) { + if (permanent.isTapped()) { + return controllerId.equals(source.getControllerId()); } } return false; } -} \ No newline at end of file +} diff --git a/Mage.Sets/src/mage/sets/worldwake/TuktukScrapper.java b/Mage.Sets/src/mage/sets/worldwake/TuktukScrapper.java index f1476ca3aee..2a22757c2ef 100644 --- a/Mage.Sets/src/mage/sets/worldwake/TuktukScrapper.java +++ b/Mage.Sets/src/mage/sets/worldwake/TuktukScrapper.java @@ -100,7 +100,7 @@ class TuktukScrapperTriggeredAbility extends TriggeredAbilityImpl { public boolean checkTrigger(GameEvent event, Game game) { Permanent permanent = game.getPermanent(event.getTargetId()); if (permanent != null) { - if (permanent.getId() == this.getSourceId()) { + if (permanent.getId().equals(this.getSourceId())) { return true; } if (permanent.hasSubtype("Ally") diff --git a/Mage.Sets/src/mage/sets/worldwake/WrexialTheRisenDeep.java b/Mage.Sets/src/mage/sets/worldwake/WrexialTheRisenDeep.java index c0c76991785..678fbf386b4 100644 --- a/Mage.Sets/src/mage/sets/worldwake/WrexialTheRisenDeep.java +++ b/Mage.Sets/src/mage/sets/worldwake/WrexialTheRisenDeep.java @@ -28,11 +28,6 @@ package mage.sets.worldwake; 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.MageInt; import mage.abilities.Ability; import mage.abilities.common.DealsCombatDamageToAPlayerTriggeredAbility; @@ -42,6 +37,11 @@ import mage.abilities.keyword.IslandwalkAbility; import mage.abilities.keyword.SwampwalkAbility; import mage.cards.Card; import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.Outcome; +import mage.constants.Rarity; +import mage.constants.Zone; import mage.filter.FilterCard; import mage.filter.predicate.Predicates; import mage.filter.predicate.mageobject.CardTypePredicate; @@ -50,7 +50,6 @@ import mage.game.Game; import mage.game.events.GameEvent; import mage.game.events.GameEvent.EventType; import mage.game.events.ZoneChangeEvent; -import mage.game.stack.Spell; import mage.game.stack.StackObject; import mage.players.Player; import mage.target.Target; @@ -156,29 +155,22 @@ class WrexialReplacementEffect extends ReplacementEffectImpl { public boolean checksEventType(GameEvent event, Game game) { return event.getType() == EventType.ZONE_CHANGE; } - + @Override public boolean applies(GameEvent event, Ability source, Game game) { ZoneChangeEvent zEvent = (ZoneChangeEvent) event; - if (zEvent.getToZone() == Zone.GRAVEYARD - && ((ZoneChangeEvent) event).getTargetId() == cardid) { - return true; - } - return false; + return zEvent.getToZone() == Zone.GRAVEYARD + && ((ZoneChangeEvent) event).getTargetId().equals(cardid); } - + @Override public boolean replaceEvent(GameEvent event, Ability source, Game game) { UUID eventObject = ((ZoneChangeEvent) event).getTargetId(); StackObject card = game.getStack().getStackObject(eventObject); Player controller = game.getPlayer(source.getControllerId()); if (card != null && controller != null) { - if (card instanceof Spell) { - game.rememberLKI(card.getId(), Zone.STACK, (Spell) card); - } if (card instanceof Card) { - controller.moveCardToExileWithInfo((Card)card, null, "", source.getSourceId(), game, game.getState().getZone(event.getTargetId()), true); - return true; + return controller.moveCards((Card) card, null, Zone.EXILED, source, game); } } return false; diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/triggers/OblivionRingTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/triggers/OblivionRingTest.java index ef5dc6ae622..d09251969fc 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/triggers/OblivionRingTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/triggers/OblivionRingTest.java @@ -90,6 +90,7 @@ public class OblivionRingTest extends CardTestPlayerBase { addCard(Zone.BATTLEFIELD, playerA, "Plains", 5); addCard(Zone.HAND, playerA, "Oblivion Ring"); addCard(Zone.BATTLEFIELD, playerA, "Jace Beleren"); + // Exile target artifact or enchantment. addCard(Zone.HAND, playerA, "Revoke Existence"); activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "-1: Target player draws a card", playerA); @@ -100,7 +101,10 @@ public class OblivionRingTest extends CardTestPlayerBase { setStopAt(1, PhaseStep.END_TURN); execute(); + assertExileCount("Oblivion Ring", 1); + assertGraveyardCount(playerA, "Revoke Existence", 1); assertPermanentCount(playerA, "Oblivion Ring", 0); + assertGraveyardCount(playerA, "Jace Beleren", 0); assertPermanentCount(playerA, "Jace Beleren", 1); // returns back assertHandCount(playerA, 2); // can use ability twice } diff --git a/Mage/src/mage/abilities/common/EntersBattlefieldAbility.java b/Mage/src/mage/abilities/common/EntersBattlefieldAbility.java index fa51f390540..64bd2c40fe5 100644 --- a/Mage/src/mage/abilities/common/EntersBattlefieldAbility.java +++ b/Mage/src/mage/abilities/common/EntersBattlefieldAbility.java @@ -1,31 +1,30 @@ /* -* Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. -* -* Redistribution and use in source and binary forms, with or without modification, are -* permitted provided that the following conditions are met: -* -* 1. Redistributions of source code must retain the above copyright notice, this list of -* conditions and the following disclaimer. -* -* 2. Redistributions in binary form must reproduce the above copyright notice, this list -* of conditions and the following disclaimer in the documentation and/or other materials -* provided with the distribution. -* -* THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED -* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND -* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR -* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR -* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON -* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING -* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF -* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -* -* The views and conclusions contained in the software and documentation are those of the -* authors and should not be interpreted as representing official policies, either expressed -* or implied, of BetaSteward_at_googlemail.com. -*/ - + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ package mage.abilities.common; import mage.abilities.StaticAbility; @@ -41,15 +40,17 @@ import mage.constants.Zone; public class EntersBattlefieldAbility extends StaticAbility { protected String abilityRule; - + public EntersBattlefieldAbility(Effect effect) { this(effect, true); } -/** - * - * @param effect effect that happens when the permanent enters the battlefield - * @param showRule show the rule for this ability - */ + + /** + * + * @param effect effect that happens when the permanent enters the + * battlefield + * @param showRule show the rule for this ability + */ public EntersBattlefieldAbility(Effect effect, Boolean showRule) { this(effect, null, showRule, null, null); } @@ -57,16 +58,19 @@ public class EntersBattlefieldAbility extends StaticAbility { public EntersBattlefieldAbility(Effect effect, String effectText) { this(effect, null, true, null, effectText); } -/** - * - * @param effect effect that happens when the permanent enters the battlefield - * @param condition only if this condition is true, the effect will happen - * @param ruleVisible show the rule for this ability - * @param abilityRule rule for this ability (no text from effects will be added) - * @param effectText this text will be used for the EnterBattlefieldEffect - */ + + /** + * + * @param effect effect that happens when the permanent enters the + * battlefield + * @param condition only if this condition is true, the effect will happen + * @param ruleVisible show the rule for this ability + * @param abilityRule rule for this ability (no text from effects will be + * added) + * @param effectText this text will be used for the EnterBattlefieldEffect + */ public EntersBattlefieldAbility(Effect effect, Condition condition, Boolean ruleVisible, String abilityRule, String effectText) { - super(Zone.BATTLEFIELD, new EntersBattlefieldEffect(effect, condition, effectText)); + super(Zone.ALL, new EntersBattlefieldEffect(effect, condition, effectText)); this.setRuleVisible(ruleVisible); this.abilityRule = abilityRule; } @@ -96,7 +100,7 @@ public class EntersBattlefieldAbility extends StaticAbility { @Override public String getRule() { if (!ruleVisible) { - return ""; + return ""; } if (abilityRule != null && !abilityRule.isEmpty()) { return abilityRule; diff --git a/Mage/src/mage/abilities/costs/common/DiscardTargetCost.java b/Mage/src/mage/abilities/costs/common/DiscardTargetCost.java index 5ba87b81916..c62ecfc3953 100644 --- a/Mage/src/mage/abilities/costs/common/DiscardTargetCost.java +++ b/Mage/src/mage/abilities/costs/common/DiscardTargetCost.java @@ -68,7 +68,7 @@ public class DiscardTargetCost extends CostImpl { @Override public boolean pay(Ability ability, Game game, UUID sourceId, UUID controllerId, boolean noMana) { this.cards.clear(); - this.targets.clear(); + this.targets.clearChosen();; Player player = game.getPlayer(controllerId); if (player == null) { return false; diff --git a/Mage/src/mage/abilities/effects/ContinuousEffects.java b/Mage/src/mage/abilities/effects/ContinuousEffects.java index 241c3de5289..de323f1202b 100644 --- a/Mage/src/mage/abilities/effects/ContinuousEffects.java +++ b/Mage/src/mage/abilities/effects/ContinuousEffects.java @@ -1246,7 +1246,7 @@ public class ContinuousEffects implements Serializable { HashSet abilities = preventionEffects.getAbility(effect.getId()); for (Ability ability : abilities) { if (ability.getSourceId().equals(sourceId)) { - if (controllerFound == null || controllerFound == ability.getControllerId()) { + if (controllerFound == null || controllerFound.equals(ability.getControllerId())) { controllerFound = ability.getControllerId(); } else { // not unique controller - No solution yet @@ -1260,7 +1260,7 @@ public class ContinuousEffects implements Serializable { for (Ability ability : abilities) { if (ability.getSourceId() != null) { if (ability.getSourceId().equals(sourceId)) { - if (controllerFound == null || controllerFound == ability.getControllerId()) { + if (controllerFound == null || controllerFound.equals(ability.getControllerId())) { controllerFound = ability.getControllerId(); } else { // not unique controller - No solution yet diff --git a/Mage/src/mage/abilities/effects/common/ReturnFromExileForSourceEffect.java b/Mage/src/mage/abilities/effects/common/ReturnFromExileForSourceEffect.java index 8d7b8a7c2be..1276b0acdff 100644 --- a/Mage/src/mage/abilities/effects/common/ReturnFromExileForSourceEffect.java +++ b/Mage/src/mage/abilities/effects/common/ReturnFromExileForSourceEffect.java @@ -101,7 +101,11 @@ public class ReturnFromExileForSourceEffect extends OneShotEffect { } ExileZone exile = game.getExile().getExileZone(CardUtil.getExileZoneId(game, source.getSourceId(), zoneChangeCounter)); if (exile != null) { // null is valid if source left battlefield before enters the battlefield effect resolved - controller.moveCards(exile, null, returnToZone, source, game); + if (returnToZone.equals(Zone.BATTLEFIELD)) { + controller.moveCards(exile.getCards(game), returnToZone, source, game, false, false, true, null); + } else { + controller.moveCards(exile, null, returnToZone, source, game); + } } return true; } diff --git a/Mage/src/mage/abilities/keyword/ReboundAbility.java b/Mage/src/mage/abilities/keyword/ReboundAbility.java index 6bd8c0d6527..7ab46d546e0 100644 --- a/Mage/src/mage/abilities/keyword/ReboundAbility.java +++ b/Mage/src/mage/abilities/keyword/ReboundAbility.java @@ -1,31 +1,30 @@ /* -* Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. -* -* Redistribution and use in source and binary forms, with or without modification, are -* permitted provided that the following conditions are met: -* -* 1. Redistributions of source code must retain the above copyright notice, this list of -* conditions and the following disclaimer. -* -* 2. Redistributions in binary form must reproduce the above copyright notice, this list -* of conditions and the following disclaimer in the documentation and/or other materials -* provided with the distribution. -* -* THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED -* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND -* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR -* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR -* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON -* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING -* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF -* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -* -* The views and conclusions contained in the software and documentation are those of the -* authors and should not be interpreted as representing official policies, either expressed -* or implied, of BetaSteward_at_googlemail.com. -*/ - + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ package mage.abilities.keyword; import java.util.UUID; @@ -48,28 +47,29 @@ import mage.game.stack.Spell; import mage.players.Player; /** - * This ability has no effect by default and will always return false on the call - * to apply. This is because of how the {@link ReboundEffect} works. It will - * install the effect if and only if the spell was cast from the {@link Zone#HAND Hand}. + * This ability has no effect by default and will always return false on the + * call to apply. This is because of how the {@link ReboundEffect} works. It + * will install the effect if and only if the spell was cast from the + * {@link Zone#HAND Hand}. *

* 702.85. Rebound *

- * 702.85a Rebound appears on some instants and sorceries. It represents a static - * ability that functions while the spell is on the stack and may create a delayed - * triggered ability. "Rebound" means "If this spell was cast from your hand, - * instead of putting it into your graveyard as it resolves, exile it and, at - * the beginning of your next upkeep, you may cast this card from exile without - * paying its mana cost." + * 702.85a Rebound appears on some instants and sorceries. It represents a + * static ability that functions while the spell is on the stack and may create + * a delayed triggered ability. "Rebound" means "If this spell was cast from + * your hand, instead of putting it into your graveyard as it resolves, exile it + * and, at the beginning of your next upkeep, you may cast this card from exile + * without paying its mana cost." *

- * 702.85b Casting a card without paying its mana cost as the result of a rebound - * ability follows the rules for paying alternative costs in rules 601.2b and 601.2e-g. + * 702.85b Casting a card without paying its mana cost as the result of a + * rebound ability follows the rules for paying alternative costs in rules + * 601.2b and 601.2e-g. *

* 702.85c Multiple instances of rebound on the same spell are redundant. * * @author maurer.it_at_gmail.com, noxx */ - -public class ReboundAbility extends SimpleStaticAbility { +public class ReboundAbility extends SimpleStaticAbility { public ReboundAbility() { super(Zone.STACK, new ReboundCastFromHandReplacementEffect()); @@ -81,8 +81,8 @@ public class ReboundAbility extends SimpleStaticAbility { @Override public ReboundAbility copy() { - return new ReboundAbility(this); - } + return new ReboundAbility(this); + } } class ReboundCastFromHandReplacementEffect extends ReplacementEffectImpl { @@ -95,7 +95,7 @@ class ReboundCastFromHandReplacementEffect extends ReplacementEffectImpl { ReboundCastFromHandReplacementEffect(ReboundCastFromHandReplacementEffect effect) { super(effect); } - + @Override public boolean checksEventType(GameEvent event, Game game) { return event.getType() == GameEvent.EventType.ZONE_CHANGE; @@ -103,16 +103,18 @@ class ReboundCastFromHandReplacementEffect extends ReplacementEffectImpl { @Override public boolean applies(GameEvent event, Ability source, Game game) { - if (((ZoneChangeEvent) event).getFromZone() == Zone.STACK && - ((ZoneChangeEvent) event).getToZone() == Zone.GRAVEYARD && - event.getSourceId() == source.getSourceId()) { // if countered the source.sourceId is different or null if it fizzles + if (((ZoneChangeEvent) event).getFromZone() == Zone.STACK + && ((ZoneChangeEvent) event).getToZone() == Zone.GRAVEYARD + && event.getSourceId() != null + && event.getSourceId().equals(source.getSourceId())) { // if countered the source.sourceId is different or null if it fizzles Spell spell = game.getStack().getSpell(event.getTargetId()); if (spell != null && spell.getFromZone().equals(Zone.HAND)) { return true; - } + } } return false; } + @Override public boolean replaceEvent(GameEvent event, Ability source, Game game) { Spell sourceSpell = game.getStack().getSpell(source.getSourceId()); @@ -126,9 +128,9 @@ class ReboundCastFromHandReplacementEffect extends ReplacementEffectImpl { // Add the delayed triggered effect ReboundEffectCastFromExileDelayedTrigger trigger = new ReboundEffectCastFromExileDelayedTrigger(source.getSourceId(), source.getSourceId()); trigger.setControllerId(source.getControllerId()); - trigger.setSourceObject(source.getSourceObject(game), game); + trigger.setSourceObject(source.getSourceObject(game), game); game.addDelayedTriggeredAbility(trigger); - + player.moveCardToExileWithInfo(sourceCard, sourceCard.getId(), player.getName() + " Rebound", source.getSourceId(), game, Zone.STACK, true); return true; } @@ -144,7 +146,6 @@ class ReboundCastFromHandReplacementEffect extends ReplacementEffectImpl { } - class ReboundEffectCastFromExileDelayedTrigger extends DelayedTriggeredAbility { ReboundEffectCastFromExileDelayedTrigger(UUID cardId, UUID sourceId) { @@ -171,6 +172,7 @@ class ReboundEffectCastFromExileDelayedTrigger extends DelayedTriggeredAbility { public boolean checkTrigger(GameEvent event, Game game) { return MyTurnCondition.getInstance().apply(game, this); } + @Override public String getRule() { return "Rebound - You may cast {this} from exile without paying its mana cost."; @@ -178,8 +180,8 @@ class ReboundEffectCastFromExileDelayedTrigger extends DelayedTriggeredAbility { } /** - * Will be triggered by {@link ReboundEffectCastFromExileDelayedTrigger} and will - * simply cast the spell then remove it from its former home in exile. + * Will be triggered by {@link ReboundEffectCastFromExileDelayedTrigger} and + * will simply cast the spell then remove it from its former home in exile. * * @author maurer.it_at_gmail.com */ diff --git a/Mage/src/mage/cards/CardImpl.java b/Mage/src/mage/cards/CardImpl.java index d6dc1f58c7d..2d3fa165cfe 100644 --- a/Mage/src/mage/cards/CardImpl.java +++ b/Mage/src/mage/cards/CardImpl.java @@ -507,8 +507,8 @@ public abstract class CardImpl extends MageObjectImpl implements Card { break; case EXILED: if (game.getExile().getCard(getId(), game) != null) { - game.getExile().removeCard(this, game); - removed = true; + removed = game.getExile().removeCard(this, game); + } break; case STACK: @@ -552,8 +552,9 @@ public abstract class CardImpl extends MageObjectImpl implements Card { + "] source [" + (sourceObject != null ? sourceObject.getName() : "null") + "]"); break; } - game.rememberLKI(objectId, fromZone, lkiObject != null ? lkiObject : this); - if (!removed) { + if (removed) { + game.rememberLKI(objectId, fromZone, lkiObject != null ? lkiObject : this); + } else { logger.warn("Couldn't find card in fromZone, card=" + getIdName() + ", fromZone=" + fromZone); } return removed; diff --git a/Mage/src/mage/game/Exile.java b/Mage/src/mage/game/Exile.java index 42b513092f3..8abb6d4cb59 100644 --- a/Mage/src/mage/game/Exile.java +++ b/Mage/src/mage/game/Exile.java @@ -107,12 +107,13 @@ public class Exile implements Serializable, Copyable { return cards; } - public void removeCard(Card card, Game game) { + public boolean removeCard(Card card, Game game) { for (ExileZone exile : exileZones.values()) { if (exile.contains(card.getId())) { - exile.remove(card); + return exile.remove(card.getId()); } } + return false; } @Override diff --git a/Mage/src/mage/players/PlayerImpl.java b/Mage/src/mage/players/PlayerImpl.java index 49e8ffb656a..bb1250e1b5c 100644 --- a/Mage/src/mage/players/PlayerImpl.java +++ b/Mage/src/mage/players/PlayerImpl.java @@ -3052,7 +3052,7 @@ public abstract class PlayerImpl implements Player, Serializable { ZoneChangeEvent event = new ZoneChangeEvent(card.getId(), source.getSourceId(), controllingPlayerId, fromZone, Zone.BATTLEFIELD, appliedEffects, tapped); if (!game.replaceEvent(event)) { // get permanent - Permanent permanent = new PermanentCard(card, controllingPlayerId, game); + Permanent permanent = new PermanentCard(card, event.getPlayerId(), game);// controlling player can be replaced so use event player now permanents.add(permanent); card.checkForCountersToAdd(permanent, game); permanent.setTapped(tapped); From 03542fbc92a70780550fa0719eaad1cd8b4cc67d Mon Sep 17 00:00:00 2001 From: LoneFox Date: Wed, 14 Oct 2015 21:00:55 +0300 Subject: [PATCH 095/268] Implement cards: Alexi's Cloak; Barbed Field; Chilling Apparition; and Latulla, Keldon Overseer --- .../src/mage/sets/prophecy/AlexisCloak.java | 78 +++++++++++++++++ .../src/mage/sets/prophecy/BarbedField.java | 84 +++++++++++++++++++ .../sets/prophecy/ChillingApparition.java | 69 +++++++++++++++ .../sets/prophecy/LatullaKeldonOverseer.java | 78 +++++++++++++++++ 4 files changed, 309 insertions(+) create mode 100644 Mage.Sets/src/mage/sets/prophecy/AlexisCloak.java create mode 100644 Mage.Sets/src/mage/sets/prophecy/BarbedField.java create mode 100644 Mage.Sets/src/mage/sets/prophecy/ChillingApparition.java create mode 100644 Mage.Sets/src/mage/sets/prophecy/LatullaKeldonOverseer.java diff --git a/Mage.Sets/src/mage/sets/prophecy/AlexisCloak.java b/Mage.Sets/src/mage/sets/prophecy/AlexisCloak.java new file mode 100644 index 00000000000..f2616d74fd2 --- /dev/null +++ b/Mage.Sets/src/mage/sets/prophecy/AlexisCloak.java @@ -0,0 +1,78 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.sets.prophecy; + +import java.util.UUID; +import mage.abilities.Ability; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.effects.common.AttachEffect; +import mage.abilities.effects.common.continuous.GainAbilityAttachedEffect; +import mage.abilities.keyword.EnchantAbility; +import mage.abilities.keyword.FlashAbility; +import mage.abilities.keyword.ShroudAbility; +import mage.cards.CardImpl; +import mage.constants.AttachmentType; +import mage.constants.CardType; +import mage.constants.Outcome; +import mage.constants.Rarity; +import mage.constants.Zone; +import mage.target.TargetPermanent; +import mage.target.common.TargetCreaturePermanent; + +/** + * + * @author LoneFox + */ +public class AlexisCloak extends CardImpl { + + public AlexisCloak(UUID ownerId) { + super(ownerId, 29, "Alexi's Cloak", Rarity.COMMON, new CardType[]{CardType.ENCHANTMENT}, "{1}{U}"); + this.expansionSetCode = "PCY"; + this.subtype.add("Aura"); + + // Flash + this.addAbility(FlashAbility.getInstance()); + // Enchant creature + TargetPermanent auraTarget = new TargetCreaturePermanent(); + this.getSpellAbility().addTarget(auraTarget); + this.getSpellAbility().addEffect(new AttachEffect(Outcome.AddAbility)); + Ability ability = new EnchantAbility(auraTarget.getTargetName()); + this.addAbility(ability); + // Enchanted creature has shroud. + this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new GainAbilityAttachedEffect(ShroudAbility.getInstance(), AttachmentType.AURA))); + } + + public AlexisCloak(final AlexisCloak card) { + super(card); + } + + @Override + public AlexisCloak copy() { + return new AlexisCloak(this); + } +} diff --git a/Mage.Sets/src/mage/sets/prophecy/BarbedField.java b/Mage.Sets/src/mage/sets/prophecy/BarbedField.java new file mode 100644 index 00000000000..794f5688e29 --- /dev/null +++ b/Mage.Sets/src/mage/sets/prophecy/BarbedField.java @@ -0,0 +1,84 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.sets.prophecy; + +import java.util.UUID; +import mage.abilities.Ability; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.costs.common.TapSourceCost; +import mage.abilities.effects.Effect; +import mage.abilities.effects.common.AttachEffect; +import mage.abilities.effects.common.DamageTargetEffect; +import mage.abilities.effects.common.continuous.GainAbilityAttachedEffect; +import mage.abilities.keyword.EnchantAbility; +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.Zone; +import mage.target.TargetPermanent; +import mage.target.common.TargetCreatureOrPlayer; +import mage.target.common.TargetLandPermanent; + +/** + * + * @author LoneFox + */ +public class BarbedField extends CardImpl { + + public BarbedField(UUID ownerId) { + super(ownerId, 83, "Barbed Field", Rarity.UNCOMMON, new CardType[]{CardType.ENCHANTMENT}, "{2}{R}{R}"); + this.expansionSetCode = "PCY"; + this.subtype.add("Aura"); + + // Enchant land + TargetPermanent auraTarget = new TargetLandPermanent(); + this.getSpellAbility().addTarget(auraTarget); + this.getSpellAbility().addEffect(new AttachEffect(Outcome.AddAbility)); + Ability ability = new EnchantAbility(auraTarget.getTargetName()); + this.addAbility(ability); + // Enchanted land has "{tap}: This land deals 1 damage to target creature or player." + ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new DamageTargetEffect(1), new TapSourceCost()); + ability.addTarget(new TargetCreatureOrPlayer()); + Effect effect = new GainAbilityAttachedEffect(ability, AttachmentType.AURA); + effect.setText("Enchanted land has \"{T}: This land deals 1 damage to target creature or player.\""); + this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, effect)); + } + + public BarbedField(final BarbedField card) { + super(card); + } + + @Override + public BarbedField copy() { + return new BarbedField(this); + } +} diff --git a/Mage.Sets/src/mage/sets/prophecy/ChillingApparition.java b/Mage.Sets/src/mage/sets/prophecy/ChillingApparition.java new file mode 100644 index 00000000000..e47fc63331e --- /dev/null +++ b/Mage.Sets/src/mage/sets/prophecy/ChillingApparition.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.prophecy; + +import java.util.UUID; +import mage.MageInt; +import mage.abilities.common.DealsDamageToOpponentTriggeredAbility; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.effects.common.RegenerateSourceEffect; +import mage.abilities.effects.common.discard.DiscardTargetEffect; +import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.Rarity; +import mage.constants.Zone; + +/** + * + * @author LoneFox + */ +public class ChillingApparition extends CardImpl { + + public ChillingApparition(UUID ownerId) { + super(ownerId, 59, "Chilling Apparition", Rarity.UNCOMMON, new CardType[]{CardType.CREATURE}, "{2}{B}"); + this.expansionSetCode = "PCY"; + this.subtype.add("Spirit"); + this.power = new MageInt(1); + this.toughness = new MageInt(1); + + // {B}: Regenerate Chilling Apparition. + this.addAbility(new SimpleActivatedAbility(Zone.BATTLEFIELD, new RegenerateSourceEffect(), new ManaCostsImpl("{B}"))); + // Whenever Chilling Apparition deals combat damage to a player, that player discards a card. + this.addAbility(new DealsDamageToOpponentTriggeredAbility(new DiscardTargetEffect(1), false, true, true)); + } + + public ChillingApparition(final ChillingApparition card) { + super(card); + } + + @Override + public ChillingApparition copy() { + return new ChillingApparition(this); + } +} diff --git a/Mage.Sets/src/mage/sets/prophecy/LatullaKeldonOverseer.java b/Mage.Sets/src/mage/sets/prophecy/LatullaKeldonOverseer.java new file mode 100644 index 00000000000..5d7ca6f1de7 --- /dev/null +++ b/Mage.Sets/src/mage/sets/prophecy/LatullaKeldonOverseer.java @@ -0,0 +1,78 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.sets.prophecy; + +import java.util.UUID; +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.costs.common.DiscardTargetCost; +import mage.abilities.costs.common.TapSourceCost; +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.dynamicvalue.common.ManacostVariableValue; +import mage.abilities.effects.common.DamageTargetEffect; +import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.Rarity; +import mage.constants.Zone; +import mage.filter.FilterCard; +import mage.target.common.TargetCardInHand; +import mage.target.common.TargetCreatureOrPlayer; + +/** + * + * @author LoneFox + */ +public class LatullaKeldonOverseer extends CardImpl { + + public LatullaKeldonOverseer(UUID ownerId) { + super(ownerId, 95, "Latulla, Keldon Overseer", Rarity.RARE, new CardType[]{CardType.CREATURE}, "{3}{R}{R}"); + this.expansionSetCode = "PCY"; + this.supertype.add("Legendary"); + this.subtype.add("Human"); + this.subtype.add("Spellshaper"); + this.power = new MageInt(3); + this.toughness = new MageInt(3); + + // {X}{R}, {tap}, Discard two cards: Latulla, Keldon Overseer deals X damage to target creature or player. + Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new DamageTargetEffect(new ManacostVariableValue()), new ManaCostsImpl("{X}{R}")); + ability.addCost(new TapSourceCost()); + ability.addCost(new DiscardTargetCost(new TargetCardInHand(2, 2, new FilterCard("two cards")))); + ability.addTarget(new TargetCreatureOrPlayer()); + this.addAbility(ability); + } + + public LatullaKeldonOverseer(final LatullaKeldonOverseer card) { + super(card); + } + + @Override + public LatullaKeldonOverseer copy() { + return new LatullaKeldonOverseer(this); + } +} From d60b5ce266f199220c78f77c27357f795ddb7dc0 Mon Sep 17 00:00:00 2001 From: LoneFox Date: Wed, 14 Oct 2015 21:17:54 +0300 Subject: [PATCH 096/268] Fix Chilling Apparition to affect any player it damages --- Mage.Sets/src/mage/sets/prophecy/ChillingApparition.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Mage.Sets/src/mage/sets/prophecy/ChillingApparition.java b/Mage.Sets/src/mage/sets/prophecy/ChillingApparition.java index e47fc63331e..816f89bac48 100644 --- a/Mage.Sets/src/mage/sets/prophecy/ChillingApparition.java +++ b/Mage.Sets/src/mage/sets/prophecy/ChillingApparition.java @@ -29,7 +29,7 @@ package mage.sets.prophecy; import java.util.UUID; import mage.MageInt; -import mage.abilities.common.DealsDamageToOpponentTriggeredAbility; +import mage.abilities.common.DealsCombatDamageToAPlayerTriggeredAbility; import mage.abilities.common.SimpleActivatedAbility; import mage.abilities.costs.mana.ManaCostsImpl; import mage.abilities.effects.common.RegenerateSourceEffect; @@ -55,7 +55,7 @@ public class ChillingApparition extends CardImpl { // {B}: Regenerate Chilling Apparition. this.addAbility(new SimpleActivatedAbility(Zone.BATTLEFIELD, new RegenerateSourceEffect(), new ManaCostsImpl("{B}"))); // Whenever Chilling Apparition deals combat damage to a player, that player discards a card. - this.addAbility(new DealsDamageToOpponentTriggeredAbility(new DiscardTargetEffect(1), false, true, true)); + this.addAbility(new DealsCombatDamageToAPlayerTriggeredAbility(new DiscardTargetEffect(1), false, true)); } public ChillingApparition(final ChillingApparition card) { From 0960b80ea7ca8796e18ab634880573fb71c31179 Mon Sep 17 00:00:00 2001 From: Anton Date: Wed, 14 Oct 2015 20:34:10 +0200 Subject: [PATCH 097/268] Added Forgotten Ancient --- .../mage/sets/archenemy/ForgottenAncient.java | 52 ++++++ .../sets/planechase/ForgottenAncient.java | 52 ++++++ .../mage/sets/scourge/ForgottenAncient.java | 158 ++++++++++++++++++ 3 files changed, 262 insertions(+) create mode 100644 Mage.Sets/src/mage/sets/archenemy/ForgottenAncient.java create mode 100644 Mage.Sets/src/mage/sets/planechase/ForgottenAncient.java create mode 100644 Mage.Sets/src/mage/sets/scourge/ForgottenAncient.java diff --git a/Mage.Sets/src/mage/sets/archenemy/ForgottenAncient.java b/Mage.Sets/src/mage/sets/archenemy/ForgottenAncient.java new file mode 100644 index 00000000000..0ac189d66b9 --- /dev/null +++ b/Mage.Sets/src/mage/sets/archenemy/ForgottenAncient.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.archenemy; + +import java.util.UUID; + +/** + * + * @author Blinke + */ +public class ForgottenAncient extends mage.sets.scourge.ForgottenAncient { + + public ForgottenAncient(UUID ownerId) { + super(ownerId); + this.cardNumber = 57; + this.expansionSetCode = "ARC"; + } + + public ForgottenAncient(final ForgottenAncient card) { + super(card); + } + + @Override + public ForgottenAncient copy() { + return new ForgottenAncient(this); + } +} diff --git a/Mage.Sets/src/mage/sets/planechase/ForgottenAncient.java b/Mage.Sets/src/mage/sets/planechase/ForgottenAncient.java new file mode 100644 index 00000000000..e8b9b7dfc5c --- /dev/null +++ b/Mage.Sets/src/mage/sets/planechase/ForgottenAncient.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.planechase; + +import java.util.UUID; + +/** + * + * @author Blinke + */ +public class ForgottenAncient extends mage.sets.scourge.ForgottenAncient { + + public ForgottenAncient(UUID ownerId) { + super(ownerId); + this.cardNumber = 73; + this.expansionSetCode = "HOP"; + } + + public ForgottenAncient(final ForgottenAncient card) { + super(card); + } + + @Override + public ForgottenAncient copy() { + return new ForgottenAncient(this); + } +} diff --git a/Mage.Sets/src/mage/sets/scourge/ForgottenAncient.java b/Mage.Sets/src/mage/sets/scourge/ForgottenAncient.java new file mode 100644 index 00000000000..8107c48a39c --- /dev/null +++ b/Mage.Sets/src/mage/sets/scourge/ForgottenAncient.java @@ -0,0 +1,158 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.sets.scourge; + +import java.util.ArrayList; +import java.util.UUID; +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.BeginningOfUpkeepTriggeredAbility; +import mage.abilities.common.SpellCastAllTriggeredAbility; +import mage.abilities.effects.Effect; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.counter.AddCountersSourceEffect; +import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.Outcome; +import mage.constants.Rarity; +import mage.constants.TargetController; +import mage.constants.Zone; +import mage.counters.CounterType; +import mage.filter.common.FilterCreaturePermanent; +import mage.filter.predicate.permanent.AnotherPredicate; +import mage.game.Game; +import mage.game.permanent.Permanent; +import mage.players.Player; +import mage.target.Target; +import mage.target.common.TargetCreaturePermanent; + +/** + * + * @author Blinke + */ +public class ForgottenAncient extends CardImpl { + private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("another creature"); + static { + filter.add(new AnotherPredicate()); + } + + public ForgottenAncient(UUID ownerId) { + super(ownerId, 120, "Forgotten Ancient", Rarity.RARE, new CardType[]{CardType.CREATURE}, "{3}{G}"); + this.expansionSetCode = "SCG"; + this.subtype.add("Elemental"); + this.power = new MageInt(0); + this.toughness = new MageInt(3); + + // Whenever a player casts a spell, you may put a +1/+1 counter on Forgotten Ancient. + Effect effect = new AddCountersSourceEffect(CounterType.P1P1.createInstance()); + Ability ability = new SpellCastAllTriggeredAbility(effect, true); + this.addAbility(ability); + + // At the beginning of your upkeep, you may move any number of +1/+1 counters from Forgotten Ancient onto other creatures. + this.addAbility(new BeginningOfUpkeepTriggeredAbility(Zone.BATTLEFIELD, new ForgottenAncientEffect(), TargetController.YOU, true)); + } + + public ForgottenAncient(final ForgottenAncient card) { + super(card); + } + + @Override + public ForgottenAncient copy() { + return new ForgottenAncient(this); + } + + class CounterMovement { + public UUID target; + public int counters; + } + + class ForgottenAncientEffect extends OneShotEffect { + + public ForgottenAncientEffect() { + super(Outcome.Benefit); + this.staticText = "you may move any number of +1/+1 counters from Forgotten Ancient onto other creatures."; + } + + public ForgottenAncientEffect(final ForgottenAncientEffect effect) { + super(effect); + } + + @Override + public ForgottenAncientEffect copy() { + return new ForgottenAncientEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player controller = game.getPlayer(source.getControllerId()); + Permanent sourcePermanent = game.getPermanent(source.getSourceId()); + + if(controller == null || sourcePermanent == null) { + return false; + } + + int numCounters = sourcePermanent.getCounters().getCount(CounterType.P1P1); + ArrayList counterMovements = new ArrayList<>(); + + do { + Target target = new TargetCreaturePermanent(1, 1, filter, true); + if(numCounters == 0 || !target.choose(Outcome.Benefit, source.getControllerId(), source.getSourceId(), game)) { + continue; + } + + int amountToMove = controller.getAmount(0, numCounters, "How many counters do you want to move? " + "(" + numCounters + ")" + " counters remaining.", game); + if(amountToMove > 0) + { + boolean previouslyChosen = false; + for (CounterMovement cm : counterMovements) { + if(cm.target.equals(target.getFirstTarget())) + { + cm.counters += amountToMove; + previouslyChosen = true; + } + } + if(!previouslyChosen) { + CounterMovement cm = new CounterMovement(); + cm.target = target.getFirstTarget(); + cm.counters = amountToMove; + counterMovements.add(cm); + } + + numCounters -= amountToMove; + } + } while(numCounters > 0 && controller.chooseUse(Outcome.Benefit, "Move additonal counters?", source, game)); + + //Move all the counters for each chosen creature + for(CounterMovement cm: counterMovements) { + sourcePermanent.removeCounters(CounterType.P1P1.createInstance(cm.counters), game); + game.getPermanent(cm.target).addCounters(CounterType.P1P1.createInstance(cm.counters), game); + } + return true; + } + } +} From 64017caa1b4b1eb23f91b0ec3c557eb724709e1a Mon Sep 17 00:00:00 2001 From: Plopman Date: Wed, 14 Oct 2015 21:19:44 +0200 Subject: [PATCH 098/268] Small changes to sylvan Library and Chrome Mox.It's now possible to select cards directly in the hand instead of in an other window --- .../mage/sets/fifthedition/SylvanLibrary.java | 35 +- .../src/mage/sets/mirrodin/ChromeMox.java | 408 +++++++++--------- 2 files changed, 237 insertions(+), 206 deletions(-) diff --git a/Mage.Sets/src/mage/sets/fifthedition/SylvanLibrary.java b/Mage.Sets/src/mage/sets/fifthedition/SylvanLibrary.java index e6d7c57a60e..afa1cd28900 100644 --- a/Mage.Sets/src/mage/sets/fifthedition/SylvanLibrary.java +++ b/Mage.Sets/src/mage/sets/fifthedition/SylvanLibrary.java @@ -30,6 +30,7 @@ package mage.sets.fifthedition; import java.util.HashSet; import java.util.Set; import java.util.UUID; +import mage.MageObject; import mage.abilities.Ability; import mage.abilities.common.BeginningOfDrawTriggeredAbility; import mage.abilities.effects.OneShotEffect; @@ -44,6 +45,7 @@ import mage.constants.TargetController; import mage.constants.WatcherScope; import mage.constants.Zone; import mage.filter.FilterCard; +import mage.filter.predicate.Predicate; import mage.game.Game; import mage.game.events.GameEvent; import mage.players.Player; @@ -110,8 +112,10 @@ class SylvanLibraryEffect extends OneShotEffect { } int numberOfTargets = Math.min(2, cards.size()); if (numberOfTargets > 0) { - TargetCardInHand target = new TargetCardInHand(numberOfTargets, new FilterCard(numberOfTargets + " cards of cards drawn this turn")); - controller.chooseTarget(outcome, cards, target, source, game); + FilterCard filter = new FilterCard(numberOfTargets + " cards of cards drawn this turn"); + filter.add(new CardIdPredicate(cards)); + TargetCardInHand target = new TargetCardInHand(numberOfTargets, filter); + controller.choose(outcome, target, source.getSourceId(), game); Cards cardsPutBack = new CardsImpl(); for (UUID cardId : target.getTargets()) { @@ -190,3 +194,30 @@ class CardsDrawnThisTurnWatcher extends Watcher { return new CardsDrawnThisTurnWatcher(this); } } + + +class CardIdPredicate implements Predicate { + + private final Cards cardsId; + + public CardIdPredicate(Cards cardsId) { + this.cardsId = cardsId; + } + + @Override + public boolean apply(MageObject input, Game game) { + for(UUID uuid : cardsId) + { + if(uuid.equals(input.getId())) + { + return true; + } + } + return false; + } + + @Override + public String toString() { + return "CardsId"; + } +} diff --git a/Mage.Sets/src/mage/sets/mirrodin/ChromeMox.java b/Mage.Sets/src/mage/sets/mirrodin/ChromeMox.java index af94a37a999..73fff870bc8 100644 --- a/Mage.Sets/src/mage/sets/mirrodin/ChromeMox.java +++ b/Mage.Sets/src/mage/sets/mirrodin/ChromeMox.java @@ -1,205 +1,205 @@ -/* - * 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.mirrodin; - -import java.util.List; -import java.util.UUID; -import mage.Mana; -import mage.ObjectColor; -import mage.abilities.Ability; -import mage.abilities.common.EntersBattlefieldTriggeredAbility; -import mage.abilities.costs.common.TapSourceCost; -import mage.abilities.effects.OneShotEffect; -import mage.abilities.effects.common.ManaEffect; -import mage.abilities.mana.SimpleManaAbility; -import mage.cards.Card; -import mage.cards.CardImpl; -import mage.choices.Choice; -import mage.choices.ChoiceImpl; -import mage.constants.CardType; -import mage.constants.Outcome; -import mage.constants.Rarity; -import mage.constants.Zone; -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.TargetCard; - -/** - * - * @author Plopman - */ -public class ChromeMox extends CardImpl { - - public ChromeMox(UUID ownerId) { - super(ownerId, 152, "Chrome Mox", Rarity.RARE, new CardType[]{CardType.ARTIFACT}, "{0}"); - this.expansionSetCode = "MRD"; - - // Imprint - When Chrome Mox enters the battlefield, you may exile a nonartifact, nonland card from your hand. - this.addAbility(new EntersBattlefieldTriggeredAbility(new ChromeMoxEffect(), true)); - // {tap}: Add one mana of any of the exiled card's colors to your mana pool. - this.addAbility(new SimpleManaAbility(Zone.BATTLEFIELD, new ChromeMoxManaEffect(), new TapSourceCost())); - } - - public ChromeMox(final ChromeMox card) { - super(card); - } - - @java.lang.Override - public ChromeMox copy() { - return new ChromeMox(this); - } -} - -class ChromeMoxEffect extends OneShotEffect { - - private static final FilterCard filter = new FilterCard("nonartifact, nonland card"); - static { - filter.add(Predicates.not(Predicates.or(new CardTypePredicate(CardType.LAND), new CardTypePredicate(CardType.ARTIFACT)))); - } - public ChromeMoxEffect() { - super(Outcome.Benefit); - staticText = "exile a nonartifact, nonland card from your hand"; - } - - public ChromeMoxEffect(ChromeMoxEffect effect) { - super(effect); - } - - @java.lang.Override - public boolean apply(Game game, Ability source) { - Player player = game.getPlayer(source.getControllerId()); - if (player.getHand().size() > 0) { - TargetCard target = new TargetCard(Zone.HAND, filter); - player.choose(Outcome.Benefit, player.getHand(), target, game); - Card card = player.getHand().get(target.getFirstTarget(), game); - if (card != null) { - card.moveToExile(getId(), "Chrome Mox (Imprint)", source.getSourceId(), game); - Permanent permanent = game.getPermanent(source.getSourceId()); - if (permanent != null) { - permanent.imprint(card.getId(), game); - } - return true; - } - } - return true; - } - - @java.lang.Override - public ChromeMoxEffect copy() { - return new ChromeMoxEffect(this); - } - - -} - -class ChromeMoxManaEffect extends ManaEffect { - - - ChromeMoxManaEffect() { - super(); - staticText = "Add one mana of any of the exiled card's colors to your mana pool"; - } - - ChromeMoxManaEffect(ChromeMoxManaEffect effect) { - super(effect); - } - - - - @java.lang.Override - public ChromeMoxManaEffect copy() { - return new ChromeMoxManaEffect(this); - } - - @java.lang.Override - public boolean apply(Game game, Ability source) { - Permanent permanent = game.getPermanent(source.getSourceId()); - Player player = game.getPlayer(source.getControllerId()); - if (permanent != null && player != null) { - List imprinted = permanent.getImprinted(); - if (imprinted.size() > 0) { - Card imprintedCard = game.getCard(imprinted.get(0)); - if (imprintedCard != null) { - Choice choice = new ChoiceImpl(true); - choice.setMessage("Pick a mana color"); - ObjectColor color = imprintedCard.getColor(game); - if (color.isBlack()) { - choice.getChoices().add("Black"); - } - if (color.isRed()) { - choice.getChoices().add("Red"); - } - if (color.isBlue()) { - choice.getChoices().add("Blue"); - } - if (color.isGreen()) { - choice.getChoices().add("Green"); - } - if (color.isWhite()) { - choice.getChoices().add("White"); - } - - if (choice.getChoices().size() > 0) { - Mana mana = new Mana(); - if (choice.getChoices().size() == 1) { - choice.setChoice(choice.getChoices().iterator().next()); - } else { - player.choose(outcome, choice, game); - } - if (choice.getChoice().equals("Black")) { - player.getManaPool().addMana(Mana.BlackMana, game, source); - } else if (choice.getChoice().equals("Blue")) { - player.getManaPool().addMana(Mana.BlueMana, game, source); - } else if (choice.getChoice().equals("Red")) { - player.getManaPool().addMana(Mana.RedMana, game, source); - } else if (choice.getChoice().equals("Green")) { - player.getManaPool().addMana(Mana.GreenMana, game, source); - } else if (choice.getChoice().equals("White")) { - player.getManaPool().addMana(Mana.WhiteMana, game, source); - } else if (choice.getChoice().equals("Colorless")) { - player.getManaPool().addMana(Mana.ColorlessMana, game, source); - } - checkToFirePossibleEvents(mana, game, source); - player.getManaPool().addMana(mana, game, source); - } - } - } - } - return true; - } - - @java.lang.Override - public Mana getMana(Game game, Ability source) { - return null; - } - +/* + * 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.mirrodin; + +import java.util.List; +import java.util.UUID; +import mage.Mana; +import mage.ObjectColor; +import mage.abilities.Ability; +import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.costs.common.TapSourceCost; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.ManaEffect; +import mage.abilities.mana.SimpleManaAbility; +import mage.cards.Card; +import mage.cards.CardImpl; +import mage.choices.Choice; +import mage.choices.ChoiceImpl; +import mage.constants.CardType; +import mage.constants.Outcome; +import mage.constants.Rarity; +import mage.constants.Zone; +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.TargetCard; + +/** + * + * @author Plopman + */ +public class ChromeMox extends CardImpl { + + public ChromeMox(UUID ownerId) { + super(ownerId, 152, "Chrome Mox", Rarity.RARE, new CardType[]{CardType.ARTIFACT}, "{0}"); + this.expansionSetCode = "MRD"; + + // Imprint - When Chrome Mox enters the battlefield, you may exile a nonartifact, nonland card from your hand. + this.addAbility(new EntersBattlefieldTriggeredAbility(new ChromeMoxEffect(), true)); + // {tap}: Add one mana of any of the exiled card's colors to your mana pool. + this.addAbility(new SimpleManaAbility(Zone.BATTLEFIELD, new ChromeMoxManaEffect(), new TapSourceCost())); + } + + public ChromeMox(final ChromeMox card) { + super(card); + } + + @java.lang.Override + public ChromeMox copy() { + return new ChromeMox(this); + } +} + +class ChromeMoxEffect extends OneShotEffect { + + private static final FilterCard filter = new FilterCard("nonartifact, nonland card"); + static { + filter.add(Predicates.not(Predicates.or(new CardTypePredicate(CardType.LAND), new CardTypePredicate(CardType.ARTIFACT)))); + } + public ChromeMoxEffect() { + super(Outcome.Benefit); + staticText = "exile a nonartifact, nonland card from your hand"; + } + + public ChromeMoxEffect(ChromeMoxEffect effect) { + super(effect); + } + + @java.lang.Override + public boolean apply(Game game, Ability source) { + Player player = game.getPlayer(source.getControllerId()); + if (player.getHand().size() > 0) { + TargetCard target = new TargetCard(Zone.HAND, filter); + player.choose(Outcome.Benefit, target, source.getSourceId(), game); + Card card = player.getHand().get(target.getFirstTarget(), game); + if (card != null) { + card.moveToExile(getId(), "Chrome Mox (Imprint)", source.getSourceId(), game); + Permanent permanent = game.getPermanent(source.getSourceId()); + if (permanent != null) { + permanent.imprint(card.getId(), game); + } + return true; + } + } + return true; + } + + @java.lang.Override + public ChromeMoxEffect copy() { + return new ChromeMoxEffect(this); + } + + +} + +class ChromeMoxManaEffect extends ManaEffect { + + + ChromeMoxManaEffect() { + super(); + staticText = "Add one mana of any of the exiled card's colors to your mana pool"; + } + + ChromeMoxManaEffect(ChromeMoxManaEffect effect) { + super(effect); + } + + + + @java.lang.Override + public ChromeMoxManaEffect copy() { + return new ChromeMoxManaEffect(this); + } + + @java.lang.Override + public boolean apply(Game game, Ability source) { + Permanent permanent = game.getPermanent(source.getSourceId()); + Player player = game.getPlayer(source.getControllerId()); + if (permanent != null && player != null) { + List imprinted = permanent.getImprinted(); + if (imprinted.size() > 0) { + Card imprintedCard = game.getCard(imprinted.get(0)); + if (imprintedCard != null) { + Choice choice = new ChoiceImpl(true); + choice.setMessage("Pick a mana color"); + ObjectColor color = imprintedCard.getColor(game); + if (color.isBlack()) { + choice.getChoices().add("Black"); + } + if (color.isRed()) { + choice.getChoices().add("Red"); + } + if (color.isBlue()) { + choice.getChoices().add("Blue"); + } + if (color.isGreen()) { + choice.getChoices().add("Green"); + } + if (color.isWhite()) { + choice.getChoices().add("White"); + } + + if (choice.getChoices().size() > 0) { + Mana mana = new Mana(); + if (choice.getChoices().size() == 1) { + choice.setChoice(choice.getChoices().iterator().next()); + } else { + player.choose(outcome, choice, game); + } + if (choice.getChoice().equals("Black")) { + player.getManaPool().addMana(Mana.BlackMana, game, source); + } else if (choice.getChoice().equals("Blue")) { + player.getManaPool().addMana(Mana.BlueMana, game, source); + } else if (choice.getChoice().equals("Red")) { + player.getManaPool().addMana(Mana.RedMana, game, source); + } else if (choice.getChoice().equals("Green")) { + player.getManaPool().addMana(Mana.GreenMana, game, source); + } else if (choice.getChoice().equals("White")) { + player.getManaPool().addMana(Mana.WhiteMana, game, source); + } else if (choice.getChoice().equals("Colorless")) { + player.getManaPool().addMana(Mana.ColorlessMana, game, source); + } + checkToFirePossibleEvents(mana, game, source); + player.getManaPool().addMana(mana, game, source); + } + } + } + } + return true; + } + + @java.lang.Override + public Mana getMana(Game game, Ability source) { + return null; + } + } \ No newline at end of file From eae82622b6181a8fd22c1959bed5d2e1d262222c Mon Sep 17 00:00:00 2001 From: LoneFox Date: Wed, 14 Oct 2015 22:32:38 +0300 Subject: [PATCH 099/268] Add TargetsPermanentPredicate and use it for existing cards. Implement card: Hydromorph Gull --- .../sets/riseoftheeldrazi/NotOfThisWorld.java | 110 ++------------ .../mage/sets/scarsofmirrodin/TurnAside.java | 134 ++---------------- .../mage/sets/torment/HydromorphGuardian.java | 40 +----- .../src/mage/sets/torment/HydromorphGull.java | 85 +++++++++++ .../src/mage/sets/urzaslegacy/Intervene.java | 116 ++------------- .../other/TargetsPermanentPredicate.java | 76 ++++++++++ 6 files changed, 200 insertions(+), 361 deletions(-) create mode 100644 Mage.Sets/src/mage/sets/torment/HydromorphGull.java create mode 100644 Mage/src/mage/filter/predicate/other/TargetsPermanentPredicate.java diff --git a/Mage.Sets/src/mage/sets/riseoftheeldrazi/NotOfThisWorld.java b/Mage.Sets/src/mage/sets/riseoftheeldrazi/NotOfThisWorld.java index 558d240f739..1ee4a1ce987 100644 --- a/Mage.Sets/src/mage/sets/riseoftheeldrazi/NotOfThisWorld.java +++ b/Mage.Sets/src/mage/sets/riseoftheeldrazi/NotOfThisWorld.java @@ -27,8 +27,6 @@ */ package mage.sets.riseoftheeldrazi; -import java.util.HashSet; -import java.util.Set; import java.util.UUID; import mage.abilities.Ability; import mage.abilities.common.SimpleStaticAbility; @@ -40,18 +38,17 @@ import mage.constants.CardType; import mage.constants.Rarity; import mage.constants.TargetController; import mage.constants.Zone; -import mage.filter.Filter; +import mage.filter.FilterSpell; +import mage.filter.common.FilterControlledPermanent; import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.mageobject.PowerPredicate; +import mage.filter.predicate.other.TargetsPermanentPredicate; import mage.filter.predicate.permanent.ControllerPredicate; import mage.game.Game; import mage.game.permanent.Permanent; -import mage.game.stack.Spell; -import mage.game.stack.StackAbility; import mage.game.stack.StackObject; import mage.target.Target; -import mage.target.TargetObject; -import mage.target.Targets; +import mage.target.TargetSpell; /** * @@ -59,15 +56,19 @@ import mage.target.Targets; */ public class NotOfThisWorld extends CardImpl { + private final static FilterSpell filter = new FilterSpell("spell that targets a permanent you control"); + + static { + filter.add(new TargetsPermanentPredicate(new FilterControlledPermanent())); + } + public NotOfThisWorld(UUID ownerId) { - super(ownerId, 8, "Not of This World", Rarity.UNCOMMON, - new CardType[]{CardType.TRIBAL, CardType.INSTANT}, "{7}"); + super(ownerId, 8, "Not of This World", Rarity.UNCOMMON, new CardType[]{CardType.TRIBAL, CardType.INSTANT}, "{7}"); this.expansionSetCode = "ROE"; this.subtype.add("Eldrazi"); // Counter target spell or ability that targets a permanent you control. - this.getSpellAbility().addTarget( - new TargetStackObjectTargetingControlledPermanent()); + this.getSpellAbility().addTarget(new TargetSpell(filter)); this.getSpellAbility().addEffect(new CounterTargetEffect()); // Not of This World costs {7} less to cast if it targets a spell or ability that targets a creature you control with power 7 or greater. this.addAbility(new SimpleStaticAbility(Zone.STACK, new SpellCostReductionSourceEffect(7, NotOfThisWorldCondition.getInstance()))); @@ -83,93 +84,6 @@ public class NotOfThisWorld extends CardImpl { } } -class TargetStackObjectTargetingControlledPermanent extends TargetObject { - - - public TargetStackObjectTargetingControlledPermanent() { - this.minNumberOfTargets = 1; - this.maxNumberOfTargets = 1; - this.zone = Zone.STACK; - this.targetName = "spell or ability that targets a permanent you control"; - } - - public TargetStackObjectTargetingControlledPermanent(final TargetStackObjectTargetingControlledPermanent target) { - super(target); - } - - @Override - public Filter getFilter() { - throw new UnsupportedOperationException("Not supported."); //To change body of generated methods, choose Tools | Templates. - } - - @Override - public boolean canTarget(UUID id, Ability source, Game game) { - StackObject stackObject = game.getStack().getStackObject(id); - if ((stackObject instanceof Spell) || (stackObject instanceof StackAbility)) { - return true; - } - return false; - } - - @Override - public boolean canChoose(UUID sourceId, UUID sourceControllerId, Game game) { - return canChoose(sourceControllerId, game); - } - - @Override - public boolean canChoose(UUID sourceControllerId, Game game) { - for (StackObject stackObject : game.getStack()) { - if ((stackObject instanceof Spell) || (stackObject instanceof StackAbility)) { - Targets objectTargets = stackObject.getStackAbility().getTargets(); - if(!objectTargets.isEmpty()) { - for (Target target : objectTargets) { - for (UUID targetId : target.getTargets()) { - Permanent targetedPermanent = game.getPermanentOrLKIBattlefield(targetId); - if (targetedPermanent != null && targetedPermanent.getControllerId().equals(sourceControllerId)) { - return true; - } - } - } - } - } - } - return false; - } - - @Override - public Set possibleTargets(UUID sourceId, UUID sourceControllerId, - Game game) { - return possibleTargets(sourceControllerId, game); - } - - @Override - public Set possibleTargets(UUID sourceControllerId, Game game) { - Set possibleTargets = new HashSet<>(); - for (StackObject stackObject : game.getStack()) { - if ((stackObject instanceof Spell) || (stackObject instanceof StackAbility)) { - Targets objectTargets = stackObject.getStackAbility().getTargets(); - if(!objectTargets.isEmpty()) { - for (Target target : objectTargets) { - for (UUID targetId : target.getTargets()) { - Permanent targetedPermanent = game.getPermanentOrLKIBattlefield(targetId); - if (targetedPermanent != null && targetedPermanent.getControllerId().equals(sourceControllerId)) { - possibleTargets.add(stackObject.getId()); - } - } - } - } - } - } - return possibleTargets; - } - - @Override - public TargetStackObjectTargetingControlledPermanent copy() { - return new TargetStackObjectTargetingControlledPermanent(this); - } - -} - class NotOfThisWorldCondition implements Condition { private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("creature you control with power 7 or greater"); diff --git a/Mage.Sets/src/mage/sets/scarsofmirrodin/TurnAside.java b/Mage.Sets/src/mage/sets/scarsofmirrodin/TurnAside.java index f6f9cb5c4c9..a878638f92d 100644 --- a/Mage.Sets/src/mage/sets/scarsofmirrodin/TurnAside.java +++ b/Mage.Sets/src/mage/sets/scarsofmirrodin/TurnAside.java @@ -28,40 +28,35 @@ package mage.sets.scarsofmirrodin; -import mage.constants.CardType; -import mage.constants.Rarity; -import mage.abilities.Ability; +import java.util.UUID; import mage.abilities.effects.common.CounterTargetEffect; import mage.cards.CardImpl; -import mage.constants.Zone; -import mage.filter.Filter; +import mage.constants.CardType; +import mage.constants.Rarity; import mage.filter.FilterSpell; -import mage.game.Game; -import mage.game.permanent.Permanent; -import mage.game.stack.Spell; -import mage.game.stack.StackObject; -import mage.target.TargetObject; +import mage.filter.common.FilterControlledPermanent; +import mage.filter.predicate.other.TargetsPermanentPredicate; +import mage.target.TargetSpell; -import java.util.HashSet; -import java.util.Set; -import java.util.UUID; -import mage.target.Target; /** * @author ayratn */ public class TurnAside extends CardImpl { - private static FilterSpell filter = new FilterSpell("spell that targets a permanent you control"); + private final static FilterSpell filter = new FilterSpell("spell that targets a permanent you control"); + + static { + filter.add(new TargetsPermanentPredicate(new FilterControlledPermanent())); + } public TurnAside(UUID ownerId) { super(ownerId, 49, "Turn Aside", Rarity.COMMON, new CardType[]{CardType.INSTANT}, "{U}"); this.expansionSetCode = "SOM"; - // Counter target spell that targets a permanent you control. this.getSpellAbility().addEffect(new CounterTargetEffect()); - this.getSpellAbility().addTarget(new CustomTargetSpell(filter)); + this.getSpellAbility().addTarget(new TargetSpell(filter)); } public TurnAside(final TurnAside card) { @@ -72,109 +67,4 @@ public class TurnAside extends CardImpl { public TurnAside copy() { return new TurnAside(this); } - - private class CustomTargetSpell extends TargetObject { - - protected FilterSpell filter; - - public CustomTargetSpell() { - this(1, 1, new FilterSpell()); - } - - public CustomTargetSpell(FilterSpell filter) { - this(1, 1, filter); - } - - public CustomTargetSpell(int numTargets, FilterSpell filter) { - this(numTargets, numTargets, filter); - } - - public CustomTargetSpell(int minNumTargets, int maxNumTargets, FilterSpell filter) { - this.minNumberOfTargets = minNumTargets; - this.maxNumberOfTargets = maxNumTargets; - this.zone = Zone.STACK; - this.filter = filter; - this.targetName = filter.getMessage(); - } - - public CustomTargetSpell(final CustomTargetSpell target) { - super(target); - this.filter = target.filter.copy(); - } - - @Override - public boolean canChoose(UUID sourceId, UUID sourceControllerId, Game game) { - return canChoose(sourceControllerId, game); - } - - @Override - public Set possibleTargets(UUID sourceId, UUID sourceControllerId, Game game) { - return possibleTargets(sourceControllerId, game); - } - - @Override - public boolean canTarget(UUID id, Ability source, Game game) { - if (super.canTarget(id, source, game)) { - if (targetsMyPermanent(id, source.getControllerId(), game)) { - return true; - } - } - return false; - } - - @Override - public boolean canChoose(UUID sourceControllerId, Game game) { - int count = 0; - for (StackObject stackObject : game.getStack()) { - if (stackObject instanceof Spell && game.getPlayer(sourceControllerId).getInRange().contains(stackObject.getControllerId()) && filter.match((Spell) stackObject, game)) { - if (targetsMyPermanent(stackObject.getId(), sourceControllerId, game)) { - count++; - if (count >= this.minNumberOfTargets) - return true; - } - } - } - return false; - } - - @Override - public Set possibleTargets(UUID sourceControllerId, Game game) { - Set possibleTargets = new HashSet(); - for (StackObject stackObject : game.getStack()) { - if (stackObject instanceof Spell && game.getPlayer(sourceControllerId).getInRange().contains(stackObject.getControllerId()) && filter.match((Spell) stackObject, game)) { - if (targetsMyPermanent(stackObject.getId(), sourceControllerId, game)) { - - possibleTargets.add(stackObject.getId()); - } - } - } - return possibleTargets; - } - - @Override - public Filter getFilter() { - return filter; - } - - private boolean targetsMyPermanent(UUID id, UUID controllerId, Game game) { - StackObject spell = game.getStack().getStackObject(id); - if (spell != null) { - Ability ability = spell.getStackAbility(); - for (Target target : ability.getTargets()) { - for (UUID permanentId : target.getTargets()) { - Permanent permanent = game.getPermanent(permanentId); - if (permanent != null && permanent.getControllerId().equals(controllerId)) { - return true; - } - } - } - } - return false; - } - - @Override - public CustomTargetSpell copy() { - return new CustomTargetSpell(this); - } - } } diff --git a/Mage.Sets/src/mage/sets/torment/HydromorphGuardian.java b/Mage.Sets/src/mage/sets/torment/HydromorphGuardian.java index 261fc1c2e34..0eaaf30cd1f 100644 --- a/Mage.Sets/src/mage/sets/torment/HydromorphGuardian.java +++ b/Mage.Sets/src/mage/sets/torment/HydromorphGuardian.java @@ -29,9 +29,7 @@ package mage.sets.torment; import java.util.UUID; import mage.MageInt; -import mage.MageObject; import mage.abilities.Ability; -import mage.abilities.Mode; import mage.abilities.common.SimpleActivatedAbility; import mage.abilities.costs.common.SacrificeSourceCost; import mage.abilities.costs.mana.ColoredManaCost; @@ -42,12 +40,8 @@ import mage.constants.ColoredManaSymbol; import mage.constants.Rarity; import mage.constants.Zone; import mage.filter.FilterSpell; -import mage.filter.predicate.ObjectSourcePlayer; -import mage.filter.predicate.ObjectSourcePlayerPredicate; -import mage.game.Game; -import mage.game.permanent.Permanent; -import mage.game.stack.Spell; -import mage.target.Target; +import mage.filter.common.FilterControlledCreaturePermanent; +import mage.filter.predicate.other.TargetsPermanentPredicate; import mage.target.TargetSpell; /** @@ -59,7 +53,7 @@ public class HydromorphGuardian extends CardImpl { private final static FilterSpell filter = new FilterSpell("spell that targets one or more creatures you control"); static { - filter.add(new HydromorphGuardianPredicate()); + filter.add(new TargetsPermanentPredicate(new FilterControlledCreaturePermanent())); } public HydromorphGuardian(UUID ownerId) { @@ -85,31 +79,3 @@ public class HydromorphGuardian extends CardImpl { return new HydromorphGuardian(this); } } - -class HydromorphGuardianPredicate implements ObjectSourcePlayerPredicate> { - - @Override - public boolean apply(ObjectSourcePlayer input, Game game) { - Spell spell = game.getStack().getSpell(input.getObject().getId()); - if (spell != null) { - for (UUID modeId : spell.getSpellAbility().getModes().getSelectedModes()) { - Mode mode = spell.getSpellAbility().getModes().get(modeId); - for (Target target : mode.getTargets()) { - for (UUID targetId : target.getTargets()) { - Permanent permanent = game.getPermanent(targetId); - if (permanent.getCardType().contains(CardType.CREATURE) - && permanent.getControllerId().equals(input.getPlayerId())) { - return true; - } - } - } - } - } - return false; - } - - @Override - public String toString() { - return "that targets one or more creatures you control"; - } -} diff --git a/Mage.Sets/src/mage/sets/torment/HydromorphGull.java b/Mage.Sets/src/mage/sets/torment/HydromorphGull.java new file mode 100644 index 00000000000..c427837724d --- /dev/null +++ b/Mage.Sets/src/mage/sets/torment/HydromorphGull.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.torment; + +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.costs.mana.ColoredManaCost; +import mage.abilities.effects.common.CounterTargetEffect; +import mage.abilities.keyword.FlyingAbility; +import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.ColoredManaSymbol; +import mage.constants.Rarity; +import mage.constants.Zone; +import mage.filter.FilterSpell; +import mage.filter.common.FilterControlledCreaturePermanent; +import mage.filter.predicate.other.TargetsPermanentPredicate; +import mage.target.TargetSpell; + +/** + * + * @author LoneFox + */ +public class HydromorphGull extends CardImpl { + + private final static FilterSpell filter = new FilterSpell("spell that targets one or more creatures you control"); + + static { + filter.add(new TargetsPermanentPredicate(new FilterControlledCreaturePermanent())); + } + + public HydromorphGull(UUID ownerId) { + super(ownerId, 40, "Hydromorph Gull", Rarity.UNCOMMON, new CardType[]{CardType.CREATURE}, "{3}{U}{U}"); + this.expansionSetCode = "TOR"; + this.subtype.add("Elemental"); + this.subtype.add("Bird"); + this.power = new MageInt(3); + this.toughness = new MageInt(3); + + // Flying + this.addAbility(FlyingAbility.getInstance()); + // {U}, Sacrifice Hydromorph Gull: Counter target spell that targets one or more creatures you control. + Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new CounterTargetEffect(), new ColoredManaCost(ColoredManaSymbol.U)); + ability.addCost(new SacrificeSourceCost()); + ability.addTarget(new TargetSpell(filter)); + this.addAbility(ability); + } + + public HydromorphGull(final HydromorphGull card) { + super(card); + } + + @Override + public HydromorphGull copy() { + return new HydromorphGull(this); + } +} diff --git a/Mage.Sets/src/mage/sets/urzaslegacy/Intervene.java b/Mage.Sets/src/mage/sets/urzaslegacy/Intervene.java index 2713856744f..aa35fd116bd 100644 --- a/Mage.Sets/src/mage/sets/urzaslegacy/Intervene.java +++ b/Mage.Sets/src/mage/sets/urzaslegacy/Intervene.java @@ -27,24 +27,15 @@ */ package mage.sets.urzaslegacy; -import java.util.HashSet; -import java.util.Set; import java.util.UUID; - -import mage.constants.CardType; -import mage.constants.Rarity; -import mage.abilities.Ability; import mage.abilities.effects.common.CounterTargetEffect; import mage.cards.CardImpl; -import mage.constants.Zone; -import mage.filter.Filter; +import mage.constants.CardType; +import mage.constants.Rarity; import mage.filter.FilterSpell; -import mage.game.Game; -import mage.game.permanent.Permanent; -import mage.game.stack.Spell; -import mage.game.stack.StackObject; -import mage.target.Target; -import mage.target.TargetObject; +import mage.filter.common.FilterCreaturePermanent; +import mage.filter.predicate.other.TargetsPermanentPredicate; +import mage.target.TargetSpell; /** * @@ -52,13 +43,19 @@ import mage.target.TargetObject; */ public class Intervene extends CardImpl { + private final static FilterSpell filter = new FilterSpell("spell that targets a creature"); + + static { + filter.add(new TargetsPermanentPredicate(new FilterCreaturePermanent())); + } + public Intervene(UUID ownerId) { super(ownerId, 33, "Intervene", Rarity.COMMON, new CardType[]{CardType.INSTANT}, "{U}"); this.expansionSetCode = "ULG"; // Counter target spell that targets a creature. - this.getSpellAbility().addTarget(new InterveneTargetSpell()); + this.getSpellAbility().addTarget(new TargetSpell(filter)); this.getSpellAbility().addEffect(new CounterTargetEffect()); } @@ -70,93 +67,4 @@ public class Intervene extends CardImpl { public Intervene copy() { return new Intervene(this); } - - private class InterveneTargetSpell extends TargetObject { - - - public InterveneTargetSpell() { - super(1, Zone.STACK); - this.targetName = "spell that targets a creature"; - } - - public InterveneTargetSpell(final InterveneTargetSpell target) { - super(target); - } - - @Override - public boolean canChoose(UUID sourceId, UUID sourceControllerId, Game game) { - return canChoose(sourceControllerId, game); - } - - @Override - public Set possibleTargets(UUID sourceId, UUID sourceControllerId, Game game) { - return possibleTargets(sourceControllerId, game); - } - - @Override - public boolean canTarget(UUID id, Ability source, Game game) { - if (super.canTarget(id, source, game)) { - if (targetsCreature(id, game)) { - return true; - } - } - return false; - } - - @Override - public boolean canChoose(UUID sourceControllerId, Game game) { - for (StackObject stackObject : game.getStack()) { - if (stackObject instanceof Spell) { - if (targetsCreature(stackObject.getId(), game)) { - return true; - } - } - } - return false; - } - - @Override - public Set possibleTargets(UUID sourceControllerId, Game game) { - Set possibleTargets = new HashSet(); - for (StackObject stackObject : game.getStack()) { - if (stackObject instanceof Spell) { - if (targetsCreature(stackObject.getId(), game)) { - possibleTargets.add(stackObject.getId()); - } - } - } - return possibleTargets; - } - - - private boolean targetsCreature(UUID id, Game game) { - StackObject spell = game.getStack().getStackObject(id); - if (spell != null) { - Ability ability = spell.getStackAbility(); - if (ability != null && !ability.getTargets().isEmpty()) { - for (Target target : ability.getTargets()) { - for (UUID targetId : target.getTargets()) { - Permanent permanent = game.getPermanent(targetId); - if (permanent != null && permanent.getCardType().contains(CardType.CREATURE)) { - return true; - } - } - } - } - } - return false; - } - - @Override - public InterveneTargetSpell copy() { - return new InterveneTargetSpell(this); - } - - @Override - public Filter getFilter() { - return new FilterSpell(); - } - } } - - diff --git a/Mage/src/mage/filter/predicate/other/TargetsPermanentPredicate.java b/Mage/src/mage/filter/predicate/other/TargetsPermanentPredicate.java new file mode 100644 index 00000000000..0cf864bbc42 --- /dev/null +++ b/Mage/src/mage/filter/predicate/other/TargetsPermanentPredicate.java @@ -0,0 +1,76 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.filter.predicate.other; + +import java.util.UUID; +import mage.MageObject; +import mage.abilities.Mode; +import mage.filter.FilterPermanent; +import mage.filter.predicate.ObjectSourcePlayer; +import mage.filter.predicate.ObjectSourcePlayerPredicate; +import mage.game.Game; +import mage.game.permanent.Permanent; +import mage.game.stack.StackObject; +import mage.target.Target; + +/** + * + * @author LoneFox + */ +public class TargetsPermanentPredicate implements ObjectSourcePlayerPredicate> { + + private final FilterPermanent targetFilter; + + public TargetsPermanentPredicate(FilterPermanent targetFilter) { + this.targetFilter = targetFilter; + } + + @Override + public boolean apply(ObjectSourcePlayer input, Game game) { + StackObject object = game.getStack().getStackObject(input.getObject().getId()); + if(object != null) { + for(UUID modeId : object.getStackAbility().getModes().getSelectedModes()) { + Mode mode = object.getStackAbility().getModes().get(modeId); + for(Target target : mode.getTargets()) { + for(UUID targetId : target.getTargets()) { + Permanent permanent = game.getPermanentOrLKIBattlefield(targetId); + if(permanent != null) { + return targetFilter.match(permanent, input.getSourceId(), input.getPlayerId(), game); + } + } + } + } + } + return false; + } + + @Override + public String toString() { + return "that targets " + targetFilter.getMessage(); + } +} From 6ec18de1fe637db463a976e75427efd3e832dde2 Mon Sep 17 00:00:00 2001 From: LoneFox Date: Wed, 14 Oct 2015 22:58:43 +0300 Subject: [PATCH 100/268] Fix TargetStackObject not handling some predicate types correctly. Implement card to test it: Diplomatic Escort --- .../mercadianmasques/DiplomaticEscort.java | 83 +++++++++++++++++++ Mage/src/mage/target/TargetStackObject.java | 32 +++---- 2 files changed, 99 insertions(+), 16 deletions(-) create mode 100644 Mage.Sets/src/mage/sets/mercadianmasques/DiplomaticEscort.java diff --git a/Mage.Sets/src/mage/sets/mercadianmasques/DiplomaticEscort.java b/Mage.Sets/src/mage/sets/mercadianmasques/DiplomaticEscort.java new file mode 100644 index 00000000000..0abf5537b9e --- /dev/null +++ b/Mage.Sets/src/mage/sets/mercadianmasques/DiplomaticEscort.java @@ -0,0 +1,83 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.sets.mercadianmasques; + +import java.util.UUID; +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.costs.common.DiscardCardCost; +import mage.abilities.costs.common.TapSourceCost; +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.effects.common.CounterTargetEffect; +import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.Rarity; +import mage.constants.Zone; +import mage.filter.FilterStackObject; +import mage.filter.common.FilterCreaturePermanent; +import mage.filter.predicate.other.TargetsPermanentPredicate; +import mage.target.TargetStackObject; + +/** + * + * @author LoneFox + */ +public class DiplomaticEscort extends CardImpl { + + private final static FilterStackObject filter = new FilterStackObject("spell or ability that targets a creature"); + + static { + filter.add(new TargetsPermanentPredicate(new FilterCreaturePermanent())); + } + + public DiplomaticEscort(UUID ownerId) { + super(ownerId, 74, "Diplomatic Escort", Rarity.UNCOMMON, new CardType[]{CardType.CREATURE}, "{1}{U}"); + this.expansionSetCode = "MMQ"; + this.subtype.add("Human"); + this.subtype.add("Spellshaper"); + this.power = new MageInt(1); + this.toughness = new MageInt(1); + + // {U}, {tap}, Discard a card: Counter target spell or ability that targets a creature. + Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new CounterTargetEffect(), new ManaCostsImpl("{U}")); + ability.addCost(new TapSourceCost()); + ability.addCost(new DiscardCardCost()); + ability.addTarget(new TargetStackObject(filter)); + this.addAbility(ability); + } + + public DiplomaticEscort(final DiplomaticEscort card) { + super(card); + } + + @Override + public DiplomaticEscort copy() { + return new DiplomaticEscort(this); + } +} diff --git a/Mage/src/mage/target/TargetStackObject.java b/Mage/src/mage/target/TargetStackObject.java index 0a8e91a4e9a..467565ee72d 100644 --- a/Mage/src/mage/target/TargetStackObject.java +++ b/Mage/src/mage/target/TargetStackObject.java @@ -1,16 +1,16 @@ /* * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. - * + * * Redistribution and use in source and binary forms, with or without modification, are * permitted provided that the following conditions are met: - * + * * 1. Redistributions of source code must retain the above copyright notice, this list of * conditions and the following disclaimer. - * + * * 2. Redistributions in binary form must reproduce the above copyright notice, this list * of conditions and the following disclaimer in the documentation and/or other materials * provided with the distribution. - * + * * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR @@ -20,7 +20,7 @@ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * + * * The views and conclusions contained in the software and documentation are those of the * authors and should not be interpreted as representing official policies, either expressed * or implied, of BetaSteward_at_googlemail.com. @@ -80,21 +80,16 @@ public class TargetStackObject extends TargetObject { public boolean canTarget(UUID id, Ability source, Game game) { StackObject stackObject = game.getStack().getStackObject(id); if (stackObject != null) { - return filter.match(stackObject, game); + return filter.match(stackObject, source.getSourceId(), source.getControllerId(), game); } return false; } @Override public boolean canChoose(UUID sourceId, UUID sourceControllerId, Game game) { - return canChoose(sourceControllerId, game); - } - - @Override - public boolean canChoose(UUID sourceControllerId, Game game) { int count = 0; for (StackObject stackObject: game.getStack()) { - if (game.getPlayer(sourceControllerId).getInRange().contains(stackObject.getControllerId()) && filter.match(stackObject, game)) { + if (game.getPlayer(sourceControllerId).getInRange().contains(stackObject.getControllerId()) && filter.match(stackObject, sourceId, sourceControllerId, game)) { count++; if (count >= this.minNumberOfTargets) { return true; @@ -105,21 +100,26 @@ public class TargetStackObject extends TargetObject { } @Override - public Set possibleTargets(UUID sourceId, UUID sourceControllerId, Game game) { - return possibleTargets(sourceControllerId, game); + public boolean canChoose(UUID sourceControllerId, Game game) { + return canChoose(null, sourceControllerId, game); } @Override - public Set possibleTargets(UUID sourceControllerId, Game game) { + public Set possibleTargets(UUID sourceId, UUID sourceControllerId, Game game) { Set possibleTargets = new HashSet<>(); for (StackObject stackObject: game.getStack()) { - if (game.getPlayer(sourceControllerId).getInRange().contains(stackObject.getControllerId()) && filter.match(stackObject, game)) { + if (game.getPlayer(sourceControllerId).getInRange().contains(stackObject.getControllerId()) && filter.match(stackObject, sourceId, sourceControllerId, game)) { possibleTargets.add(stackObject.getId()); } } return possibleTargets; } + @Override + public Set possibleTargets(UUID sourceControllerId, Game game) { + return this.possibleTargets(null, sourceControllerId, game); + } + @Override public TargetStackObject copy() { return new TargetStackObject(this); From 046da0f5d1f5c5250a09084bf3184b94438800ba Mon Sep 17 00:00:00 2001 From: LevelX2 Date: Thu, 15 Oct 2015 08:32:58 +0200 Subject: [PATCH 101/268] * Some changed to card moving (not finished) --- .../avacynrestored/InfiniteReflection.java | 5 +- .../sets/timespiral/ScionOfTheUrDragon.java | 12 +-- .../cards/copy/InfiniteReflectionTest.java | 69 ++++++++++++++ .../org/mage/test/cards/copy/VesuvaTest.java | 22 ++--- .../java/org/mage/test/player/TestPlayer.java | 5 + .../common/AsEntersBattlefieldAbility.java | 7 +- .../abilities/effects/ContinuousEffects.java | 4 +- .../effects/EntersBattlefieldEffect.java | 6 +- .../effects/common/ChooseColorEffect.java | 9 +- .../abilities/effects/common/CopyEffect.java | 91 ++++++++++--------- ...romGraveyardToBattlefieldTargetEffect.java | 2 +- .../counter/AddCountersSourceEffect.java | 27 +++--- Mage/src/mage/game/stack/Spell.java | 5 + Mage/src/mage/players/Player.java | 3 + Mage/src/mage/players/PlayerImpl.java | 39 ++++---- 15 files changed, 202 insertions(+), 104 deletions(-) create mode 100644 Mage.Tests/src/test/java/org/mage/test/cards/copy/InfiniteReflectionTest.java diff --git a/Mage.Sets/src/mage/sets/avacynrestored/InfiniteReflection.java b/Mage.Sets/src/mage/sets/avacynrestored/InfiniteReflection.java index 1744100e918..e2b81f4ec57 100644 --- a/Mage.Sets/src/mage/sets/avacynrestored/InfiniteReflection.java +++ b/Mage.Sets/src/mage/sets/avacynrestored/InfiniteReflection.java @@ -46,6 +46,7 @@ import mage.constants.Zone; import mage.filter.FilterPermanent; import mage.filter.common.FilterControlledCreaturePermanent; import mage.game.Game; +import mage.game.events.EntersTheBattlefieldEvent; import mage.game.events.GameEvent; import mage.game.permanent.Permanent; import mage.game.permanent.PermanentToken; @@ -141,7 +142,7 @@ class InfiniteReflectionEntersBattlefieldEffect extends ReplacementEffectImpl { @Override public boolean applies(GameEvent event, Ability source, Game game) { - Permanent permanent = game.getPermanent(event.getTargetId()); + Permanent permanent = ((EntersTheBattlefieldEvent) event).getTarget(); return permanent != null && permanent.getControllerId().equals(source.getControllerId()) && permanent.getCardType().contains(CardType.CREATURE) && !(permanent instanceof PermanentToken); @@ -149,7 +150,7 @@ class InfiniteReflectionEntersBattlefieldEffect extends ReplacementEffectImpl { @Override public boolean replaceEvent(GameEvent event, Ability source, Game game) { - MageObject toCopyToObject = game.getObject(event.getTargetId()); + MageObject toCopyToObject = ((EntersTheBattlefieldEvent) event).getTarget(); Permanent sourcePermanent = game.getPermanent(source.getSourceId()); if (sourcePermanent != null && toCopyToObject != null && sourcePermanent.getAttachedTo() != null) { Permanent toCopyFromPermanent = game.getPermanent(sourcePermanent.getAttachedTo()); diff --git a/Mage.Sets/src/mage/sets/timespiral/ScionOfTheUrDragon.java b/Mage.Sets/src/mage/sets/timespiral/ScionOfTheUrDragon.java index 3112e6b86b7..1a3700f00b2 100644 --- a/Mage.Sets/src/mage/sets/timespiral/ScionOfTheUrDragon.java +++ b/Mage.Sets/src/mage/sets/timespiral/ScionOfTheUrDragon.java @@ -53,7 +53,6 @@ import mage.target.common.TargetCardInLibrary; /** * @author duncant */ - public class ScionOfTheUrDragon extends CardImpl { public ScionOfTheUrDragon(UUID ownerId) { @@ -69,8 +68,8 @@ public class ScionOfTheUrDragon extends CardImpl { // {2}: Search your library for a Dragon permanent card and put it into your graveyard. If you do, Scion of the Ur-Dragon becomes a copy of that card until end of turn. Then shuffle your library. this.addAbility(new SimpleActivatedAbility(Zone.BATTLEFIELD, - new ScionOfTheUrDragonEffect(), - new ManaCostsImpl("{2}"))); + new ScionOfTheUrDragonEffect(), + new ManaCostsImpl("{2}"))); } public ScionOfTheUrDragon(final ScionOfTheUrDragon card) { @@ -84,15 +83,16 @@ public class ScionOfTheUrDragon extends CardImpl { } class ScionOfTheUrDragonEffect extends SearchEffect { + private static final FilterCard filter = new FilterPermanentCard("Dragon permanent card"); - + static { filter.add(new SubtypePredicate("Dragon")); } - + public ScionOfTheUrDragonEffect() { super(new TargetCardInLibrary(filter), Outcome.Copy); - staticText = "Search your library for a Dragon permanent card and put it into your graveyard. If you do, Scion of the Ur-Dragon becomes a copy of that card until end of turn. Then shuffle your library."; + staticText = "Search your library for a Dragon permanent card and put it into your graveyard. If you do, {this} becomes a copy of that card until end of turn. Then shuffle your library."; } ScionOfTheUrDragonEffect(final ScionOfTheUrDragonEffect effect) { diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/copy/InfiniteReflectionTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/copy/InfiniteReflectionTest.java new file mode 100644 index 00000000000..c60f7e912b9 --- /dev/null +++ b/Mage.Tests/src/test/java/org/mage/test/cards/copy/InfiniteReflectionTest.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 org.mage.test.cards.copy; + +import mage.constants.PhaseStep; +import mage.constants.Zone; +import org.junit.Test; +import org.mage.test.serverside.base.CardTestPlayerBase; + +/** + * + * @author LevelX2 + */ +public class InfiniteReflectionTest extends CardTestPlayerBase { + + /** + * + */ + @Test + public void testCopyAsEnters() { + addCard(Zone.BATTLEFIELD, playerA, "Island", 1); + addCard(Zone.BATTLEFIELD, playerA, "Swamp", 9); + addCard(Zone.BATTLEFIELD, playerA, "Silvercoat Lion", 1); +// addCard(Zone.BATTLEFIELD, playerA, "Birds of Paradise", 1); +// addCard(Zone.HAND, playerA, "Nantuko Husk", 1);// {2}{B} + addCard(Zone.GRAVEYARD, playerA, "Pillarfield Ox", 1); + // Put target creature card from a graveyard onto the battlefield under your control. You lose life equal to its converted mana cost. + addCard(Zone.HAND, playerA, "Reanimate", 1); // {B} + + // Enchant creature + // When Infinite Reflection enters the battlefield attached to a creature, each other nontoken creature you control becomes a copy of that creature. + // Nontoken creatures you control enter the battlefield as a copy of enchanted creature. + addCard(Zone.HAND, playerA, "Infinite Reflection", 1); // {5}{U} + + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Infinite Reflection", "Silvercoat Lion"); +// castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Nantuko Husk"); + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Reanimate", "Pillarfield Ox"); + setStopAt(1, PhaseStep.BEGIN_COMBAT); + execute(); + + assertPermanentCount(playerA, "Silvercoat Lion", 2); + } + +} diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/copy/VesuvaTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/copy/VesuvaTest.java index 601be2d21f4..48fc3962b1f 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/copy/VesuvaTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/copy/VesuvaTest.java @@ -60,12 +60,11 @@ public class VesuvaTest extends CardTestPlayerBase { addCard(Zone.HAND, playerB, "Glimmerpost", 1); - playLand(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Glimmerpost"); playLand(2, PhaseStep.PRECOMBAT_MAIN, playerB, "Glimmerpost"); playLand(3, PhaseStep.PRECOMBAT_MAIN, playerA, "Vesuva"); setChoice(playerA, "Glimmerpost"); - + setStopAt(3, PhaseStep.BEGIN_COMBAT); execute(); @@ -75,31 +74,32 @@ public class VesuvaTest extends CardTestPlayerBase { assertLife(playerA, 24); // 20 + 1 + 3 assertLife(playerB, 22); // 20 + 2 } - + @Test public void testDarkDepth() { // Dark Depths enters the battlefield with ten ice counters on it. // {3}: Remove an ice counter from Dark Depths. // When Dark Depths has no ice counters on it, sacrifice it. If you do, put a legendary 20/20 black Avatar creature token with flying and "This creature is indestructible" named Marit Lage onto the battlefield. addCard(Zone.BATTLEFIELD, playerB, "Dark Depths", 1); - + // You may have Vesuva enter the battlefield tapped as a copy of any land on the battlefield. - addCard(Zone.HAND, playerA, "Vesuva", 1); - + addCard(Zone.HAND, playerA, "Vesuva", 1); + playLand(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Vesuva"); setChoice(playerA, "Dark Depths"); - + setStopAt(1, PhaseStep.BEGIN_COMBAT); execute(); - assertPermanentCount(playerA, "Dark Depths", 1); assertPermanentCount(playerB, "Dark Depths", 1); - + assertPermanentCount(playerA, "Vesuva", 0); + assertPermanentCount(playerA, "Dark Depths", 1); + Permanent darkDepth = getPermanent("Dark Depths", playerA); if (darkDepth != null) { - Assert.assertEquals(darkDepth.getCounters().getCount("ice"), 10); + Assert.assertEquals(10, darkDepth.getCounters().getCount("ice")); } - + assertTappedCount("Dark Depths", true, 1); } } diff --git a/Mage.Tests/src/test/java/org/mage/test/player/TestPlayer.java b/Mage.Tests/src/test/java/org/mage/test/player/TestPlayer.java index 55ebad8d17f..5d0df67f11a 100644 --- a/Mage.Tests/src/test/java/org/mage/test/player/TestPlayer.java +++ b/Mage.Tests/src/test/java/org/mage/test/player/TestPlayer.java @@ -1970,6 +1970,11 @@ public class TestPlayer implements Player { return computerPlayer.scry(value, source, game); } + @Override + public boolean moveCards(Card card, Zone toZone, Ability source, Game game, boolean tapped, boolean faceDown, boolean byOwner, ArrayList appliedEffects) { + return computerPlayer.moveCards(card, toZone, source, game, tapped, faceDown, byOwner, appliedEffects); + } + @Override public boolean moveCards(Set cards, Zone toZone, Ability source, Game game, boolean tapped, boolean faceDown, boolean byOwner, ArrayList appliedEffects) { return computerPlayer.moveCards(cards, toZone, source, game, tapped, faceDown, byOwner, appliedEffects); diff --git a/Mage/src/mage/abilities/common/AsEntersBattlefieldAbility.java b/Mage/src/mage/abilities/common/AsEntersBattlefieldAbility.java index e41774bf772..d6f0e0fea6a 100644 --- a/Mage/src/mage/abilities/common/AsEntersBattlefieldAbility.java +++ b/Mage/src/mage/abilities/common/AsEntersBattlefieldAbility.java @@ -39,11 +39,11 @@ import mage.constants.Zone; public class AsEntersBattlefieldAbility extends StaticAbility { public AsEntersBattlefieldAbility(Effect effect) { - super(Zone.BATTLEFIELD, new EntersBattlefieldEffect(effect)); + super(Zone.ALL, new EntersBattlefieldEffect(effect)); } public AsEntersBattlefieldAbility(Effect effect, String text) { - super(Zone.BATTLEFIELD, new EntersBattlefieldEffect(effect, text)); + super(Zone.ALL, new EntersBattlefieldEffect(effect, text)); } public AsEntersBattlefieldAbility(AsEntersBattlefieldAbility ability) { @@ -59,10 +59,9 @@ public class AsEntersBattlefieldAbility extends StaticAbility { return; } } - super.addEffect(effect); + super.addEffect(effect); } - @Override public AsEntersBattlefieldAbility copy() { return new AsEntersBattlefieldAbility(this); diff --git a/Mage/src/mage/abilities/effects/ContinuousEffects.java b/Mage/src/mage/abilities/effects/ContinuousEffects.java index de323f1202b..c5b4661816b 100644 --- a/Mage/src/mage/abilities/effects/ContinuousEffects.java +++ b/Mage/src/mage/abilities/effects/ContinuousEffects.java @@ -876,7 +876,9 @@ public class ContinuousEffects implements Serializable { } } // Must be called here for some effects to be able to work correctly - // TODO: add info which effects need that call + // For example: Vesuva copying a Dark Depth (VesuvaTest:testDarkDepth) + // This call should be removed if possible as replacement effects of EntersTheBattlefield events + // do no longer work correctly because the entering permanents are not yet on the battlefield (before they were). game.applyEffects(); } while (true); return caught; diff --git a/Mage/src/mage/abilities/effects/EntersBattlefieldEffect.java b/Mage/src/mage/abilities/effects/EntersBattlefieldEffect.java index 5a03cbcf339..ef6bb795d16 100644 --- a/Mage/src/mage/abilities/effects/EntersBattlefieldEffect.java +++ b/Mage/src/mage/abilities/effects/EntersBattlefieldEffect.java @@ -34,6 +34,7 @@ import mage.abilities.condition.Condition; import mage.constants.Duration; import mage.constants.Zone; import mage.game.Game; +import mage.game.events.EntersTheBattlefieldEvent; import mage.game.events.GameEvent; import mage.game.events.GameEvent.EventType; import mage.game.stack.Spell; @@ -51,6 +52,7 @@ public class EntersBattlefieldEffect extends ReplacementEffectImpl { protected Condition condition; protected boolean optional; + public static final String ENTERING_PERMANENT = "enteringPermanent"; public static final String SOURCE_CAST_SPELL_ABILITY = "sourceCastSpellAbility"; public EntersBattlefieldEffect(Effect baseEffect) { @@ -112,7 +114,7 @@ public class EntersBattlefieldEffect extends ReplacementEffectImpl { if (controller == null || object == null) { return false; } - if (!controller.chooseUse(outcome, new StringBuilder("Use effect of ").append(object.getLogName()).append("?").toString(), source, game)) { + if (!controller.chooseUse(outcome, "Use effect of " + object.getLogName() + "?", source, game)) { return false; } } @@ -131,6 +133,8 @@ public class EntersBattlefieldEffect extends ReplacementEffectImpl { if (spell != null) { effect.setValue(SOURCE_CAST_SPELL_ABILITY, spell.getSpellAbility()); } + // Because the permanent is not on the battlefield yet, it has to be taken from the event + effect.setValue(ENTERING_PERMANENT, ((EntersTheBattlefieldEvent) event).getTarget()); effect.apply(game, source); } } diff --git a/Mage/src/mage/abilities/effects/common/ChooseColorEffect.java b/Mage/src/mage/abilities/effects/common/ChooseColorEffect.java index 8f22a961ad7..43836dd2f74 100644 --- a/Mage/src/mage/abilities/effects/common/ChooseColorEffect.java +++ b/Mage/src/mage/abilities/effects/common/ChooseColorEffect.java @@ -25,10 +25,10 @@ * authors and should not be interpreted as representing official policies, either expressed * or implied, of BetaSteward_at_googlemail.com. */ - package mage.abilities.effects.common; import mage.abilities.Ability; +import mage.abilities.effects.EntersBattlefieldEffect; import mage.abilities.effects.OneShotEffect; import mage.choices.ChoiceColor; import mage.constants.Outcome; @@ -56,6 +56,9 @@ public class ChooseColorEffect extends OneShotEffect { public boolean apply(Game game, Ability source) { Player controller = game.getPlayer(source.getControllerId()); Permanent permanent = game.getPermanent(source.getSourceId()); + if (permanent == null) { + permanent = (Permanent) getValue(EntersBattlefieldEffect.ENTERING_PERMANENT); + } if (controller != null && permanent != null) { ChoiceColor choice = new ChoiceColor(); while (!choice.isChosen()) { @@ -65,7 +68,7 @@ public class ChooseColorEffect extends OneShotEffect { } } if (!game.isSimulation()) { - game.informPlayers(permanent.getLogName()+": "+controller.getLogName()+" has chosen "+choice.getChoice()); + game.informPlayers(permanent.getLogName() + ": " + controller.getLogName() + " has chosen " + choice.getChoice()); } game.getState().setValue(source.getSourceId() + "_color", choice.getColor()); permanent.addInfo("chosen color", CardUtil.addToolTipMarkTags("Chosen color: " + choice.getChoice()), game); @@ -79,4 +82,4 @@ public class ChooseColorEffect extends OneShotEffect { return new ChooseColorEffect(this); } -} \ No newline at end of file +} diff --git a/Mage/src/mage/abilities/effects/common/CopyEffect.java b/Mage/src/mage/abilities/effects/common/CopyEffect.java index 9d1194fda2a..86bc3f060fb 100644 --- a/Mage/src/mage/abilities/effects/common/CopyEffect.java +++ b/Mage/src/mage/abilities/effects/common/CopyEffect.java @@ -1,16 +1,16 @@ /* * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. - * + * * Redistribution and use in source and binary forms, with or without modification, are * permitted provided that the following conditions are met: - * + * * 1. Redistributions of source code must retain the above copyright notice, this list of * conditions and the following disclaimer. - * + * * 2. Redistributions in binary form must reproduce the above copyright notice, this list * of conditions and the following disclaimer in the documentation and/or other materials * provided with the distribution. - * + * * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR @@ -20,15 +20,13 @@ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * + * * The views and conclusions contained in the software and documentation are those of the * authors and should not be interpreted as representing official policies, either expressed * or implied, of BetaSteward_at_googlemail.com. */ - package mage.abilities.effects.common; - import java.util.UUID; import mage.MageObject; import mage.MageObjectReference; @@ -56,39 +54,42 @@ public class CopyEffect extends ContinuousEffectImpl { /** * Object we copy from */ - private MageObject target; - - private UUID sourceId; + private MageObject copyFromObject; + + private UUID copyToObjectId; private ApplyToPermanent applier; - - public CopyEffect(MageObject target, UUID sourceId) { - this(Duration.Custom, target, sourceId); + + public CopyEffect(MageObject copyFromObject, UUID copyToObjectId) { + this(Duration.Custom, copyFromObject, copyToObjectId); } - - public CopyEffect(Duration duration, MageObject target, UUID sourceId) { + + public CopyEffect(Duration duration, MageObject copyFromObject, UUID copyToObjectId) { super(duration, Layer.CopyEffects_1, SubLayer.NA, Outcome.BecomeCreature); - this.target = target; - this.sourceId = sourceId; + this.copyFromObject = copyFromObject; + this.copyToObjectId = copyToObjectId; } public CopyEffect(final CopyEffect effect) { super(effect); - this.target = effect.target.copy(); - this.sourceId = effect.sourceId; + this.copyFromObject = effect.copyFromObject.copy(); + this.copyToObjectId = effect.copyToObjectId; this.applier = effect.applier; } @Override public void init(Ability source, Game game) { super.init(source, game); - if (!(target instanceof Permanent) && (target instanceof Card)) { - this.target = new PermanentCard((Card)target, source.getControllerId(), game); + if (!(copyFromObject instanceof Permanent) && (copyFromObject instanceof Card)) { + this.copyFromObject = new PermanentCard((Card) copyFromObject, source.getControllerId(), game); } - affectedObjectList.add(new MageObjectReference(getSourceId(), game)); + } @Override public boolean apply(Game game, Ability source) { + if (affectedObjectList.isEmpty()) { + affectedObjectList.add(new MageObjectReference(getSourceId(), game)); + } Permanent permanent = affectedObjectList.get(0).getPermanent(game); if (permanent == null) { permanent = (Permanent) game.getLastKnownInformation(getSourceId(), Zone.BATTLEFIELD, source.getSourceObjectZoneChangeCounter()); @@ -99,31 +100,31 @@ public class CopyEffect extends ContinuousEffectImpl { } } permanent.setCopy(true); - permanent.setName(target.getName()); - permanent.getColor(game).setColor(target.getColor(game)); + permanent.setName(copyFromObject.getName()); + permanent.getColor(game).setColor(copyFromObject.getColor(game)); permanent.getManaCost().clear(); - permanent.getManaCost().add(target.getManaCost()); + permanent.getManaCost().add(copyFromObject.getManaCost()); permanent.getCardType().clear(); - for (CardType type: target.getCardType()) { + for (CardType type : copyFromObject.getCardType()) { permanent.getCardType().add(type); } permanent.getSubtype().clear(); - for (String type: target.getSubtype()) { + for (String type : copyFromObject.getSubtype()) { permanent.getSubtype().add(type); } permanent.getSupertype().clear(); - for (String type: target.getSupertype()) { + for (String type : copyFromObject.getSupertype()) { permanent.getSupertype().add(type); } permanent.removeAllAbilities(source.getSourceId(), game); - for (Ability ability: target.getAbilities()) { - permanent.addAbility(ability, getSourceId(), game, false); // no new Id so consumed replacement effects are known while new continuousEffects.apply happen. + for (Ability ability : copyFromObject.getAbilities()) { + permanent.addAbility(ability, getSourceId(), game, false); // no new Id so consumed replacement effects are known while new continuousEffects.apply happen. } - permanent.getPower().setValue(target.getPower().getValue()); - permanent.getToughness().setValue(target.getToughness().getValue()); - if (target instanceof Permanent) { - Permanent targetPermanent = (Permanent) target; + permanent.getPower().setValue(copyFromObject.getPower().getValue()); + permanent.getToughness().setValue(copyFromObject.getToughness().getValue()); + if (copyFromObject instanceof Permanent) { + Permanent targetPermanent = (Permanent) copyFromObject; permanent.setTransformed(targetPermanent.isTransformed()); permanent.setSecondCardFace(targetPermanent.getSecondCardFace()); permanent.setFlipCard(targetPermanent.isFlipCard()); @@ -131,13 +132,13 @@ public class CopyEffect extends ContinuousEffectImpl { } // to get the image of the copied permanent copy number und expansionCode - if (target instanceof PermanentCard) { - permanent.setCardNumber(((PermanentCard) target).getCard().getCardNumber()); - permanent.setExpansionSetCode(((PermanentCard) target).getCard().getExpansionSetCode()); - } else if (target instanceof PermanentToken || target instanceof Card) { - permanent.setCardNumber(((Card) target).getCardNumber()); - permanent.setExpansionSetCode(((Card) target).getExpansionSetCode()); - } + if (copyFromObject instanceof PermanentCard) { + permanent.setCardNumber(((PermanentCard) copyFromObject).getCard().getCardNumber()); + permanent.setExpansionSetCode(((PermanentCard) copyFromObject).getCard().getExpansionSetCode()); + } else if (copyFromObject instanceof PermanentToken || copyFromObject instanceof Card) { + permanent.setCardNumber(((Card) copyFromObject).getCardNumber()); + permanent.setExpansionSetCode(((Card) copyFromObject).getExpansionSetCode()); + } return true; } @@ -147,15 +148,15 @@ public class CopyEffect extends ContinuousEffectImpl { } public MageObject getTarget() { - return target; + return copyFromObject; } public void setTarget(MageObject target) { - this.target = target; + this.copyFromObject = target; } public UUID getSourceId() { - return sourceId; + return copyToObjectId; } public ApplyToPermanent getApplier() { @@ -165,5 +166,5 @@ public class CopyEffect extends ContinuousEffectImpl { public void setApplier(ApplyToPermanent applier) { this.applier = applier; } - + } diff --git a/Mage/src/mage/abilities/effects/common/ReturnFromGraveyardToBattlefieldTargetEffect.java b/Mage/src/mage/abilities/effects/common/ReturnFromGraveyardToBattlefieldTargetEffect.java index da7960e7437..dd2e2797041 100644 --- a/Mage/src/mage/abilities/effects/common/ReturnFromGraveyardToBattlefieldTargetEffect.java +++ b/Mage/src/mage/abilities/effects/common/ReturnFromGraveyardToBattlefieldTargetEffect.java @@ -73,7 +73,7 @@ public class ReturnFromGraveyardToBattlefieldTargetEffect extends OneShotEffect for (UUID targetId : getTargetPointer().getTargets(game, source)) { Card card = game.getCard(targetId); if (card != null) { - controller.putOntoBattlefieldWithInfo(card, game, Zone.GRAVEYARD, source.getSourceId(), tapped); + controller.moveCards(card, Zone.BATTLEFIELD, source, game, tapped, false, false, null); } } return true; diff --git a/Mage/src/mage/abilities/effects/common/counter/AddCountersSourceEffect.java b/Mage/src/mage/abilities/effects/common/counter/AddCountersSourceEffect.java index 82c14c0cdb9..0633ff60c63 100644 --- a/Mage/src/mage/abilities/effects/common/counter/AddCountersSourceEffect.java +++ b/Mage/src/mage/abilities/effects/common/counter/AddCountersSourceEffect.java @@ -1,16 +1,16 @@ /* * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. - * + * * Redistribution and use in source and binary forms, with or without modification, are * permitted provided that the following conditions are met: - * + * * 1. Redistributions of source code must retain the above copyright notice, this list of * conditions and the following disclaimer. - * + * * 2. Redistributions in binary form must reproduce the above copyright notice, this list * of conditions and the following disclaimer in the documentation and/or other materials * provided with the distribution. - * + * * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR @@ -20,20 +20,20 @@ * 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.counter; -import mage.constants.Outcome; import mage.abilities.Ability; import mage.abilities.dynamicvalue.DynamicValue; import mage.abilities.dynamicvalue.common.StaticValue; +import mage.abilities.effects.EntersBattlefieldEffect; import mage.abilities.effects.OneShotEffect; import mage.cards.Card; +import mage.constants.Outcome; import mage.counters.Counter; import mage.game.Game; import mage.game.permanent.Permanent; @@ -63,11 +63,12 @@ public class AddCountersSourceEffect extends OneShotEffect { } /** - * + * * @param counter * @param amount this amount will be added to the counter instances * @param informPlayers - * @param putOnCard - counters have to be put on a card instead of a permanent + * @param putOnCard - counters have to be put on a card instead of a + * permanent */ public AddCountersSourceEffect(Counter counter, DynamicValue amount, boolean informPlayers, boolean putOnCard) { super(Outcome.Benefit); @@ -106,7 +107,7 @@ public class AddCountersSourceEffect extends OneShotEffect { if (informPlayers && !game.isSimulation()) { Player player = game.getPlayer(source.getControllerId()); if (player != null) { - game.informPlayers(new StringBuilder(player.getLogName()).append(" puts ").append(newCounter.getCount()).append(" ").append(newCounter.getName().toLowerCase()).append(" counter on ").append(card.getLogName()).toString()); + game.informPlayers(player.getLogName() + " puts " + newCounter.getCount() + " " + newCounter.getName().toLowerCase() + " counter on " + card.getLogName()); } } } @@ -114,6 +115,9 @@ public class AddCountersSourceEffect extends OneShotEffect { } } else { Permanent permanent = game.getPermanent(source.getSourceId()); + if (permanent == null) { + permanent = (Permanent) getValue(EntersBattlefieldEffect.ENTERING_PERMANENT); + } if (permanent != null) { if (counter != null) { Counter newCounter = counter.copy(); @@ -129,7 +133,7 @@ public class AddCountersSourceEffect extends OneShotEffect { int amountAdded = permanent.getCounters().getCount(newCounter.getName()) - before; Player player = game.getPlayer(source.getControllerId()); if (player != null) { - game.informPlayers(player.getLogName()+" puts "+amountAdded+" "+newCounter.getName().toLowerCase()+" counter on "+permanent.getLogName()); + game.informPlayers(player.getLogName() + " puts " + amountAdded + " " + newCounter.getName().toLowerCase() + " counter on " + permanent.getLogName()); } } } @@ -165,5 +169,4 @@ public class AddCountersSourceEffect extends OneShotEffect { return new AddCountersSourceEffect(this); } - } diff --git a/Mage/src/mage/game/stack/Spell.java b/Mage/src/mage/game/stack/Spell.java index 2972b65d2de..482bfb8451e 100644 --- a/Mage/src/mage/game/stack/Spell.java +++ b/Mage/src/mage/game/stack/Spell.java @@ -167,6 +167,10 @@ public class Spell extends StackObjImpl implements Card { @Override public boolean resolve(Game game) { boolean result; + Player controller = game.getPlayer(getControllerId()); + if (controller == null) { + return false; + } if (this.getCardType().contains(CardType.INSTANT) || this.getCardType().contains(CardType.SORCERY)) { int index = 0; result = false; @@ -261,6 +265,7 @@ public class Spell extends StackObjImpl implements Card { } } else { updateOptionalCosts(0); +// return controller.moveCards(card, Zone.BATTLEFIELD, ability, game, false, faceDown, false, null); result = card.putOntoBattlefield(game, Zone.STACK, ability.getSourceId(), controllerId, false, faceDown); return result; } diff --git a/Mage/src/mage/players/Player.java b/Mage/src/mage/players/Player.java index d00471867c3..b484fb8ccf9 100644 --- a/Mage/src/mage/players/Player.java +++ b/Mage/src/mage/players/Player.java @@ -635,6 +635,8 @@ public interface Player extends MageItem, Copyable { boolean moveCards(Set cards, Zone fromZone, Zone toZone, Ability source, Game game); + boolean moveCards(Card card, Zone toZone, Ability source, Game game, boolean tapped, boolean faceDown, boolean byOwner, ArrayList appliedEffects); + /** * * @param cards @@ -646,6 +648,7 @@ public interface Player extends MageItem, Copyable { * @param byOwner the card is moved (or put onto battlefield) by the owner * of the card and if target zone is battlefield controlls the permanent * (instead of the controller of the source) + * @param appliedEffects * @return */ boolean moveCards(Set cards, Zone toZone, Ability source, Game game, boolean tapped, boolean faceDown, boolean byOwner, ArrayList appliedEffects); diff --git a/Mage/src/mage/players/PlayerImpl.java b/Mage/src/mage/players/PlayerImpl.java index bb1250e1b5c..011d716acd2 100644 --- a/Mage/src/mage/players/PlayerImpl.java +++ b/Mage/src/mage/players/PlayerImpl.java @@ -1022,7 +1022,7 @@ public abstract class PlayerImpl implements Player, Serializable { game.fireEvent(GameEvent.getEvent(GameEvent.EventType.LAND_PLAYED, card.getId(), card.getId(), playerId)); game.fireInformEvent(getLogName() + " plays " + card.getLogName()); // game.removeBookmark(bookmark); - resetStoredBookmark(game); + resetStoredBookmark(game); // prevent undo after playing a land return true; } // putOntoBattlefield retured false if putOntoBattlefield was replaced by replacement effect (e.g. Kjeldorian Outpost). @@ -2998,22 +2998,6 @@ public abstract class PlayerImpl implements Player, Serializable { successfulMovedCards = moveCardsToGraveyardWithInfo(cards, source, game, fromZone); break; case HAND: - for (Card card : cards) { - fromZone = game.getState().getZone(card.getId()); -// if (fromZone == Zone.STACK) { -// // If a spell is returned to its owner's hand, it's removed from the stack and thus will not resolve -// Spell spell = game.getStack().getSpell(card.getId()); -// if (spell != null) { -// game.getStack().remove(spell); -// } -// } - boolean hideCard = fromZone.equals(Zone.LIBRARY) - || (card.isFaceDown(game) && !fromZone.equals(Zone.STACK) && !fromZone.equals(Zone.BATTLEFIELD)); - if (moveCardToHandWithInfo(card, source == null ? null : source.getSourceId(), game, !hideCard)) { - successfulMovedCards.add(card); - } - } - break; case BATTLEFIELD: return moveCards(cards, toZone, source, game, false, false, false, null); case LIBRARY: @@ -3032,6 +3016,15 @@ public abstract class PlayerImpl implements Player, Serializable { return successfulMovedCards.size() > 0; } + @Override + public boolean moveCards(Card card, Zone toZone, Ability source, Game game, boolean tapped, boolean faceDown, boolean byOwner, ArrayList appliedEffects) { + Set cardList = new HashSet<>(); + if (card != null) { + cardList.add(card); + } + return moveCards(cardList, toZone, source, game, tapped, faceDown, byOwner, appliedEffects); + } + @Override public boolean moveCards(Set cards, Zone toZone, Ability source, Game game, boolean tapped, boolean faceDown, boolean byOwner, ArrayList appliedEffects) { if (cards.isEmpty()) { @@ -3070,7 +3063,6 @@ public abstract class PlayerImpl implements Player, Serializable { } } game.setScopeRelevant(false); - game.applyEffects(); for (Permanent permanent : permanentsEntered) { fromZone = game.getState().getZone(permanent.getId()); if (((Card) permanent).removeFromZone(game, fromZone, source.getSourceId())) { @@ -3086,6 +3078,17 @@ public abstract class PlayerImpl implements Player, Serializable { game.addSimultaneousEvent(new ZoneChangeEvent(permanent, permanent.getControllerId(), fromZone, Zone.BATTLEFIELD)); } } + game.applyEffects(); + break; + case HAND: + for (Card card : cards) { + fromZone = game.getState().getZone(card.getId()); + boolean hideCard = fromZone.equals(Zone.LIBRARY) + || (card.isFaceDown(game) && !fromZone.equals(Zone.STACK) && !fromZone.equals(Zone.BATTLEFIELD)); + if (moveCardToHandWithInfo(card, source == null ? null : source.getSourceId(), game, !hideCard)) { + successfulMovedCards.add(card); + } + } break; default: throw new UnsupportedOperationException("to Zone not supported yet"); From 9687e21bf1021b6376fb18ee6ac811c3b930fc1c Mon Sep 17 00:00:00 2001 From: LoneFox Date: Thu, 15 Oct 2015 09:51:59 +0300 Subject: [PATCH 102/268] Fix compilation (But why did it work before? I tested it...) --- Mage.Sets/src/mage/sets/riseoftheeldrazi/NotOfThisWorld.java | 1 + 1 file changed, 1 insertion(+) diff --git a/Mage.Sets/src/mage/sets/riseoftheeldrazi/NotOfThisWorld.java b/Mage.Sets/src/mage/sets/riseoftheeldrazi/NotOfThisWorld.java index 1ee4a1ce987..97363cb0aa8 100644 --- a/Mage.Sets/src/mage/sets/riseoftheeldrazi/NotOfThisWorld.java +++ b/Mage.Sets/src/mage/sets/riseoftheeldrazi/NotOfThisWorld.java @@ -38,6 +38,7 @@ import mage.constants.CardType; import mage.constants.Rarity; import mage.constants.TargetController; import mage.constants.Zone; +import mage.filter.Filter; import mage.filter.FilterSpell; import mage.filter.common.FilterControlledPermanent; import mage.filter.common.FilterCreaturePermanent; From 0e3f28c8674e18384810d34d01f6515572ff33a0 Mon Sep 17 00:00:00 2001 From: LoneFox Date: Thu, 15 Oct 2015 09:53:24 +0300 Subject: [PATCH 103/268] Check all targets if necessary and not just the first one --- .../filter/predicate/other/TargetsPermanentPredicate.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Mage/src/mage/filter/predicate/other/TargetsPermanentPredicate.java b/Mage/src/mage/filter/predicate/other/TargetsPermanentPredicate.java index 0cf864bbc42..5471eae280c 100644 --- a/Mage/src/mage/filter/predicate/other/TargetsPermanentPredicate.java +++ b/Mage/src/mage/filter/predicate/other/TargetsPermanentPredicate.java @@ -59,8 +59,8 @@ public class TargetsPermanentPredicate implements ObjectSourcePlayerPredicate Date: Thu, 15 Oct 2015 09:28:02 +0200 Subject: [PATCH 104/268] Added Spoils of Evil --- .../src/mage/sets/iceage/SpoilsOfEvil.java | 105 ++++++++++++++++++ .../mage/sets/scourge/ForgottenAncient.java | 2 +- 2 files changed, 106 insertions(+), 1 deletion(-) create mode 100644 Mage.Sets/src/mage/sets/iceage/SpoilsOfEvil.java diff --git a/Mage.Sets/src/mage/sets/iceage/SpoilsOfEvil.java b/Mage.Sets/src/mage/sets/iceage/SpoilsOfEvil.java new file mode 100644 index 00000000000..731676b24a4 --- /dev/null +++ b/Mage.Sets/src/mage/sets/iceage/SpoilsOfEvil.java @@ -0,0 +1,105 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.sets.iceage; + +import java.util.UUID; +import mage.Mana; +import mage.abilities.Ability; +import mage.abilities.effects.OneShotEffect; +import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.Outcome; +import mage.constants.Rarity; +import mage.filter.FilterCard; +import mage.filter.predicate.Predicates; +import mage.filter.predicate.mageobject.CardTypePredicate; +import mage.game.Game; +import mage.players.Player; +import mage.target.common.TargetOpponent; + +/** + * + * @author Blinke + */ +public class SpoilsOfEvil extends CardImpl { + private static final FilterCard filter = new FilterCard("artifact or creature card in target opponents graveyard"); + static { + filter.add(Predicates.or( + new CardTypePredicate(CardType.ARTIFACT), + new CardTypePredicate(CardType.CREATURE))); + } + + public SpoilsOfEvil(UUID ownerId) { + super(ownerId, 51, "Spoils of Evil", Rarity.RARE, new CardType[]{CardType.INSTANT}, "{2}{B}"); + this.expansionSetCode = "ICE"; + + // For each artifact or creature card in target opponent's graveyard, add {1} to your mana pool and you gain 1 life. + this.getSpellAbility().addEffect(new SpoilsOfEvilEffect()); + this.getSpellAbility().addTarget(new TargetOpponent()); + } + + public SpoilsOfEvil(final SpoilsOfEvil card) { + super(card); + } + + @Override + public SpoilsOfEvil copy() { + return new SpoilsOfEvil(this); + } + + class SpoilsOfEvilEffect extends OneShotEffect { + + public SpoilsOfEvilEffect() { + super(Outcome.GainLife); + this.staticText = "For each artifact or creature card in target opponent's graveyard, add {1} to your mana pool and you gain 1 life."; + } + + public SpoilsOfEvilEffect(final SpoilsOfEvilEffect effect) { + super(effect); + } + + @Override + public SpoilsOfEvilEffect copy() { + return new SpoilsOfEvilEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player targetOpponent = game.getPlayer(targetPointer.getFirst(game, source)); + Player controller = game.getPlayer(source.getControllerId()); + + if(targetOpponent != null && controller != null) { + int cardCount = targetOpponent.getGraveyard().count(filter, game); + controller.gainLife(cardCount, game); + controller.getManaPool().addMana(Mana.ColorlessMana(cardCount), game, source); + return true; + } + return false; + } + } +} diff --git a/Mage.Sets/src/mage/sets/scourge/ForgottenAncient.java b/Mage.Sets/src/mage/sets/scourge/ForgottenAncient.java index 8107c48a39c..b6ad87f8e20 100644 --- a/Mage.Sets/src/mage/sets/scourge/ForgottenAncient.java +++ b/Mage.Sets/src/mage/sets/scourge/ForgottenAncient.java @@ -95,7 +95,7 @@ public class ForgottenAncient extends CardImpl { public ForgottenAncientEffect() { super(Outcome.Benefit); - this.staticText = "you may move any number of +1/+1 counters from Forgotten Ancient onto other creatures."; + this.staticText = "you may move any number of +1/+1 counters from {this} onto other creatures."; } public ForgottenAncientEffect(final ForgottenAncientEffect effect) { From 7433ba06969e76da70e0020fbc357f0b6d090edb Mon Sep 17 00:00:00 2001 From: LoneFox Date: Thu, 15 Oct 2015 12:11:06 +0300 Subject: [PATCH 105/268] Implement cards: Avoid Fate, Rebuff the Wicked, Ring of Immortals, and Vigilant Martyr --- .../src/mage/sets/legends/AvoidFate.java | 73 +++++++++++++++ .../mage/sets/legends/RingOfImmortals.java | 80 +++++++++++++++++ .../src/mage/sets/mirage/VigilantMartyr.java | 89 +++++++++++++++++++ .../sets/planarchaos/RebuffTheWicked.java | 70 +++++++++++++++ .../src/mage/sets/timeshifted/AvoidFate.java | 54 +++++++++++ 5 files changed, 366 insertions(+) create mode 100644 Mage.Sets/src/mage/sets/legends/AvoidFate.java create mode 100644 Mage.Sets/src/mage/sets/legends/RingOfImmortals.java create mode 100644 Mage.Sets/src/mage/sets/mirage/VigilantMartyr.java create mode 100644 Mage.Sets/src/mage/sets/planarchaos/RebuffTheWicked.java create mode 100644 Mage.Sets/src/mage/sets/timeshifted/AvoidFate.java diff --git a/Mage.Sets/src/mage/sets/legends/AvoidFate.java b/Mage.Sets/src/mage/sets/legends/AvoidFate.java new file mode 100644 index 00000000000..457ace9b738 --- /dev/null +++ b/Mage.Sets/src/mage/sets/legends/AvoidFate.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.legends; + +import java.util.UUID; +import mage.abilities.effects.common.CounterTargetEffect; +import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.Rarity; +import mage.filter.FilterSpell; +import mage.filter.common.FilterControlledPermanent; +import mage.filter.predicate.Predicates; +import mage.filter.predicate.mageobject.CardTypePredicate; +import mage.filter.predicate.mageobject.SubtypePredicate; +import mage.filter.predicate.other.TargetsPermanentPredicate; +import mage.target.TargetSpell; + +/** + * + * @author LoneFox + */ +public class AvoidFate extends CardImpl { + + private final static FilterSpell filter = new FilterSpell("instant or Aura spell that targets a permanent you control"); + + static { + filter.add(Predicates.or(new CardTypePredicate(CardType.INSTANT), new SubtypePredicate("Aura"))); + filter.add(new TargetsPermanentPredicate(new FilterControlledPermanent())); + } + + public AvoidFate(UUID ownerId) { + super(ownerId, 89, "Avoid Fate", Rarity.COMMON, new CardType[]{CardType.INSTANT}, "{G}"); + this.expansionSetCode = "LEG"; + + // Counter target instant or Aura spell that targets a permanent you control. + this.getSpellAbility().addEffect(new CounterTargetEffect()); + this.getSpellAbility().addTarget(new TargetSpell(filter)); + } + + public AvoidFate(final AvoidFate card) { + super(card); + } + + @Override + public AvoidFate copy() { + return new AvoidFate(this); + } +} diff --git a/Mage.Sets/src/mage/sets/legends/RingOfImmortals.java b/Mage.Sets/src/mage/sets/legends/RingOfImmortals.java new file mode 100644 index 00000000000..4679b275d39 --- /dev/null +++ b/Mage.Sets/src/mage/sets/legends/RingOfImmortals.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.abilities.Ability; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.costs.common.TapSourceCost; +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.effects.common.CounterTargetEffect; +import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.Rarity; +import mage.constants.Zone; +import mage.filter.FilterSpell; +import mage.filter.common.FilterControlledPermanent; +import mage.filter.predicate.Predicates; +import mage.filter.predicate.mageobject.CardTypePredicate; +import mage.filter.predicate.mageobject.SubtypePredicate; +import mage.filter.predicate.other.TargetsPermanentPredicate; +import mage.target.TargetSpell; + +/** + * + * @author LoneFox + */ +public class RingOfImmortals extends CardImpl { + + private final static FilterSpell filter = new FilterSpell("instant or Aura spell that targets a permanent you control"); + + static { + filter.add(Predicates.or(new CardTypePredicate(CardType.INSTANT), new SubtypePredicate("Aura"))); + filter.add(new TargetsPermanentPredicate(new FilterControlledPermanent())); + } + + public RingOfImmortals(UUID ownerId) { + super(ownerId, 238, "Ring of Immortals", Rarity.RARE, new CardType[]{CardType.ARTIFACT}, "{5}"); + this.expansionSetCode = "LEG"; + + // {3}, {tap}: Counter target instant or Aura spell that targets a permanent you control. + Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new CounterTargetEffect(), new ManaCostsImpl("{3}")); + ability.addCost(new TapSourceCost()); + ability.addTarget(new TargetSpell(filter)); + this.addAbility(ability); + } + + public RingOfImmortals(final RingOfImmortals card) { + super(card); + } + + @Override + public RingOfImmortals copy() { + return new RingOfImmortals(this); + } +} diff --git a/Mage.Sets/src/mage/sets/mirage/VigilantMartyr.java b/Mage.Sets/src/mage/sets/mirage/VigilantMartyr.java new file mode 100644 index 00000000000..c0bfb95c423 --- /dev/null +++ b/Mage.Sets/src/mage/sets/mirage/VigilantMartyr.java @@ -0,0 +1,89 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.sets.mirage; + +import java.util.UUID; +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.costs.common.SacrificeSourceCost; +import mage.abilities.costs.common.TapSourceCost; +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.effects.common.CounterTargetEffect; +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.FilterSpell; +import mage.filter.common.FilterEnchantmentPermanent; +import mage.filter.predicate.other.TargetsPermanentPredicate; +import mage.target.TargetSpell; +import mage.target.common.TargetCreaturePermanent; + +/** + * + * @author LoneFox + */ +public class VigilantMartyr extends CardImpl { + + private final static FilterSpell filter = new FilterSpell("spell that targets an enchantment"); + + static { + filter.add(new TargetsPermanentPredicate(new FilterEnchantmentPermanent())); + } + + public VigilantMartyr(UUID ownerId) { + super(ownerId, 249, "Vigilant Martyr", Rarity.UNCOMMON, new CardType[]{CardType.CREATURE}, "{W}"); + this.expansionSetCode = "MIR"; + this.subtype.add("Human"); + this.subtype.add("Cleric"); + this.power = new MageInt(1); + this.toughness = new MageInt(1); + + // Sacrifice Vigilant Martyr: Regenerate target creature. + Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new RegenerateTargetEffect(), new SacrificeSourceCost()); + ability.addTarget(new TargetCreaturePermanent()); + this.addAbility(ability); + // {W}{W}, {tap}, Sacrifice Vigilant Martyr: Counter target spell that targets an enchantment. + ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new CounterTargetEffect(), new ManaCostsImpl("{W}{W}")); + ability.addCost(new TapSourceCost()); + ability.addCost(new SacrificeSourceCost()); + ability.addTarget(new TargetSpell(filter)); + this.addAbility(ability); + } + + public VigilantMartyr(final VigilantMartyr card) { + super(card); + } + + @Override + public VigilantMartyr copy() { + return new VigilantMartyr(this); + } +} diff --git a/Mage.Sets/src/mage/sets/planarchaos/RebuffTheWicked.java b/Mage.Sets/src/mage/sets/planarchaos/RebuffTheWicked.java new file mode 100644 index 00000000000..cf3e1780ce9 --- /dev/null +++ b/Mage.Sets/src/mage/sets/planarchaos/RebuffTheWicked.java @@ -0,0 +1,70 @@ +/* + * 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.planarchaos; + +import java.util.UUID; +import mage.abilities.effects.common.CounterTargetEffect; +import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.Rarity; +import mage.filter.FilterSpell; +import mage.filter.common.FilterControlledPermanent; +import mage.filter.predicate.Predicates; +import mage.filter.predicate.other.TargetsPermanentPredicate; +import mage.target.TargetSpell; + +/** + * + * @author LoneFox + */ +public class RebuffTheWicked extends CardImpl { + + private final static FilterSpell filter = new FilterSpell("spell that targets a permanent you control"); + + static { + filter.add(new TargetsPermanentPredicate(new FilterControlledPermanent())); + } + + public RebuffTheWicked(UUID ownerId) { + super(ownerId, 12, "Rebuff the Wicked", Rarity.UNCOMMON, new CardType[]{CardType.INSTANT}, "{W}"); + this.expansionSetCode = "PLC"; + + // Counter target spell that targets a permanent you control. + this.getSpellAbility().addEffect(new CounterTargetEffect()); + this.getSpellAbility().addTarget(new TargetSpell(filter)); + } + + public RebuffTheWicked(final RebuffTheWicked card) { + super(card); + } + + @Override + public RebuffTheWicked copy() { + return new RebuffTheWicked(this); + } +} diff --git a/Mage.Sets/src/mage/sets/timeshifted/AvoidFate.java b/Mage.Sets/src/mage/sets/timeshifted/AvoidFate.java new file mode 100644 index 00000000000..7d4f7d23cfb --- /dev/null +++ b/Mage.Sets/src/mage/sets/timeshifted/AvoidFate.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.timeshifted; + +import java.util.UUID; +import mage.constants.Rarity; + +/** + * + * @author LoneFox + */ +public class AvoidFate extends mage.sets.legends.AvoidFate { + + public AvoidFate(UUID ownerId) { + super(ownerId); + this.cardNumber = 73; + this.expansionSetCode = "TSB"; + this.rarity = Rarity.SPECIAL; + } + + public AvoidFate(final AvoidFate card) { + super(card); + } + + @Override + public AvoidFate copy() { + return new AvoidFate(this); + } +} From 96a506440b94afa64a473f2c9d94e3f6857f29e6 Mon Sep 17 00:00:00 2001 From: LoneFox Date: Thu, 15 Oct 2015 13:50:12 +0300 Subject: [PATCH 106/268] Implement cards: Castle Raptors, Confound, Ironshell Beetle, and Juniper Order Advocate --- .../sets/alliances/JuniperOrderAdvocate.java | 84 +++++++++++++++++++ .../mage/sets/judgment/IronshellBeetle.java | 68 +++++++++++++++ .../JuniperOrderAdvocate.java | 52 ++++++++++++ .../src/mage/sets/planeshift/Confound.java | 73 ++++++++++++++++ .../mage/sets/timespiral/CastleRaptors.java | 74 ++++++++++++++++ 5 files changed, 351 insertions(+) create mode 100644 Mage.Sets/src/mage/sets/alliances/JuniperOrderAdvocate.java create mode 100644 Mage.Sets/src/mage/sets/judgment/IronshellBeetle.java create mode 100644 Mage.Sets/src/mage/sets/masterseditionii/JuniperOrderAdvocate.java create mode 100644 Mage.Sets/src/mage/sets/planeshift/Confound.java create mode 100644 Mage.Sets/src/mage/sets/timespiral/CastleRaptors.java diff --git a/Mage.Sets/src/mage/sets/alliances/JuniperOrderAdvocate.java b/Mage.Sets/src/mage/sets/alliances/JuniperOrderAdvocate.java new file mode 100644 index 00000000000..6faff763326 --- /dev/null +++ b/Mage.Sets/src/mage/sets/alliances/JuniperOrderAdvocate.java @@ -0,0 +1,84 @@ +/* + * 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.alliances; + +import java.util.UUID; +import mage.MageInt; +import mage.ObjectColor; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.condition.InvertCondition; +import mage.abilities.condition.common.SourceTappedCondition; +import mage.abilities.decorator.ConditionalContinuousEffect; +import mage.abilities.effects.common.continuous.BoostAllEffect; +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.common.FilterCreaturePermanent; +import mage.filter.predicate.mageobject.ColorPredicate; +import mage.filter.predicate.permanent.ControllerPredicate; + +/** + * + * @author LoneFox + */ +public class JuniperOrderAdvocate extends CardImpl { + + private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("green creatures you control"); + + static { + filter.add(new ColorPredicate(ObjectColor.GREEN)); + filter.add(new ControllerPredicate(TargetController.YOU)); + } + + public JuniperOrderAdvocate(UUID ownerId) { + super(ownerId, 132, "Juniper Order Advocate", Rarity.UNCOMMON, new CardType[]{CardType.CREATURE}, "{2}{W}"); + this.expansionSetCode = "ALL"; + this.subtype.add("Human"); + this.subtype.add("Knight"); + this.power = new MageInt(1); + this.toughness = new MageInt(2); + + // As long as Juniper Order Advocate is untapped, green creatures you control get +1/+1. + this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new ConditionalContinuousEffect( + new BoostAllEffect(1, 1, Duration.WhileOnBattlefield, filter, false), + new InvertCondition(new SourceTappedCondition()), + "As long as {this} is untapped, green creatures you control get +1/+1."))); + } + + public JuniperOrderAdvocate(final JuniperOrderAdvocate card) { + super(card); + } + + @Override + public JuniperOrderAdvocate copy() { + return new JuniperOrderAdvocate(this); + } +} diff --git a/Mage.Sets/src/mage/sets/judgment/IronshellBeetle.java b/Mage.Sets/src/mage/sets/judgment/IronshellBeetle.java new file mode 100644 index 00000000000..b914f9ad59c --- /dev/null +++ b/Mage.Sets/src/mage/sets/judgment/IronshellBeetle.java @@ -0,0 +1,68 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.sets.judgment; + +import java.util.UUID; +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.effects.common.counter.AddCountersTargetEffect; +import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.Rarity; +import mage.counters.CounterType; +import mage.target.common.TargetCreaturePermanent; + +/** + * + * @author LoneFox + */ +public class IronshellBeetle extends CardImpl { + + public IronshellBeetle(UUID ownerId) { + super(ownerId, 121, "Ironshell Beetle", Rarity.COMMON, new CardType[]{CardType.CREATURE}, "{1}{G}"); + this.expansionSetCode = "JUD"; + this.subtype.add("Insect"); + this.power = new MageInt(1); + this.toughness = new MageInt(1); + + // When Ironshell Beetle enters the battlefield, put a +1/+1 counter on target creature. + Ability ability = new EntersBattlefieldTriggeredAbility(new AddCountersTargetEffect(CounterType.P1P1.createInstance())); + ability.addTarget(new TargetCreaturePermanent()); + this.addAbility(ability); + } + + public IronshellBeetle(final IronshellBeetle card) { + super(card); + } + + @Override + public IronshellBeetle copy() { + return new IronshellBeetle(this); + } +} diff --git a/Mage.Sets/src/mage/sets/masterseditionii/JuniperOrderAdvocate.java b/Mage.Sets/src/mage/sets/masterseditionii/JuniperOrderAdvocate.java new file mode 100644 index 00000000000..16f458ecba6 --- /dev/null +++ b/Mage.Sets/src/mage/sets/masterseditionii/JuniperOrderAdvocate.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.masterseditionii; + +import java.util.UUID; + +/** + * + * @author LoneFox + */ +public class JuniperOrderAdvocate extends mage.sets.alliances.JuniperOrderAdvocate { + + public JuniperOrderAdvocate(UUID ownerId) { + super(ownerId); + this.cardNumber = 20; + this.expansionSetCode = "ME2"; + } + + public JuniperOrderAdvocate(final JuniperOrderAdvocate card) { + super(card); + } + + @Override + public JuniperOrderAdvocate copy() { + return new JuniperOrderAdvocate(this); + } +} diff --git a/Mage.Sets/src/mage/sets/planeshift/Confound.java b/Mage.Sets/src/mage/sets/planeshift/Confound.java new file mode 100644 index 00000000000..44f266b00bf --- /dev/null +++ b/Mage.Sets/src/mage/sets/planeshift/Confound.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.planeshift; + +import java.util.UUID; +import mage.abilities.effects.common.CounterTargetEffect; +import mage.abilities.effects.common.DrawCardSourceControllerEffect; +import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.Rarity; +import mage.filter.FilterSpell; +import mage.filter.common.FilterCreaturePermanent; +import mage.filter.predicate.Predicates; +import mage.filter.predicate.other.TargetsPermanentPredicate; +import mage.target.TargetSpell; + +/** + * + * @author LoneFox + */ +public class Confound extends CardImpl { + + private final static FilterSpell filter = new FilterSpell("spell that targets one or more creatures"); + + static { + filter.add(new TargetsPermanentPredicate(new FilterCreaturePermanent())); + } + + public Confound(UUID ownerId) { + super(ownerId, 22, "Confound", Rarity.COMMON, new CardType[]{CardType.INSTANT}, "{1}{U}"); + this.expansionSetCode = "PLS"; + + // Counter target spell that targets one or more creatures. + this.getSpellAbility().addEffect(new CounterTargetEffect()); + this.getSpellAbility().addTarget(new TargetSpell(filter)); + // Draw a card. + this.getSpellAbility().addEffect(new DrawCardSourceControllerEffect(1)); + } + + public Confound(final Confound card) { + super(card); + } + + @Override + public Confound copy() { + return new Confound(this); + } +} diff --git a/Mage.Sets/src/mage/sets/timespiral/CastleRaptors.java b/Mage.Sets/src/mage/sets/timespiral/CastleRaptors.java new file mode 100644 index 00000000000..08b2bb0502b --- /dev/null +++ b/Mage.Sets/src/mage/sets/timespiral/CastleRaptors.java @@ -0,0 +1,74 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.sets.timespiral; + +import java.util.UUID; +import mage.MageInt; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.condition.InvertCondition; +import mage.abilities.condition.common.SourceTappedCondition; +import mage.abilities.decorator.ConditionalContinuousEffect; +import mage.abilities.effects.common.continuous.BoostSourceEffect; +import mage.abilities.keyword.FlyingAbility; +import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.Rarity; +import mage.constants.Zone; + +/** + * + * @author LoneFox + */ +public class CastleRaptors extends CardImpl { + + public CastleRaptors(UUID ownerId) { + super(ownerId, 5, "Castle Raptors", Rarity.COMMON, new CardType[]{CardType.CREATURE}, "{4}{W}"); + this.expansionSetCode = "TSP"; + this.subtype.add("Bird"); + this.subtype.add("Soldier"); + this.power = new MageInt(3); + this.toughness = new MageInt(3); + + // Flying + this.addAbility(FlyingAbility.getInstance()); + // As long as Castle Raptors is untapped, it gets +0/+2. + this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new ConditionalContinuousEffect( + new BoostSourceEffect(0, 2, Duration.WhileOnBattlefield), new InvertCondition(new SourceTappedCondition()), + "As long as {this} is untapped, it gets +0/+2."))); + } + + public CastleRaptors(final CastleRaptors card) { + super(card); + } + + @Override + public CastleRaptors copy() { + return new CastleRaptors(this); + } +} From 780b99b7f184e0969e5a8d4b984a690389d910f5 Mon Sep 17 00:00:00 2001 From: LevelX2 Date: Thu, 15 Oct 2015 17:19:34 +0200 Subject: [PATCH 107/268] Minor change. --- Mage/src/mage/abilities/common/DiesAttachedTriggeredAbility.java | 1 + 1 file changed, 1 insertion(+) diff --git a/Mage/src/mage/abilities/common/DiesAttachedTriggeredAbility.java b/Mage/src/mage/abilities/common/DiesAttachedTriggeredAbility.java index 70113a4564a..963df6092bc 100644 --- a/Mage/src/mage/abilities/common/DiesAttachedTriggeredAbility.java +++ b/Mage/src/mage/abilities/common/DiesAttachedTriggeredAbility.java @@ -60,6 +60,7 @@ public class DiesAttachedTriggeredAbility extends TriggeredAbilityImpl { // So check here with the LKI of the enchantment Permanent attachment = game.getPermanentOrLKIBattlefield(getSourceId()); if (attachment != null + && zEvent.getTargetId() != null && attachment.getAttachedTo() != null && zEvent.getTargetId().equals(attachment.getAttachedTo()) && attachment.getAttachedToZoneChangeCounter() == zEvent.getTarget().getZoneChangeCounter(game) - 1) { triggered = true; From 1302feac1e7f6f0b06793a1f16ef8017b8017578 Mon Sep 17 00:00:00 2001 From: LevelX2 Date: Thu, 15 Oct 2015 21:56:03 +0200 Subject: [PATCH 108/268] Replaced some custom classes by ChooseCreatureTypeEffect. --- .../sets/avacynrestored/CavernOfSouls.java | 70 ++++--------------- .../sets/avacynrestored/RidersOfGavony.java | 63 ++++------------- .../mage/sets/magic2014/DoorOfDestinies.java | 47 +------------ .../src/mage/sets/magic2015/ObeliskOfUrd.java | 52 ++------------ .../src/mage/sets/newphyrexia/Xenograft.java | 58 +++------------ .../tempestremastered/VolrathsLaboratory.java | 15 ++-- 6 files changed, 50 insertions(+), 255 deletions(-) diff --git a/Mage.Sets/src/mage/sets/avacynrestored/CavernOfSouls.java b/Mage.Sets/src/mage/sets/avacynrestored/CavernOfSouls.java index 00e88453cb5..5ff7b12ef69 100644 --- a/Mage.Sets/src/mage/sets/avacynrestored/CavernOfSouls.java +++ b/Mage.Sets/src/mage/sets/avacynrestored/CavernOfSouls.java @@ -38,15 +38,12 @@ import mage.abilities.common.AsEntersBattlefieldAbility; import mage.abilities.common.SimpleStaticAbility; import mage.abilities.costs.common.TapSourceCost; import mage.abilities.effects.ContinuousRuleModifyingEffectImpl; -import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.ChooseCreatureTypeEffect; import mage.abilities.mana.ColorlessManaAbility; import mage.abilities.mana.ConditionalAnyColorManaAbility; import mage.abilities.mana.builder.ConditionalManaBuilder; import mage.abilities.mana.conditional.CreatureCastManaCondition; import mage.cards.CardImpl; -import mage.cards.repository.CardRepository; -import mage.choices.Choice; -import mage.choices.ChoiceImpl; import mage.constants.CardType; import mage.constants.Duration; import mage.constants.Outcome; @@ -55,10 +52,8 @@ import mage.constants.WatcherScope; import mage.constants.Zone; import mage.game.Game; import mage.game.events.GameEvent; -import mage.game.permanent.Permanent; import mage.game.stack.Spell; import mage.players.Player; -import mage.util.CardUtil; import mage.watchers.Watcher; /** @@ -67,14 +62,12 @@ import mage.watchers.Watcher; */ public class CavernOfSouls extends CardImpl { - private static final String ruleText = "choose a creature type"; - public CavernOfSouls(UUID ownerId) { super(ownerId, 226, "Cavern of Souls", Rarity.RARE, new CardType[]{CardType.LAND}, ""); this.expansionSetCode = "AVR"; // As Cavern of Souls enters the battlefield, choose a creature type. - this.addAbility(new AsEntersBattlefieldAbility(new CavernOfSoulsEffect(), ruleText)); + this.addAbility(new AsEntersBattlefieldAbility(new ChooseCreatureTypeEffect(Outcome.BoostCreature))); // {T}: Add {1} to your mana pool. this.addAbility(new ColorlessManaAbility()); @@ -82,7 +75,7 @@ public class CavernOfSouls extends CardImpl { // {T}: Add one mana of any color to your mana pool. Spend this mana only to cast a creature spell of the chosen type, and that spell can't be countered. Ability ability = new ConditionalAnyColorManaAbility(new TapSourceCost(), 1, new CavernOfSoulsManaBuilder(), true); this.addAbility(ability, new CavernOfSoulsWatcher(ability.getOriginalId())); - this.addAbility(new SimpleStaticAbility(Zone.ALL, new CavernOfSoulsCantCounterEffect())); + this.addAbility(new SimpleStaticAbility(Zone.ALL, new CavernOfSoulsCantCounterEffect())); } public CavernOfSouls(final CavernOfSouls card) { @@ -95,60 +88,23 @@ public class CavernOfSouls extends CardImpl { } } -class CavernOfSoulsEffect extends OneShotEffect { - - public CavernOfSoulsEffect() { - super(Outcome.Benefit); - staticText = "As {this} enters the battlefield, choose a creature type"; - } - - public CavernOfSoulsEffect(final CavernOfSoulsEffect effect) { - super(effect); - } - - @Override - public boolean apply(Game game, Ability source) { - Player player = game.getPlayer(source.getControllerId()); - Permanent permanent = game.getPermanent(source.getSourceId()); - if (player != null && permanent != null) { - Choice typeChoice = new ChoiceImpl(true); - typeChoice.setMessage("Choose creature type"); - typeChoice.setChoices(CardRepository.instance.getCreatureTypes()); - while (!player.choose(Outcome.Benefit, typeChoice, game)) { - if (!player.canRespond()) { - return false; - } - } - game.informPlayers(permanent.getName() + ": " + player.getLogName() + " has chosen " + typeChoice.getChoice()); - game.getState().setValue(permanent.getId() + "_type", typeChoice.getChoice()); - permanent.addInfo("chosen type", CardUtil.addToolTipMarkTags("Chosen type: " + typeChoice.getChoice()), game); - } - return false; - } - - @Override - public CavernOfSoulsEffect copy() { - return new CavernOfSoulsEffect(this); - } -} - class CavernOfSoulsManaBuilder extends ConditionalManaBuilder { String creatureType; - + @Override public ConditionalManaBuilder setMana(Mana mana, Ability source, Game game) { Object value = game.getState().getValue(source.getSourceId() + "_type"); if (value != null && value instanceof String) { creatureType = (String) value; - } + } Player controller = game.getPlayer(source.getControllerId()); MageObject sourceObject = game.getObject(source.getSourceId()); if (controller != null && sourceObject != null) { - game.informPlayers(controller.getLogName() + " produces " + mana.toString() + " with " + sourceObject.getLogName() + - " (can only be spend to cast for creatures of type " + creatureType + " and that spell can't be countered)"); - } - return super.setMana(mana, source, game); + game.informPlayers(controller.getLogName() + " produces " + mana.toString() + " with " + sourceObject.getLogName() + + " (can only be spend to cast for creatures of type " + creatureType + " and that spell can't be countered)"); + } + return super.setMana(mana, source, game); } @Override @@ -174,11 +130,11 @@ class CavernOfSoulsConditionalMana extends ConditionalMana { class CavernOfSoulsManaCondition extends CreatureCastManaCondition { String creatureType; - + CavernOfSoulsManaCondition(String creatureType) { this.creatureType = creatureType; } - + @Override public boolean apply(Game game, Ability source, UUID manaProducer) { // check: ... to cast a creature spell @@ -197,7 +153,7 @@ class CavernOfSoulsWatcher extends Watcher { private List spells = new ArrayList<>(); private final String originalId; - + public CavernOfSoulsWatcher(UUID originalId) { super("ManaPaidFromCavernOfSoulsWatcher", WatcherScope.CARD); this.originalId = originalId.toString(); @@ -222,7 +178,7 @@ class CavernOfSoulsWatcher extends Watcher { } } } - + public boolean spellCantBeCountered(UUID spellId) { return spells.contains(spellId); } diff --git a/Mage.Sets/src/mage/sets/avacynrestored/RidersOfGavony.java b/Mage.Sets/src/mage/sets/avacynrestored/RidersOfGavony.java index 8a0ead3bfc9..2f687150aa7 100644 --- a/Mage.Sets/src/mage/sets/avacynrestored/RidersOfGavony.java +++ b/Mage.Sets/src/mage/sets/avacynrestored/RidersOfGavony.java @@ -27,27 +27,28 @@ */ package mage.sets.avacynrestored; -import mage.constants.*; +import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.AsEntersBattlefieldAbility; import mage.abilities.common.SimpleStaticAbility; import mage.abilities.effects.ContinuousEffectImpl; -import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.ChooseCreatureTypeEffect; import mage.abilities.keyword.ProtectionAbility; import mage.abilities.keyword.VigilanceAbility; import mage.cards.CardImpl; -import mage.cards.repository.CardRepository; -import mage.choices.Choice; -import mage.choices.ChoiceImpl; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.Layer; +import mage.constants.Outcome; +import mage.constants.Rarity; +import mage.constants.SubLayer; +import mage.constants.Zone; import mage.filter.FilterPermanent; import mage.filter.common.FilterControlledCreaturePermanent; import mage.filter.predicate.mageobject.SubtypePredicate; import mage.game.Game; import mage.game.permanent.Permanent; -import mage.players.Player; - -import java.util.UUID; /** * @author noxx @@ -66,7 +67,7 @@ public class RidersOfGavony extends CardImpl { this.addAbility(VigilanceAbility.getInstance()); // As Riders of Gavony enters the battlefield, choose a creature type. - this.addAbility(new AsEntersBattlefieldAbility(new RidersOfGavonyEffect())); + this.addAbility(new AsEntersBattlefieldAbility(new ChooseCreatureTypeEffect(Outcome.Protect))); // Human creatures you control have protection from creatures of the chosen type. this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new RidersOfGavonyGainAbilityControlledEffect())); @@ -82,46 +83,6 @@ public class RidersOfGavony extends CardImpl { } } -class RidersOfGavonyEffect extends OneShotEffect { - - public RidersOfGavonyEffect() { - super(Outcome.BoostCreature); - staticText = "choose a creature type"; - } - - public RidersOfGavonyEffect(final RidersOfGavonyEffect effect) { - super(effect); - } - - @Override - public boolean apply(Game game, Ability source) { - Player player = game.getPlayer(source.getControllerId()); - Permanent permanent = game.getPermanent(source.getSourceId()); - if (player != null && permanent != null) { - Choice typeChoice = new ChoiceImpl(true); - typeChoice.setMessage("Choose creature type"); - typeChoice.setChoices(CardRepository.instance.getCreatureTypes()); - while (!player.choose(Outcome.BoostCreature, typeChoice, game)) { - if (!player.canRespond()) { - return false; - } - } - if (typeChoice.getChoice() != null) { - game.informPlayers(permanent.getName() + ": " + player.getLogName() + " has chosen " + typeChoice.getChoice()); - game.getState().setValue(permanent.getId() + "_type", typeChoice.getChoice()); - permanent.addInfo("chosen type", "Chosen type: " + typeChoice.getChoice() + "", game); - } - } - return false; - } - - @Override - public RidersOfGavonyEffect copy() { - return new RidersOfGavonyEffect(this); - } - -} - class RidersOfGavonyGainAbilityControlledEffect extends ContinuousEffectImpl { private static final FilterControlledCreaturePermanent filter = new FilterControlledCreaturePermanent("Human creatures you control"); @@ -154,13 +115,13 @@ class RidersOfGavonyGainAbilityControlledEffect extends ContinuousEffectImpl { if (permanent != null) { String subtype = (String) game.getState().getValue(permanent.getId() + "_type"); if (subtype != null) { - protectionFilter = new FilterPermanent(subtype+"s"); + protectionFilter = new FilterPermanent(subtype + "s"); protectionFilter.add(new SubtypePredicate(subtype)); } } } if (protectionFilter != null) { - for (Permanent perm: game.getBattlefield().getAllActivePermanents(filter, source.getControllerId(), game)) { + for (Permanent perm : game.getBattlefield().getAllActivePermanents(filter, source.getControllerId(), game)) { perm.addAbility(new ProtectionAbility(protectionFilter), source.getSourceId(), game); } return true; diff --git a/Mage.Sets/src/mage/sets/magic2014/DoorOfDestinies.java b/Mage.Sets/src/mage/sets/magic2014/DoorOfDestinies.java index 95ef1ee6103..d1aab901884 100644 --- a/Mage.Sets/src/mage/sets/magic2014/DoorOfDestinies.java +++ b/Mage.Sets/src/mage/sets/magic2014/DoorOfDestinies.java @@ -33,12 +33,9 @@ import mage.abilities.TriggeredAbilityImpl; import mage.abilities.common.AsEntersBattlefieldAbility; import mage.abilities.common.SimpleStaticAbility; import mage.abilities.effects.ContinuousEffectImpl; -import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.ChooseCreatureTypeEffect; import mage.abilities.effects.common.counter.AddCountersSourceEffect; import mage.cards.CardImpl; -import mage.cards.repository.CardRepository; -import mage.choices.Choice; -import mage.choices.ChoiceImpl; import mage.constants.CardType; import mage.constants.Duration; import mage.constants.Layer; @@ -57,7 +54,6 @@ import mage.game.events.GameEvent; import mage.game.events.GameEvent.EventType; import mage.game.permanent.Permanent; import mage.game.stack.Spell; -import mage.players.Player; /** * @@ -70,7 +66,8 @@ public class DoorOfDestinies extends CardImpl { this.expansionSetCode = "M14"; // As Door of Destinies enters the battlefield, choose a creature type. - this.addAbility(new AsEntersBattlefieldAbility(new ChooseCreatureTypeEffect())); + this.addAbility(new AsEntersBattlefieldAbility(new ChooseCreatureTypeEffect(Outcome.BoostCreature))); + // Whenever you cast a spell of the chosen type, put a charge counter on Door of Destinies. this.addAbility(new AddCounterAbility()); // Creatures you control of the chosen type get +1/+1 for each charge counter on Door of Destinies. @@ -87,44 +84,6 @@ public class DoorOfDestinies extends CardImpl { } } -class ChooseCreatureTypeEffect extends OneShotEffect { - - public ChooseCreatureTypeEffect() { - super(Outcome.BoostCreature); - staticText = "choose a creature type"; - } - - public ChooseCreatureTypeEffect(final ChooseCreatureTypeEffect effect) { - super(effect); - } - - @Override - public boolean apply(Game game, Ability source) { - Player player = game.getPlayer(source.getControllerId()); - Permanent permanent = game.getPermanent(source.getSourceId()); - if (player != null && permanent != null) { - Choice typeChoice = new ChoiceImpl(true); - typeChoice.setMessage("Choose creature type"); - typeChoice.setChoices(CardRepository.instance.getCreatureTypes()); - while (!player.choose(Outcome.BoostCreature, typeChoice, game)) { - if (!player.canRespond()) { - return false; - } - } - game.informPlayers(permanent.getName() + ": " + player.getLogName() + " has chosen " + typeChoice.getChoice()); - game.getState().setValue(permanent.getId() + "_type", typeChoice.getChoice()); - permanent.addInfo("chosen type", "Chosen type: " + typeChoice.getChoice().toString() + "", game); - } - return false; - } - - @Override - public ChooseCreatureTypeEffect copy() { - return new ChooseCreatureTypeEffect(this); - } - -} - class AddCounterAbility extends TriggeredAbilityImpl { public AddCounterAbility() { diff --git a/Mage.Sets/src/mage/sets/magic2015/ObeliskOfUrd.java b/Mage.Sets/src/mage/sets/magic2015/ObeliskOfUrd.java index d4a6c4f3a15..7a20f8d5867 100644 --- a/Mage.Sets/src/mage/sets/magic2015/ObeliskOfUrd.java +++ b/Mage.Sets/src/mage/sets/magic2015/ObeliskOfUrd.java @@ -32,12 +32,9 @@ import mage.abilities.Ability; import mage.abilities.common.AsEntersBattlefieldAbility; import mage.abilities.common.SimpleStaticAbility; import mage.abilities.effects.ContinuousEffectImpl; -import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.ChooseCreatureTypeEffect; import mage.abilities.keyword.ConvokeAbility; import mage.cards.CardImpl; -import mage.cards.repository.CardRepository; -import mage.choices.Choice; -import mage.choices.ChoiceImpl; import mage.constants.CardType; import mage.constants.Duration; import mage.constants.Layer; @@ -48,8 +45,6 @@ import mage.constants.Zone; import mage.filter.common.FilterCreaturePermanent; import mage.game.Game; import mage.game.permanent.Permanent; -import mage.players.Player; -import mage.util.CardUtil; /** * @@ -63,10 +58,10 @@ public class ObeliskOfUrd extends CardImpl { // Convoke this.addAbility(new ConvokeAbility()); - + // As Obelisk of Urd enters the battlefield, choose a creature type. - this.addAbility(new AsEntersBattlefieldAbility(new ObeliskOfUrdEnterBattlefieldEffect())); - + this.addAbility(new AsEntersBattlefieldAbility(new ChooseCreatureTypeEffect(Outcome.BoostCreature))); + // Creatures you control of the chosen type get +2/+2. this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new ObeliskOfUrdBoostEffect())); } @@ -81,43 +76,6 @@ public class ObeliskOfUrd extends CardImpl { } } -class ObeliskOfUrdEnterBattlefieldEffect extends OneShotEffect { - - ObeliskOfUrdEnterBattlefieldEffect() { - super(Outcome.BoostCreature); - staticText = "choose a creature type"; - } - - ObeliskOfUrdEnterBattlefieldEffect(final ObeliskOfUrdEnterBattlefieldEffect effect) { - super(effect); - } - - @Override - public ObeliskOfUrdEnterBattlefieldEffect copy() { - return new ObeliskOfUrdEnterBattlefieldEffect(this); - } - - @Override - public boolean apply(Game game, Ability source) { - Player player = game.getPlayer(source.getControllerId()); - Permanent permanent = game.getPermanent(source.getSourceId()); - if (player != null && permanent != null) { - Choice typeChoice = new ChoiceImpl(true); - typeChoice.setMessage("Choose a creature type:"); - typeChoice.setChoices(CardRepository.instance.getCreatureTypes()); - while (!player.choose(Outcome.BoostCreature, typeChoice, game)) { - if (!player.canRespond()) { - return false; - } - } - game.informPlayers(permanent.getName() + ": " + player.getLogName() + " has chosen " + typeChoice.getChoice()); - game.getState().setValue(permanent.getId() + "_type", typeChoice.getChoice()); - permanent.addInfo("chosen type", CardUtil.addToolTipMarkTags("Chosen type: " + typeChoice.getChoice()), game); - } - return false; - } -} - class ObeliskOfUrdBoostEffect extends ContinuousEffectImpl { private static final FilterCreaturePermanent filter = new FilterCreaturePermanent(); @@ -142,7 +100,7 @@ class ObeliskOfUrdBoostEffect extends ContinuousEffectImpl { if (permanent != null) { String subtype = (String) game.getState().getValue(permanent.getId() + "_type"); if (subtype != null) { - for (Permanent perm: game.getBattlefield().getAllActivePermanents(filter, source.getControllerId(), game)) { + for (Permanent perm : game.getBattlefield().getAllActivePermanents(filter, source.getControllerId(), game)) { if (perm.hasSubtype(subtype)) { perm.addPower(2); perm.addToughness(2); diff --git a/Mage.Sets/src/mage/sets/newphyrexia/Xenograft.java b/Mage.Sets/src/mage/sets/newphyrexia/Xenograft.java index df7da676226..0bcb89be3a9 100644 --- a/Mage.Sets/src/mage/sets/newphyrexia/Xenograft.java +++ b/Mage.Sets/src/mage/sets/newphyrexia/Xenograft.java @@ -29,6 +29,12 @@ package mage.sets.newphyrexia; import java.util.List; import java.util.UUID; +import mage.abilities.Ability; +import mage.abilities.common.AsEntersBattlefieldAbility; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.effects.ContinuousEffectImpl; +import mage.abilities.effects.common.ChooseCreatureTypeEffect; +import mage.cards.CardImpl; import mage.constants.CardType; import mage.constants.Duration; import mage.constants.Layer; @@ -36,19 +42,9 @@ import mage.constants.Outcome; import mage.constants.Rarity; import mage.constants.SubLayer; import mage.constants.Zone; -import mage.abilities.Ability; -import mage.abilities.common.AsEntersBattlefieldAbility; -import mage.abilities.common.SimpleStaticAbility; -import mage.abilities.effects.ContinuousEffectImpl; -import mage.abilities.effects.OneShotEffect; -import mage.cards.CardImpl; -import mage.cards.repository.CardRepository; -import mage.choices.Choice; -import mage.choices.ChoiceImpl; import mage.filter.common.FilterCreaturePermanent; import mage.game.Game; import mage.game.permanent.Permanent; -import mage.players.Player; /** * @@ -60,9 +56,8 @@ public class Xenograft extends CardImpl { super(ownerId, 51, "Xenograft", Rarity.RARE, new CardType[]{CardType.ENCHANTMENT}, "{4}{U}"); this.expansionSetCode = "NPH"; - // As Xenograft enters the battlefield, choose a creature type. - this.addAbility(new AsEntersBattlefieldAbility(new XenograftEffect())); + this.addAbility(new AsEntersBattlefieldAbility(new ChooseCreatureTypeEffect(Outcome.Detriment))); // Each creature you control is the chosen type in addition to its other types. this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new XenograftAddSubtypeEffect())); } @@ -77,43 +72,6 @@ public class Xenograft extends CardImpl { } } -class XenograftEffect extends OneShotEffect { - - public XenograftEffect() { - super(Outcome.DrawCard); - staticText = "choose a creature type"; - } - - public XenograftEffect(final XenograftEffect effect) { - super(effect); - } - - @Override - public boolean apply(Game game, Ability source) { - Player player = game.getPlayer(source.getControllerId()); - Permanent permanent = game.getPermanent(source.getSourceId()); - if (player != null && permanent != null) { - Choice typeChoice = new ChoiceImpl(true); - typeChoice.setMessage("Choose creature type"); - typeChoice.setChoices(CardRepository.instance.getCreatureTypes()); - while (!player.choose(Outcome.BoostCreature, typeChoice, game)) { - if (!player.canRespond()) { - return false; - } - } - game.informPlayers(permanent.getName() + ": " + player.getLogName() + " has chosen " + typeChoice.getChoice()); - game.getState().setValue(source.getSourceId() + "_XenograftType", typeChoice.getChoice()); - permanent.addInfo("chosen type", "Chosen type: " + typeChoice.getChoice().toString() + "", game); - } - return false; - } - - @Override - public XenograftEffect copy() { - return new XenograftEffect(this); - } -} - class XenograftAddSubtypeEffect extends ContinuousEffectImpl { public XenograftAddSubtypeEffect() { @@ -127,7 +85,7 @@ class XenograftAddSubtypeEffect extends ContinuousEffectImpl { @Override public boolean apply(Game game, Ability source) { - String subtype = (String) game.getState().getValue(source.getSourceId() + "_XenograftType"); + String subtype = (String) game.getState().getValue(source.getSourceId() + "_type"); if (subtype != null) { List permanents = game.getBattlefield().getAllActivePermanents(new FilterCreaturePermanent(), source.getControllerId(), game); for (Permanent permanent : permanents) { diff --git a/Mage.Sets/src/mage/sets/tempestremastered/VolrathsLaboratory.java b/Mage.Sets/src/mage/sets/tempestremastered/VolrathsLaboratory.java index 10b1208bbe7..70f4a27f8c7 100644 --- a/Mage.Sets/src/mage/sets/tempestremastered/VolrathsLaboratory.java +++ b/Mage.Sets/src/mage/sets/tempestremastered/VolrathsLaboratory.java @@ -35,6 +35,7 @@ import mage.abilities.common.EntersBattlefieldAbility; import mage.abilities.common.SimpleActivatedAbility; import mage.abilities.costs.common.TapSourceCost; import mage.abilities.costs.mana.GenericManaCost; +import mage.abilities.effects.Effect; import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.ChooseColorEffect; import mage.abilities.effects.common.ChooseCreatureTypeEffect; @@ -57,10 +58,12 @@ public class VolrathsLaboratory extends CardImpl { this.expansionSetCode = "TPR"; // As Volrath's Laboratory enters the battlefield, choose a color and a creature type. - Ability ability = new EntersBattlefieldAbility(new ChooseColorEffect(Outcome.Neutral), null, true, "As Volrath's Laboratory enters the battlefield, choose a color and a creature type.", ""); + Ability ability = new EntersBattlefieldAbility(new ChooseColorEffect(Outcome.Neutral)); + Effect effect = new ChooseColorEffect(Outcome.Neutral); + effect.setText("and a creature type"); ability.addEffect(new ChooseCreatureTypeEffect(Outcome.Neutral)); this.addAbility(ability); - + // {5}, {T}: Put a 2/2 creature token of the chosen color and type onto the battlefield. ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new VolrathsLaboratoryEffect(), new GenericManaCost(5)); ability.addCost(new TapSourceCost()); @@ -78,21 +81,21 @@ public class VolrathsLaboratory extends CardImpl { } class VolrathsLaboratoryEffect extends OneShotEffect { - + VolrathsLaboratoryEffect() { super(Outcome.PutCreatureInPlay); this.staticText = "Put a 2/2 creature token of the chosen color and type onto the battlefield"; } - + VolrathsLaboratoryEffect(final VolrathsLaboratoryEffect effect) { super(effect); } - + @Override public VolrathsLaboratoryEffect copy() { return new VolrathsLaboratoryEffect(this); } - + @Override public boolean apply(Game game, Ability source) { ObjectColor color = (ObjectColor) game.getState().getValue(source.getSourceId() + "_color"); From 268e83e1707895877f3d31fe47b2296f6ae92a49 Mon Sep 17 00:00:00 2001 From: LevelX2 Date: Thu, 15 Oct 2015 22:02:04 +0200 Subject: [PATCH 109/268] * Phylactery Lich - Fixed that the replacement effect to select an artifact was handled targeted. --- .../mage/sets/magic2011/PhylacteryLich.java | 32 +++++++++++-------- 1 file changed, 18 insertions(+), 14 deletions(-) diff --git a/Mage.Sets/src/mage/sets/magic2011/PhylacteryLich.java b/Mage.Sets/src/mage/sets/magic2011/PhylacteryLich.java index a42e28768db..6cf3a7c7243 100644 --- a/Mage.Sets/src/mage/sets/magic2011/PhylacteryLich.java +++ b/Mage.Sets/src/mage/sets/magic2011/PhylacteryLich.java @@ -1,16 +1,16 @@ /* * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. - * + * * Redistribution and use in source and binary forms, with or without modification, are * permitted provided that the following conditions are met: - * + * * 1. Redistributions of source code must retain the above copyright notice, this list of * conditions and the following disclaimer. - * + * * 2. Redistributions in binary form must reproduce the above copyright notice, this list * of conditions and the following disclaimer in the documentation and/or other materials * provided with the distribution. - * + * * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR @@ -20,19 +20,14 @@ * 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.magic2011; import java.util.UUID; -import mage.constants.CardType; -import mage.constants.Outcome; -import mage.constants.Rarity; -import mage.constants.Zone; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.StateTriggeredAbility; @@ -41,6 +36,10 @@ import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.SacrificeSourceEffect; import mage.abilities.keyword.IndestructibleAbility; import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.Outcome; +import mage.constants.Rarity; +import mage.constants.Zone; import mage.counters.Counter; import mage.filter.common.FilterControlledPermanent; import mage.filter.predicate.mageobject.CardTypePredicate; @@ -64,8 +63,13 @@ public class PhylacteryLich extends CardImpl { this.power = new MageInt(5); this.toughness = new MageInt(5); - this.addAbility(new AsEntersBattlefieldAbility(new PhylacteryLichEffect(), "put a phylactery counter on an artifact you control")); + // Indestructible this.addAbility(IndestructibleAbility.getInstance()); + + // As Phylactery Lich enters the battlefield, put a phylactery counter on an artifact you control. + this.addAbility(new AsEntersBattlefieldAbility(new PhylacteryLichEffect(), "put a phylactery counter on an artifact you control")); + + // When you control no permanents with phylactery counters on them, sacrifice Phylactery Lich. this.addAbility(new PhylacteryLichAbility()); } @@ -95,7 +99,7 @@ public class PhylacteryLich extends CardImpl { @Override public boolean checkTrigger(GameEvent event, Game game) { - for (Permanent perm: game.getBattlefield().getAllActivePermanents(controllerId)) { + for (Permanent perm : game.getBattlefield().getAllActivePermanents(controllerId)) { if (perm.getCounters().getCount("phylactery") > 0) { return false; } @@ -133,7 +137,7 @@ class PhylacteryLichEffect extends OneShotEffect { public boolean apply(Game game, Ability source) { Player player = game.getPlayer(source.getControllerId()); if (player != null) { - TargetControlledPermanent target = new TargetControlledPermanent(filter); + TargetControlledPermanent target = new TargetControlledPermanent(1, 1, filter, true); if (target.canChoose(source.getControllerId(), game)) { if (player.choose(Outcome.Neutral, target, source.getSourceId(), game)) { Permanent permanent = game.getPermanent(target.getFirstTarget()); @@ -151,4 +155,4 @@ class PhylacteryLichEffect extends OneShotEffect { return new PhylacteryLichEffect(this); } -} \ No newline at end of file +} From 07565d81bd04475a0c9a045de554d58ac87f9602 Mon Sep 17 00:00:00 2001 From: LevelX2 Date: Thu, 15 Oct 2015 22:15:23 +0200 Subject: [PATCH 110/268] * Replaced some custom choose player effects. --- .../src/mage/sets/commander/SewerNemesis.java | 42 +------------ .../sets/commander2013/TrueNameNemesis.java | 62 ++++--------------- .../src/mage/sets/timespiral/StuffyDoll.java | 42 +------------ .../effects/common/ChoosePlayerEffect.java | 55 ++++++++++++++++ 4 files changed, 73 insertions(+), 128 deletions(-) create mode 100644 Mage/src/mage/abilities/effects/common/ChoosePlayerEffect.java diff --git a/Mage.Sets/src/mage/sets/commander/SewerNemesis.java b/Mage.Sets/src/mage/sets/commander/SewerNemesis.java index fa7df34d3fa..e8955959eee 100644 --- a/Mage.Sets/src/mage/sets/commander/SewerNemesis.java +++ b/Mage.Sets/src/mage/sets/commander/SewerNemesis.java @@ -35,7 +35,7 @@ import mage.abilities.common.AsEntersBattlefieldAbility; import mage.abilities.common.SimpleStaticAbility; import mage.abilities.dynamicvalue.DynamicValue; import mage.abilities.effects.Effect; -import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.ChoosePlayerEffect; import mage.abilities.effects.common.PutTopCardOfLibraryIntoGraveTargetEffect; import mage.abilities.effects.common.continuous.SetPowerToughnessSourceEffect; import mage.cards.CardImpl; @@ -47,9 +47,7 @@ import mage.constants.Zone; import mage.game.Game; import mage.game.events.GameEvent; import mage.game.events.GameEvent.EventType; -import mage.game.permanent.Permanent; import mage.players.Player; -import mage.target.TargetPlayer; import mage.target.targetpointer.FixedTarget; /** @@ -67,7 +65,7 @@ public class SewerNemesis extends CardImpl { this.toughness = new MageInt(0); // As Sewer Nemesis enters the battlefield, choose a player. - this.addAbility(new AsEntersBattlefieldAbility(new SewerNemesisChoosePlayerEffect())); + this.addAbility(new AsEntersBattlefieldAbility(new ChoosePlayerEffect(Outcome.Detriment))); // Sewer Nemesis's power and toughness are each equal to the number of cards in the chosen player's graveyard. this.addAbility(new SimpleStaticAbility(Zone.ALL, new SetPowerToughnessSourceEffect(new CardsInTargetOpponentsGraveyardCount(), Duration.WhileOnBattlefield))); // Whenever the chosen player casts a spell, that player puts the top card of his or her library into his or her graveyard. @@ -85,42 +83,8 @@ public class SewerNemesis extends CardImpl { } } -class SewerNemesisChoosePlayerEffect extends OneShotEffect { - - public SewerNemesisChoosePlayerEffect() { - super(Outcome.Detriment); - this.staticText = "choose a player"; - } - - public SewerNemesisChoosePlayerEffect(final SewerNemesisChoosePlayerEffect effect) { - super(effect); - } - - @Override - public SewerNemesisChoosePlayerEffect copy() { - return new SewerNemesisChoosePlayerEffect(this); - } - - @Override - public boolean apply(Game game, Ability source) { - Player player = game.getPlayer(source.getControllerId()); - Permanent permanent = game.getPermanent(source.getSourceId()); - if (player != null && permanent != null) { - TargetPlayer target = new TargetPlayer(1,1,true); - if (player.choose(this.outcome, target, source.getSourceId(), game)) { - Player chosenPlayer = game.getPlayer(target.getFirstTarget()); - if (chosenPlayer != null) { - game.informPlayers(permanent.getLogName() + ": " + player.getLogName() + " has chosen " + chosenPlayer.getLogName()); - game.getState().setValue(permanent.getId() + "_player", target.getFirstTarget()); - return true; - } - } - } - return false; - } -} - class CardsInTargetOpponentsGraveyardCount implements DynamicValue { + @Override public int calculate(Game game, Ability sourceAbility, Effect effect) { if (sourceAbility != null) { diff --git a/Mage.Sets/src/mage/sets/commander2013/TrueNameNemesis.java b/Mage.Sets/src/mage/sets/commander2013/TrueNameNemesis.java index 18c7db6b708..6c3967a3e6d 100644 --- a/Mage.Sets/src/mage/sets/commander2013/TrueNameNemesis.java +++ b/Mage.Sets/src/mage/sets/commander2013/TrueNameNemesis.java @@ -30,9 +30,8 @@ package mage.sets.commander2013; import java.util.UUID; import mage.MageInt; import mage.MageObject; -import mage.abilities.Ability; import mage.abilities.common.AsEntersBattlefieldAbility; -import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.ChoosePlayerEffect; import mage.abilities.keyword.ProtectionAbility; import mage.cards.Card; import mage.cards.CardImpl; @@ -44,18 +43,19 @@ import mage.game.Game; import mage.game.permanent.Permanent; import mage.game.stack.Spell; import mage.game.stack.StackObject; -import mage.players.Player; -import mage.target.TargetPlayer; /** - * Protection from a player is a new variant of the protection ability. It means the following: - * -- True-Name Nemesis can’t be the target of spells or abilities controlled by the chosen player. - * -- True-Name Nemesis can’t be enchanted by Auras or equipped by Equipment controlled - * by the chosen player. (The same is true for Fortifications controlled by the chosen player, - * if True-Name Nemesis becomes a land.) - * -- True-Name Nemesis can’t be blocked by creatures controlled by the chosen player. - * -- All damage that would be dealt to True-Name Nemesis by sources controlled by the chosen player - * is prevented. (The same is true for sources owned by the chosen player that don’t have controllers.) + * Protection from a player is a new variant of the protection ability. It means + * the following: -- True-Name Nemesis can’t be the target of spells or + * abilities controlled by the chosen player. -- True-Name Nemesis can’t be + * enchanted by Auras or equipped by Equipment controlled by the chosen player. + * (The same is true for Fortifications controlled by the chosen player, if + * True-Name Nemesis becomes a land.) -- True-Name Nemesis can’t be blocked by + * creatures controlled by the chosen player. -- All damage that would be dealt + * to True-Name Nemesis by sources controlled by the chosen player is prevented. + * (The same is true for sources owned by the chosen player that don’t have + * controllers.) + * * @author LevelX2 */ public class TrueNameNemesis extends CardImpl { @@ -70,7 +70,7 @@ public class TrueNameNemesis extends CardImpl { this.toughness = new MageInt(1); // As True-Name Nemesis enters the battlefield, choose a player. - this.addAbility(new AsEntersBattlefieldAbility(new TrueNameNemesisChoosePlayerEffect())); + this.addAbility(new AsEntersBattlefieldAbility(new ChoosePlayerEffect(Outcome.Protect))); // True-Name Nemesis has protection from the chosen player. this.addAbility(new ProtectionFromPlayerAbility()); } @@ -85,42 +85,6 @@ public class TrueNameNemesis extends CardImpl { } } -class TrueNameNemesisChoosePlayerEffect extends OneShotEffect { - - public TrueNameNemesisChoosePlayerEffect() { - super(Outcome.Detriment); - this.staticText = "choose a player"; - } - - public TrueNameNemesisChoosePlayerEffect(final TrueNameNemesisChoosePlayerEffect effect) { - super(effect); - } - - @Override - public TrueNameNemesisChoosePlayerEffect copy() { - return new TrueNameNemesisChoosePlayerEffect(this); - } - - @Override - public boolean apply(Game game, Ability source) { - Player player = game.getPlayer(source.getControllerId()); - Permanent permanent = game.getPermanent(source.getSourceId()); - if (player != null && permanent != null) { - TargetPlayer target = new TargetPlayer(1,1,true); - if (player.choose(this.outcome, target, source.getSourceId(), game)) { - Player chosenPlayer = game.getPlayer(target.getFirstTarget()); - if (chosenPlayer != null) { - game.informPlayers(permanent.getName() + ": " + player.getLogName() + " has chosen " + chosenPlayer.getLogName()); - game.getState().setValue(permanent.getId() + "_player", target.getFirstTarget()); - permanent.addInfo("chosen player", "Chosen player: " + chosenPlayer.getLogName() + "", game); - return true; - } - } - } - return false; - } -} - class ProtectionFromPlayerAbility extends ProtectionAbility { public ProtectionFromPlayerAbility() { diff --git a/Mage.Sets/src/mage/sets/timespiral/StuffyDoll.java b/Mage.Sets/src/mage/sets/timespiral/StuffyDoll.java index 7927019a7b4..2a30d327984 100644 --- a/Mage.Sets/src/mage/sets/timespiral/StuffyDoll.java +++ b/Mage.Sets/src/mage/sets/timespiral/StuffyDoll.java @@ -35,6 +35,7 @@ import mage.abilities.common.AsEntersBattlefieldAbility; import mage.abilities.common.SimpleActivatedAbility; import mage.abilities.costs.common.TapSourceCost; import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.ChoosePlayerEffect; import mage.abilities.effects.common.DamageSelfEffect; import mage.abilities.keyword.IndestructibleAbility; import mage.cards.CardImpl; @@ -45,10 +46,7 @@ import mage.constants.Zone; import mage.game.Game; import mage.game.events.GameEvent; import mage.game.events.GameEvent.EventType; -import mage.game.permanent.Permanent; import mage.players.Player; -import mage.target.TargetPlayer; - /** * @@ -64,7 +62,7 @@ public class StuffyDoll extends CardImpl { this.toughness = new MageInt(1); // As Stuffy Doll enters the battlefield, choose a player. - this.addAbility(new AsEntersBattlefieldAbility(new StuffyDollChoosePlayerEffect())); + this.addAbility(new AsEntersBattlefieldAbility(new ChoosePlayerEffect(Outcome.Damage))); // Stuffy Doll is indestructible. this.addAbility(IndestructibleAbility.getInstance()); // Whenever Stuffy Doll is dealt damage, it deals that much damage to the chosen player. @@ -83,41 +81,6 @@ public class StuffyDoll extends CardImpl { } } -class StuffyDollChoosePlayerEffect extends OneShotEffect { - - public StuffyDollChoosePlayerEffect() { - super(Outcome.Detriment); - this.staticText = "choose a player"; - } - - public StuffyDollChoosePlayerEffect(final StuffyDollChoosePlayerEffect effect) { - super(effect); - } - - @Override - public StuffyDollChoosePlayerEffect copy() { - return new StuffyDollChoosePlayerEffect(this); - } - - @Override - public boolean apply(Game game, Ability source) { - Player player = game.getPlayer(source.getControllerId()); - Permanent permanent = game.getPermanent(source.getSourceId()); - if (player != null && permanent != null) { - TargetPlayer target = new TargetPlayer(); - if (player.choose(this.outcome, target, source.getSourceId(), game)) { - Player chosenPlayer = game.getPlayer(target.getFirstTarget()); - if (chosenPlayer != null) { - game.informPlayers(permanent.getName() + ": " + player.getLogName() + " has chosen " + chosenPlayer.getLogName()); - game.getState().setValue(permanent.getId() + "_player", target.getFirstTarget()); - return true; - } - } - } - return false; - } -} - class StuffyDollTriggeredAbility extends TriggeredAbilityImpl { public StuffyDollTriggeredAbility() { @@ -179,4 +142,3 @@ class StuffyDollGainLifeEffect extends OneShotEffect { return true; } } - diff --git a/Mage/src/mage/abilities/effects/common/ChoosePlayerEffect.java b/Mage/src/mage/abilities/effects/common/ChoosePlayerEffect.java new file mode 100644 index 00000000000..9f4481515c5 --- /dev/null +++ b/Mage/src/mage/abilities/effects/common/ChoosePlayerEffect.java @@ -0,0 +1,55 @@ +/* + * To change this license header, choose License Headers in Project Properties. + * To change this template file, choose Tools | Templates + * and open the template in the editor. + */ +package mage.abilities.effects.common; + +import mage.abilities.Ability; +import mage.abilities.effects.OneShotEffect; +import mage.constants.Outcome; +import mage.game.Game; +import mage.game.permanent.Permanent; +import mage.players.Player; +import mage.target.TargetPlayer; +import mage.util.CardUtil; + +/** + * + * @author LevelX2 + */ +public class ChoosePlayerEffect extends OneShotEffect { + + public ChoosePlayerEffect(Outcome outcome) { + super(outcome); + this.staticText = "choose a player"; + } + + public ChoosePlayerEffect(final ChoosePlayerEffect effect) { + super(effect); + } + + @Override + public ChoosePlayerEffect copy() { + return new ChoosePlayerEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player player = game.getPlayer(source.getControllerId()); + Permanent permanent = game.getPermanent(source.getSourceId()); + if (player != null && permanent != null) { + TargetPlayer target = new TargetPlayer(1, 1, true); + if (player.choose(this.outcome, target, source.getSourceId(), game)) { + Player chosenPlayer = game.getPlayer(target.getFirstTarget()); + if (chosenPlayer != null) { + game.informPlayers(permanent.getName() + ": " + player.getLogName() + " has chosen " + chosenPlayer.getLogName()); + game.getState().setValue(permanent.getId() + "_player", target.getFirstTarget()); + permanent.addInfo("chosen player", CardUtil.addToolTipMarkTags("Chosen player: " + chosenPlayer.getLogName()), game); + return true; + } + } + } + return false; + } +} From 66b196efc9a4b3a4bd4b4af96e601bdddf78af66 Mon Sep 17 00:00:00 2001 From: LevelX2 Date: Thu, 15 Oct 2015 22:25:52 +0200 Subject: [PATCH 111/268] * Replaced some custom name a card effects. --- .../src/mage/sets/innistrad/Nevermore.java | 67 +++---------------- .../mirrodinbesieged/PhyrexianRevoker.java | 65 +++--------------- .../sets/planarchaos/VoidstoneGargoyle.java | 11 +-- .../effects/common/NameACardEffect.java | 6 +- 4 files changed, 31 insertions(+), 118 deletions(-) diff --git a/Mage.Sets/src/mage/sets/innistrad/Nevermore.java b/Mage.Sets/src/mage/sets/innistrad/Nevermore.java index dee67c6f07f..dee1d81fe79 100644 --- a/Mage.Sets/src/mage/sets/innistrad/Nevermore.java +++ b/Mage.Sets/src/mage/sets/innistrad/Nevermore.java @@ -1,16 +1,16 @@ /* * Copyright 2011 BetaSteward_at_googlemail.com. All rights reserved. - * + * * Redistribution and use in source and binary forms, with or without modification, are * permitted provided that the following conditions are met: - * + * * 1. Redistributions of source code must retain the above copyright notice, this list of * conditions and the following disclaimer. - * + * * 2. Redistributions in binary form must reproduce the above copyright notice, this list * of conditions and the following disclaimer in the documentation and/or other materials * provided with the distribution. - * + * * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR @@ -20,7 +20,7 @@ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * + * * The views and conclusions contained in the software and documentation are those of the * authors and should not be interpreted as representing official policies, either expressed * or implied, of BetaSteward_at_googlemail.com. @@ -33,11 +33,8 @@ import mage.abilities.Ability; import mage.abilities.common.AsEntersBattlefieldAbility; import mage.abilities.common.SimpleStaticAbility; import mage.abilities.effects.ContinuousRuleModifyingEffectImpl; -import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.NameACardEffect; import mage.cards.CardImpl; -import mage.cards.repository.CardRepository; -import mage.choices.Choice; -import mage.choices.ChoiceImpl; import mage.constants.CardType; import mage.constants.Duration; import mage.constants.Outcome; @@ -46,9 +43,6 @@ import mage.constants.Zone; import mage.game.Game; import mage.game.events.GameEvent; import mage.game.events.GameEvent.EventType; -import mage.game.permanent.Permanent; -import mage.players.Player; -import mage.util.CardUtil; /** * @@ -60,11 +54,10 @@ public class Nevermore extends CardImpl { super(ownerId, 25, "Nevermore", Rarity.RARE, new CardType[]{CardType.ENCHANTMENT}, "{1}{W}{W}"); this.expansionSetCode = "ISD"; + // As Nevermore enters the battlefield, name a nonland card. + this.addAbility(new AsEntersBattlefieldAbility(new NameACardEffect(NameACardEffect.TypeOfName.NON_LAND_NAME))); - //As Nevermore enters the battlefield, name a nonland card. - this.addAbility(new AsEntersBattlefieldAbility(new NevermoreEffect1())); - - //The named card can't be cast. + // The named card can't be cast. this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new NevermoreEffect2())); } @@ -80,46 +73,6 @@ public class Nevermore extends CardImpl { } -class NevermoreEffect1 extends OneShotEffect { - - public NevermoreEffect1() { - super(Outcome.Detriment); - staticText = "name a nonland card"; - } - - public NevermoreEffect1(final NevermoreEffect1 effect) { - super(effect); - } - - @Override - public boolean apply(Game game, Ability source) { - Player controller = game.getPlayer(source.getControllerId()); - Permanent permanent = game.getPermanent(source.getSourceId()); - if (controller != null && permanent != null) { - Choice cardChoice = new ChoiceImpl(); - cardChoice.setChoices(CardRepository.instance.getNonLandNames()); - cardChoice.clearChoice(); - while (!controller.choose(Outcome.Detriment, cardChoice, game)) { - if (!controller.canRespond()) { - return false; - } - } - String cardName = cardChoice.getChoice(); - game.informPlayers(permanent.getLogName() + ", named card: [" + cardName + "]"); - game.getState().setValue(source.getSourceId().toString(), cardName); - permanent.addInfo("named card", CardUtil.addToolTipMarkTags("Named card: [" + cardName +"]"), game); - return true; - } - return false; - } - - @Override - public NevermoreEffect1 copy() { - return new NevermoreEffect1(this); - } - -} - class NevermoreEffect2 extends ContinuousRuleModifyingEffectImpl { public NevermoreEffect2() { @@ -145,7 +98,7 @@ class NevermoreEffect2 extends ContinuousRuleModifyingEffectImpl { public boolean applies(GameEvent event, Ability source, Game game) { if (event.getType() == EventType.CAST_SPELL) { MageObject object = game.getObject(event.getSourceId()); - if (object != null && object.getName().equals(game.getState().getValue(source.getSourceId().toString()))) { + if (object != null && object.getName().equals(game.getState().getValue(source.getSourceId().toString() + NameACardEffect.INFO_KEY))) { return true; } } diff --git a/Mage.Sets/src/mage/sets/mirrodinbesieged/PhyrexianRevoker.java b/Mage.Sets/src/mage/sets/mirrodinbesieged/PhyrexianRevoker.java index 279bd693526..6a51fef04bc 100644 --- a/Mage.Sets/src/mage/sets/mirrodinbesieged/PhyrexianRevoker.java +++ b/Mage.Sets/src/mage/sets/mirrodinbesieged/PhyrexianRevoker.java @@ -25,32 +25,25 @@ * authors and should not be interpreted as representing official policies, either expressed * or implied, of BetaSteward_at_googlemail.com. */ - package mage.sets.mirrodinbesieged; 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.MageInt; import mage.MageObject; import mage.abilities.Ability; import mage.abilities.common.AsEntersBattlefieldAbility; import mage.abilities.common.SimpleStaticAbility; import mage.abilities.effects.ContinuousRuleModifyingEffectImpl; -import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.NameACardEffect; import mage.cards.CardImpl; -import mage.cards.repository.CardRepository; -import mage.choices.Choice; -import mage.choices.ChoiceImpl; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.Outcome; +import mage.constants.Rarity; +import mage.constants.Zone; import mage.game.Game; import mage.game.events.GameEvent; import mage.game.events.GameEvent.EventType; -import mage.game.permanent.Permanent; -import mage.players.Player; -import mage.util.CardUtil; /** * @@ -66,7 +59,7 @@ public class PhyrexianRevoker extends CardImpl { this.toughness = new MageInt(1); // As Phyrexian Revoker enters the battlefield, name a nonland card. - this.addAbility(new AsEntersBattlefieldAbility(new PhyrexianRevokerEffect1())); + this.addAbility(new AsEntersBattlefieldAbility(new NameACardEffect(NameACardEffect.TypeOfName.NON_LAND_NAME))); // Activated abilities of sources with the chosen name can't be activated. this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new PhyrexianRevokerEffect2())); @@ -83,46 +76,6 @@ public class PhyrexianRevoker extends CardImpl { } -class PhyrexianRevokerEffect1 extends OneShotEffect { - - public PhyrexianRevokerEffect1() { - super(Outcome.Detriment); - staticText = "name a nonland card"; - } - - public PhyrexianRevokerEffect1(final PhyrexianRevokerEffect1 effect) { - super(effect); - } - - @Override - public boolean apply(Game game, Ability source) { - Player controller = game.getPlayer(source.getControllerId()); - Permanent permanent = game.getPermanent(source.getSourceId()); - if (controller != null && permanent != null) { - Choice cardChoice = new ChoiceImpl(); - cardChoice.setChoices(CardRepository.instance.getNonLandNames()); - cardChoice.clearChoice(); - while (!controller.choose(Outcome.Detriment, cardChoice, game)) { - if (!controller.canRespond()) { - return false; - } - } - String cardName = cardChoice.getChoice(); - game.informPlayers(permanent.getLogName() + ", named card: [" + cardName + "]"); - game.getState().setValue(source.getSourceId().toString(), cardName); - permanent.addInfo("named card", CardUtil.addToolTipMarkTags("Named card: [" + cardName +"]"), game); - return true; - } - return false; - } - - @Override - public PhyrexianRevokerEffect1 copy() { - return new PhyrexianRevokerEffect1(this); - } - -} - class PhyrexianRevokerEffect2 extends ContinuousRuleModifyingEffectImpl { public PhyrexianRevokerEffect2() { @@ -143,7 +96,7 @@ class PhyrexianRevokerEffect2 extends ContinuousRuleModifyingEffectImpl { public PhyrexianRevokerEffect2 copy() { return new PhyrexianRevokerEffect2(this); } - + @Override public String getInfoMessage(Ability source, GameEvent event, Game game) { MageObject mageObject = game.getObject(source.getSourceId()); @@ -157,7 +110,7 @@ class PhyrexianRevokerEffect2 extends ContinuousRuleModifyingEffectImpl { public boolean applies(GameEvent event, Ability source, Game game) { if (event.getType() == EventType.ACTIVATE_ABILITY) { MageObject object = game.getObject(event.getSourceId()); - if (object != null && object.getName().equals(game.getState().getValue(source.getSourceId().toString()))) { + if (object != null && object.getName().equals(game.getState().getValue(source.getSourceId().toString() + NameACardEffect.INFO_KEY))) { return true; } } diff --git a/Mage.Sets/src/mage/sets/planarchaos/VoidstoneGargoyle.java b/Mage.Sets/src/mage/sets/planarchaos/VoidstoneGargoyle.java index 9292efe16a6..4505e346779 100644 --- a/Mage.Sets/src/mage/sets/planarchaos/VoidstoneGargoyle.java +++ b/Mage.Sets/src/mage/sets/planarchaos/VoidstoneGargoyle.java @@ -34,7 +34,9 @@ import mage.abilities.Ability; import mage.abilities.common.AsEntersBattlefieldAbility; import mage.abilities.common.SimpleStaticAbility; import mage.abilities.effects.ContinuousRuleModifyingEffectImpl; +import mage.abilities.effects.EntersBattlefieldEffect; import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.NameACardEffect; import mage.abilities.keyword.FlyingAbility; import mage.cards.CardImpl; import mage.cards.repository.CardRepository; @@ -69,7 +71,7 @@ public class VoidstoneGargoyle extends CardImpl { // Flying this.addAbility(FlyingAbility.getInstance()); // As Voidstone Gargoyle enters the battlefield, name a nonland card. - this.addAbility(new AsEntersBattlefieldAbility(new VoidstoneGargoyleChooseCardEffect())); + this.addAbility(new AsEntersBattlefieldAbility(new NameACardEffect(NameACardEffect.TypeOfName.NON_LAND_NAME))); // The named card can't be cast. this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new VoidstoneGargoyleReplacementEffect1())); // Activated abilities of sources with the chosen name can't be activated. @@ -100,7 +102,7 @@ class VoidstoneGargoyleChooseCardEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { Player controller = game.getPlayer(source.getControllerId()); - Permanent permanent = game.getPermanent(source.getSourceId()); + Permanent permanent = (Permanent) getValue(EntersBattlefieldEffect.ENTERING_PERMANENT); if (controller != null && permanent != null) { Choice cardChoice = new ChoiceImpl(); cardChoice.setChoices(CardRepository.instance.getNonLandNames()); @@ -160,7 +162,8 @@ class VoidstoneGargoyleReplacementEffect1 extends ContinuousRuleModifyingEffectI public boolean applies(GameEvent event, Ability source, Game game) { if (event.getType() == GameEvent.EventType.CAST_SPELL) { MageObject object = game.getObject(event.getSourceId()); - if (object != null && object.getName().equals(game.getState().getValue(source.getSourceId().toString()))) { + if (object != null + && object.getName().equals(game.getState().getValue(source.getSourceId().toString() + NameACardEffect.INFO_KEY))) { return true; } } @@ -203,7 +206,7 @@ class VoidstoneGargoyleRuleModifyingEffect2 extends ContinuousRuleModifyingEffec public boolean applies(GameEvent event, Ability source, Game game) { if (event.getType() == EventType.ACTIVATE_ABILITY) { MageObject object = game.getObject(event.getSourceId()); - if (object != null && object.getName().equals(game.getState().getValue(source.getSourceId().toString()))) { + if (object != null && object.getName().equals(game.getState().getValue(source.getSourceId().toString() + NameACardEffect.INFO_KEY))) { return true; } } diff --git a/Mage/src/mage/abilities/effects/common/NameACardEffect.java b/Mage/src/mage/abilities/effects/common/NameACardEffect.java index 0123f9fd6f6..b75279a993f 100644 --- a/Mage/src/mage/abilities/effects/common/NameACardEffect.java +++ b/Mage/src/mage/abilities/effects/common/NameACardEffect.java @@ -29,6 +29,7 @@ package mage.abilities.effects.common; import mage.MageObject; import mage.abilities.Ability; +import mage.abilities.effects.EntersBattlefieldEffect; import mage.abilities.effects.OneShotEffect; import mage.cards.repository.CardRepository; import mage.choices.Choice; @@ -71,7 +72,10 @@ public class NameACardEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { Player controller = game.getPlayer(source.getControllerId()); - MageObject sourceObject = game.getObject(source.getSourceId()); + MageObject sourceObject = (Permanent) getValue(EntersBattlefieldEffect.ENTERING_PERMANENT); + if (sourceObject == null) { + game.getObject(source.getSourceId()); + } if (controller != null && sourceObject != null) { Choice cardChoice = new ChoiceImpl(); switch (typeOfName) { From d264dd83e1c72d1a4968fd0a0eab2c56573c2872 Mon Sep 17 00:00:00 2001 From: LevelX2 Date: Thu, 15 Oct 2015 23:47:06 +0200 Subject: [PATCH 112/268] * Replaced some custom card effects. Updated enters battlefield replacement effects for new handling. --- .../sets/alarareborn/ArsenalThresher.java | 25 +++---- .../mage/sets/commander/TheMimeoplasm.java | 15 ++-- .../mage/sets/commander2014/BitterFeud.java | 3 +- Mage.Sets/src/mage/sets/conflux/Nyxathid.java | 53 +++----------- .../mage/sets/eventide/CankerAbomination.java | 28 ++++---- .../src/mage/sets/exodus/EntropicSpecter.java | 60 ++++------------ .../src/mage/sets/fourthedition/TheRack.java | 44 +----------- .../src/mage/sets/futuresight/CloudKey.java | 17 +++-- .../src/mage/sets/gatecrash/Realmwright.java | 63 ++++------------ .../mage/sets/guildpact/StompingGround.java | 13 ++-- .../sets/journeyintonyx/HallOfTriumph.java | 48 +------------ .../src/mage/sets/limitedalpha/BlackVise.java | 47 ++---------- .../sets/limitedalpha/PhantasmalTerrain.java | 58 +++------------ .../mage/sets/magic2010/ConvincingMirage.java | 72 +++++-------------- .../src/mage/sets/magic2012/SuturedGhoul.java | 46 ++++++------ .../returntoravnica/TabletOfTheGuilds.java | 16 ++--- .../riseoftheeldrazi/CurseOfWizardry.java | 40 +---------- .../sets/shadowmoor/LureboundScarecrow.java | 4 +- .../mage/sets/shadowmoor/PaintersServant.java | 43 ++--------- .../cards/single/avr/CavernOfSoulsTest.java | 55 +++++++------- .../common/ChooseBasicLandTypeEffect.java | 68 ++++++++++++++++++ .../effects/common/ChooseColorEffect.java | 17 +++-- .../common/ChooseCreatureTypeEffect.java | 18 +++-- .../effects/common/ChooseLandTypeEffect.java | 17 +++-- .../common/ChooseNewTargetsTargetEffect.java | 63 ++++++++-------- .../effects/common/ChooseOpponentEffect.java | 64 +++++++++++++++++ .../effects/common/ChoosePlayerEffect.java | 21 ++++-- .../common/TapSourceUnlessPaysEffect.java | 18 ++--- .../abilities/keyword/ModularAbility.java | 33 +++++---- 29 files changed, 437 insertions(+), 632 deletions(-) create mode 100644 Mage/src/mage/abilities/effects/common/ChooseBasicLandTypeEffect.java create mode 100644 Mage/src/mage/abilities/effects/common/ChooseOpponentEffect.java diff --git a/Mage.Sets/src/mage/sets/alarareborn/ArsenalThresher.java b/Mage.Sets/src/mage/sets/alarareborn/ArsenalThresher.java index 16bc181405a..f4203cb0d58 100644 --- a/Mage.Sets/src/mage/sets/alarareborn/ArsenalThresher.java +++ b/Mage.Sets/src/mage/sets/alarareborn/ArsenalThresher.java @@ -31,6 +31,7 @@ import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.AsEntersBattlefieldAbility; +import mage.abilities.effects.EntersBattlefieldEffect; import mage.abilities.effects.OneShotEffect; import mage.cards.CardImpl; import mage.cards.Cards; @@ -41,7 +42,6 @@ import mage.constants.Rarity; import mage.counters.CounterType; import mage.filter.common.FilterArtifactCard; import mage.filter.predicate.mageobject.AnotherCardPredicate; -import mage.filter.predicate.permanent.AnotherPredicate; import mage.game.Game; import mage.game.permanent.Permanent; import mage.players.Player; @@ -62,7 +62,8 @@ public class ArsenalThresher extends CardImpl { this.toughness = new MageInt(2); // As Arsenal Thresher enters the battlefield, you may reveal any number of other artifact cards from your hand. Arsenal Thresher enters the battlefield with a +1/+1 counter on it for each card revealed this way. - this.addAbility(new AsEntersBattlefieldAbility(new ArsenalThresherEffect(), "you may reveal any number of other artifact cards from your hand. {this} enters the battlefield with a +1/+1 counter on it for each card revealed this way")); + this.addAbility(new AsEntersBattlefieldAbility(new ArsenalThresherEffect(), + "you may reveal any number of other artifact cards from your hand. {this} enters the battlefield with a +1/+1 counter on it for each card revealed this way")); } public ArsenalThresher(final ArsenalThresher card) { @@ -92,29 +93,29 @@ class ArsenalThresherEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { - Player you = game.getPlayer(source.getControllerId()); - if (you == null) { + Player controller = game.getPlayer(source.getControllerId()); + if (controller == null) { return false; } - Permanent arsenalThresher = game.getPermanent(source.getSourceId()); + Permanent arsenalThresher = (Permanent) getValue(EntersBattlefieldEffect.ENTERING_PERMANENT); FilterArtifactCard filter = new FilterArtifactCard(); filter.add(new AnotherCardPredicate()); - if (you.chooseUse(Outcome.Benefit, "Do you want to reveal other artifacts in your hand?", source, game)) { + if (controller.chooseUse(Outcome.Benefit, "Do you want to reveal other artifacts in your hand?", source, game)) { Cards cards = new CardsImpl(); - if (you.getHand().count(filter, source.getSourceId(), source.getControllerId(), game) > 0) { + if (controller.getHand().count(filter, source.getSourceId(), source.getControllerId(), game) > 0) { TargetCardInHand target = new TargetCardInHand(0, Integer.MAX_VALUE, filter); - if (you.choose(Outcome.Benefit, target, source.getSourceId(), game)) { + if (controller.choose(Outcome.Benefit, target, source.getSourceId(), game)) { for (UUID uuid : target.getTargets()) { - cards.add(you.getHand().get(uuid, game)); + cards.add(controller.getHand().get(uuid, game)); } - you.revealCards("Revealed cards", cards, game); if (arsenalThresher != null) { + controller.revealCards(arsenalThresher.getIdName(), cards, game); arsenalThresher.addCounters(CounterType.P1P1.createInstance(cards.size()), game); - return true; } } } + return true; } return false; } -} \ No newline at end of file +} diff --git a/Mage.Sets/src/mage/sets/commander/TheMimeoplasm.java b/Mage.Sets/src/mage/sets/commander/TheMimeoplasm.java index 5be1bed0a24..238bb1bc6c3 100644 --- a/Mage.Sets/src/mage/sets/commander/TheMimeoplasm.java +++ b/Mage.Sets/src/mage/sets/commander/TheMimeoplasm.java @@ -32,6 +32,7 @@ import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.AsEntersBattlefieldAbility; import mage.abilities.dynamicvalue.common.CardsInAllGraveyardsCount; +import mage.abilities.effects.EntersBattlefieldEffect; import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.CopyEffect; import mage.cards.Card; @@ -80,27 +81,27 @@ public class TheMimeoplasm extends CardImpl { } class TheMimeoplasmEffect extends OneShotEffect { - + TheMimeoplasmEffect() { super(Outcome.Copy); } - + TheMimeoplasmEffect(final TheMimeoplasmEffect effect) { super(effect); } - + @Override public TheMimeoplasmEffect copy() { return new TheMimeoplasmEffect(this); } - + @Override public boolean apply(Game game, Ability source) { Player controller = game.getPlayer(source.getControllerId()); - Permanent permanent = game.getPermanent(source.getSourceId()); + Permanent permanent = (Permanent) getValue(EntersBattlefieldEffect.ENTERING_PERMANENT); if (controller != null && permanent != null) { if (new CardsInAllGraveyardsCount(new FilterCreatureCard()).calculate(game, source, this) >= 2) { - if (controller.chooseUse(Outcome.Benefit, "Do you want to exile two creature cards from graveyards?", source, game)) { + if (controller.chooseUse(Outcome.Benefit, "Do you want to exile two creature cards from graveyards?", source, game)) { TargetCardInGraveyard targetCopy = new TargetCardInGraveyard(new FilterCreatureCard("creature card to become a copy of")); TargetCardInGraveyard targetCounters = new TargetCardInGraveyard(new FilterCreatureCard("creature card to determine amount of additional +1/+1 counters")); if (controller.choose(Outcome.Copy, targetCopy, source.getSourceId(), game)) { @@ -122,7 +123,7 @@ class TheMimeoplasmEffect extends OneShotEffect { } } } - return true; + return true; } return false; } diff --git a/Mage.Sets/src/mage/sets/commander2014/BitterFeud.java b/Mage.Sets/src/mage/sets/commander2014/BitterFeud.java index 7ba41f23715..22d87b793ea 100644 --- a/Mage.Sets/src/mage/sets/commander2014/BitterFeud.java +++ b/Mage.Sets/src/mage/sets/commander2014/BitterFeud.java @@ -32,6 +32,7 @@ import mage.MageObject; import mage.abilities.Ability; import mage.abilities.common.AsEntersBattlefieldAbility; import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.effects.EntersBattlefieldEffect; import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.ReplacementEffectImpl; import mage.cards.Card; @@ -91,7 +92,7 @@ class BitterFeudEntersBattlefieldEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { Player controller = game.getPlayer(source.getControllerId()); - Permanent permanent = game.getPermanent(source.getSourceId()); + Permanent permanent = (Permanent) getValue(EntersBattlefieldEffect.ENTERING_PERMANENT); if (controller != null && permanent != null) { TargetPlayer target = new TargetPlayer(2, 2, true); controller.chooseTarget(outcome, target, source, game); diff --git a/Mage.Sets/src/mage/sets/conflux/Nyxathid.java b/Mage.Sets/src/mage/sets/conflux/Nyxathid.java index 22fb19bcede..0a7e5fee51a 100644 --- a/Mage.Sets/src/mage/sets/conflux/Nyxathid.java +++ b/Mage.Sets/src/mage/sets/conflux/Nyxathid.java @@ -27,6 +27,7 @@ */ package mage.sets.conflux; +import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.AsEntersBattlefieldAbility; @@ -34,16 +35,16 @@ import mage.abilities.common.SimpleStaticAbility; import mage.abilities.dynamicvalue.DynamicValue; import mage.abilities.dynamicvalue.common.SignInversionDynamicValue; import mage.abilities.effects.Effect; -import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.ChooseOpponentEffect; import mage.abilities.effects.common.continuous.BoostSourceEffect; import mage.cards.CardImpl; -import mage.constants.*; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.Outcome; +import mage.constants.Rarity; +import mage.constants.Zone; import mage.game.Game; -import mage.game.permanent.Permanent; import mage.players.Player; -import mage.target.common.TargetOpponent; - -import java.util.UUID; /** * @@ -60,7 +61,7 @@ public class Nyxathid extends CardImpl { this.toughness = new MageInt(7); // As Nyxathid enters the battlefield, choose an opponent. - this.addAbility(new AsEntersBattlefieldAbility(new ChooseOpponent())); + this.addAbility(new AsEntersBattlefieldAbility(new ChooseOpponentEffect(Outcome.Detriment))); // Nyxathid gets -1/-1 for each card in the chosen player's hand. DynamicValue chosenPlayerHand = new SignInversionDynamicValue(new CardsInChosenPlayerHandCount()); @@ -78,48 +79,12 @@ public class Nyxathid extends CardImpl { } } -class ChooseOpponent extends OneShotEffect { - - public ChooseOpponent() { - super(Outcome.Neutral); - this.staticText = "choose an opponent"; - } - - public ChooseOpponent(final ChooseOpponent effect) { - super(effect); - } - - @Override - public ChooseOpponent copy() { - return new ChooseOpponent(this); - } - - @Override - public boolean apply(Game game, Ability source) { - Player player = game.getPlayer(source.getControllerId()); - Permanent permanent = game.getPermanent(source.getSourceId()); - if (player != null && permanent != null) { - TargetOpponent target = new TargetOpponent(); - target.setNotTarget(true); - if (player.choose(this.outcome, target, source.getSourceId(), game)) { - Player chosenPlayer = game.getPlayer(target.getFirstTarget()); - if (chosenPlayer != null) { - game.informPlayers(permanent.getName() + ": " + player.getLogName() + " has chosen " + chosenPlayer.getLogName()); - game.getState().setValue(permanent.getId() + "_player", target.getFirstTarget()); - return true; - } - } - } - return false; - } -} - class CardsInChosenPlayerHandCount implements DynamicValue { @Override public int calculate(Game game, Ability sourceAbility, Effect effect) { if (sourceAbility != null) { - UUID playerId = (UUID) game.getState().getValue(sourceAbility.getSourceId() + "_player"); + UUID playerId = (UUID) game.getState().getValue(sourceAbility.getSourceId() + ChooseOpponentEffect.VALUE_KEY); Player chosenPlayer = game.getPlayer(playerId); if (chosenPlayer != null) { return chosenPlayer.getHand().size(); diff --git a/Mage.Sets/src/mage/sets/eventide/CankerAbomination.java b/Mage.Sets/src/mage/sets/eventide/CankerAbomination.java index 5b8107dd5f1..812f571064a 100644 --- a/Mage.Sets/src/mage/sets/eventide/CankerAbomination.java +++ b/Mage.Sets/src/mage/sets/eventide/CankerAbomination.java @@ -31,6 +31,7 @@ import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.AsEntersBattlefieldAbility; +import mage.abilities.effects.EntersBattlefieldEffect; import mage.abilities.effects.OneShotEffect; import mage.cards.CardImpl; import mage.constants.CardType; @@ -61,11 +62,7 @@ public class CankerAbomination extends CardImpl { this.toughness = new MageInt(6); // As Canker Abomination enters the battlefield, choose an opponent. Canker Abomination enters the battlefield with a -1/-1 counter on it for each creature that player controls. - Ability ability = new AsEntersBattlefieldAbility(new CankerAbominationEffect()); - Target target = new TargetOpponent(); - target.setNotTarget(true); - ability.addTarget(target); - this.addAbility(ability); + this.addAbility(new AsEntersBattlefieldAbility(new CankerAbominationEffect())); } @@ -97,14 +94,19 @@ class CankerAbominationEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { - Player player = game.getPlayer(source.getControllerId()); - Permanent CankerAbomination = game.getPermanent(source.getSourceId()); - if (player != null && CankerAbomination != null) { - Player chosenPlayer = game.getPlayer(source.getFirstTarget()); - if (chosenPlayer != null) { - game.informPlayers(CankerAbomination.getName() + ": " + player.getLogName() + " has chosen " + chosenPlayer.getLogName()); - int amount = game.getBattlefield().getAllActivePermanents(new FilterCreaturePermanent(), chosenPlayer.getId(), game).size(); - CankerAbomination.addCounters(CounterType.M1M1.createInstance(amount), game); + Player controller = game.getPlayer(source.getControllerId()); + Permanent cankerAbomination = (Permanent) getValue(EntersBattlefieldEffect.ENTERING_PERMANENT); + if (controller != null && cankerAbomination != null) { + Target target = new TargetOpponent(); + target.setNotTarget(true); + controller.choose(outcome, target, source.getSourceId(), game); + Player opponent = game.getPlayer(target.getFirstTarget()); + if (opponent != null) { + game.informPlayers(cankerAbomination.getName() + ": " + controller.getLogName() + " has chosen " + opponent.getLogName()); + int amount = game.getBattlefield().getAllActivePermanents(new FilterCreaturePermanent(), opponent.getId(), game).size(); + if (amount > 0) { + cankerAbomination.addCounters(CounterType.M1M1.createInstance(amount), game); + } return true; } } diff --git a/Mage.Sets/src/mage/sets/exodus/EntropicSpecter.java b/Mage.Sets/src/mage/sets/exodus/EntropicSpecter.java index 1e5348392f8..b2e6ebf7cca 100644 --- a/Mage.Sets/src/mage/sets/exodus/EntropicSpecter.java +++ b/Mage.Sets/src/mage/sets/exodus/EntropicSpecter.java @@ -27,6 +27,7 @@ */ package mage.sets.exodus; +import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.AsEntersBattlefieldAbility; @@ -34,18 +35,18 @@ import mage.abilities.common.DealsDamageToAPlayerTriggeredAbility; import mage.abilities.common.SimpleStaticAbility; import mage.abilities.dynamicvalue.DynamicValue; import mage.abilities.effects.Effect; -import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.ChooseOpponentEffect; import mage.abilities.effects.common.continuous.SetPowerToughnessSourceEffect; import mage.abilities.effects.common.discard.DiscardTargetEffect; import mage.abilities.keyword.FlyingAbility; import mage.cards.CardImpl; -import mage.constants.*; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.Outcome; +import mage.constants.Rarity; +import mage.constants.Zone; import mage.game.Game; -import mage.game.permanent.Permanent; import mage.players.Player; -import mage.target.common.TargetOpponent; - -import java.util.UUID; /** * @@ -64,13 +65,13 @@ public class EntropicSpecter extends CardImpl { // Flying this.addAbility(FlyingAbility.getInstance()); - + // As Entropic Specter enters the battlefield, choose an opponent. - this.addAbility(new AsEntersBattlefieldAbility(new ChooseOpponent())); - + this.addAbility(new AsEntersBattlefieldAbility(new ChooseOpponentEffect(Outcome.Detriment))); + // Entropic Specter's power and toughness are each equal to the number of cards in the chosen player's hand. this.addAbility(new SimpleStaticAbility(Zone.ALL, new SetPowerToughnessSourceEffect(new CardsInTargetPlayerHandCount(), Duration.WhileOnBattlefield))); - + // Whenever Entropic Specter deals damage to a player, that player discards a card. this.addAbility(new DealsDamageToAPlayerTriggeredAbility(new DiscardTargetEffect(1, false), false, true)); } @@ -85,47 +86,12 @@ public class EntropicSpecter extends CardImpl { } } -class ChooseOpponent extends OneShotEffect { - - public ChooseOpponent() { - super(Outcome.Neutral); - this.staticText = "choose an opponent"; - } - - public ChooseOpponent(final ChooseOpponent effect) { - super(effect); - } - - @Override - public ChooseOpponent copy() { - return new ChooseOpponent(this); - } - - @Override - public boolean apply(Game game, Ability source) { - Player player = game.getPlayer(source.getControllerId()); - Permanent permanent = game.getPermanent(source.getSourceId()); - if (player != null && permanent != null) { - TargetOpponent target = new TargetOpponent(); - target.setNotTarget(true); - if (player.choose(this.outcome, target, source.getSourceId(), game)) { - Player chosenPlayer = game.getPlayer(target.getFirstTarget()); - if (chosenPlayer != null) { - game.informPlayers(permanent.getName() + ": " + player.getLogName() + " has chosen " + chosenPlayer.getLogName()); - game.getState().setValue(permanent.getId() + "_player", target.getFirstTarget()); - return true; - } - } - } - return false; - } -} - class CardsInTargetPlayerHandCount implements DynamicValue { + @Override public int calculate(Game game, Ability sourceAbility, Effect effect) { if (sourceAbility != null) { - UUID playerId = (UUID) game.getState().getValue(sourceAbility.getSourceId() + "_player"); + UUID playerId = (UUID) game.getState().getValue(sourceAbility.getSourceId() + ChooseOpponentEffect.VALUE_KEY); Player chosenPlayer = game.getPlayer(playerId); if (chosenPlayer != null) { return chosenPlayer.getHand().size(); diff --git a/Mage.Sets/src/mage/sets/fourthedition/TheRack.java b/Mage.Sets/src/mage/sets/fourthedition/TheRack.java index 98b564a6bbf..a99f13634fa 100644 --- a/Mage.Sets/src/mage/sets/fourthedition/TheRack.java +++ b/Mage.Sets/src/mage/sets/fourthedition/TheRack.java @@ -32,6 +32,7 @@ import mage.abilities.Ability; import mage.abilities.TriggeredAbilityImpl; import mage.abilities.common.AsEntersBattlefieldAbility; import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.ChooseOpponentEffect; import mage.cards.CardImpl; import mage.constants.CardType; import mage.constants.Outcome; @@ -40,9 +41,7 @@ import mage.constants.Zone; import mage.game.Game; import mage.game.events.GameEvent; import mage.game.events.GameEvent.EventType; -import mage.game.permanent.Permanent; import mage.players.Player; -import mage.target.common.TargetOpponent; /** * @@ -55,7 +54,7 @@ public class TheRack extends CardImpl { this.expansionSetCode = "4ED"; // As The Rack enters the battlefield, choose an opponent. - this.addAbility(new AsEntersBattlefieldAbility(new ChooseOpponent())); + this.addAbility(new AsEntersBattlefieldAbility(new ChooseOpponentEffect(Outcome.Detriment))); // At the beginning of the chosen player's upkeep, The Rack deals X damage to that player, where X is 3 minus the number of cards in his or her hand. this.addAbility(new TheRackTriggeredAbility()); } @@ -72,7 +71,6 @@ public class TheRack extends CardImpl { class TheRackTriggeredAbility extends TriggeredAbilityImpl { - public TheRackTriggeredAbility() { super(Zone.BATTLEFIELD, new TheRackEffect(), false); } @@ -93,7 +91,7 @@ class TheRackTriggeredAbility extends TriggeredAbilityImpl { @Override public boolean checkTrigger(GameEvent event, Game game) { - return event.getPlayerId().equals((UUID) game.getState().getValue(new StringBuilder(this.getSourceId().toString()).append("_player").toString())); + return event.getPlayerId().equals((UUID) game.getState().getValue(this.getSourceId().toString() + ChooseOpponentEffect.VALUE_KEY)); } @Override @@ -103,42 +101,6 @@ class TheRackTriggeredAbility extends TriggeredAbilityImpl { } -class ChooseOpponent extends OneShotEffect { - - public ChooseOpponent() { - super(Outcome.Neutral); - this.staticText = "choose an opponent"; - } - - public ChooseOpponent(final ChooseOpponent effect) { - super(effect); - } - - @Override - public ChooseOpponent copy() { - return new ChooseOpponent(this); - } - - @Override - public boolean apply(Game game, Ability source) { - Player player = game.getPlayer(source.getControllerId()); - Permanent permanent = game.getPermanent(source.getSourceId()); - if (player != null && permanent != null) { - TargetOpponent target = new TargetOpponent(); - target.setNotTarget(true); - if (player.choose(this.outcome, target, source.getSourceId(), game)) { - Player chosenPlayer = game.getPlayer(target.getFirstTarget()); - if (chosenPlayer != null) { - game.informPlayers(permanent.getName() + ": " + player.getLogName() + " has chosen " + chosenPlayer.getLogName()); - game.getState().setValue(permanent.getId() + "_player", target.getFirstTarget()); - return true; - } - } - } - return false; - } -} - class TheRackEffect extends OneShotEffect { public TheRackEffect() { diff --git a/Mage.Sets/src/mage/sets/futuresight/CloudKey.java b/Mage.Sets/src/mage/sets/futuresight/CloudKey.java index 7fc55b94457..33e946d9393 100644 --- a/Mage.Sets/src/mage/sets/futuresight/CloudKey.java +++ b/Mage.Sets/src/mage/sets/futuresight/CloudKey.java @@ -11,6 +11,7 @@ import mage.abilities.Ability; import mage.abilities.SpellAbility; import mage.abilities.common.AsEntersBattlefieldAbility; import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.effects.EntersBattlefieldEffect; import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.cost.CostModificationEffectImpl; import mage.cards.Card; @@ -23,6 +24,7 @@ import mage.constants.Outcome; import mage.constants.Rarity; import mage.constants.Zone; import mage.game.Game; +import mage.game.permanent.Permanent; import mage.players.Player; import mage.util.CardUtil; @@ -73,8 +75,11 @@ class CloudKeyChooseTypeEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { Player controller = game.getPlayer(source.getControllerId()); - MageObject sourceObject = source.getSourceObject(game); - if (sourceObject != null && controller != null) { + MageObject mageObject = (Permanent) getValue(EntersBattlefieldEffect.ENTERING_PERMANENT); + if (mageObject == null) { + mageObject = game.getObject(source.getSourceId()); + } + if (mageObject != null && controller != null) { ChoiceImpl choices = new ChoiceImpl(true); choices.setMessage("Choose a spell type"); choices.getChoices().add(CardType.ARTIFACT.toString()); @@ -82,9 +87,12 @@ class CloudKeyChooseTypeEffect extends OneShotEffect { choices.getChoices().add(CardType.ENCHANTMENT.toString()); choices.getChoices().add(CardType.INSTANT.toString()); choices.getChoices().add(CardType.SORCERY.toString()); - if(controller.choose(Outcome.Neutral, choices, game)) { - game.informPlayers(sourceObject.getLogName() + ": chosen spell type is " + choices.getChoice()); + if (controller.choose(Outcome.Neutral, choices, game)) { + game.informPlayers(mageObject.getLogName() + ": chosen spell type is " + choices.getChoice()); game.getState().setValue(source.getSourceId().toString() + "_CloudKey", choices.getChoice()); + if (mageObject instanceof Permanent) { + ((Permanent) mageObject).addInfo("chosenCardType", CardUtil.addToolTipMarkTags("Chosen card type: " + choices.getChoice()), game); + } return true; } } @@ -129,4 +137,3 @@ class CloudKeyCostModificationEffect extends CostModificationEffectImpl { return false; } } - diff --git a/Mage.Sets/src/mage/sets/gatecrash/Realmwright.java b/Mage.Sets/src/mage/sets/gatecrash/Realmwright.java index dfb670e3dd7..f0707af005d 100644 --- a/Mage.Sets/src/mage/sets/gatecrash/Realmwright.java +++ b/Mage.Sets/src/mage/sets/gatecrash/Realmwright.java @@ -29,6 +29,18 @@ package mage.sets.gatecrash; import java.util.List; import java.util.UUID; +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.AsEntersBattlefieldAbility; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.effects.ContinuousEffectImpl; +import mage.abilities.effects.common.ChooseBasicLandTypeEffect; +import mage.abilities.mana.BlackManaAbility; +import mage.abilities.mana.BlueManaAbility; +import mage.abilities.mana.GreenManaAbility; +import mage.abilities.mana.RedManaAbility; +import mage.abilities.mana.WhiteManaAbility; +import mage.cards.CardImpl; import mage.constants.CardType; import mage.constants.Duration; import mage.constants.Layer; @@ -36,15 +48,6 @@ import mage.constants.Outcome; import mage.constants.Rarity; import mage.constants.SubLayer; import mage.constants.Zone; -import mage.MageInt; -import mage.abilities.Ability; -import mage.abilities.common.AsEntersBattlefieldAbility; -import mage.abilities.common.SimpleStaticAbility; -import mage.abilities.effects.ContinuousEffectImpl; -import mage.abilities.effects.OneShotEffect; -import mage.abilities.mana.*; -import mage.cards.CardImpl; -import mage.choices.ChoiceImpl; import mage.filter.common.FilterControlledLandPermanent; import mage.game.Game; import mage.game.permanent.Permanent; @@ -66,7 +69,7 @@ public class Realmwright extends CardImpl { this.toughness = new MageInt(1); // As Realmwright enters the battlefield, choose a basic land type. - this.addAbility(new AsEntersBattlefieldAbility(new RealmwrightEffect())); + this.addAbility(new AsEntersBattlefieldAbility(new ChooseBasicLandTypeEffect(Outcome.Neutral))); // Lands you control are the chosen type in addition to their other types. this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new RealmwrightEffect2())); @@ -82,44 +85,6 @@ public class Realmwright extends CardImpl { } } -class RealmwrightEffect extends OneShotEffect { - - public RealmwrightEffect() { - super(Outcome.Neutral); - this.staticText = "Choose a basic land type"; - } - - public RealmwrightEffect(final RealmwrightEffect effect) { - super(effect); - } - - @Override - public RealmwrightEffect copy() { - return new RealmwrightEffect(this); - } - - @Override - public boolean apply(Game game, Ability source) { - Player you = game.getPlayer(source.getControllerId()); - if (you != null) { - ChoiceImpl choices = new ChoiceImpl(true); - choices.setMessage("Choose basic land type"); - choices.isRequired(); - choices.getChoices().add("Forest"); - choices.getChoices().add("Plains"); - choices.getChoices().add("Mountain"); - choices.getChoices().add("Island"); - choices.getChoices().add("Swamp"); - if (you.choose(Outcome.Neutral, choices, game)) { - game.informPlayers(new StringBuilder("Realmwright: ").append(" Chosen basic land type is ").append(choices.getChoice()).toString()); - game.getState().setValue(source.getSourceId().toString() + "_Realmwright", choices.getChoice()); - return true; - } - } - return false; - } -} - class RealmwrightEffect2 extends ContinuousEffectImpl { public RealmwrightEffect2() { @@ -140,7 +105,7 @@ class RealmwrightEffect2 extends ContinuousEffectImpl { public boolean apply(Layer layer, SubLayer sublayer, Ability source, Game game) { Player you = game.getPlayer(source.getControllerId()); List lands = game.getBattlefield().getAllActivePermanents(new FilterControlledLandPermanent(), source.getControllerId(), game); - String choice = (String) game.getState().getValue(source.getSourceId().toString() + "_Realmwright"); + String choice = (String) game.getState().getValue(source.getSourceId().toString() + ChooseBasicLandTypeEffect.VALUE_KEY); if (you != null && choice != null) { for (Permanent land : lands) { if (land != null) { diff --git a/Mage.Sets/src/mage/sets/guildpact/StompingGround.java b/Mage.Sets/src/mage/sets/guildpact/StompingGround.java index 0bce0460177..85c8b2ce2d4 100644 --- a/Mage.Sets/src/mage/sets/guildpact/StompingGround.java +++ b/Mage.Sets/src/mage/sets/guildpact/StompingGround.java @@ -25,18 +25,17 @@ * authors and should not be interpreted as representing official policies, either expressed * or implied, of BetaSteward_at_googlemail.com. */ - package mage.sets.guildpact; import java.util.UUID; -import mage.constants.CardType; -import mage.constants.Rarity; import mage.abilities.common.AsEntersBattlefieldAbility; import mage.abilities.costs.common.PayLifeCost; import mage.abilities.effects.common.TapSourceUnlessPaysEffect; import mage.abilities.mana.GreenManaAbility; import mage.abilities.mana.RedManaAbility; import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.Rarity; /** * @@ -44,17 +43,19 @@ import mage.cards.CardImpl; */ public class StompingGround extends CardImpl { - public StompingGround (UUID ownerId) { + public StompingGround(UUID ownerId) { super(ownerId, 165, "Stomping Ground", Rarity.RARE, new CardType[]{CardType.LAND}, null); this.expansionSetCode = "GPT"; this.subtype.add("Mountain"); this.subtype.add("Forest"); + this.addAbility(new RedManaAbility()); this.addAbility(new GreenManaAbility()); - this.addAbility(new AsEntersBattlefieldAbility(new TapSourceUnlessPaysEffect(new PayLifeCost(2)), "you may pay 2 life. If you don't, Stomping Ground enters the battlefield tapped")); + this.addAbility(new AsEntersBattlefieldAbility(new TapSourceUnlessPaysEffect(new PayLifeCost(2)), + "you may pay 2 life. If you don't, {this} enters the battlefield tapped")); } - public StompingGround (final StompingGround card) { + public StompingGround(final StompingGround card) { super(card); } diff --git a/Mage.Sets/src/mage/sets/journeyintonyx/HallOfTriumph.java b/Mage.Sets/src/mage/sets/journeyintonyx/HallOfTriumph.java index 6fb34b789b2..6423e7622b4 100644 --- a/Mage.Sets/src/mage/sets/journeyintonyx/HallOfTriumph.java +++ b/Mage.Sets/src/mage/sets/journeyintonyx/HallOfTriumph.java @@ -33,9 +33,8 @@ import mage.abilities.Ability; import mage.abilities.common.AsEntersBattlefieldAbility; import mage.abilities.common.SimpleStaticAbility; import mage.abilities.effects.ContinuousEffectImpl; -import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.ChooseColorEffect; import mage.cards.CardImpl; -import mage.choices.ChoiceColor; import mage.constants.CardType; import mage.constants.Duration; import mage.constants.Layer; @@ -46,8 +45,6 @@ import mage.constants.Zone; import mage.filter.common.FilterCreaturePermanent; import mage.game.Game; import mage.game.permanent.Permanent; -import mage.players.Player; - /** * @@ -61,7 +58,7 @@ public class HallOfTriumph extends CardImpl { this.supertype.add("Legendary"); // As Hall of Triumph enters the battlefield choose a color. - this.addAbility(new AsEntersBattlefieldAbility(new HallOfTriumphEffect())); + this.addAbility(new AsEntersBattlefieldAbility(new ChooseColorEffect(Outcome.Neutral))); // Creatures you control of the chosen color get +1/+1. this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new HallOfTriumphBoostControlledEffect())); } @@ -76,45 +73,6 @@ public class HallOfTriumph extends CardImpl { } } -class HallOfTriumphEffect extends OneShotEffect { - - public HallOfTriumphEffect() { - super(Outcome.BoostCreature); - staticText = "choose a color"; - } - - public HallOfTriumphEffect(final HallOfTriumphEffect effect) { - super(effect); - } - - @Override - public boolean apply(Game game, Ability source) { - Player player = game.getPlayer(source.getControllerId()); - Permanent permanent = game.getPermanent(source.getSourceId()); - if (player != null && permanent != null) { - ChoiceColor colorChoice = new ChoiceColor(); - colorChoice.setMessage("Choose color"); - while (!player.choose(Outcome.BoostCreature, colorChoice, game)) { - if (!player.canRespond()) { - return false; - } - } - if (colorChoice.getChoice() != null) { - game.informPlayers(permanent.getName() + ": " + player.getLogName() + " has chosen " + colorChoice.getChoice()); - game.getState().setValue(permanent.getId() + "_color", colorChoice.getColor()); - permanent.addInfo("chosen color", "Chosen color: " + colorChoice.getColor().getDescription() + "", game); - } - } - return false; - } - - @Override - public HallOfTriumphEffect copy() { - return new HallOfTriumphEffect(this); - } - -} - class HallOfTriumphBoostControlledEffect extends ContinuousEffectImpl { private static final FilterCreaturePermanent filter = new FilterCreaturePermanent(); @@ -137,7 +95,7 @@ class HallOfTriumphBoostControlledEffect extends ContinuousEffectImpl { public boolean apply(Game game, Ability source) { ObjectColor color = (ObjectColor) game.getState().getValue(source.getSourceId() + "_color"); if (color != null) { - for (Permanent perm: game.getBattlefield().getAllActivePermanents(filter, source.getControllerId(), game)) { + for (Permanent perm : game.getBattlefield().getAllActivePermanents(filter, source.getControllerId(), game)) { if (perm.getColor(game).shares(color)) { perm.addPower(1); perm.addToughness(1); diff --git a/Mage.Sets/src/mage/sets/limitedalpha/BlackVise.java b/Mage.Sets/src/mage/sets/limitedalpha/BlackVise.java index 057ebaa541b..57732f49119 100644 --- a/Mage.Sets/src/mage/sets/limitedalpha/BlackVise.java +++ b/Mage.Sets/src/mage/sets/limitedalpha/BlackVise.java @@ -32,6 +32,7 @@ import mage.abilities.Ability; import mage.abilities.TriggeredAbilityImpl; import mage.abilities.common.AsEntersBattlefieldAbility; import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.ChooseOpponentEffect; import mage.cards.CardImpl; import mage.constants.CardType; import mage.constants.Outcome; @@ -40,9 +41,7 @@ import mage.constants.Zone; import mage.game.Game; import mage.game.events.GameEvent; import mage.game.events.GameEvent.EventType; -import mage.game.permanent.Permanent; import mage.players.Player; -import mage.target.common.TargetOpponent; /** * @@ -55,7 +54,7 @@ public class BlackVise extends CardImpl { this.expansionSetCode = "LEA"; // As Black Vise enters the battlefield, choose an opponent. - this.addAbility(new AsEntersBattlefieldAbility(new BlackViseChooseOpponent())); + this.addAbility(new AsEntersBattlefieldAbility(new ChooseOpponentEffect(Outcome.Detriment))); // At the beginning of the chosen player's upkeep, Black Vise deals X damage to that player, where X is the number of cards in his or her hand minus 4. this.addAbility(new BlackViseTriggeredAbility()); } @@ -70,42 +69,6 @@ public class BlackVise extends CardImpl { } } -class BlackViseChooseOpponent extends OneShotEffect { - - public BlackViseChooseOpponent() { - super(Outcome.Neutral); - this.staticText = "choose an opponent"; - } - - public BlackViseChooseOpponent(final BlackViseChooseOpponent effect) { - super(effect); - } - - @Override - public BlackViseChooseOpponent copy() { - return new BlackViseChooseOpponent(this); - } - - @Override - public boolean apply(Game game, Ability source) { - Player player = game.getPlayer(source.getControllerId()); - Permanent permanent = game.getPermanent(source.getSourceId()); - if (player != null && permanent != null) { - TargetOpponent target = new TargetOpponent(); - target.setNotTarget(true); - if (player.choose(this.outcome, target, source.getSourceId(), game)) { - Player chosenPlayer = game.getPlayer(target.getFirstTarget()); - if (chosenPlayer != null) { - game.informPlayers(permanent.getName() + ": " + player.getLogName() + " has chosen " + chosenPlayer.getLogName()); - game.getState().setValue(permanent.getId() + "_player", target.getFirstTarget()); - return true; - } - } - } - return false; - } -} - class BlackViseTriggeredAbility extends TriggeredAbilityImpl { public BlackViseTriggeredAbility() { @@ -128,12 +91,12 @@ class BlackViseTriggeredAbility extends TriggeredAbilityImpl { @Override public boolean checkTrigger(GameEvent event, Game game) { - return event.getPlayerId().equals(game.getState().getValue(getSourceId().toString() + "_player")); + return event.getPlayerId().equals(game.getState().getValue(getSourceId().toString() + ChooseOpponentEffect.VALUE_KEY)); } @Override public String getRule() { - return new StringBuilder("At the beginning of the chosen player's upkeep, ").append(super.getRule()).toString(); + return "At the beginning of the chosen player's upkeep, " + super.getRule(); } } @@ -155,7 +118,7 @@ class BlackViseEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { - UUID playerId = (UUID) game.getState().getValue(source.getSourceId().toString() + "_player"); + UUID playerId = (UUID) game.getState().getValue(source.getSourceId().toString() + ChooseOpponentEffect.VALUE_KEY); Player chosenPlayer = game.getPlayer(playerId); if (chosenPlayer != null) { int damage = chosenPlayer.getHand().size() - 4; diff --git a/Mage.Sets/src/mage/sets/limitedalpha/PhantasmalTerrain.java b/Mage.Sets/src/mage/sets/limitedalpha/PhantasmalTerrain.java index f38d3ea0f7d..d7de486907b 100644 --- a/Mage.Sets/src/mage/sets/limitedalpha/PhantasmalTerrain.java +++ b/Mage.Sets/src/mage/sets/limitedalpha/PhantasmalTerrain.java @@ -28,13 +28,12 @@ package mage.sets.limitedalpha; import java.util.UUID; -import mage.MageObject; import mage.abilities.Ability; import mage.abilities.common.AsEntersBattlefieldAbility; import mage.abilities.common.SimpleStaticAbility; import mage.abilities.effects.ContinuousEffectImpl; -import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.AttachEffect; +import mage.abilities.effects.common.ChooseBasicLandTypeEffect; import mage.abilities.keyword.EnchantAbility; import mage.abilities.mana.BlackManaAbility; import mage.abilities.mana.BlueManaAbility; @@ -42,7 +41,6 @@ import mage.abilities.mana.GreenManaAbility; import mage.abilities.mana.RedManaAbility; import mage.abilities.mana.WhiteManaAbility; import mage.cards.CardImpl; -import mage.choices.ChoiceImpl; import mage.constants.CardType; import mage.constants.Duration; import mage.constants.Layer; @@ -52,7 +50,6 @@ import mage.constants.SubLayer; import mage.constants.Zone; import mage.game.Game; import mage.game.permanent.Permanent; -import mage.players.Player; import mage.target.TargetPermanent; import mage.target.common.TargetLandPermanent; @@ -72,10 +69,10 @@ public class PhantasmalTerrain extends CardImpl { this.getSpellAbility().addTarget(auraTarget); this.getSpellAbility().addEffect(new AttachEffect(Outcome.Detriment)); this.addAbility(new EnchantAbility(auraTarget.getTargetName())); - + // As Phantasmal Terrain enters the battlefield, choose a basic land type. - this.addAbility(new AsEntersBattlefieldAbility(new PhantasmalTerrainChooseEffect())); - + this.addAbility(new AsEntersBattlefieldAbility(new ChooseBasicLandTypeEffect(Outcome.Neutral))); + // Enchanted land is the chosen type. this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new PhantasmalTerrainContinuousEffect())); } @@ -90,52 +87,13 @@ public class PhantasmalTerrain extends CardImpl { } } -class PhantasmalTerrainChooseEffect extends OneShotEffect { - - public PhantasmalTerrainChooseEffect() { - super(Outcome.Neutral); - this.staticText = "choose a basic land type"; - } - - public PhantasmalTerrainChooseEffect(final PhantasmalTerrainChooseEffect effect) { - super(effect); - } - - @Override - public PhantasmalTerrainChooseEffect copy() { - return new PhantasmalTerrainChooseEffect(this); - } - - @Override - public boolean apply(Game game, Ability source) { - Player controller = game.getPlayer(source.getControllerId()); - MageObject sourceObject = source.getSourceObject(game); - if (sourceObject != null && controller != null) { - ChoiceImpl choices = new ChoiceImpl(true); - choices.setMessage("Choose basic land type"); - choices.getChoices().add("Forest"); - choices.getChoices().add("Plains"); - choices.getChoices().add("Mountain"); - choices.getChoices().add("Island"); - choices.getChoices().add("Swamp"); - if (controller.choose(Outcome.Neutral, choices, game)) { - game.informPlayers(sourceObject.getLogName() + ": chosen basic land type is " + choices.getChoice()); - game.getState().setValue(source.getSourceId().toString() + "_PhantasmalTerrain", choices.getChoice()); - return true; - } - } - return false; - } - -} - class PhantasmalTerrainContinuousEffect extends ContinuousEffectImpl { - public PhantasmalTerrainContinuousEffect(){ + public PhantasmalTerrainContinuousEffect() { super(Duration.WhileOnBattlefield, Outcome.Neutral); this.staticText = "enchanted land is the chosen type"; } - + public PhantasmalTerrainContinuousEffect(final PhantasmalTerrainContinuousEffect effect) { super(effect); } @@ -148,7 +106,7 @@ class PhantasmalTerrainContinuousEffect extends ContinuousEffectImpl { @Override public boolean apply(Layer layer, SubLayer sublayer, Ability source, Game game) { Permanent enchantment = game.getPermanent(source.getSourceId()); - String choice = (String) game.getState().getValue(source.getSourceId().toString() + "_PhantasmalTerrain"); + String choice = (String) game.getState().getValue(source.getSourceId().toString() + ChooseBasicLandTypeEffect.VALUE_KEY); if (enchantment != null && enchantment.getAttachedTo() != null && choice != null) { Permanent land = game.getPermanent(enchantment.getAttachedTo()); if (land != null) { @@ -195,5 +153,5 @@ class PhantasmalTerrainContinuousEffect extends ContinuousEffectImpl { public boolean hasLayer(Layer layer) { return layer == Layer.AbilityAddingRemovingEffects_6 || layer == Layer.TypeChangingEffects_4; } - + } diff --git a/Mage.Sets/src/mage/sets/magic2010/ConvincingMirage.java b/Mage.Sets/src/mage/sets/magic2010/ConvincingMirage.java index 5ee4db516fb..9049656edd4 100644 --- a/Mage.Sets/src/mage/sets/magic2010/ConvincingMirage.java +++ b/Mage.Sets/src/mage/sets/magic2010/ConvincingMirage.java @@ -27,21 +27,13 @@ */ package mage.sets.magic2010; -import java.util.Set; import java.util.UUID; -import mage.constants.CardType; -import mage.constants.Duration; -import mage.constants.Layer; -import mage.constants.Outcome; -import mage.constants.Rarity; -import mage.constants.SubLayer; -import mage.constants.Zone; import mage.abilities.Ability; import mage.abilities.common.AsEntersBattlefieldAbility; import mage.abilities.common.SimpleStaticAbility; import mage.abilities.effects.ContinuousEffectImpl; -import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.AttachEffect; +import mage.abilities.effects.common.ChooseBasicLandTypeEffect; import mage.abilities.keyword.EnchantAbility; import mage.abilities.mana.BlackManaAbility; import mage.abilities.mana.BlueManaAbility; @@ -49,10 +41,15 @@ import mage.abilities.mana.GreenManaAbility; import mage.abilities.mana.RedManaAbility; import mage.abilities.mana.WhiteManaAbility; import mage.cards.CardImpl; -import mage.choices.ChoiceImpl; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.Layer; +import mage.constants.Outcome; +import mage.constants.Rarity; +import mage.constants.SubLayer; +import mage.constants.Zone; import mage.game.Game; import mage.game.permanent.Permanent; -import mage.players.Player; import mage.target.TargetPermanent; import mage.target.common.TargetLandPermanent; @@ -67,13 +64,12 @@ public class ConvincingMirage extends CardImpl { this.expansionSetCode = "M10"; this.subtype.add("Aura"); - // Enchant land TargetPermanent auraTarget = new TargetLandPermanent(); this.getSpellAbility().addTarget(auraTarget); this.getSpellAbility().addEffect(new AttachEffect(Outcome.Detriment)); // As Convincing Mirage enters the battlefield, choose a basic land type. - this.addAbility(new AsEntersBattlefieldAbility(new ConvincingMirageEffect())); + this.addAbility(new AsEntersBattlefieldAbility(new ChooseBasicLandTypeEffect(Outcome.Neutral))); // Enchanted land is the chosen type. Ability ability = new EnchantAbility(auraTarget.getTargetName()); this.addAbility(ability); @@ -90,42 +86,6 @@ public class ConvincingMirage extends CardImpl { } } -class ConvincingMirageEffect extends OneShotEffect { - - public ConvincingMirageEffect() { - super(Outcome.Neutral); - this.staticText = "choose a basic land type"; - } - - public ConvincingMirageEffect(final ConvincingMirageEffect effect) { - super(effect); - } - - @Override - public ConvincingMirageEffect copy() { - return new ConvincingMirageEffect(this); - } - - @Override - public boolean apply(Game game, Ability source) { - Player player = game.getPlayer(source.getControllerId()); - if (player != null) { - ChoiceImpl choices = new ChoiceImpl(true); - Set choicesSet = choices.getChoices(); - choicesSet.add("Forest"); - choicesSet.add("Plains"); - choicesSet.add("Mountain"); - choicesSet.add("Island"); - choicesSet.add("Swamp"); - if (player.choose(Outcome.Neutral, choices, game)) { - game.getState().setValue(source.getSourceId().toString() + "_ConvincingMirage", choices.getChoice()); - return true; - } - } - return false; - } -} - class ConvincingMirageContinousEffect extends ContinuousEffectImpl { public ConvincingMirageContinousEffect() { @@ -145,7 +105,7 @@ class ConvincingMirageContinousEffect extends ContinuousEffectImpl { @Override public boolean apply(Layer layer, SubLayer sublayer, Ability source, Game game) { Permanent enchantment = game.getPermanent(source.getSourceId()); - String choice = (String) game.getState().getValue(source.getSourceId().toString() + "_ConvincingMirage"); + String choice = (String) game.getState().getValue(source.getSourceId().toString() + ChooseBasicLandTypeEffect.VALUE_KEY); if (enchantment != null && enchantment.getAttachedTo() != null && choice != null) { Permanent land = game.getPermanent(enchantment.getAttachedTo()); if (land != null) { @@ -160,19 +120,19 @@ class ConvincingMirageContinousEffect extends ContinuousEffectImpl { if (sublayer == SubLayer.NA) { land.getAbilities().clear(); if (choice.equals("Forest")) { - land.addAbility(new GreenManaAbility(), game); + land.addAbility(new GreenManaAbility(), source.getSourceId(), game); } if (choice.equals("Plains")) { - land.addAbility(new WhiteManaAbility(), game); + land.addAbility(new WhiteManaAbility(), source.getSourceId(), game); } if (choice.equals("Mountain")) { - land.addAbility(new RedManaAbility(), game); + land.addAbility(new RedManaAbility(), source.getSourceId(), game); } if (choice.equals("Island")) { - land.addAbility(new BlueManaAbility(), game); + land.addAbility(new BlueManaAbility(), source.getSourceId(), game); } if (choice.equals("Swamp")) { - land.addAbility(new BlackManaAbility(), game); + land.addAbility(new BlackManaAbility(), source.getSourceId(), game); } } break; @@ -192,4 +152,4 @@ class ConvincingMirageContinousEffect extends ContinuousEffectImpl { public boolean hasLayer(Layer layer) { return layer == Layer.AbilityAddingRemovingEffects_6 || layer == Layer.TypeChangingEffects_4; } -} \ No newline at end of file +} diff --git a/Mage.Sets/src/mage/sets/magic2012/SuturedGhoul.java b/Mage.Sets/src/mage/sets/magic2012/SuturedGhoul.java index 42a2b16593f..44cc9264d27 100644 --- a/Mage.Sets/src/mage/sets/magic2012/SuturedGhoul.java +++ b/Mage.Sets/src/mage/sets/magic2012/SuturedGhoul.java @@ -27,26 +27,32 @@ */ package mage.sets.magic2012; +import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.AsEntersBattlefieldAbility; import mage.abilities.common.SimpleStaticAbility; import mage.abilities.dynamicvalue.DynamicValue; import mage.abilities.effects.Effect; +import mage.abilities.effects.EntersBattlefieldEffect; import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.continuous.BoostSourceEffect; import mage.abilities.keyword.TrampleAbility; import mage.cards.Card; import mage.cards.CardImpl; -import mage.constants.*; +import mage.cards.Cards; +import mage.cards.CardsImpl; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.Outcome; +import mage.constants.Rarity; +import mage.constants.Zone; import mage.filter.common.FilterCreatureCard; import mage.game.Game; import mage.game.permanent.Permanent; import mage.players.Player; import mage.target.common.TargetCardInYourGraveyard; -import java.util.UUID; - /** * @author nantuko */ @@ -97,30 +103,32 @@ class SuturedGhoulEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { - Player player = game.getPlayer(source.getControllerId()); - Permanent permanent = game.getPermanent(source.getSourceId()); - if (player.getGraveyard().size() > 0) { - + Player controller = game.getPlayer(source.getControllerId()); + Permanent permanent = (Permanent) getValue(EntersBattlefieldEffect.ENTERING_PERMANENT); + if (permanent == null) { + return false; + } + if (controller.getGraveyard().size() > 0) { TargetCardInYourGraveyard target = new TargetCardInYourGraveyard(0, Integer.MAX_VALUE, new FilterCreatureCard("creature cards from your graveyard")); - if (player.chooseTarget(Outcome.Benefit, target, source, game)) { + if (controller.chooseTarget(Outcome.Benefit, target, source, game)) { int count = 0; for (UUID uuid : target.getTargets()) { - Card card = player.getGraveyard().get(uuid, game); + Card card = controller.getGraveyard().get(uuid, game); if (card != null) { - card.moveToExile(getId(), "Sutured Ghoul", source.getSourceId(), game); - if (permanent != null) { - permanent.imprint(card.getId(), game); - count++; - } + card.moveToExile(getId(), permanent.getIdName(), source.getSourceId(), game); + permanent.imprint(card.getId(), game); + count++; } } + Cards cardsToExile = new CardsImpl(target.getTargets()); + controller.moveCards(cardsToExile, null, Zone.EXILED, source, game); String msg = count == 1 ? "1 card" : count + "cards"; - game.informPlayers("Sutured Ghoul: " + player.getLogName() + " exiled " + msg); + game.informPlayers(permanent.getLogName() + ": " + controller.getLogName() + " exiled " + msg); } } else { - game.informPlayers("Sutured Ghoul: No cards in graveyard."); + game.informPlayers(permanent.getLogName() + ": No cards in graveyard."); } return true; } @@ -147,7 +155,7 @@ class SuturedGhoulPowerCount implements DynamicValue { int amount = 0; Permanent permanent = game.getPermanent(sourceAbility.getSourceId()); if (permanent != null) { - for (UUID uuid: permanent.getImprinted()) { + for (UUID uuid : permanent.getImprinted()) { Card card = game.getCard(uuid); if (card != null) { amount += card.getPower().getValue(); @@ -189,7 +197,7 @@ class SuturedGhoulToughnessCount implements DynamicValue { int amount = 0; Permanent permanent = game.getPermanent(sourceAbility.getSourceId()); if (permanent != null) { - for (UUID uuid: permanent.getImprinted()) { + for (UUID uuid : permanent.getImprinted()) { Card card = game.getCard(uuid); if (card != null) { amount += card.getToughness().getValue(); @@ -214,5 +222,3 @@ class SuturedGhoulToughnessCount implements DynamicValue { return "the total toughness of the exiled cards"; } } - - diff --git a/Mage.Sets/src/mage/sets/returntoravnica/TabletOfTheGuilds.java b/Mage.Sets/src/mage/sets/returntoravnica/TabletOfTheGuilds.java index ffe0df331bd..c13d4cf6131 100644 --- a/Mage.Sets/src/mage/sets/returntoravnica/TabletOfTheGuilds.java +++ b/Mage.Sets/src/mage/sets/returntoravnica/TabletOfTheGuilds.java @@ -28,17 +28,17 @@ package mage.sets.returntoravnica; import java.util.UUID; - -import mage.constants.CardType; -import mage.constants.Outcome; -import mage.constants.Rarity; import mage.ObjectColor; import mage.abilities.Ability; import mage.abilities.common.AsEntersBattlefieldAbility; import mage.abilities.common.SpellCastControllerTriggeredAbility; +import mage.abilities.effects.EntersBattlefieldEffect; import mage.abilities.effects.OneShotEffect; import mage.cards.CardImpl; import mage.choices.ChoiceColor; +import mage.constants.CardType; +import mage.constants.Outcome; +import mage.constants.Rarity; import mage.filter.FilterSpell; import mage.game.Game; import mage.game.permanent.Permanent; @@ -59,7 +59,7 @@ public class TabletOfTheGuilds extends CardImpl { this.addAbility(new AsEntersBattlefieldAbility(new TabletOfTheGuildsEntersBattlefieldEffect())); // Whenever you cast a spell, if it's at least one of the chosen colors, you gain 1 life for each of the chosen colors it is. - this.addAbility(new SpellCastControllerTriggeredAbility(new TabletOfTheGuildsGainLifeEffect(), new FilterSpell("a spell"), false, true )); + this.addAbility(new SpellCastControllerTriggeredAbility(new TabletOfTheGuildsGainLifeEffect(), new FilterSpell("a spell"), false, true)); } public TabletOfTheGuilds(final TabletOfTheGuilds card) { @@ -86,7 +86,7 @@ class TabletOfTheGuildsEntersBattlefieldEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { Player player = game.getPlayer(source.getControllerId()); - Permanent permanent = game.getPermanent(source.getSourceId()); + Permanent permanent = (Permanent) getValue(EntersBattlefieldEffect.ENTERING_PERMANENT); if (player != null && permanent != null) { String colors; ChoiceColor colorChoice = new ChoiceColor(); @@ -101,7 +101,7 @@ class TabletOfTheGuildsEntersBattlefieldEffect extends OneShotEffect { colorChoice.getChoices().remove(colorChoice.getChoice()); colorChoice.setMessage("Choose the second color"); - while (!player.choose(Outcome.GainLife, colorChoice, game) && player.canRespond()) { + while (!player.choose(Outcome.GainLife, colorChoice, game) && player.canRespond()) { game.debugMessage("player canceled choosing type. retrying."); } game.getState().setValue(permanent.getId() + "_color2", colorChoice.getColor().toString()); @@ -157,4 +157,4 @@ class TabletOfTheGuildsGainLifeEffect extends OneShotEffect { public TabletOfTheGuildsGainLifeEffect copy() { return new TabletOfTheGuildsGainLifeEffect(this); } -} \ No newline at end of file +} diff --git a/Mage.Sets/src/mage/sets/riseoftheeldrazi/CurseOfWizardry.java b/Mage.Sets/src/mage/sets/riseoftheeldrazi/CurseOfWizardry.java index bd4d6e4b53f..db2d0e39027 100644 --- a/Mage.Sets/src/mage/sets/riseoftheeldrazi/CurseOfWizardry.java +++ b/Mage.Sets/src/mage/sets/riseoftheeldrazi/CurseOfWizardry.java @@ -29,13 +29,11 @@ package mage.sets.riseoftheeldrazi; import java.util.UUID; import mage.ObjectColor; -import mage.abilities.Ability; import mage.abilities.TriggeredAbilityImpl; import mage.abilities.common.AsEntersBattlefieldAbility; -import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.ChooseColorEffect; import mage.abilities.effects.common.LoseLifeTargetEffect; import mage.cards.CardImpl; -import mage.choices.ChoiceColor; import mage.constants.CardType; import mage.constants.Outcome; import mage.constants.Rarity; @@ -45,7 +43,6 @@ import mage.game.events.GameEvent; import mage.game.events.GameEvent.EventType; import mage.game.permanent.Permanent; import mage.game.stack.Spell; -import mage.players.Player; import mage.target.targetpointer.FixedTarget; /** @@ -57,9 +54,8 @@ public class CurseOfWizardry extends CardImpl { super(ownerId, 104, "Curse of Wizardry", Rarity.UNCOMMON, new CardType[]{CardType.ENCHANTMENT}, "{2}{B}{B}"); this.expansionSetCode = "ROE"; - // As Curse of Wizardry enters the battlefield, choose a color. - this.addAbility(new AsEntersBattlefieldAbility(new CurseOfWizardryChooseColorEffect())); + this.addAbility(new AsEntersBattlefieldAbility(new ChooseColorEffect(Outcome.Neutral))); // Whenever a player casts a spell of the chosen color, that player loses 1 life. this.addAbility(new CurseOfWizardryPlayerCastsSpellChosenColorTriggeredAbility()); @@ -76,38 +72,6 @@ public class CurseOfWizardry extends CardImpl { } } -class CurseOfWizardryChooseColorEffect extends OneShotEffect { - - public CurseOfWizardryChooseColorEffect() { - super(Outcome.Detriment); - staticText = "choose a color"; - } - - public CurseOfWizardryChooseColorEffect(final CurseOfWizardryChooseColorEffect effect) { - super(effect); - } - - @Override - public boolean apply(Game game, Ability source) { - Player player = game.getPlayer(source.getControllerId()); - Permanent curseOfWizardry = game.getPermanent(source.getSourceId()); - if (player != null && curseOfWizardry != null) { - ChoiceColor colorChoice = new ChoiceColor(); - if (player.choose(Outcome.Detriment, colorChoice, game)) { - game.informPlayers(curseOfWizardry.getName() + ": " + player.getLogName() + " has chosen " + colorChoice.getChoice()); - game.getState().setValue(curseOfWizardry.getId() + "_color", colorChoice.getColor()); - curseOfWizardry.addInfo("chosen color", "Chosen color: " + colorChoice.getColor().getDescription() + "", game); - } - } - return false; - } - - @Override - public CurseOfWizardryChooseColorEffect copy() { - return new CurseOfWizardryChooseColorEffect(this); - } -} - class CurseOfWizardryPlayerCastsSpellChosenColorTriggeredAbility extends TriggeredAbilityImpl { public CurseOfWizardryPlayerCastsSpellChosenColorTriggeredAbility() { diff --git a/Mage.Sets/src/mage/sets/shadowmoor/LureboundScarecrow.java b/Mage.Sets/src/mage/sets/shadowmoor/LureboundScarecrow.java index 1964cd1cc43..ba232975d03 100644 --- a/Mage.Sets/src/mage/sets/shadowmoor/LureboundScarecrow.java +++ b/Mage.Sets/src/mage/sets/shadowmoor/LureboundScarecrow.java @@ -32,9 +32,11 @@ import mage.MageInt; import mage.ObjectColor; import mage.abilities.StateTriggeredAbility; import mage.abilities.common.AsEntersBattlefieldAbility; +import mage.abilities.effects.common.ChooseColorEffect; import mage.abilities.effects.common.SacrificeSourceEffect; import mage.cards.CardImpl; import mage.constants.CardType; +import mage.constants.Outcome; import mage.constants.Rarity; import mage.constants.Zone; import mage.game.Game; @@ -56,7 +58,7 @@ public class LureboundScarecrow extends CardImpl { this.toughness = new MageInt(4); // As Lurebound Scarecrow enters the battlefield, choose a color. - this.addAbility(new AsEntersBattlefieldAbility(new ChooseColorEffect())); + this.addAbility(new AsEntersBattlefieldAbility(new ChooseColorEffect(Outcome.Detriment))); // When you control no permanents of the chosen color, sacrifice Lurebound Scarecrow. this.addAbility(new LureboundScarecrowTriggeredAbility()); diff --git a/Mage.Sets/src/mage/sets/shadowmoor/PaintersServant.java b/Mage.Sets/src/mage/sets/shadowmoor/PaintersServant.java index 10364727e8c..8ec07fbc98f 100644 --- a/Mage.Sets/src/mage/sets/shadowmoor/PaintersServant.java +++ b/Mage.Sets/src/mage/sets/shadowmoor/PaintersServant.java @@ -35,10 +35,9 @@ import mage.abilities.Ability; import mage.abilities.common.AsEntersBattlefieldAbility; import mage.abilities.common.SimpleStaticAbility; import mage.abilities.effects.ContinuousEffectImpl; -import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.ChooseColorEffect; import mage.cards.Card; import mage.cards.CardImpl; -import mage.choices.ChoiceColor; import mage.constants.CardType; import mage.constants.Duration; import mage.constants.Layer; @@ -68,7 +67,7 @@ public class PaintersServant extends CardImpl { this.toughness = new MageInt(3); // As Painter's Servant enters the battlefield, choose a color. - this.addAbility(new AsEntersBattlefieldAbility(new ChooseColorEffect())); + this.addAbility(new AsEntersBattlefieldAbility(new ChooseColorEffect(Outcome.Detriment))); // All cards that aren't on the battlefield, spells, and permanents are the chosen color in addition to their other colors. this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new PaintersServantEffect())); @@ -84,40 +83,6 @@ public class PaintersServant extends CardImpl { } } -class ChooseColorEffect extends OneShotEffect { - - public ChooseColorEffect() { - super(Outcome.Detriment); - staticText = "choose a color"; - } - - public ChooseColorEffect(final ChooseColorEffect effect) { - super(effect); - } - - @Override - public boolean apply(Game game, Ability source) { - Player player = game.getPlayer(source.getControllerId()); - Permanent permanent = game.getPermanent(source.getSourceId()); - if (player != null && permanent != null) { - ChoiceColor colorChoice = new ChoiceColor(); - if (player.choose(Outcome.Neutral, colorChoice, game)) { - game.informPlayers(new StringBuilder(permanent.getName()).append(": ").append(player.getLogName()).append(" has chosen ").append(colorChoice.getChoice()).toString()); - game.getState().setValue(source.getSourceId() + "_color", colorChoice.getColor()); - permanent.addInfo("chosen color", "Chosen color: " + colorChoice.getColor().getDescription() + "", game); - } - return true; - } - return false; - } - - @Override - public ChooseColorEffect copy() { - return new ChooseColorEffect(this); - } - -} - class PaintersServantEffect extends ContinuousEffectImpl { public PaintersServantEffect() { @@ -175,10 +140,10 @@ class PaintersServantEffect extends ContinuousEffectImpl { } return false; } - + protected static void setCardColor(Card card, String colorString, Game game) { ObjectColor color = game.getState().getCreateCardAttribute(card).getColor(); - switch (colorString) { + switch (colorString) { case "W": color.setWhite(true); break; diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/single/avr/CavernOfSoulsTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/single/avr/CavernOfSoulsTest.java index eb69c8b1c41..5062c9244ab 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/single/avr/CavernOfSoulsTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/single/avr/CavernOfSoulsTest.java @@ -33,8 +33,9 @@ public class CavernOfSoulsTest extends CardTestPlayerBase { } /** - * Tests "Cavern of Souls" with "Human" creature type chosen. - * Then tests casting Azure Drake (should fail) and Elite Vanguard (should be ok as it has "Human" subtype) + * Tests "Cavern of Souls" with "Human" creature type chosen. Then tests + * casting Azure Drake (should fail) and Elite Vanguard (should be ok as it + * has "Human" subtype) */ @Test public void testNoCastBecauseOfCreatureType() { @@ -87,6 +88,9 @@ public class CavernOfSoulsTest extends CardTestPlayerBase { @Test public void testDrakeCantBeCountered() { addCard(Zone.BATTLEFIELD, playerA, "Mountain", 3); + // As Cavern of Souls enters the battlefield, choose a creature type. + // {T}: Add {1} to your mana pool. + // {T}: Add one mana of any color to your mana pool. Spend this mana only to cast a creature spell of the chosen type, and that spell can't be countered. addCard(Zone.HAND, playerA, "Cavern of Souls"); addCard(Zone.HAND, playerA, "Azure Drake"); @@ -108,6 +112,7 @@ public class CavernOfSoulsTest extends CardTestPlayerBase { assertGraveyardCount(playerA, "Azure Drake", 0); assertPermanentCount(playerA, "Azure Drake", 1); } + /** * Tests spell can be countered if cast with colorless mana from Cavern */ @@ -136,59 +141,59 @@ public class CavernOfSoulsTest extends CardTestPlayerBase { assertGraveyardCount(playerA, "Azure Drake", 1); assertPermanentCount(playerA, "Azure Drake", 0); } - + /** - * Tests conditional mana from Cavern in pool will still work if Cavern got back to hand and is played again with other creature type + * Tests conditional mana from Cavern in pool will still work if Cavern got + * back to hand and is played again with other creature type */ @Test public void testConditionlManaWorksIfCavernIsReplayed() { addCard(Zone.HAND, playerA, "Cavern of Souls"); addCard(Zone.HAND, playerA, "Gladecover Scout"); // Elf costing {G} // addCard(Zone.HAND, playerA, "Fume Spitter"); // Horror costing {B} - + // Instant - {U}{U} - Return target permanent to its owner's hand. addCard(Zone.HAND, playerB, "Boomerang"); addCard(Zone.BATTLEFIELD, playerB, "Island", 2); playLand(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Cavern of Souls"); setChoice(playerA, "Elf"); - + // getting green mana for Elf into pool activateManaAbility(3, PhaseStep.PRECOMBAT_MAIN, playerA, "{T}: Add 1 mana of any one color to your mana pool. Spend this mana only to cast a creature spell of the chosen type, and that spell can't be countered."); - setChoice(playerA, "Green"); - + setChoice(playerA, "Green"); + // return cavern to hand castSpell(3, PhaseStep.PRECOMBAT_MAIN, playerB, "Boomerang", "Cavern of Souls"); - + // playing the cavern again choose different creature type playLand(3, PhaseStep.PRECOMBAT_MAIN, playerA, "Cavern of Souls"); setChoice(playerA, "Horror"); - // the green mana usable for Elf should be in the mana pool + // the green mana usable for Elf should be in the mana pool castSpell(3, PhaseStep.PRECOMBAT_MAIN, playerA, "Gladecover Scout"); activateManaAbility(3, PhaseStep.PRECOMBAT_MAIN, playerA, "{T}: Add 1 mana of any one color to your mana pool. Spend this mana only to cast a creature spell of the chosen type, and that spell can't be countered."); - setChoice(playerA, "Black"); + setChoice(playerA, "Black"); - // the black mana usable for Horror should be in the mana pool + // the black mana usable for Horror should be in the mana pool // castSpell(3, PhaseStep.PRECOMBAT_MAIN, playerA, "Fume Spitter"); - setStopAt(3, PhaseStep.BEGIN_COMBAT); execute(); - assertGraveyardCount(playerB, "Boomerang", 1); assertPermanentCount(playerA, "Cavern of Souls", 1); - + // Check the elf was cast assertPermanentCount(playerA, "Gladecover Scout", 1); // Check Horror on the Battlefield // assertPermanentCount(playerA, "Fume Spitter", 1); - } + } /** - * Return to the Ranks cannot be countered if mana produced by Cavern of Souls - * was used to pay X. Can be bug also for all other spells with X in their cost, not sure. + * Return to the Ranks cannot be countered if mana produced by Cavern of + * Souls was used to pay X. Can be bug also for all other spells with X in + * their cost, not sure. * */ @Test @@ -205,12 +210,11 @@ public class CavernOfSoulsTest extends CardTestPlayerBase { addCard(Zone.HAND, playerB, "Counterspell"); addCard(Zone.BATTLEFIELD, playerB, "Island", 2); - playLand(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Cavern of Souls"); setChoice(playerA, "Drake"); castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Return to the Ranks", "Silvercoat Lion"); setChoice(playerA, "X=1"); - + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerB, "Counterspell", "Return to the Ranks"); setStopAt(1, PhaseStep.BEGIN_COMBAT); @@ -223,11 +227,12 @@ public class CavernOfSoulsTest extends CardTestPlayerBase { assertPermanentCount(playerA, "Silvercoat Lion", 0); } - + /** - * Cavern of Souls can produce any colour of mana with its second ability when Contamination is in play. + * Cavern of Souls can produce any colour of mana with its second ability + * when Contamination is in play. */ - @Test + @Test public void testUseWithConversionInPlay() { addCard(Zone.BATTLEFIELD, playerA, "Plains", 3); addCard(Zone.HAND, playerA, "Cavern of Souls"); @@ -235,8 +240,6 @@ public class CavernOfSoulsTest extends CardTestPlayerBase { addCard(Zone.HAND, playerA, "Desert Drake"); addCard(Zone.BATTLEFIELD, playerB, "Contamination", 1); - - playLand(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Cavern of Souls"); setChoice(playerA, "Drake"); @@ -249,5 +252,5 @@ public class CavernOfSoulsTest extends CardTestPlayerBase { assertPermanentCount(playerA, "Desert Drake", 0); } - + } diff --git a/Mage/src/mage/abilities/effects/common/ChooseBasicLandTypeEffect.java b/Mage/src/mage/abilities/effects/common/ChooseBasicLandTypeEffect.java new file mode 100644 index 00000000000..07c1e706e9b --- /dev/null +++ b/Mage/src/mage/abilities/effects/common/ChooseBasicLandTypeEffect.java @@ -0,0 +1,68 @@ +/* + * To change this license header, choose License Headers in Project Properties. + * To change this template file, choose Tools | Templates + * and open the template in the editor. + */ +package mage.abilities.effects.common; + +import mage.MageObject; +import mage.abilities.Ability; +import mage.abilities.effects.EntersBattlefieldEffect; +import mage.abilities.effects.OneShotEffect; +import mage.choices.ChoiceImpl; +import mage.constants.Outcome; +import mage.game.Game; +import mage.game.permanent.Permanent; +import mage.players.Player; +import mage.util.CardUtil; + +/** + * + * @author LevelX2 + */ +public class ChooseBasicLandTypeEffect extends OneShotEffect { + + public static String VALUE_KEY = "BasicLandType"; + + public ChooseBasicLandTypeEffect(Outcome outcome) { + super(outcome); + this.staticText = "Choose a basic land type"; + } + + public ChooseBasicLandTypeEffect(final ChooseBasicLandTypeEffect effect) { + super(effect); + } + + @Override + public ChooseBasicLandTypeEffect copy() { + return new ChooseBasicLandTypeEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player controller = game.getPlayer(source.getControllerId()); + MageObject mageObject = (Permanent) getValue(EntersBattlefieldEffect.ENTERING_PERMANENT); + if (mageObject == null) { + mageObject = game.getObject(source.getSourceId()); + } + if (controller != null && mageObject != null) { + ChoiceImpl choices = new ChoiceImpl(true); + choices.setMessage("Choose basic land type"); + choices.isRequired(); + choices.getChoices().add("Forest"); + choices.getChoices().add("Plains"); + choices.getChoices().add("Mountain"); + choices.getChoices().add("Island"); + choices.getChoices().add("Swamp"); + if (controller.choose(Outcome.Neutral, choices, game)) { + game.informPlayers(mageObject.getName() + ": Chosen basic land type is " + choices.getChoice()); + game.getState().setValue(mageObject.getId().toString() + VALUE_KEY, choices.getChoice()); + if (mageObject instanceof Permanent) { + ((Permanent) mageObject).addInfo("chosen color", CardUtil.addToolTipMarkTags("Chosen basic land type: " + choices.getChoice()), game); + } + return true; + } + } + return false; + } +} diff --git a/Mage/src/mage/abilities/effects/common/ChooseColorEffect.java b/Mage/src/mage/abilities/effects/common/ChooseColorEffect.java index 43836dd2f74..2fe01116753 100644 --- a/Mage/src/mage/abilities/effects/common/ChooseColorEffect.java +++ b/Mage/src/mage/abilities/effects/common/ChooseColorEffect.java @@ -27,6 +27,7 @@ */ package mage.abilities.effects.common; +import mage.MageObject; import mage.abilities.Ability; import mage.abilities.effects.EntersBattlefieldEffect; import mage.abilities.effects.OneShotEffect; @@ -55,11 +56,11 @@ public class ChooseColorEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { Player controller = game.getPlayer(source.getControllerId()); - Permanent permanent = game.getPermanent(source.getSourceId()); - if (permanent == null) { - permanent = (Permanent) getValue(EntersBattlefieldEffect.ENTERING_PERMANENT); + MageObject mageObject = (Permanent) getValue(EntersBattlefieldEffect.ENTERING_PERMANENT); + if (mageObject == null) { + mageObject = game.getObject(source.getSourceId()); } - if (controller != null && permanent != null) { + if (controller != null && mageObject != null) { ChoiceColor choice = new ChoiceColor(); while (!choice.isChosen()) { controller.choose(outcome, choice, game); @@ -68,10 +69,12 @@ public class ChooseColorEffect extends OneShotEffect { } } if (!game.isSimulation()) { - game.informPlayers(permanent.getLogName() + ": " + controller.getLogName() + " has chosen " + choice.getChoice()); + game.informPlayers(mageObject.getLogName() + ": " + controller.getLogName() + " has chosen " + choice.getChoice()); + } + game.getState().setValue(mageObject.getId() + "_color", choice.getColor()); + if (mageObject instanceof Permanent) { + ((Permanent) mageObject).addInfo("chosen color", CardUtil.addToolTipMarkTags("Chosen color: " + choice.getChoice()), game); } - game.getState().setValue(source.getSourceId() + "_color", choice.getColor()); - permanent.addInfo("chosen color", CardUtil.addToolTipMarkTags("Chosen color: " + choice.getChoice()), game); return true; } return false; diff --git a/Mage/src/mage/abilities/effects/common/ChooseCreatureTypeEffect.java b/Mage/src/mage/abilities/effects/common/ChooseCreatureTypeEffect.java index 2ebd99cc9d2..06178b02843 100644 --- a/Mage/src/mage/abilities/effects/common/ChooseCreatureTypeEffect.java +++ b/Mage/src/mage/abilities/effects/common/ChooseCreatureTypeEffect.java @@ -27,7 +27,9 @@ */ package mage.abilities.effects.common; +import mage.MageObject; import mage.abilities.Ability; +import mage.abilities.effects.EntersBattlefieldEffect; import mage.abilities.effects.OneShotEffect; import mage.cards.repository.CardRepository; import mage.choices.Choice; @@ -42,7 +44,6 @@ import mage.util.CardUtil; * * @author LevelX2 */ - public class ChooseCreatureTypeEffect extends OneShotEffect { public ChooseCreatureTypeEffect(Outcome outcome) { @@ -57,8 +58,11 @@ public class ChooseCreatureTypeEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { Player controller = game.getPlayer(source.getControllerId()); - Permanent permanent = game.getPermanent(source.getSourceId()); - if (controller != null && permanent != null) { + MageObject mageObject = (Permanent) getValue(EntersBattlefieldEffect.ENTERING_PERMANENT); + if (mageObject == null) { + mageObject = game.getObject(source.getSourceId()); + } + if (controller != null && mageObject != null) { Choice typeChoice = new ChoiceImpl(true); typeChoice.setMessage("Choose creature type"); typeChoice.setChoices(CardRepository.instance.getCreatureTypes()); @@ -68,10 +72,12 @@ public class ChooseCreatureTypeEffect extends OneShotEffect { } } if (!game.isSimulation()) { - game.informPlayers(permanent.getName() + ": " + controller.getLogName() + " has chosen " + typeChoice.getChoice()); + game.informPlayers(mageObject.getName() + ": " + controller.getLogName() + " has chosen " + typeChoice.getChoice()); + } + game.getState().setValue(mageObject.getId() + "_type", typeChoice.getChoice()); + if (mageObject instanceof Permanent) { + ((Permanent) mageObject).addInfo("chosen type", CardUtil.addToolTipMarkTags("Chosen type: " + typeChoice.getChoice()), game); } - game.getState().setValue(permanent.getId() + "_type", typeChoice.getChoice()); - permanent.addInfo("chosen type", CardUtil.addToolTipMarkTags("Chosen type: " + typeChoice.getChoice()), game); } return false; } diff --git a/Mage/src/mage/abilities/effects/common/ChooseLandTypeEffect.java b/Mage/src/mage/abilities/effects/common/ChooseLandTypeEffect.java index 0480effa493..52259dbac52 100644 --- a/Mage/src/mage/abilities/effects/common/ChooseLandTypeEffect.java +++ b/Mage/src/mage/abilities/effects/common/ChooseLandTypeEffect.java @@ -5,7 +5,9 @@ */ package mage.abilities.effects.common; +import mage.MageObject; import mage.abilities.Ability; +import mage.abilities.effects.EntersBattlefieldEffect; import mage.abilities.effects.OneShotEffect; import mage.cards.repository.CardRepository; import mage.choices.Choice; @@ -34,8 +36,11 @@ public class ChooseLandTypeEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { Player controller = game.getPlayer(source.getControllerId()); - Permanent permanent = game.getPermanent(source.getSourceId()); - if (controller != null && permanent != null) { + MageObject mageObject = (Permanent) getValue(EntersBattlefieldEffect.ENTERING_PERMANENT); + if (mageObject == null) { + mageObject = game.getObject(source.getSourceId()); + } + if (controller != null && mageObject != null) { Choice typeChoice = new ChoiceImpl(true); typeChoice.setMessage("Choose land type"); typeChoice.setChoices(CardRepository.instance.getLandTypes()); @@ -45,10 +50,12 @@ public class ChooseLandTypeEffect extends OneShotEffect { } } if (!game.isSimulation()) { - game.informPlayers(permanent.getName() + ": " + controller.getLogName() + " has chosen " + typeChoice.getChoice()); + game.informPlayers(mageObject.getName() + ": " + controller.getLogName() + " has chosen " + typeChoice.getChoice()); + } + game.getState().setValue(mageObject.getId() + "_type", typeChoice.getChoice()); + if (mageObject instanceof Permanent) { + ((Permanent) mageObject).addInfo("chosen type", CardUtil.addToolTipMarkTags("Chosen type: " + typeChoice.getChoice()), game); } - game.getState().setValue(permanent.getId() + "_type", typeChoice.getChoice()); - permanent.addInfo("chosen type", CardUtil.addToolTipMarkTags("Chosen type: " + typeChoice.getChoice()), game); } return false; } diff --git a/Mage/src/mage/abilities/effects/common/ChooseNewTargetsTargetEffect.java b/Mage/src/mage/abilities/effects/common/ChooseNewTargetsTargetEffect.java index 265b66e9cdd..35ac9818cd5 100644 --- a/Mage/src/mage/abilities/effects/common/ChooseNewTargetsTargetEffect.java +++ b/Mage/src/mage/abilities/effects/common/ChooseNewTargetsTargetEffect.java @@ -1,38 +1,36 @@ /* -* 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 mage.constants.Outcome; import mage.abilities.Ability; import mage.abilities.Mode; import mage.abilities.effects.OneShotEffect; -import mage.filter.Filter; +import mage.constants.Outcome; import mage.filter.FilterPermanent; import mage.game.Game; import mage.game.stack.StackObject; @@ -46,21 +44,22 @@ public class ChooseNewTargetsTargetEffect extends OneShotEffect { private boolean forceChange; private boolean onlyOneTarget; private FilterPermanent filterNewTarget; - + public ChooseNewTargetsTargetEffect() { this(false, false); } + public ChooseNewTargetsTargetEffect(boolean forceChange, boolean onlyOneTarget) { this(forceChange, onlyOneTarget, null); } /** * - * @param forceChange forces the user to choose another target (only targets with maxtargets = 1 supported) + * @param forceChange forces the user to choose another target (only targets + * with maxtargets = 1 supported) * @param onlyOneTarget only one target can be selected for the change * @param filterNewTarget restriction to the new target */ - public ChooseNewTargetsTargetEffect(boolean forceChange, boolean onlyOneTarget, FilterPermanent filterNewTarget) { super(Outcome.Benefit); this.forceChange = forceChange; diff --git a/Mage/src/mage/abilities/effects/common/ChooseOpponentEffect.java b/Mage/src/mage/abilities/effects/common/ChooseOpponentEffect.java new file mode 100644 index 00000000000..9ac1910128e --- /dev/null +++ b/Mage/src/mage/abilities/effects/common/ChooseOpponentEffect.java @@ -0,0 +1,64 @@ +/* + * To change this license header, choose License Headers in Project Properties. + * To change this template file, choose Tools | Templates + * and open the template in the editor. + */ +package mage.abilities.effects.common; + +import mage.MageObject; +import mage.abilities.Ability; +import mage.abilities.effects.EntersBattlefieldEffect; +import mage.abilities.effects.OneShotEffect; +import mage.constants.Outcome; +import mage.game.Game; +import mage.game.permanent.Permanent; +import mage.players.Player; +import mage.target.common.TargetOpponent; +import mage.util.CardUtil; + +/** + * + * @author LevelX2 + */ +public class ChooseOpponentEffect extends OneShotEffect { + + public static String VALUE_KEY = "_opponent"; + + public ChooseOpponentEffect(Outcome outcome) { + super(outcome); + this.staticText = "choose an opponent"; + } + + public ChooseOpponentEffect(final ChooseOpponentEffect effect) { + super(effect); + } + + @Override + public ChooseOpponentEffect copy() { + return new ChooseOpponentEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player controller = game.getPlayer(source.getControllerId()); + MageObject mageObject = (Permanent) getValue(EntersBattlefieldEffect.ENTERING_PERMANENT); + if (mageObject == null) { + mageObject = game.getObject(source.getSourceId()); + } + if (controller != null && mageObject != null) { + TargetOpponent target = new TargetOpponent(true); + if (controller.choose(this.outcome, target, source.getSourceId(), game)) { + Player chosenPlayer = game.getPlayer(target.getFirstTarget()); + if (chosenPlayer != null) { + game.informPlayers(mageObject.getName() + ": " + controller.getLogName() + " has chosen " + chosenPlayer.getLogName()); + game.getState().setValue(mageObject.getId() + VALUE_KEY, target.getFirstTarget()); + if (mageObject instanceof Permanent) { + ((Permanent) mageObject).addInfo("chosen opponent", CardUtil.addToolTipMarkTags("Chosen player: " + chosenPlayer.getLogName()), game); + } + return true; + } + } + } + return false; + } +} diff --git a/Mage/src/mage/abilities/effects/common/ChoosePlayerEffect.java b/Mage/src/mage/abilities/effects/common/ChoosePlayerEffect.java index 9f4481515c5..7e5c6402c1b 100644 --- a/Mage/src/mage/abilities/effects/common/ChoosePlayerEffect.java +++ b/Mage/src/mage/abilities/effects/common/ChoosePlayerEffect.java @@ -5,7 +5,9 @@ */ package mage.abilities.effects.common; +import mage.MageObject; import mage.abilities.Ability; +import mage.abilities.effects.EntersBattlefieldEffect; import mage.abilities.effects.OneShotEffect; import mage.constants.Outcome; import mage.game.Game; @@ -36,16 +38,21 @@ public class ChoosePlayerEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { - Player player = game.getPlayer(source.getControllerId()); - Permanent permanent = game.getPermanent(source.getSourceId()); - if (player != null && permanent != null) { + Player controller = game.getPlayer(source.getControllerId()); + MageObject mageObject = (Permanent) getValue(EntersBattlefieldEffect.ENTERING_PERMANENT); + if (mageObject == null) { + mageObject = game.getObject(source.getSourceId()); + } + if (controller != null && mageObject != null) { TargetPlayer target = new TargetPlayer(1, 1, true); - if (player.choose(this.outcome, target, source.getSourceId(), game)) { + if (controller.choose(this.outcome, target, source.getSourceId(), game)) { Player chosenPlayer = game.getPlayer(target.getFirstTarget()); if (chosenPlayer != null) { - game.informPlayers(permanent.getName() + ": " + player.getLogName() + " has chosen " + chosenPlayer.getLogName()); - game.getState().setValue(permanent.getId() + "_player", target.getFirstTarget()); - permanent.addInfo("chosen player", CardUtil.addToolTipMarkTags("Chosen player: " + chosenPlayer.getLogName()), game); + game.informPlayers(mageObject.getName() + ": " + controller.getLogName() + " has chosen " + chosenPlayer.getLogName()); + game.getState().setValue(mageObject.getId() + "_player", target.getFirstTarget()); + if (mageObject instanceof Permanent) { + ((Permanent) mageObject).addInfo("chosen player", CardUtil.addToolTipMarkTags("Chosen player: " + chosenPlayer.getLogName()), game); + } return true; } } diff --git a/Mage/src/mage/abilities/effects/common/TapSourceUnlessPaysEffect.java b/Mage/src/mage/abilities/effects/common/TapSourceUnlessPaysEffect.java index 55bc3ad99ed..0d2e474b159 100644 --- a/Mage/src/mage/abilities/effects/common/TapSourceUnlessPaysEffect.java +++ b/Mage/src/mage/abilities/effects/common/TapSourceUnlessPaysEffect.java @@ -1,16 +1,16 @@ /* * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. - * + * * Redistribution and use in source and binary forms, with or without modification, are * permitted provided that the following conditions are met: - * + * * 1. Redistributions of source code must retain the above copyright notice, this list of * conditions and the following disclaimer. - * + * * 2. Redistributions in binary form must reproduce the above copyright notice, this list * of conditions and the following disclaimer in the documentation and/or other materials * provided with the distribution. - * + * * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR @@ -20,16 +20,16 @@ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * + * * The views and conclusions contained in the software and documentation are those of the * authors and should not be interpreted as representing official policies, either expressed * or implied, of BetaSteward_at_googlemail.com. */ - package mage.abilities.effects.common; import mage.abilities.Ability; import mage.abilities.costs.Cost; +import mage.abilities.effects.EntersBattlefieldEffect; import mage.abilities.effects.OneShotEffect; import mage.constants.Outcome; import mage.game.Game; @@ -59,7 +59,10 @@ public class TapSourceUnlessPaysEffect extends OneShotEffect { public boolean apply(Game game, Ability source) { Player player = game.getPlayer(source.getControllerId()); Permanent permanent = game.getPermanent(source.getSourceId()); - if (player != null && permanent != null) { + if (permanent == null) { + permanent = (Permanent) getValue(EntersBattlefieldEffect.ENTERING_PERMANENT); + } + if (player != null && permanent != null) { if (cost.canPay(source, source.getSourceId(), source.getControllerId(), game) && player.chooseUse(Outcome.Benefit, cost.getText() + "? (otherwise " + permanent.getName() + " becomes tapped)", source, game)) { cost.clearPaid(); @@ -78,5 +81,4 @@ public class TapSourceUnlessPaysEffect extends OneShotEffect { return new TapSourceUnlessPaysEffect(this); } - } diff --git a/Mage/src/mage/abilities/keyword/ModularAbility.java b/Mage/src/mage/abilities/keyword/ModularAbility.java index 19219e21b2d..3d9133f57ec 100644 --- a/Mage/src/mage/abilities/keyword/ModularAbility.java +++ b/Mage/src/mage/abilities/keyword/ModularAbility.java @@ -22,24 +22,24 @@ import mage.target.Target; import mage.target.common.TargetArtifactPermanent; import mage.util.CardUtil; - /** * * 702.41. Modular * - * 702.41a Modular represents both a static ability and a triggered ability. - * "Modular N" means "This permanent enters the battlefield with N +1/+1 - * counters on it" and "When this permanent is put into a graveyard - * from the battlefield, you may put a +1/+1 counter on target artifact - * creature for each +1/+1 counter on this permanent." - * 702.41b If a creature has multiple instances of modular, each one works separately. + * 702.41a Modular represents both a static ability and a triggered ability. + * "Modular N" means "This permanent enters the battlefield with N +1/+1 + * counters on it" and "When this permanent is put into a graveyard from the + * battlefield, you may put a +1/+1 counter on target artifact creature for each + * +1/+1 counter on this permanent." 702.41b If a creature has multiple + * instances of modular, each one works separately. + * * - * * @author Loki, LevelX2 */ - public class ModularAbility extends DiesTriggeredAbility { + private static final FilterArtifactPermanent filter = new FilterArtifactPermanent("artifact creature"); + static { filter.add(new CardTypePredicate(CardType.CREATURE)); } @@ -74,7 +74,7 @@ public class ModularAbility extends DiesTriggeredAbility { @Override public boolean checkTrigger(GameEvent event, Game game) { if (super.checkTrigger(event, game)) { - ZoneChangeEvent zEvent = (ZoneChangeEvent)event; + ZoneChangeEvent zEvent = (ZoneChangeEvent) event; if (zEvent.getTarget().getCounters().getCount(CounterType.P1P1) > 0) { return true; } @@ -94,9 +94,9 @@ public class ModularAbility extends DiesTriggeredAbility { sb.append("-Sunburst (This enters the battlefield with a +1/+1 counter on it for each color of mana spent to cast it. When it dies, you may put its +1/+1 counters on target artifact creature.)"); } else { sb.append(" ").append(amount).append(" (This enters the battlefield with ") - .append(CardUtil.numberToText(amount, "a")) - .append(" +1/+1 counter").append(amount != 1 ? "s":"") - .append(" on it. When it dies, you may put its +1/+1 counters on target artifact creature.)"); + .append(CardUtil.numberToText(amount, "a")) + .append(" +1/+1 counter").append(amount != 1 ? "s" : "") + .append(" on it. When it dies, you may put its +1/+1 counters on target artifact creature.)"); } return sb.toString(); } @@ -109,9 +109,7 @@ class ModularStaticAbility extends StaticAbility { public ModularStaticAbility(int amount) { super(Zone.BATTLEFIELD, new EntersBattlefieldEffect(new AddCountersSourceEffect(CounterType.P1P1.createInstance(amount)))); - ruleText = new StringBuilder("This enters the battlefield with ").append(CardUtil.numberToText(amount, "a")) - .append(" +1/+1 counter").append(amount != 1 ? "s":"") - .append(" on it.").toString(); + ruleText = "This enters the battlefield with " + CardUtil.numberToText(amount, "a") + " +1/+1 counter" + (amount != 1 ? "s" : "") + " on it."; this.setRuleVisible(false); } @@ -131,9 +129,10 @@ class ModularStaticAbility extends StaticAbility { } } - class ModularDistributeCounterEffect extends OneShotEffect { + private static final FilterArtifactPermanent filter = new FilterArtifactPermanent("artifact creature"); + static { filter.add(new CardTypePredicate(CardType.CREATURE)); } From 6dfbcab5ab4784b16ee2106fd26764a1bf516638 Mon Sep 17 00:00:00 2001 From: LevelX2 Date: Fri, 16 Oct 2015 00:32:55 +0200 Subject: [PATCH 113/268] * Updated enters battlefield replacement effects for new handling. --- .../sets/riseoftheeldrazi/NotOfThisWorld.java | 105 ++++++++++++++++-- .../EntersBattlefieldTappedAbility.java | 17 ++- .../EntersBattlefieldWithXCountersEffect.java | 3 + .../effects/common/TapSourceEffect.java | 60 +++++----- .../continuous/GainAbilitySourceEffect.java | 20 ++-- .../abilities/keyword/BloodthirstAbility.java | 14 ++- .../mage/abilities/keyword/FadingAbility.java | 36 +++--- .../abilities/keyword/SunburstAbility.java | 40 +++---- .../abilities/keyword/TributeAbility.java | 25 ++--- 9 files changed, 201 insertions(+), 119 deletions(-) diff --git a/Mage.Sets/src/mage/sets/riseoftheeldrazi/NotOfThisWorld.java b/Mage.Sets/src/mage/sets/riseoftheeldrazi/NotOfThisWorld.java index 97363cb0aa8..42b6e9c8f46 100644 --- a/Mage.Sets/src/mage/sets/riseoftheeldrazi/NotOfThisWorld.java +++ b/Mage.Sets/src/mage/sets/riseoftheeldrazi/NotOfThisWorld.java @@ -27,6 +27,8 @@ */ package mage.sets.riseoftheeldrazi; +import java.util.HashSet; +import java.util.Set; import java.util.UUID; import mage.abilities.Ability; import mage.abilities.common.SimpleStaticAbility; @@ -39,17 +41,17 @@ import mage.constants.Rarity; import mage.constants.TargetController; import mage.constants.Zone; import mage.filter.Filter; -import mage.filter.FilterSpell; -import mage.filter.common.FilterControlledPermanent; import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.mageobject.PowerPredicate; -import mage.filter.predicate.other.TargetsPermanentPredicate; import mage.filter.predicate.permanent.ControllerPredicate; import mage.game.Game; import mage.game.permanent.Permanent; +import mage.game.stack.Spell; +import mage.game.stack.StackAbility; import mage.game.stack.StackObject; import mage.target.Target; -import mage.target.TargetSpell; +import mage.target.TargetObject; +import mage.target.Targets; /** * @@ -57,19 +59,14 @@ import mage.target.TargetSpell; */ public class NotOfThisWorld extends CardImpl { - private final static FilterSpell filter = new FilterSpell("spell that targets a permanent you control"); - - static { - filter.add(new TargetsPermanentPredicate(new FilterControlledPermanent())); - } - public NotOfThisWorld(UUID ownerId) { super(ownerId, 8, "Not of This World", Rarity.UNCOMMON, new CardType[]{CardType.TRIBAL, CardType.INSTANT}, "{7}"); this.expansionSetCode = "ROE"; this.subtype.add("Eldrazi"); // Counter target spell or ability that targets a permanent you control. - this.getSpellAbility().addTarget(new TargetSpell(filter)); + this.getSpellAbility().addTarget( + new TargetStackObjectTargetingControlledPermanent()); this.getSpellAbility().addEffect(new CounterTargetEffect()); // Not of This World costs {7} less to cast if it targets a spell or ability that targets a creature you control with power 7 or greater. this.addAbility(new SimpleStaticAbility(Zone.STACK, new SpellCostReductionSourceEffect(7, NotOfThisWorldCondition.getInstance()))); @@ -85,6 +82,92 @@ public class NotOfThisWorld extends CardImpl { } } +class TargetStackObjectTargetingControlledPermanent extends TargetObject { + + public TargetStackObjectTargetingControlledPermanent() { + this.minNumberOfTargets = 1; + this.maxNumberOfTargets = 1; + this.zone = Zone.STACK; + this.targetName = "spell or ability that targets a permanent you control"; + } + + public TargetStackObjectTargetingControlledPermanent(final TargetStackObjectTargetingControlledPermanent target) { + super(target); + } + + @Override + public Filter getFilter() { + throw new UnsupportedOperationException("Not supported."); //To change body of generated methods, choose Tools | Templates. + } + + @Override + public boolean canTarget(UUID id, Ability source, Game game) { + StackObject stackObject = game.getStack().getStackObject(id); + if ((stackObject instanceof Spell) || (stackObject instanceof StackAbility)) { + return true; + } + return false; + } + + @Override + public boolean canChoose(UUID sourceId, UUID sourceControllerId, Game game) { + return canChoose(sourceControllerId, game); + } + + @Override + public boolean canChoose(UUID sourceControllerId, Game game) { + for (StackObject stackObject : game.getStack()) { + if ((stackObject instanceof Spell) || (stackObject instanceof StackAbility)) { + Targets objectTargets = stackObject.getStackAbility().getTargets(); + if (!objectTargets.isEmpty()) { + for (Target target : objectTargets) { + for (UUID targetId : target.getTargets()) { + Permanent targetedPermanent = game.getPermanentOrLKIBattlefield(targetId); + if (targetedPermanent != null && targetedPermanent.getControllerId().equals(sourceControllerId)) { + return true; + } + } + } + } + } + } + return false; + } + + @Override + public Set possibleTargets(UUID sourceId, UUID sourceControllerId, + Game game) { + return possibleTargets(sourceControllerId, game); + } + + @Override + public Set possibleTargets(UUID sourceControllerId, Game game) { + Set possibleTargets = new HashSet<>(); + for (StackObject stackObject : game.getStack()) { + if ((stackObject instanceof Spell) || (stackObject instanceof StackAbility)) { + Targets objectTargets = stackObject.getStackAbility().getTargets(); + if (!objectTargets.isEmpty()) { + for (Target target : objectTargets) { + for (UUID targetId : target.getTargets()) { + Permanent targetedPermanent = game.getPermanentOrLKIBattlefield(targetId); + if (targetedPermanent != null && targetedPermanent.getControllerId().equals(sourceControllerId)) { + possibleTargets.add(stackObject.getId()); + } + } + } + } + } + } + return possibleTargets; + } + + @Override + public TargetStackObjectTargetingControlledPermanent copy() { + return new TargetStackObjectTargetingControlledPermanent(this); + } + +} + class NotOfThisWorldCondition implements Condition { private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("creature you control with power 7 or greater"); diff --git a/Mage/src/mage/abilities/common/EntersBattlefieldTappedAbility.java b/Mage/src/mage/abilities/common/EntersBattlefieldTappedAbility.java index 1d8d119f17c..f62f02ab29e 100644 --- a/Mage/src/mage/abilities/common/EntersBattlefieldTappedAbility.java +++ b/Mage/src/mage/abilities/common/EntersBattlefieldTappedAbility.java @@ -1,16 +1,16 @@ /* * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. - * + * * Redistribution and use in source and binary forms, with or without modification, are * permitted provided that the following conditions are met: - * + * * 1. Redistributions of source code must retain the above copyright notice, this list of * conditions and the following disclaimer. - * + * * 2. Redistributions in binary form must reproduce the above copyright notice, this list * of conditions and the following disclaimer in the documentation and/or other materials * provided with the distribution. - * + * * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR @@ -20,18 +20,17 @@ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * + * * The views and conclusions contained in the software and documentation are those of the * authors and should not be interpreted as representing official policies, either expressed * or implied, of BetaSteward_at_googlemail.com. */ - package mage.abilities.common; -import mage.constants.Zone; import mage.abilities.StaticAbility; import mage.abilities.effects.EntersBattlefieldEffect; import mage.abilities.effects.common.TapSourceEffect; +import mage.constants.Zone; /** * @@ -40,9 +39,9 @@ import mage.abilities.effects.common.TapSourceEffect; public class EntersBattlefieldTappedAbility extends StaticAbility { private String ruleText; - + public EntersBattlefieldTappedAbility() { - super(Zone.BATTLEFIELD, new EntersBattlefieldEffect(new TapSourceEffect(true))); + super(Zone.ALL, new EntersBattlefieldEffect(new TapSourceEffect(true))); } public EntersBattlefieldTappedAbility(String ruleText) { diff --git a/Mage/src/mage/abilities/effects/common/EntersBattlefieldWithXCountersEffect.java b/Mage/src/mage/abilities/effects/common/EntersBattlefieldWithXCountersEffect.java index 999e70423dc..7451cd90dbb 100644 --- a/Mage/src/mage/abilities/effects/common/EntersBattlefieldWithXCountersEffect.java +++ b/Mage/src/mage/abilities/effects/common/EntersBattlefieldWithXCountersEffect.java @@ -59,6 +59,9 @@ public class EntersBattlefieldWithXCountersEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { Permanent permanent = game.getPermanent(source.getSourceId()); + if (permanent == null) { + permanent = (Permanent) getValue(EntersBattlefieldEffect.ENTERING_PERMANENT); + } if (permanent != null) { SpellAbility spellAbility = (SpellAbility) getValue(EntersBattlefieldEffect.SOURCE_CAST_SPELL_ABILITY); if (spellAbility != null diff --git a/Mage/src/mage/abilities/effects/common/TapSourceEffect.java b/Mage/src/mage/abilities/effects/common/TapSourceEffect.java index fcbc92c1e4c..aa655d15bfe 100644 --- a/Mage/src/mage/abilities/effects/common/TapSourceEffect.java +++ b/Mage/src/mage/abilities/effects/common/TapSourceEffect.java @@ -1,36 +1,36 @@ /* -* 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 mage.constants.Outcome; import mage.abilities.Ability; +import mage.abilities.effects.EntersBattlefieldEffect; import mage.abilities.effects.OneShotEffect; +import mage.constants.Outcome; import mage.game.Game; import mage.game.permanent.Permanent; @@ -39,6 +39,7 @@ import mage.game.permanent.Permanent; * @author BetaSteward_at_googlemail.com */ public class TapSourceEffect extends OneShotEffect { + private boolean withoutTrigger; public TapSourceEffect() { @@ -64,6 +65,9 @@ public class TapSourceEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { Permanent permanent = game.getPermanent(source.getSourceId()); + if (permanent == null) { + permanent = (Permanent) getValue(EntersBattlefieldEffect.ENTERING_PERMANENT); + } if (permanent != null) { if (withoutTrigger) { permanent.setTapped(true); diff --git a/Mage/src/mage/abilities/effects/common/continuous/GainAbilitySourceEffect.java b/Mage/src/mage/abilities/effects/common/continuous/GainAbilitySourceEffect.java index 81fc17c970c..6d37cfc4bad 100644 --- a/Mage/src/mage/abilities/effects/common/continuous/GainAbilitySourceEffect.java +++ b/Mage/src/mage/abilities/effects/common/continuous/GainAbilitySourceEffect.java @@ -1,16 +1,16 @@ /* * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. - * + * * Redistribution and use in source and binary forms, with or without modification, are * permitted provided that the following conditions are met: - * + * * 1. Redistributions of source code must retain the above copyright notice, this list of * conditions and the following disclaimer. - * + * * 2. Redistributions in binary form must reproduce the above copyright notice, this list * of conditions and the following disclaimer in the documentation and/or other materials * provided with the distribution. - * + * * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR @@ -20,7 +20,7 @@ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * + * * The views and conclusions contained in the software and documentation are those of the * authors and should not be interpreted as representing official policies, either expressed * or implied, of BetaSteward_at_googlemail.com. @@ -30,6 +30,7 @@ package mage.abilities.effects.common.continuous; import mage.MageObjectReference; import mage.abilities.Ability; import mage.abilities.effects.ContinuousEffectImpl; +import mage.abilities.effects.EntersBattlefieldEffect; import mage.cards.Card; import mage.constants.Duration; import mage.constants.Layer; @@ -88,12 +89,17 @@ public class GainAbilitySourceEffect extends ContinuousEffectImpl implements Sou public GainAbilitySourceEffect copy() { return new GainAbilitySourceEffect(this); } - + @Override public void init(Ability source, Game game) { super.init(source, game); if (affectedObjectsSet) { - affectedObjectList.add(new MageObjectReference(source.getSourceId(), game)); + Permanent permanent = (Permanent) getValue(EntersBattlefieldEffect.ENTERING_PERMANENT); + if (permanent != null) { + affectedObjectList.add(new MageObjectReference(source.getSourceId(), game.getState().getZoneChangeCounter(source.getSourceId()) + 1, game)); + } else { + affectedObjectList.add(new MageObjectReference(source.getSourceId(), game)); + } } } diff --git a/Mage/src/mage/abilities/keyword/BloodthirstAbility.java b/Mage/src/mage/abilities/keyword/BloodthirstAbility.java index f93ca9824d6..a7ae3282a18 100644 --- a/Mage/src/mage/abilities/keyword/BloodthirstAbility.java +++ b/Mage/src/mage/abilities/keyword/BloodthirstAbility.java @@ -2,6 +2,7 @@ package mage.abilities.keyword; import mage.abilities.Ability; import mage.abilities.common.EntersBattlefieldAbility; +import mage.abilities.effects.EntersBattlefieldEffect; import mage.abilities.effects.OneShotEffect; import mage.constants.Outcome; import mage.counters.CounterType; @@ -12,10 +13,11 @@ import mage.util.CardUtil; import mage.watchers.common.BloodthirstWatcher; /** - * + * * @author Loki */ public class BloodthirstAbility extends EntersBattlefieldAbility { + private int amount; public BloodthirstAbility(int amount) { @@ -48,12 +50,13 @@ public class BloodthirstAbility extends EntersBattlefieldAbility { } class BloodthirstEffect extends OneShotEffect { + private final int amount; BloodthirstEffect(int amount) { super(Outcome.BoostCreature); this.amount = amount; - staticText = new StringBuilder("this permanent comes into play with ").append(this.amount).append(" +1/+1 counters on it").toString(); + staticText = new StringBuilder("this permanent comes into play with ").append(this.amount).append(" +1/+1 counters on it").toString(); } BloodthirstEffect(final BloodthirstEffect effect) { @@ -67,9 +70,9 @@ class BloodthirstEffect extends OneShotEffect { if (player != null) { BloodthirstWatcher watcher = (BloodthirstWatcher) game.getState().getWatchers().get("DamagedOpponents", source.getControllerId()); if (watcher != null && watcher.conditionMet()) { - Permanent p = game.getPermanent(source.getSourceId()); - if (p != null) { - p.addCounters(CounterType.P1P1.createInstance(amount), game); + Permanent permanent = (Permanent) getValue(EntersBattlefieldEffect.ENTERING_PERMANENT); + if (permanent != null) { + permanent.addCounters(CounterType.P1P1.createInstance(amount), game); } } @@ -83,4 +86,3 @@ class BloodthirstEffect extends OneShotEffect { return new BloodthirstEffect(this); } } - diff --git a/Mage/src/mage/abilities/keyword/FadingAbility.java b/Mage/src/mage/abilities/keyword/FadingAbility.java index 4a66d7dcda7..a433ac3cd5c 100644 --- a/Mage/src/mage/abilities/keyword/FadingAbility.java +++ b/Mage/src/mage/abilities/keyword/FadingAbility.java @@ -3,6 +3,7 @@ package mage.abilities.keyword; import mage.abilities.Ability; import mage.abilities.common.BeginningOfUpkeepTriggeredAbility; import mage.abilities.common.EntersBattlefieldAbility; +import mage.abilities.effects.EntersBattlefieldEffect; import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.counter.AddCountersSourceEffect; import mage.cards.Card; @@ -18,25 +19,17 @@ import mage.game.permanent.Permanent; * 702.31a Fading is a keyword that represents two abilities. “Fading N” means “This permanent enters the battlefield with N fade counters on it” and “At the beginning of your upkeep, remove a fade counter from this permanent. If you can’t, sacrifice the permanent.” * */ - public class FadingAbility extends EntersBattlefieldAbility { - - + private String ruleText; - + public FadingAbility(int fadeCounter, Card card) { super(new AddCountersSourceEffect(CounterType.FADE.createInstance(fadeCounter)), "with"); Ability ability = new BeginningOfUpkeepTriggeredAbility(new FadingEffect(), TargetController.YOU, false); ability.setRuleVisible(false); addSubAbility(ability); - StringBuilder sb = new StringBuilder("Fading "); - sb.append(fadeCounter); - sb.append(" (This permanent enters the battlefield with ") - .append(fadeCounter) - .append(" fade counters on it. ") - .append(" At the beginning of your upkeep, remove a fade counter from this permanent. If you can’t, sacrifice the permanent.") - .append(")"); - ruleText = sb.toString(); + ruleText = "Fading " + fadeCounter + " (This permanent enters the battlefield with " + fadeCounter + " fade counters on it." + + " At the beginning of your upkeep, remove a fade counter from this permanent. If you can’t, sacrifice the permanent."; } public FadingAbility(final FadingAbility ability) { @@ -54,7 +47,9 @@ public class FadingAbility extends EntersBattlefieldAbility { return ruleText; } } + class FadingEffect extends OneShotEffect { + FadingEffect() { super(Outcome.Sacrifice); staticText = "remove a fade counter from this permanent. If you can’t, sacrifice the permanent"; @@ -64,18 +59,15 @@ class FadingEffect extends OneShotEffect { super(effect); } - @Override public boolean apply(Game game, Ability source) { - Permanent p = game.getPermanent(source.getSourceId()); - if (p != null) { - int amount = p.getCounters().getCount(CounterType.FADE); + Permanent permanent = (Permanent) getValue(EntersBattlefieldEffect.ENTERING_PERMANENT); + if (permanent != null) { + int amount = permanent.getCounters().getCount(CounterType.FADE); if (amount > 0) { - p.removeCounters(CounterType.FADE.createInstance(), game); - } - else - { - p.sacrifice(source.getSourceId(), game); + permanent.removeCounters(CounterType.FADE.createInstance(), game); + } else { + permanent.sacrifice(source.getSourceId(), game); } return true; } @@ -86,4 +78,4 @@ class FadingEffect extends OneShotEffect { public FadingEffect copy() { return new FadingEffect(this); } -} \ No newline at end of file +} diff --git a/Mage/src/mage/abilities/keyword/SunburstAbility.java b/Mage/src/mage/abilities/keyword/SunburstAbility.java index 12b9d7834ae..bc4a9319046 100644 --- a/Mage/src/mage/abilities/keyword/SunburstAbility.java +++ b/Mage/src/mage/abilities/keyword/SunburstAbility.java @@ -25,13 +25,13 @@ * authors and should not be interpreted as representing official policies, either expressed * or implied, of BetaSteward_at_googlemail.com. */ - package mage.abilities.keyword; import mage.abilities.Ability; import mage.abilities.common.EntersBattlefieldAbility; import mage.abilities.dynamicvalue.DynamicValue; import mage.abilities.dynamicvalue.common.SunburstCount; +import mage.abilities.effects.EntersBattlefieldEffect; import mage.abilities.effects.OneShotEffect; import mage.cards.Card; import mage.constants.CardType; @@ -46,25 +46,22 @@ import mage.players.Player; * * @author Plopman */ +public class SunburstAbility extends EntersBattlefieldAbility { - -public class SunburstAbility extends EntersBattlefieldAbility{ - - private final static String ruleCreature ="Sunburst (This enters the battlefield with a +1/+1 counter on it for each color of mana spent to cast it.)"; - private final static String ruleNonCreature ="Sunburst (This enters the battlefield with a charge counter on it for each color of mana spent to cast it.)"; + private final static String ruleCreature = "Sunburst (This enters the battlefield with a +1/+1 counter on it for each color of mana spent to cast it.)"; + private final static String ruleNonCreature = "Sunburst (This enters the battlefield with a charge counter on it for each color of mana spent to cast it.)"; private boolean isCreature; - public SunburstAbility(Card card){ - super(new SunburstEffect(),""); + public SunburstAbility(Card card) { + super(new SunburstEffect(), ""); isCreature = card.getCardType().contains(CardType.CREATURE); } - - public SunburstAbility(final SunburstAbility ability){ + + public SunburstAbility(final SunburstAbility ability) { super(ability); this.isCreature = ability.isCreature; } - - + @Override public EntersBattlefieldAbility copy() { return new SunburstAbility(this); @@ -74,15 +71,13 @@ public class SunburstAbility extends EntersBattlefieldAbility{ public String getRule() { return isCreature ? ruleCreature : ruleNonCreature; } - - + } class SunburstEffect extends OneShotEffect { private static final DynamicValue amount = new SunburstCount(); - public SunburstEffect() { super(Outcome.Benefit); staticText = "Sunburst"; @@ -94,22 +89,21 @@ class SunburstEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { - Permanent permanent = game.getPermanent(source.getSourceId()); + Permanent permanent = (Permanent) getValue(EntersBattlefieldEffect.ENTERING_PERMANENT); if (permanent != null) { Counter counter; - if(permanent.getCardType().contains(CardType.CREATURE)){ - counter = CounterType.P1P1.createInstance(amount.calculate(game, source, this)); - } - else{ - counter = CounterType.CHARGE.createInstance(amount.calculate(game, source, this)); + if (permanent.getCardType().contains(CardType.CREATURE)) { + counter = CounterType.P1P1.createInstance(amount.calculate(game, source, this)); + } else { + counter = CounterType.CHARGE.createInstance(amount.calculate(game, source, this)); } if (counter != null) { - + permanent.addCounters(counter, game); if (!game.isSimulation()) { Player player = game.getPlayer(source.getControllerId()); if (player != null) { - game.informPlayers(player.getLogName()+ " puts " + counter.getCount() + " " + counter.getName() + " counter on " + permanent.getName()); + game.informPlayers(player.getLogName() + " puts " + counter.getCount() + " " + counter.getName() + " counter on " + permanent.getName()); } } } diff --git a/Mage/src/mage/abilities/keyword/TributeAbility.java b/Mage/src/mage/abilities/keyword/TributeAbility.java index ad5ad5b6b7b..f752865498b 100644 --- a/Mage/src/mage/abilities/keyword/TributeAbility.java +++ b/Mage/src/mage/abilities/keyword/TributeAbility.java @@ -25,12 +25,12 @@ * authors and should not be interpreted as representing official policies, either expressed * or implied, of BetaSteward_at_googlemail.com. */ - package mage.abilities.keyword; import java.util.UUID; import mage.abilities.Ability; import mage.abilities.common.EntersBattlefieldAbility; +import mage.abilities.effects.EntersBattlefieldEffect; import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.counter.AddCountersSourceEffect; import mage.constants.Outcome; @@ -46,23 +46,20 @@ import mage.util.CardUtil; * * @author LevelX2 */ - - -public class TributeAbility extends EntersBattlefieldAbility{ +public class TributeAbility extends EntersBattlefieldAbility { private int tributeValue; - public TributeAbility(int tributeValue){ + public TributeAbility(int tributeValue) { super(new TributeEffect(tributeValue), false); this.tributeValue = tributeValue; } - public TributeAbility(final TributeAbility ability){ + public TributeAbility(final TributeAbility ability) { super(ability); this.tributeValue = ability.tributeValue; } - @Override public EntersBattlefieldAbility copy() { return new TributeAbility(this); @@ -81,7 +78,7 @@ public class TributeAbility extends EntersBattlefieldAbility{ class TributeEffect extends OneShotEffect { - private int tributeValue; + private final int tributeValue; public TributeEffect(int tributeValue) { super(Outcome.Detriment); @@ -101,7 +98,7 @@ class TributeEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { Player controller = game.getPlayer(source.getControllerId()); - Permanent sourcePermanent = game.getPermanent(source.getSourceId()); + Permanent sourcePermanent = (Permanent) getValue(EntersBattlefieldEffect.ENTERING_PERMANENT); if (controller != null && sourcePermanent != null) { UUID opponentId; if (game.getOpponents(controller.getId()).size() == 1) { @@ -117,16 +114,18 @@ class TributeEffect extends OneShotEffect { StringBuilder sb = new StringBuilder("Pay tribute to "); sb.append(sourcePermanent.getName()); sb.append(" (add ").append(CardUtil.numberToText(tributeValue)).append(" +1/+1 counter"); - sb.append(tributeValue > 1 ? "s":"").append(" to it)?"); + sb.append(tributeValue > 1 ? "s" : "").append(" to it)?"); if (opponent.chooseUse(outcome, sb.toString(), source, game)) { - if (!game.isSimulation()) + if (!game.isSimulation()) { game.informPlayers(opponent.getLogName() + " pays tribute to " + sourcePermanent.getLogName()); + } game.getState().setValue("tributeValue" + source.getSourceId(), "yes"); return new AddCountersSourceEffect(CounterType.P1P1.createInstance(tributeValue), true).apply(game, source); } else { - if (!game.isSimulation()) + if (!game.isSimulation()) { game.informPlayers(opponent.getLogName() + " does not pay tribute to " + sourcePermanent.getLogName()); - game.getState().setValue("tributeValue"+ source.getSourceId(), "no"); + } + game.getState().setValue("tributeValue" + source.getSourceId(), "no"); } return true; } From c6421650206ffe02f097374488fd00f831d8224a Mon Sep 17 00:00:00 2001 From: LevelX2 Date: Fri, 16 Oct 2015 00:39:16 +0200 Subject: [PATCH 114/268] * Updated enters battlefield replacement effects for new handling. --- Mage/src/mage/abilities/keyword/FadingAbility.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/Mage/src/mage/abilities/keyword/FadingAbility.java b/Mage/src/mage/abilities/keyword/FadingAbility.java index a433ac3cd5c..e8e45295810 100644 --- a/Mage/src/mage/abilities/keyword/FadingAbility.java +++ b/Mage/src/mage/abilities/keyword/FadingAbility.java @@ -3,7 +3,6 @@ package mage.abilities.keyword; import mage.abilities.Ability; import mage.abilities.common.BeginningOfUpkeepTriggeredAbility; import mage.abilities.common.EntersBattlefieldAbility; -import mage.abilities.effects.EntersBattlefieldEffect; import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.counter.AddCountersSourceEffect; import mage.cards.Card; @@ -61,7 +60,7 @@ class FadingEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { - Permanent permanent = (Permanent) getValue(EntersBattlefieldEffect.ENTERING_PERMANENT); + Permanent permanent = game.getPermanent(source.getSourceId()); if (permanent != null) { int amount = permanent.getCounters().getCount(CounterType.FADE); if (amount > 0) { From bc06e83ce17027a0413730194199162d55c6a4c3 Mon Sep 17 00:00:00 2001 From: LevelX2 Date: Fri, 9 Oct 2015 14:55:39 +0200 Subject: [PATCH 115/268] * Nissa, Sage Animist - Added test for +1 ability. --- .../sets/magicorigins/NissaSageAnimist.java | 14 ++++++------- .../abilities/keywords/TransformTest.java | 20 +++++++++++++++---- 2 files changed, 23 insertions(+), 11 deletions(-) diff --git a/Mage.Sets/src/mage/sets/magicorigins/NissaSageAnimist.java b/Mage.Sets/src/mage/sets/magicorigins/NissaSageAnimist.java index 7959cf7f6b3..d3a209c463a 100644 --- a/Mage.Sets/src/mage/sets/magicorigins/NissaSageAnimist.java +++ b/Mage.Sets/src/mage/sets/magicorigins/NissaSageAnimist.java @@ -28,6 +28,7 @@ package mage.sets.magicorigins; import java.util.UUID; +import mage.MageObject; import mage.abilities.Ability; import mage.abilities.LoyaltyAbility; import mage.abilities.common.EntersBattlefieldAbility; @@ -112,19 +113,18 @@ class NissaSageAnimistPlusOneEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { Player controller = game.getPlayer(source.getControllerId()); - if (controller != null && controller.getLibrary().size() > 0) { + MageObject sourceObject = game.getObject(source.getSourceId()); + if (sourceObject != null && controller != null && controller.getLibrary().size() > 0) { Card card = controller.getLibrary().getFromTop(game); if (card == null) { return false; } - CardsImpl cards = new CardsImpl(); - cards.add(card); - controller.revealCards("Nissa, Sage Animist", cards, game); + controller.revealCards(sourceObject.getIdName(), new CardsImpl(card), game); + Zone targetZone = Zone.HAND; if (card.getCardType().contains(CardType.LAND)) { - return controller.putOntoBattlefieldWithInfo(card, game, Zone.LIBRARY, source.getSourceId()); - } else { - return controller.moveCards(card, Zone.LIBRARY, Zone.HAND, source, game); + targetZone = Zone.BATTLEFIELD; } + return controller.moveCards(card, null, targetZone, source, game); } return true; } diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/abilities/keywords/TransformTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/abilities/keywords/TransformTest.java index 14e6c0db6a3..d37249116ca 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/abilities/keywords/TransformTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/abilities/keywords/TransformTest.java @@ -44,23 +44,35 @@ public class TransformTest extends CardTestPlayerBase { addCard(Zone.LIBRARY, playerA, "Forest"); - addCard(Zone.BATTLEFIELD, playerA, "Forest", 6); + addCard(Zone.BATTLEFIELD, playerA, "Forest", 5); + addCard(Zone.BATTLEFIELD, playerA, "Swamp", 1); // When Nissa, Vastwood Seer enters the battlefield, you may search your library for a basic Forest card, reveal it, put it into your hand, then shuffle your library. // Whenever a land enters the battlefield under your control, if you control seven or more lands, exile Nissa, then return her to the battlefield transformed under her owner's control. addCard(Zone.HAND, playerA, "Nissa, Vastwood Seer"); + addCard(Zone.BATTLEFIELD, playerB, "Forest", 2); + // {G}{G}, Sacrifice Rootrunner: Put target land on top of its owner's library. + addCard(Zone.BATTLEFIELD, playerB, "Rootrunner"); // {2}{G}{G} + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Nissa, Vastwood Seer"); playLand(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Forest"); - setStopAt(1, PhaseStep.BEGIN_COMBAT); + activateAbility(1, PhaseStep.POSTCOMBAT_MAIN, playerB, "{G}{G}", "Swamp"); + activateAbility(1, PhaseStep.POSTCOMBAT_MAIN, playerA, "+1: Reveal"); + + setStopAt(1, PhaseStep.END_TURN); execute(); - assertPermanentCount(playerA, "Forest", 7); + assertGraveyardCount(playerB, "Rootrunner", 1); assertPermanentCount(playerA, "Nissa, Vastwood Seer", 0); assertPermanentCount(playerA, "Nissa, Sage Animist", 1); - assertCounterCount("Nissa, Sage Animist", CounterType.LOYALTY, 3); + + assertCounterCount("Nissa, Sage Animist", CounterType.LOYALTY, 4); + assertPermanentCount(playerA, "Forest", 6); + assertPermanentCount(playerA, "Swamp", 1); + } @Test From 0d127ae2e03154f03c8cecc81674481dcdcff954 Mon Sep 17 00:00:00 2001 From: LoneFox Date: Sun, 11 Oct 2015 11:33:59 +0300 Subject: [PATCH 116/268] Implement cards: Armor Thrull, Dwarven Armorer, Dwarven Lieutenant, and Elven Lyre --- .../mage/sets/fallenempires/ArmorThrull1.java | 52 +++++++ .../mage/sets/fallenempires/ArmorThrull2.java | 52 +++++++ .../mage/sets/fallenempires/ArmorThrull3.java | 52 +++++++ .../mage/sets/fallenempires/ArmorThrull4.java | 52 +++++++ .../sets/fallenempires/DwarvenArmorer.java | 128 ++++++++++++++++++ .../sets/fallenempires/DwarvenLieutenant.java | 79 +++++++++++ .../mage/sets/fallenempires/ElvenLyre.java | 54 ++++++++ .../sets/masterseditionii/ArmorThrull.java | 72 ++++++++++ .../mage/sets/masterseditionii/ElvenLyre.java | 71 ++++++++++ Mage/src/mage/counters/CounterType.java | 6 + 10 files changed, 618 insertions(+) create mode 100644 Mage.Sets/src/mage/sets/fallenempires/ArmorThrull1.java create mode 100644 Mage.Sets/src/mage/sets/fallenempires/ArmorThrull2.java create mode 100644 Mage.Sets/src/mage/sets/fallenempires/ArmorThrull3.java create mode 100644 Mage.Sets/src/mage/sets/fallenempires/ArmorThrull4.java create mode 100644 Mage.Sets/src/mage/sets/fallenempires/DwarvenArmorer.java create mode 100644 Mage.Sets/src/mage/sets/fallenempires/DwarvenLieutenant.java create mode 100644 Mage.Sets/src/mage/sets/fallenempires/ElvenLyre.java create mode 100644 Mage.Sets/src/mage/sets/masterseditionii/ArmorThrull.java create mode 100644 Mage.Sets/src/mage/sets/masterseditionii/ElvenLyre.java diff --git a/Mage.Sets/src/mage/sets/fallenempires/ArmorThrull1.java b/Mage.Sets/src/mage/sets/fallenempires/ArmorThrull1.java new file mode 100644 index 00000000000..e543304cf03 --- /dev/null +++ b/Mage.Sets/src/mage/sets/fallenempires/ArmorThrull1.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.fallenempires; + +import java.util.UUID; + +/** + * + * @author LoneFox + */ +public class ArmorThrull1 extends mage.sets.masterseditionii.ArmorThrull { + + public ArmorThrull1(UUID ownerId) { + super(ownerId); + this.cardNumber = 1; + this.expansionSetCode = "FEM"; + } + + public ArmorThrull1(final ArmorThrull1 card) { + super(card); + } + + @Override + public ArmorThrull1 copy() { + return new ArmorThrull1(this); + } +} diff --git a/Mage.Sets/src/mage/sets/fallenempires/ArmorThrull2.java b/Mage.Sets/src/mage/sets/fallenempires/ArmorThrull2.java new file mode 100644 index 00000000000..c39b457788b --- /dev/null +++ b/Mage.Sets/src/mage/sets/fallenempires/ArmorThrull2.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.fallenempires; + +import java.util.UUID; + +/** + * + * @author LoneFox + */ +public class ArmorThrull2 extends mage.sets.masterseditionii.ArmorThrull { + + public ArmorThrull2(UUID ownerId) { + super(ownerId); + this.cardNumber = 2; + this.expansionSetCode = "FEM"; + } + + public ArmorThrull2(final ArmorThrull2 card) { + super(card); + } + + @Override + public ArmorThrull2 copy() { + return new ArmorThrull2(this); + } +} diff --git a/Mage.Sets/src/mage/sets/fallenempires/ArmorThrull3.java b/Mage.Sets/src/mage/sets/fallenempires/ArmorThrull3.java new file mode 100644 index 00000000000..2a16cd7b3fd --- /dev/null +++ b/Mage.Sets/src/mage/sets/fallenempires/ArmorThrull3.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.fallenempires; + +import java.util.UUID; + +/** + * + * @author LoneFox + */ +public class ArmorThrull3 extends mage.sets.masterseditionii.ArmorThrull { + + public ArmorThrull3(UUID ownerId) { + super(ownerId); + this.cardNumber = 3; + this.expansionSetCode = "FEM"; + } + + public ArmorThrull3(final ArmorThrull3 card) { + super(card); + } + + @Override + public ArmorThrull3 copy() { + return new ArmorThrull3(this); + } +} diff --git a/Mage.Sets/src/mage/sets/fallenempires/ArmorThrull4.java b/Mage.Sets/src/mage/sets/fallenempires/ArmorThrull4.java new file mode 100644 index 00000000000..97d46f88982 --- /dev/null +++ b/Mage.Sets/src/mage/sets/fallenempires/ArmorThrull4.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.fallenempires; + +import java.util.UUID; + +/** + * + * @author LoneFox + */ +public class ArmorThrull4 extends mage.sets.masterseditionii.ArmorThrull { + + public ArmorThrull4(UUID ownerId) { + super(ownerId); + this.cardNumber = 4; + this.expansionSetCode = "FEM"; + } + + public ArmorThrull4(final ArmorThrull4 card) { + super(card); + } + + @Override + public ArmorThrull4 copy() { + return new ArmorThrull4(this); + } +} diff --git a/Mage.Sets/src/mage/sets/fallenempires/DwarvenArmorer.java b/Mage.Sets/src/mage/sets/fallenempires/DwarvenArmorer.java new file mode 100644 index 00000000000..b98704b1ec6 --- /dev/null +++ b/Mage.Sets/src/mage/sets/fallenempires/DwarvenArmorer.java @@ -0,0 +1,128 @@ +/* + * 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.fallenempires; + +import java.util.HashSet; +import java.util.UUID; +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.costs.common.DiscardCardCost; +import mage.abilities.costs.common.TapSourceCost; +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.effects.Effect; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.counter.AddCountersTargetEffect; +import mage.cards.CardImpl; +import mage.choices.Choice; +import mage.choices.ChoiceImpl; +import mage.constants.CardType; +import mage.constants.Outcome; +import mage.constants.Rarity; +import mage.constants.Zone; +import mage.counters.Counter; +import mage.counters.CounterType; +import mage.game.Game; +import mage.players.Player; +import mage.target.common.TargetCreaturePermanent; +import mage.target.targetpointer.FixedTarget; + +/** + * + * @author LoneFox + */ +public class DwarvenArmorer extends CardImpl { + + public DwarvenArmorer(UUID ownerId) { + super(ownerId, 104, "Dwarven Armorer", Rarity.RARE, new CardType[]{CardType.CREATURE}, "{R}"); + this.expansionSetCode = "FEM"; + this.subtype.add("Dwarf"); + this.power = new MageInt(0); + this.toughness = new MageInt(2); + + // {R}, {tap}, Discard a card: Put a +0/+1 counter or a +1/+0 counter on target creature. + Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new DwarvenArmorerEffect(), new ManaCostsImpl("{R}")); + ability.addCost(new TapSourceCost()); + ability.addCost(new DiscardCardCost()); + ability.addTarget(new TargetCreaturePermanent()); + this.addAbility(ability); + } + + public DwarvenArmorer(final DwarvenArmorer card) { + super(card); + } + + @Override + public DwarvenArmorer copy() { + return new DwarvenArmorer(this); + } +} + +class DwarvenArmorerEffect extends OneShotEffect { + + private static final HashSet choices = new HashSet<>(); + + static { + choices.add("+0/+1"); + choices.add("+1/+0"); + } + + public DwarvenArmorerEffect() { + super(Outcome.Benefit); + staticText = "Put a +0/+1 counter or a +1/+0 counter on target creature."; + } + + public DwarvenArmorerEffect(final DwarvenArmorerEffect effect) { + super(effect); + } + + @java.lang.Override + public DwarvenArmorerEffect copy() { + return new DwarvenArmorerEffect(this); + } + + @java.lang.Override + public boolean apply(Game game, Ability source) { + Player controller = game.getPlayer(source.getControllerId()); + if(controller != null) { + Choice choice = new ChoiceImpl(true); + choice.setMessage("Choose type of counter to add"); + choice.setChoices(choices); + while(!controller.choose(outcome, choice, game)) { + if(controller.canRespond()) { + return false; + } + } + Counter counter = choice.getChoice().equals("+0/+1") ? CounterType.P0P1.createInstance() : CounterType.P1P0.createInstance(); + Effect effect = new AddCountersTargetEffect(counter); + effect.setTargetPointer(new FixedTarget(this.getTargetPointer().getFirst(game, source))); + return effect.apply(game, source); + } + return false; + } +} diff --git a/Mage.Sets/src/mage/sets/fallenempires/DwarvenLieutenant.java b/Mage.Sets/src/mage/sets/fallenempires/DwarvenLieutenant.java new file mode 100644 index 00000000000..2cc864b9fc7 --- /dev/null +++ b/Mage.Sets/src/mage/sets/fallenempires/DwarvenLieutenant.java @@ -0,0 +1,79 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.sets.fallenempires; + +import java.util.UUID; +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.effects.common.continuous.BoostTargetEffect; +import mage.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.mageobject.SubtypePredicate; +import mage.target.common.TargetCreaturePermanent; + +/** + * + * @author LoneFox + */ +public class DwarvenLieutenant extends CardImpl { + + static FilterCreaturePermanent filter = new FilterCreaturePermanent("Dwarf creature"); + + static { + filter.add(new SubtypePredicate("Dwarf")); + } + + public DwarvenLieutenant(UUID ownerId) { + super(ownerId, 106, "Dwarven Lieutenant", Rarity.UNCOMMON, new CardType[]{CardType.CREATURE}, "{R}{R}"); + this.expansionSetCode = "FEM"; + this.subtype.add("Dwarf"); + this.subtype.add("Soldier"); + this.power = new MageInt(1); + this.toughness = new MageInt(2); + + // {1}{R}: Target Dwarf creature gets +1/+0 until end of turn. + Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new BoostTargetEffect(1, 0, Duration.EndOfTurn), new ManaCostsImpl("{1}{R}")); + ability.addTarget(new TargetCreaturePermanent(filter)); + this.addAbility(ability); + } + + public DwarvenLieutenant(final DwarvenLieutenant card) { + super(card); + } + + @Override + public DwarvenLieutenant copy() { + return new DwarvenLieutenant(this); + } +} diff --git a/Mage.Sets/src/mage/sets/fallenempires/ElvenLyre.java b/Mage.Sets/src/mage/sets/fallenempires/ElvenLyre.java new file mode 100644 index 00000000000..8657136f098 --- /dev/null +++ b/Mage.Sets/src/mage/sets/fallenempires/ElvenLyre.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.fallenempires; + +import java.util.UUID; +import mage.constants.Rarity; + +/** + * + * @author LoneFox + */ +public class ElvenLyre extends mage.sets.masterseditionii.ElvenLyre { + + public ElvenLyre(UUID ownerId) { + super(ownerId); + this.cardNumber = 172; + this.expansionSetCode = "FEM"; + this.rarity = Rarity.RARE; + } + + public ElvenLyre(final ElvenLyre card) { + super(card); + } + + @Override + public ElvenLyre copy() { + return new ElvenLyre(this); + } +} diff --git a/Mage.Sets/src/mage/sets/masterseditionii/ArmorThrull.java b/Mage.Sets/src/mage/sets/masterseditionii/ArmorThrull.java new file mode 100644 index 00000000000..dbd058685b3 --- /dev/null +++ b/Mage.Sets/src/mage/sets/masterseditionii/ArmorThrull.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.masterseditionii; + +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.costs.common.TapSourceCost; +import mage.abilities.effects.common.counter.AddCountersTargetEffect; +import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.Rarity; +import mage.constants.Zone; +import mage.counters.CounterType; +import mage.target.common.TargetCreaturePermanent; + +/** + * + * @author LoneFox + */ +public class ArmorThrull extends CardImpl { + + public ArmorThrull(UUID ownerId) { + super(ownerId, 77, "Armor Thrull", Rarity.COMMON, new CardType[]{CardType.CREATURE}, "{2}{B}"); + this.expansionSetCode = "ME2"; + this.subtype.add("Thrull"); + this.power = new MageInt(1); + this.toughness = new MageInt(3); + + // {T}, Sacrifice Armor Thrull: Put a +1/+2 counter on target creature. + Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new AddCountersTargetEffect(CounterType.P1P2.createInstance()), new TapSourceCost()); + ability.addCost(new SacrificeSourceCost()); + ability.addTarget(new TargetCreaturePermanent()); + this.addAbility(ability); + } + + public ArmorThrull(final ArmorThrull card) { + super(card); + } + + @Override + public ArmorThrull copy() { + return new ArmorThrull(this); + } +} diff --git a/Mage.Sets/src/mage/sets/masterseditionii/ElvenLyre.java b/Mage.Sets/src/mage/sets/masterseditionii/ElvenLyre.java new file mode 100644 index 00000000000..5fd78b1f651 --- /dev/null +++ b/Mage.Sets/src/mage/sets/masterseditionii/ElvenLyre.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.masterseditionii; + +import java.util.UUID; +import mage.abilities.Ability; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.costs.common.SacrificeSourceCost; +import mage.abilities.costs.common.TapSourceCost; +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.effects.common.continuous.BoostTargetEffect; +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 ElvenLyre extends CardImpl { + + public ElvenLyre(UUID ownerId) { + super(ownerId, 208, "Elven Lyre", Rarity.COMMON, new CardType[]{CardType.ARTIFACT}, "{2}"); + this.expansionSetCode = "ME2"; + + // {1}, {tap}, Sacrifice Elven Lyre: Target creature gets +2/+2 until end of turn. + Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new BoostTargetEffect(2, 2, Duration.EndOfTurn), new ManaCostsImpl("{1}")); + ability.addCost(new TapSourceCost()); + ability.addCost(new SacrificeSourceCost()); + ability.addTarget(new TargetCreaturePermanent()); + this.addAbility(ability); + + } + + public ElvenLyre(final ElvenLyre card) { + super(card); + } + + @Override + public ElvenLyre copy() { + return new ElvenLyre(this); + } +} diff --git a/Mage/src/mage/counters/CounterType.java b/Mage/src/mage/counters/CounterType.java index eaf7bde19ef..da70425325e 100644 --- a/Mage/src/mage/counters/CounterType.java +++ b/Mage/src/mage/counters/CounterType.java @@ -75,8 +75,10 @@ public enum CounterType { M2M2(new BoostCounter(-2, -2).name), MINING("mining"), MUSTER("muster"), + P0P1(new BoostCounter(0, 1).name), P1P0(new BoostCounter(1, 0).name), P1P1(new BoostCounter(1, 1).name), + P1P2(new BoostCounter(1, 2).name), P2P2(new BoostCounter(2, 2).name), PAGE("page"), PAIN("pain"), @@ -134,10 +136,14 @@ public enum CounterType { */ public Counter createInstance(int amount) { switch (this) { + case P0P1: + return new BoostCounter(0, 1, amount); case P1P0: return new BoostCounter(1, 0, amount); case P1P1: return new BoostCounter(1, 1, amount); + case P1P2: + return new BoostCounter(1, 2, amount); case P2P2: return new BoostCounter(2, 2, amount); case M1M1: From 1227d8fc6fb23d4ecc783f533ec259ec95aaaac9 Mon Sep 17 00:00:00 2001 From: LoneFox Date: Sun, 11 Oct 2015 12:28:24 +0300 Subject: [PATCH 117/268] Fix Bloodied Ghost's tooltip text --- Mage.Sets/src/mage/sets/eventide/BloodiedGhost.java | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/Mage.Sets/src/mage/sets/eventide/BloodiedGhost.java b/Mage.Sets/src/mage/sets/eventide/BloodiedGhost.java index 2d046b50dfa..dd8ae7ec4ba 100644 --- a/Mage.Sets/src/mage/sets/eventide/BloodiedGhost.java +++ b/Mage.Sets/src/mage/sets/eventide/BloodiedGhost.java @@ -29,13 +29,13 @@ package mage.sets.eventide; import java.util.UUID; -import mage.constants.CardType; -import mage.constants.Rarity; import mage.MageInt; import mage.abilities.common.EntersBattlefieldAbility; import mage.abilities.effects.common.counter.AddCountersSourceEffect; import mage.abilities.keyword.FlyingAbility; import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.Rarity; import mage.counters.CounterType; /** @@ -48,12 +48,15 @@ public class BloodiedGhost extends CardImpl { super(ownerId, 83, "Bloodied Ghost", Rarity.UNCOMMON, new CardType[]{CardType.CREATURE}, "{1}{W/B}{W/B}"); this.expansionSetCode = "EVE"; this.subtype.add("Spirit"); - - this.power = new MageInt(3); this.toughness = new MageInt(3); + + // Flying this.addAbility(FlyingAbility.getInstance()); - this.addAbility(new EntersBattlefieldAbility(new AddCountersSourceEffect(CounterType.M1M1.createInstance()), "Bloodied Ghost gets a -1/-1 counter")); + + // Bloodied Ghost enters the battlefield with a -1/-1 counter on it. + this.addAbility(new EntersBattlefieldAbility(new AddCountersSourceEffect(CounterType.M1M1.createInstance()), + "with a -1/-1 counter on it.")); } public BloodiedGhost (final BloodiedGhost card) { From f81605847b5e9a8ce682af68c1db1a5a32fdcaae Mon Sep 17 00:00:00 2001 From: LevelX2 Date: Mon, 12 Oct 2015 17:35:04 +0200 Subject: [PATCH 118/268] * Paradox Haze - Fixed that check if a step is the first upkeep step of a turn did not work always correctly (fixes #1313). --- .../src/mage/sets/tempest/VerdantForce.java | 7 +- .../src/mage/sets/timespiral/ParadoxHaze.java | 39 ++++---- .../cards/enchantments/ParadoxHazeTest.java | 88 +++++++++++++++++++ .../watchers/common/FirstTimeStepWatcher.java | 72 +++++++++++++++ 4 files changed, 183 insertions(+), 23 deletions(-) create mode 100644 Mage.Tests/src/test/java/org/mage/test/cards/enchantments/ParadoxHazeTest.java create mode 100644 Mage/src/mage/watchers/common/FirstTimeStepWatcher.java diff --git a/Mage.Sets/src/mage/sets/tempest/VerdantForce.java b/Mage.Sets/src/mage/sets/tempest/VerdantForce.java index 4377abe9c5b..b383f7df446 100644 --- a/Mage.Sets/src/mage/sets/tempest/VerdantForce.java +++ b/Mage.Sets/src/mage/sets/tempest/VerdantForce.java @@ -28,13 +28,12 @@ package mage.sets.tempest; import java.util.UUID; - -import mage.constants.CardType; -import mage.constants.Rarity; import mage.MageInt; import mage.abilities.common.BeginningOfUpkeepTriggeredAbility; import mage.abilities.effects.common.CreateTokenEffect; import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.Rarity; import mage.constants.TargetController; import mage.game.permanent.token.SaprolingToken; @@ -51,6 +50,8 @@ public class VerdantForce extends CardImpl { this.power = new MageInt(7); this.toughness = new MageInt(7); + + // At the beginning of each upkeep, put a 1/1 green Saproling creature token onto the battlefield. this.addAbility(new BeginningOfUpkeepTriggeredAbility(new CreateTokenEffect(new SaprolingToken()), TargetController.ANY, false)); } diff --git a/Mage.Sets/src/mage/sets/timespiral/ParadoxHaze.java b/Mage.Sets/src/mage/sets/timespiral/ParadoxHaze.java index 40c612225b4..76b84e06c36 100644 --- a/Mage.Sets/src/mage/sets/timespiral/ParadoxHaze.java +++ b/Mage.Sets/src/mage/sets/timespiral/ParadoxHaze.java @@ -47,6 +47,7 @@ import mage.game.turn.UpkeepStep; import mage.players.Player; import mage.target.TargetPlayer; import mage.target.targetpointer.FixedTarget; +import mage.watchers.common.FirstTimeStepWatcher; /** * @@ -59,15 +60,14 @@ public class ParadoxHaze extends CardImpl { this.expansionSetCode = "TSP"; this.subtype.add("Aura"); - // Enchant player TargetPlayer auraTarget = new TargetPlayer(); this.getSpellAbility().addTarget(auraTarget); this.getSpellAbility().addEffect(new AttachEffect(Outcome.Neutral)); this.addAbility(new EnchantAbility(auraTarget.getTargetName())); - + // At the beginning of enchanted player's first upkeep each turn, that player gets an additional upkeep step after this step. - this.addAbility(new ParadoxHazeTriggeredAbility()); + this.addAbility(new ParadoxHazeTriggeredAbility(), new FirstTimeStepWatcher(EventType.UPKEEP_STEP_POST)); } public ParadoxHaze(final ParadoxHaze card) { @@ -81,18 +81,15 @@ public class ParadoxHaze extends CardImpl { } class ParadoxHazeTriggeredAbility extends TriggeredAbilityImpl { - - protected int lastTriggerTurnNumber; - + ParadoxHazeTriggeredAbility() { super(Zone.BATTLEFIELD, new ParadoxHazeEffect(), false); } - + ParadoxHazeTriggeredAbility(final ParadoxHazeTriggeredAbility ability) { super(ability); - lastTriggerTurnNumber = ability.lastTriggerTurnNumber; } - + @Override public ParadoxHazeTriggeredAbility copy() { return new ParadoxHazeTriggeredAbility(this); @@ -102,21 +99,23 @@ class ParadoxHazeTriggeredAbility extends TriggeredAbilityImpl { public boolean checkEventType(GameEvent event, Game game) { return event.getType() == EventType.UPKEEP_STEP_PRE; } - + @Override public boolean checkTrigger(GameEvent event, Game game) { - Permanent permanent = game.getPermanent(this.sourceId); + Permanent permanent = game.getPermanent(getSourceId()); if (permanent != null) { Player player = game.getPlayer(permanent.getAttachedTo()); - if (player != null && game.getActivePlayerId().equals(player.getId()) && lastTriggerTurnNumber != game.getTurnNum()) { - lastTriggerTurnNumber = game.getTurnNum(); - this.getEffects().get(0).setTargetPointer(new FixedTarget(player.getId())); - return true; + if (player != null && game.getActivePlayerId().equals(player.getId())) { + FirstTimeStepWatcher watcher = (FirstTimeStepWatcher) game.getState().getWatchers().get(EventType.UPKEEP_STEP_POST.toString() + FirstTimeStepWatcher.class.getName()); + if (watcher != null && !watcher.conditionMet()) { + this.getEffects().get(0).setTargetPointer(new FixedTarget(player.getId())); + return true; + } } } return false; } - + @Override public String getRule() { return "At the beginning of enchanted player's first upkeep each turn, that player gets an additional upkeep step after this step."; @@ -124,21 +123,21 @@ class ParadoxHazeTriggeredAbility extends TriggeredAbilityImpl { } class ParadoxHazeEffect extends OneShotEffect { - + ParadoxHazeEffect() { super(Outcome.Benefit); this.staticText = "that player gets an additional upkeep step after this step"; } - + ParadoxHazeEffect(final ParadoxHazeEffect effect) { super(effect); } - + @Override public ParadoxHazeEffect copy() { return new ParadoxHazeEffect(this); } - + @Override public boolean apply(Game game, Ability source) { game.getState().getTurnMods().add(new TurnMod(this.getTargetPointer().getFirst(game, source), new UpkeepStep(), null)); diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/enchantments/ParadoxHazeTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/enchantments/ParadoxHazeTest.java new file mode 100644 index 00000000000..917e25519d4 --- /dev/null +++ b/Mage.Tests/src/test/java/org/mage/test/cards/enchantments/ParadoxHazeTest.java @@ -0,0 +1,88 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package org.mage.test.cards.enchantments; + +import mage.constants.PhaseStep; +import mage.constants.Zone; +import org.junit.Test; +import org.mage.test.serverside.base.CardTestPlayerBase; + +/** + * + * @author LevelX2 + */ +public class ParadoxHazeTest extends CardTestPlayerBase { + + @Test + public void testNormal() { + addCard(Zone.BATTLEFIELD, playerA, "Island", 3); + addCard(Zone.BATTLEFIELD, playerA, "Forest", 8); + // Enchant player + // At the beginning of enchanted player's first upkeep each turn, that player gets an additional upkeep step after this step. + addCard(Zone.HAND, playerA, "Paradox Haze", 1); // {2}{U} + // At the beginning of each upkeep, put a 1/1 green Saproling creature token onto the battlefield. + addCard(Zone.HAND, playerA, "Verdant Force", 1); // {5}{G}{G}{G} + + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Paradox Haze", playerA); + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Verdant Force"); + + setStopAt(3, PhaseStep.PRECOMBAT_MAIN); + execute(); + + assertPermanentCount(playerA, "Paradox Haze", 1); + assertPermanentCount(playerA, "Verdant Force", 1); + assertPermanentCount(playerA, "Saproling", 3);// 1 from turn 2 and 2 from turn 3 + } + + @Test + public void testCopied() { + addCard(Zone.BATTLEFIELD, playerA, "Island", 6); + addCard(Zone.BATTLEFIELD, playerA, "Forest", 8); + // Enchant player + // At the beginning of enchanted player's first upkeep each turn, that player gets an additional upkeep step after this step. + addCard(Zone.HAND, playerA, "Paradox Haze", 1); // {2}{U} + + // You may have Copy Enchantment enter the battlefield as a copy of any enchantment on the battlefield. + addCard(Zone.HAND, playerA, "Copy Enchantment", 1); // {2}{U} + + // At the beginning of each upkeep, put a 1/1 green Saproling creature token onto the battlefield. + addCard(Zone.HAND, playerA, "Verdant Force", 1); // {5}{G}{G}{G} + + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Paradox Haze", playerA); + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Copy Enchantment"); + setChoice(playerA, "Paradox Haze"); + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Verdant Force"); + + setStopAt(3, PhaseStep.PRECOMBAT_MAIN); + execute(); + + assertPermanentCount(playerA, "Paradox Haze", 2); + assertPermanentCount(playerA, "Verdant Force", 1); + assertPermanentCount(playerA, "Saproling", 4); // 1 from turn 2 and 3 from turn 3 + } +} diff --git a/Mage/src/mage/watchers/common/FirstTimeStepWatcher.java b/Mage/src/mage/watchers/common/FirstTimeStepWatcher.java new file mode 100644 index 00000000000..911a3ecf93f --- /dev/null +++ b/Mage/src/mage/watchers/common/FirstTimeStepWatcher.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.watchers.common; + +import mage.constants.WatcherScope; +import mage.game.Game; +import mage.game.events.GameEvent; +import mage.game.events.GameEvent.EventType; +import mage.watchers.Watcher; + +/** + * The wachter checks if a specific phase event has already happened during the + * current turn. If not it returns false, otheriwsed true. + * + * @author LevelX2 + */ +public class FirstTimeStepWatcher extends Watcher { + + private final EventType eventType; + + public FirstTimeStepWatcher(EventType eventType) { + super(eventType.toString() + FirstTimeStepWatcher.class.getName(), WatcherScope.GAME); + this.eventType = eventType; + } + + public FirstTimeStepWatcher(final FirstTimeStepWatcher watcher) { + super(watcher); + this.eventType = watcher.eventType; + } + + @Override + public FirstTimeStepWatcher copy() { + return new FirstTimeStepWatcher(this); + } + + @Override + public void watch(GameEvent event, Game game) { + if (event.getType() == eventType) { + condition = true; + } + } + + @Override + public void reset() { + super.reset(); + } +} From ccf33f15ca7bd30f79a05f50551f01f9443969f8 Mon Sep 17 00:00:00 2001 From: LoneFox Date: Mon, 12 Oct 2015 19:18:58 +0300 Subject: [PATCH 119/268] Add RemoveAllCountersSourceEffect and use it for Witherscale Wurm. Implement cards: Homarid and Tidal Influence TODO: The tooltip text of Tidal Infuence's first ability is wrong. The idea is copied from Feast of Blood, which also has the same problem. --- .../src/mage/sets/fallenempires/Homarid1.java | 120 +++++++++++++ .../src/mage/sets/fallenempires/Homarid2.java | 51 ++++++ .../src/mage/sets/fallenempires/Homarid3.java | 51 ++++++ .../src/mage/sets/fallenempires/Homarid4.java | 51 ++++++ .../sets/fallenempires/TidalInfluence.java | 167 ++++++++++++++++++ .../mage/sets/shadowmoor/WitherscaleWurm.java | 37 +--- .../common/RemoveAllCountersSourceEffect.java | 73 ++++++++ Mage/src/mage/counters/CounterType.java | 1 + 8 files changed, 516 insertions(+), 35 deletions(-) create mode 100644 Mage.Sets/src/mage/sets/fallenempires/Homarid1.java create mode 100644 Mage.Sets/src/mage/sets/fallenempires/Homarid2.java create mode 100644 Mage.Sets/src/mage/sets/fallenempires/Homarid3.java create mode 100644 Mage.Sets/src/mage/sets/fallenempires/Homarid4.java create mode 100644 Mage.Sets/src/mage/sets/fallenempires/TidalInfluence.java create mode 100644 Mage/src/mage/abilities/effects/common/RemoveAllCountersSourceEffect.java diff --git a/Mage.Sets/src/mage/sets/fallenempires/Homarid1.java b/Mage.Sets/src/mage/sets/fallenempires/Homarid1.java new file mode 100644 index 00000000000..a69771b1056 --- /dev/null +++ b/Mage.Sets/src/mage/sets/fallenempires/Homarid1.java @@ -0,0 +1,120 @@ +/* + * 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.fallenempires; + +import java.util.UUID; +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.StateTriggeredAbility; +import mage.abilities.common.BeginningOfUpkeepTriggeredAbility; +import mage.abilities.common.EntersBattlefieldAbility; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.condition.common.SourceHasCounterCondition; +import mage.abilities.decorator.ConditionalContinuousEffect; +import mage.abilities.dynamicvalue.common.CountersCount; +import mage.abilities.effects.Effect; +import mage.abilities.effects.common.RemoveAllCountersSourceEffect; +import mage.abilities.effects.common.continuous.BoostSourceEffect; +import mage.abilities.effects.common.counter.AddCountersSourceEffect; +import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.Rarity; +import mage.constants.TargetController; +import mage.constants.Zone; +import mage.counters.CounterType; +import mage.game.Game; +import mage.game.events.GameEvent; + +/** + * + * @author LoneFox + */ +public class Homarid1 extends CardImpl { + + public Homarid1(UUID ownerId) { + super(ownerId, 38, "Homarid", Rarity.COMMON, new CardType[]{CardType.CREATURE}, "{2}{U}"); + this.expansionSetCode = "FEM"; + this.subtype.add("Homarid"); + this.power = new MageInt(2); + this.toughness = new MageInt(2); + + // Homarid enters the battlefield with a tide counter on it. + this.addAbility(new EntersBattlefieldAbility(new AddCountersSourceEffect(CounterType.TIDE.createInstance()), + "with a tide counter on it.")); + // At the beginning of your upkeep, put a tide counter on Homarid. + this.addAbility(new BeginningOfUpkeepTriggeredAbility(new AddCountersSourceEffect(CounterType.TIDE.createInstance()), + TargetController.YOU, false)); + // As long as there is exactly one tide counter on Homarid, it gets -1/-1. + this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new ConditionalContinuousEffect( + new BoostSourceEffect(-1, -1, Duration.WhileOnBattlefield), new SourceHasCounterCondition(CounterType.TIDE, 1, 1), + "As long as there is exactly one tide counter on {this}, it gets -1/-1."))); + // As long as there are exactly three tide counters on Homarid, it gets +1/+1. + this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new ConditionalContinuousEffect( + new BoostSourceEffect(1, 1, Duration.WhileOnBattlefield), new SourceHasCounterCondition(CounterType.TIDE, 3, 3), + "As long as there are exactly three tide counter on {this}, it gets +1/+1."))); + // Whenever there are four tide counters on Homarid, remove all tide counters from it. + this.addAbility(new HomaridTriggeredAbility(new RemoveAllCountersSourceEffect(CounterType.TIDE))); + } + + public Homarid1(final Homarid1 card) { + super(card); + } + + @Override + public Homarid1 copy() { + return new Homarid1(this); + } +} + +class HomaridTriggeredAbility extends StateTriggeredAbility { + + public HomaridTriggeredAbility(Effect effect) { + super(Zone.BATTLEFIELD, effect); + } + + public HomaridTriggeredAbility(final HomaridTriggeredAbility ability) { + super(ability); + } + + @Override + public HomaridTriggeredAbility copy() { + return new HomaridTriggeredAbility(this); + } + + @Override + public boolean checkTrigger(GameEvent event, Game game) { + return new CountersCount(CounterType.TIDE).calculate(game, this, null) == 4; + } + + @Override + public String getRule() { + return "Whenever there are four tide counters on {this}, " + super.getRule(); + } + +} diff --git a/Mage.Sets/src/mage/sets/fallenempires/Homarid2.java b/Mage.Sets/src/mage/sets/fallenempires/Homarid2.java new file mode 100644 index 00000000000..51d33e80bb5 --- /dev/null +++ b/Mage.Sets/src/mage/sets/fallenempires/Homarid2.java @@ -0,0 +1,51 @@ +/* + * 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.fallenempires; + +import java.util.UUID; + +/** + * + * @author LoneFox + */ +public class Homarid2 extends Homarid1 { + + public Homarid2(UUID ownerId) { + super(ownerId); + this.cardNumber = 39; + } + + public Homarid2(final Homarid2 card) { + super(card); + } + + @Override + public Homarid2 copy() { + return new Homarid2(this); + } +} diff --git a/Mage.Sets/src/mage/sets/fallenempires/Homarid3.java b/Mage.Sets/src/mage/sets/fallenempires/Homarid3.java new file mode 100644 index 00000000000..f42970458e1 --- /dev/null +++ b/Mage.Sets/src/mage/sets/fallenempires/Homarid3.java @@ -0,0 +1,51 @@ +/* + * 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.fallenempires; + +import java.util.UUID; + +/** + * + * @author LoneFox + */ +public class Homarid3 extends Homarid1 { + + public Homarid3(UUID ownerId) { + super(ownerId); + this.cardNumber = 40; + } + + public Homarid3(final Homarid3 card) { + super(card); + } + + @Override + public Homarid3 copy() { + return new Homarid3(this); + } +} diff --git a/Mage.Sets/src/mage/sets/fallenempires/Homarid4.java b/Mage.Sets/src/mage/sets/fallenempires/Homarid4.java new file mode 100644 index 00000000000..4ae2066c646 --- /dev/null +++ b/Mage.Sets/src/mage/sets/fallenempires/Homarid4.java @@ -0,0 +1,51 @@ +/* + * 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.fallenempires; + +import java.util.UUID; + +/** + * + * @author LoneFox + */ +public class Homarid4 extends Homarid1 { + + public Homarid4(UUID ownerId) { + super(ownerId); + this.cardNumber = 41; + } + + public Homarid4(final Homarid4 card) { + super(card); + } + + @Override + public Homarid4 copy() { + return new Homarid4(this); + } +} diff --git a/Mage.Sets/src/mage/sets/fallenempires/TidalInfluence.java b/Mage.Sets/src/mage/sets/fallenempires/TidalInfluence.java new file mode 100644 index 00000000000..5de52d6b938 --- /dev/null +++ b/Mage.Sets/src/mage/sets/fallenempires/TidalInfluence.java @@ -0,0 +1,167 @@ +/* + * 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.fallenempires; + +import java.util.UUID; +import mage.ObjectColor; +import mage.abilities.Ability; +import mage.abilities.StateTriggeredAbility; +import mage.abilities.common.BeginningOfUpkeepTriggeredAbility; +import mage.abilities.common.EntersBattlefieldAbility; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.condition.common.SourceHasCounterCondition; +import mage.abilities.costs.CostImpl; +import mage.abilities.decorator.ConditionalContinuousEffect; +import mage.abilities.dynamicvalue.common.CountersCount; +import mage.abilities.effects.Effect; +import mage.abilities.effects.common.RemoveAllCountersSourceEffect; +import mage.abilities.effects.common.continuous.BoostAllEffect; +import mage.abilities.effects.common.counter.AddCountersSourceEffect; +import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.Rarity; +import mage.constants.TargetController; +import mage.constants.Zone; +import mage.counters.CounterType; +import mage.filter.FilterPermanent; +import mage.filter.common.FilterCreaturePermanent; +import mage.filter.predicate.mageobject.ColorPredicate; +import mage.filter.predicate.mageobject.NamePredicate; +import mage.game.Game; +import mage.game.events.GameEvent; + +/** + * + * @author LoneFox + */ +public class TidalInfluence extends CardImpl { + + private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("blue creatures"); + + static { + filter.add(new ColorPredicate(ObjectColor.BLUE)); + } + + public TidalInfluence(UUID ownerId) { + super(ownerId, 57, "Tidal Influence", Rarity.UNCOMMON, new CardType[]{CardType.ENCHANTMENT}, "{2}{U}"); + this.expansionSetCode = "FEM"; + + // Cast Tidal Influence only if no permanents named Tidal Influence are on the battlefield. + this.getSpellAbility().addCost(new TidalInfluenceCost()); + // Tidal Influence enters the battlefield with a tide counter on it. + this.addAbility(new EntersBattlefieldAbility(new AddCountersSourceEffect(CounterType.TIDE.createInstance()), + "with a tide counter on it.")); + // At the beginning of your upkeep, put a tide counter on Tidal Influence. + this.addAbility(new BeginningOfUpkeepTriggeredAbility(new AddCountersSourceEffect(CounterType.TIDE.createInstance()), + TargetController.YOU, false)); + // As long as there is exactly one tide counter on Tidal Influence, all blue creatures get -2/-0. + this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new ConditionalContinuousEffect( + new BoostAllEffect(-2, -0, Duration.WhileOnBattlefield, filter, false), + new SourceHasCounterCondition(CounterType.TIDE, 1, 1), + "As long as there is exactly one tide counter on {this}, all blue creatures get -2/-0."))); + // As long as there are exactly three tide counters on Tidal Influence, all blue creatures get +2/+0. + this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new ConditionalContinuousEffect( + new BoostAllEffect(2, -0, Duration.WhileOnBattlefield, filter, false), + new SourceHasCounterCondition(CounterType.TIDE, 3, 3), + "As long as there are exactly three tide counter on {this}, all blue creatures get +2/-0."))); + // Whenever there are four tide counters on Tidal Influence, remove all tide counters from it. + this.addAbility(new TidalInfluenceTriggeredAbility(new RemoveAllCountersSourceEffect(CounterType.TIDE))); + } + + public TidalInfluence(final TidalInfluence card) { + super(card); + } + + @Override + public TidalInfluence copy() { + return new TidalInfluence(this); + } +} + + +class TidalInfluenceCost extends CostImpl { + + private static final FilterPermanent filter = new FilterPermanent(); + + static { + filter.add(new NamePredicate("Tidal Influence")); + } + + public TidalInfluenceCost() { + this.text = "Cast Tidal Influence only if no permanents named Tidal Influence are on the battlefield"; + } + + public TidalInfluenceCost(final TidalInfluenceCost cost) { + super(cost); + } + + @Override + public boolean canPay(Ability ability, UUID sourceId, UUID controllerId, Game game) { + return !game.getBattlefield().contains(filter, 1, game); + } + + @Override + public boolean pay(Ability ability, Game game, UUID sourceId, UUID controllerId, boolean noMana) { + this.paid = true; + return paid; + } + + @Override + public TidalInfluenceCost copy() { + return new TidalInfluenceCost(this); + } +} + + +class TidalInfluenceTriggeredAbility extends StateTriggeredAbility { + + public TidalInfluenceTriggeredAbility(Effect effect) { + super(Zone.BATTLEFIELD, effect); + } + + public TidalInfluenceTriggeredAbility(final TidalInfluenceTriggeredAbility ability) { + super(ability); + } + + @Override + public TidalInfluenceTriggeredAbility copy() { + return new TidalInfluenceTriggeredAbility(this); + } + + @Override + public boolean checkTrigger(GameEvent event, Game game) { + return new CountersCount(CounterType.TIDE).calculate(game, this, null) == 4; + } + + @Override + public String getRule() { + return "Whenever there are four tide counters on {this}, " + super.getRule(); + } + +} diff --git a/Mage.Sets/src/mage/sets/shadowmoor/WitherscaleWurm.java b/Mage.Sets/src/mage/sets/shadowmoor/WitherscaleWurm.java index bc3e1f3d06c..9f8ba6c97d4 100644 --- a/Mage.Sets/src/mage/sets/shadowmoor/WitherscaleWurm.java +++ b/Mage.Sets/src/mage/sets/shadowmoor/WitherscaleWurm.java @@ -29,21 +29,17 @@ package mage.sets.shadowmoor; import java.util.UUID; import mage.MageInt; -import mage.abilities.Ability; import mage.abilities.common.BlocksOrBecomesBlockedByCreatureTriggeredAbility; import mage.abilities.common.DealsDamageToOpponentTriggeredAbility; import mage.abilities.effects.Effect; -import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.RemoveAllCountersSourceEffect; import mage.abilities.effects.common.continuous.GainAbilityTargetEffect; import mage.abilities.keyword.WitherAbility; import mage.cards.CardImpl; import mage.constants.CardType; import mage.constants.Duration; -import mage.constants.Outcome; import mage.constants.Rarity; import mage.counters.CounterType; -import mage.game.Game; -import mage.game.permanent.Permanent; /** * @@ -65,7 +61,7 @@ public class WitherscaleWurm extends CardImpl { this.addAbility(new BlocksOrBecomesBlockedByCreatureTriggeredAbility(effect, false)); // Whenever Witherscale Wurm deals damage to an opponent, remove all -1/-1 counters from it. - this.addAbility(new DealsDamageToOpponentTriggeredAbility(new WitherscaleWurmEffect(), false)); + this.addAbility(new DealsDamageToOpponentTriggeredAbility(new RemoveAllCountersSourceEffect(CounterType.M1M1), false)); } @@ -78,32 +74,3 @@ public class WitherscaleWurm extends CardImpl { return new WitherscaleWurm(this); } } - -class WitherscaleWurmEffect extends OneShotEffect { - - public WitherscaleWurmEffect() { - super(Outcome.Benefit); - staticText = "remove all -1/-1 counters from it"; - } - - public WitherscaleWurmEffect(WitherscaleWurmEffect effect) { - super(effect); - } - - @Override - public boolean apply(Game game, Ability source) { - Permanent witherscaleWurm = game.getPermanent(source.getSourceId()); - if (witherscaleWurm != null - && witherscaleWurm.getCounters().containsKey(CounterType.M1M1)) { - int M1M1Counters = witherscaleWurm.getCounters().getCount(CounterType.M1M1); - witherscaleWurm.getCounters().removeCounter(CounterType.M1M1, M1M1Counters); - return true; - } - return false; - } - - @Override - public WitherscaleWurmEffect copy() { - return new WitherscaleWurmEffect(this); - } -} diff --git a/Mage/src/mage/abilities/effects/common/RemoveAllCountersSourceEffect.java b/Mage/src/mage/abilities/effects/common/RemoveAllCountersSourceEffect.java new file mode 100644 index 00000000000..abc70475f47 --- /dev/null +++ b/Mage/src/mage/abilities/effects/common/RemoveAllCountersSourceEffect.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.abilities.effects.common; + +import mage.abilities.Ability; +import mage.abilities.effects.OneShotEffect; +import mage.constants.Outcome; +import mage.counters.CounterType; +import mage.game.Game; +import mage.game.permanent.Permanent; + +/** + * + * @author LoneFox + */ +public class RemoveAllCountersSourceEffect extends OneShotEffect { + + private final CounterType counterType; + + public RemoveAllCountersSourceEffect(CounterType counterType) { + super(Outcome.Neutral); + this.counterType = counterType; + staticText = "remove all " + counterType.getName() + " counters from it."; + } + + public RemoveAllCountersSourceEffect(final RemoveAllCountersSourceEffect effect) { + super(effect); + this.counterType = effect.counterType; + } + + @Override + public RemoveAllCountersSourceEffect copy() { + return new RemoveAllCountersSourceEffect(this); + } + + @java.lang.Override + public boolean apply(Game game, Ability source) { + Permanent sourcePermanent = game.getPermanent(source.getSourceId()); + if(sourcePermanent != null) { + int count = sourcePermanent.getCounters().getCount(counterType); + sourcePermanent.getCounters().removeCounter(counterType, count); + return true; + } + return false; + } +} + diff --git a/Mage/src/mage/counters/CounterType.java b/Mage/src/mage/counters/CounterType.java index da70425325e..f7537638758 100644 --- a/Mage/src/mage/counters/CounterType.java +++ b/Mage/src/mage/counters/CounterType.java @@ -96,6 +96,7 @@ public enum CounterType { STRIFE("strife"), STUDY("study"), THEFT("theft"), + TIDE("tide"), TIME("time"), TOWER("tower"), VELOCITY("velocity"), From b8c96fda2d442d52185e49010aa9d7cce012381b Mon Sep 17 00:00:00 2001 From: LoneFox Date: Mon, 12 Oct 2015 20:47:43 +0300 Subject: [PATCH 120/268] Implement cards: Deep Spawn, Homarid Shaman, Homarid Warrior, and Vodalian Mage --- .../mage/sets/fallenempires/DeepSpawn.java | 88 +++++++++++++++++++ .../sets/fallenempires/HomaridShaman.java | 79 +++++++++++++++++ .../sets/fallenempires/HomaridWarrior1.java | 78 ++++++++++++++++ .../sets/fallenempires/HomaridWarrior2.java | 51 +++++++++++ .../sets/fallenempires/HomaridWarrior3.java | 51 +++++++++++ .../sets/fallenempires/VodalianMage1.java | 73 +++++++++++++++ .../sets/fallenempires/VodalianMage2.java | 51 +++++++++++ .../sets/fallenempires/VodalianMage3.java | 51 +++++++++++ .../sets/fifthedition/HomaridWarrior.java | 52 +++++++++++ .../mage/sets/masterseditionii/DeepSpawn.java | 54 ++++++++++++ 10 files changed, 628 insertions(+) create mode 100644 Mage.Sets/src/mage/sets/fallenempires/DeepSpawn.java create mode 100644 Mage.Sets/src/mage/sets/fallenempires/HomaridShaman.java create mode 100644 Mage.Sets/src/mage/sets/fallenempires/HomaridWarrior1.java create mode 100644 Mage.Sets/src/mage/sets/fallenempires/HomaridWarrior2.java create mode 100644 Mage.Sets/src/mage/sets/fallenempires/HomaridWarrior3.java create mode 100644 Mage.Sets/src/mage/sets/fallenempires/VodalianMage1.java create mode 100644 Mage.Sets/src/mage/sets/fallenempires/VodalianMage2.java create mode 100644 Mage.Sets/src/mage/sets/fallenempires/VodalianMage3.java create mode 100644 Mage.Sets/src/mage/sets/fifthedition/HomaridWarrior.java create mode 100644 Mage.Sets/src/mage/sets/masterseditionii/DeepSpawn.java diff --git a/Mage.Sets/src/mage/sets/fallenempires/DeepSpawn.java b/Mage.Sets/src/mage/sets/fallenempires/DeepSpawn.java new file mode 100644 index 00000000000..129e152a1c9 --- /dev/null +++ b/Mage.Sets/src/mage/sets/fallenempires/DeepSpawn.java @@ -0,0 +1,88 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.sets.fallenempires; + +import java.util.UUID; +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.BeginningOfUpkeepTriggeredAbility; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.costs.common.PutTopCardOfYourLibraryToGraveyardCost; +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.effects.Effect; +import mage.abilities.effects.common.DontUntapInControllersNextUntapStepSourceEffect; +import mage.abilities.effects.common.SacrificeSourceUnlessPaysEffect; +import mage.abilities.effects.common.TapSourceEffect; +import mage.abilities.effects.common.continuous.GainAbilitySourceEffect; +import mage.abilities.keyword.ShroudAbility; +import mage.abilities.keyword.TrampleAbility; +import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.Rarity; +import mage.constants.TargetController; +import mage.constants.Zone; + +/** + * + * @author LoneFox + */ +public class DeepSpawn extends CardImpl { + + public DeepSpawn(UUID ownerId) { + super(ownerId, 34, "Deep Spawn", Rarity.UNCOMMON, new CardType[]{CardType.CREATURE}, "{5}{U}{U}{U}"); + this.expansionSetCode = "FEM"; + this.subtype.add("Homarid"); + this.power = new MageInt(6); + this.toughness = new MageInt(6); + + // Trample + this.addAbility(TrampleAbility.getInstance()); + // At the beginning of your upkeep, sacrifice Deep Spawn unless you put the top two cards of your library into your graveyard. + Effect effect = new SacrificeSourceUnlessPaysEffect(new PutTopCardOfYourLibraryToGraveyardCost(2)); + effect.setText("sacrifice {this} unless you put the top two cards of your library into your graveyard"); + this.addAbility(new BeginningOfUpkeepTriggeredAbility(effect, TargetController.YOU, false)); + // {U}: Deep Spawn gains shroud until end of turn and doesn't untap during your next untap step. Tap Deep Spawn. + Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new GainAbilitySourceEffect( + ShroudAbility.getInstance(), Duration.EndOfTurn), new ManaCostsImpl("{U}")); + effect = new DontUntapInControllersNextUntapStepSourceEffect(); + effect.setText("and doesn't untap during your next untap step"); + ability.addEffect(effect); + ability.addEffect(new TapSourceEffect()); + this.addAbility(ability); + } + + public DeepSpawn(final DeepSpawn card) { + super(card); + } + + @Override + public DeepSpawn copy() { + return new DeepSpawn(this); + } +} diff --git a/Mage.Sets/src/mage/sets/fallenempires/HomaridShaman.java b/Mage.Sets/src/mage/sets/fallenempires/HomaridShaman.java new file mode 100644 index 00000000000..e092c8daa75 --- /dev/null +++ b/Mage.Sets/src/mage/sets/fallenempires/HomaridShaman.java @@ -0,0 +1,79 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.sets.fallenempires; + +import java.util.UUID; +import mage.MageInt; +import mage.ObjectColor; +import mage.abilities.Ability; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.effects.common.TapTargetEffect; +import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.Rarity; +import mage.constants.Zone; +import mage.filter.common.FilterCreaturePermanent; +import mage.filter.predicate.mageobject.ColorPredicate; +import mage.target.common.TargetCreaturePermanent; + +/** + * + * @author LoneFox + */ +public class HomaridShaman extends CardImpl { + + private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("green creature"); + + static { + filter.add(new ColorPredicate(ObjectColor.GREEN)); + } + + public HomaridShaman(UUID ownerId) { + super(ownerId, 42, "Homarid Shaman", Rarity.RARE, new CardType[]{CardType.CREATURE}, "{2}{U}{U}"); + this.expansionSetCode = "FEM"; + this.subtype.add("Homarid"); + this.subtype.add("Shaman"); + this.power = new MageInt(2); + this.toughness = new MageInt(1); + + // {U}: Tap target green creature. + Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new TapTargetEffect(), new ManaCostsImpl("{U}")); + ability.addTarget(new TargetCreaturePermanent(filter)); + this.addAbility(ability); + } + + public HomaridShaman(final HomaridShaman card) { + super(card); + } + + @Override + public HomaridShaman copy() { + return new HomaridShaman(this); + } +} diff --git a/Mage.Sets/src/mage/sets/fallenempires/HomaridWarrior1.java b/Mage.Sets/src/mage/sets/fallenempires/HomaridWarrior1.java new file mode 100644 index 00000000000..24114869260 --- /dev/null +++ b/Mage.Sets/src/mage/sets/fallenempires/HomaridWarrior1.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.fallenempires; + +import java.util.UUID; +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.effects.Effect; +import mage.abilities.effects.common.DontUntapInControllersNextUntapStepSourceEffect; +import mage.abilities.effects.common.TapSourceEffect; +import mage.abilities.effects.common.continuous.GainAbilitySourceEffect; +import mage.abilities.keyword.ShroudAbility; +import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.Rarity; +import mage.constants.Zone; + +/** + * + * @author LoneFox + */ +public class HomaridWarrior1 extends CardImpl { + + public HomaridWarrior1(UUID ownerId) { + super(ownerId, 44, "Homarid Warrior", Rarity.COMMON, new CardType[]{CardType.CREATURE}, "{4}{U}"); + this.expansionSetCode = "FEM"; + this.subtype.add("Homarid"); + this.subtype.add("Warrior"); + this.power = new MageInt(3); + this.toughness = new MageInt(3); + + // {U}: Homarid Warrior gains shroud until end of turn and doesn't untap during your next untap step. Tap Homarid Warrior. + Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new GainAbilitySourceEffect( + ShroudAbility.getInstance(), Duration.EndOfTurn), new ManaCostsImpl("{U}")); + Effect effect = new DontUntapInControllersNextUntapStepSourceEffect(); + effect.setText("and doesn't untap during your next untap step"); + ability.addEffect(effect); + ability.addEffect(new TapSourceEffect()); + this.addAbility(ability); + } + + public HomaridWarrior1(final HomaridWarrior1 card) { + super(card); + } + + @Override + public HomaridWarrior1 copy() { + return new HomaridWarrior1(this); + } +} diff --git a/Mage.Sets/src/mage/sets/fallenempires/HomaridWarrior2.java b/Mage.Sets/src/mage/sets/fallenempires/HomaridWarrior2.java new file mode 100644 index 00000000000..f927b68c666 --- /dev/null +++ b/Mage.Sets/src/mage/sets/fallenempires/HomaridWarrior2.java @@ -0,0 +1,51 @@ +/* + * 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.fallenempires; + +import java.util.UUID; + +/** + * + * @author LoneFox + */ +public class HomaridWarrior2 extends HomaridWarrior1 { + + public HomaridWarrior2(UUID ownerId) { + super(ownerId); + this.cardNumber = 45; + } + + public HomaridWarrior2(final HomaridWarrior2 card) { + super(card); + } + + @Override + public HomaridWarrior2 copy() { + return new HomaridWarrior2(this); + } +} diff --git a/Mage.Sets/src/mage/sets/fallenempires/HomaridWarrior3.java b/Mage.Sets/src/mage/sets/fallenempires/HomaridWarrior3.java new file mode 100644 index 00000000000..92ba080f52c --- /dev/null +++ b/Mage.Sets/src/mage/sets/fallenempires/HomaridWarrior3.java @@ -0,0 +1,51 @@ +/* + * 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.fallenempires; + +import java.util.UUID; + +/** + * + * @author LoneFox + */ +public class HomaridWarrior3 extends HomaridWarrior1 { + + public HomaridWarrior3(UUID ownerId) { + super(ownerId); + this.cardNumber = 46; + } + + public HomaridWarrior3(final HomaridWarrior3 card) { + super(card); + } + + @Override + public HomaridWarrior3 copy() { + return new HomaridWarrior3(this); + } +} diff --git a/Mage.Sets/src/mage/sets/fallenempires/VodalianMage1.java b/Mage.Sets/src/mage/sets/fallenempires/VodalianMage1.java new file mode 100644 index 00000000000..ec3c12ddde3 --- /dev/null +++ b/Mage.Sets/src/mage/sets/fallenempires/VodalianMage1.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.fallenempires; + +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.costs.mana.ManaCostsImpl; +import mage.abilities.effects.common.CounterUnlessPaysEffect; +import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.Rarity; +import mage.constants.Zone; +import mage.target.TargetSpell; + +/** + * + * @author LoneFox + */ +public class VodalianMage1 extends CardImpl { + + public VodalianMage1(UUID ownerId) { + super(ownerId, 59, "Vodalian Mage", Rarity.COMMON, new CardType[]{CardType.CREATURE}, "{2}{U}"); + this.expansionSetCode = "FEM"; + this.subtype.add("Merfolk"); + this.subtype.add("Wizard"); + this.power = new MageInt(1); + this.toughness = new MageInt(1); + + // {U}, {tap}: Counter target spell unless its controller pays {1}. + Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new CounterUnlessPaysEffect(new ManaCostsImpl("{1}")), + new ManaCostsImpl("{U}")); + ability.addCost(new TapSourceCost()); + ability.addTarget(new TargetSpell()); + this.addAbility(ability); + } + + public VodalianMage1(final VodalianMage1 card) { + super(card); + } + + @Override + public VodalianMage1 copy() { + return new VodalianMage1(this); + } +} diff --git a/Mage.Sets/src/mage/sets/fallenempires/VodalianMage2.java b/Mage.Sets/src/mage/sets/fallenempires/VodalianMage2.java new file mode 100644 index 00000000000..c1d98f22070 --- /dev/null +++ b/Mage.Sets/src/mage/sets/fallenempires/VodalianMage2.java @@ -0,0 +1,51 @@ +/* + * 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.fallenempires; + +import java.util.UUID; + +/** + * + * @author LoneFox + */ +public class VodalianMage2 extends VodalianMage1 { + + public VodalianMage2(UUID ownerId) { + super(ownerId); + this.cardNumber = 60; + } + + public VodalianMage2(final VodalianMage2 card) { + super(card); + } + + @Override + public VodalianMage2 copy() { + return new VodalianMage2(this); + } +} diff --git a/Mage.Sets/src/mage/sets/fallenempires/VodalianMage3.java b/Mage.Sets/src/mage/sets/fallenempires/VodalianMage3.java new file mode 100644 index 00000000000..c7d1789e17f --- /dev/null +++ b/Mage.Sets/src/mage/sets/fallenempires/VodalianMage3.java @@ -0,0 +1,51 @@ +/* + * 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.fallenempires; + +import java.util.UUID; + +/** + * + * @author LoneFox + */ +public class VodalianMage3 extends VodalianMage1 { + + public VodalianMage3(UUID ownerId) { + super(ownerId); + this.cardNumber = 61; + } + + public VodalianMage3(final VodalianMage3 card) { + super(card); + } + + @Override + public VodalianMage3 copy() { + return new VodalianMage3(this); + } +} diff --git a/Mage.Sets/src/mage/sets/fifthedition/HomaridWarrior.java b/Mage.Sets/src/mage/sets/fifthedition/HomaridWarrior.java new file mode 100644 index 00000000000..a5498872d0b --- /dev/null +++ b/Mage.Sets/src/mage/sets/fifthedition/HomaridWarrior.java @@ -0,0 +1,52 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.sets.fifthedition; + +import java.util.UUID; + +/** + * + * @author LoneFox + */ +public class HomaridWarrior extends mage.sets.fallenempires.HomaridWarrior1 { + + public HomaridWarrior(UUID ownerId) { + super(ownerId); + this.cardNumber = 92; + this.expansionSetCode = "5ED"; + } + + public HomaridWarrior(final HomaridWarrior card) { + super(card); + } + + @Override + public HomaridWarrior copy() { + return new HomaridWarrior(this); + } +} diff --git a/Mage.Sets/src/mage/sets/masterseditionii/DeepSpawn.java b/Mage.Sets/src/mage/sets/masterseditionii/DeepSpawn.java new file mode 100644 index 00000000000..f990a1afa13 --- /dev/null +++ b/Mage.Sets/src/mage/sets/masterseditionii/DeepSpawn.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.masterseditionii; + +import java.util.UUID; +import mage.constants.Rarity; + +/** + * + * @author LoneFox + */ +public class DeepSpawn extends mage.sets.fallenempires.DeepSpawn { + + public DeepSpawn(UUID ownerId) { + super(ownerId); + this.cardNumber = 45; + this.expansionSetCode = "ME2"; + this.rarity = Rarity.RARE; + } + + public DeepSpawn(final DeepSpawn card) { + super(card); + } + + @Override + public DeepSpawn copy() { + return new DeepSpawn(this); + } +} From 68c354086336678a42d9eff9e2460601b397196e Mon Sep 17 00:00:00 2001 From: LoneFox Date: Mon, 12 Oct 2015 21:42:42 +0300 Subject: [PATCH 121/268] Implement cards: Basal Thrull, Combat Medic, Elven Fortress, and Ring of Renewal --- .../mage/sets/fallenempires/BasalThrull1.java | 70 ++++++++++++++++++ .../mage/sets/fallenempires/BasalThrull2.java | 51 +++++++++++++ .../mage/sets/fallenempires/BasalThrull3.java | 51 +++++++++++++ .../mage/sets/fallenempires/BasalThrull4.java | 51 +++++++++++++ .../mage/sets/fallenempires/CombatMedic1.java | 52 ++++++++++++++ .../mage/sets/fallenempires/CombatMedic2.java | 52 ++++++++++++++ .../mage/sets/fallenempires/CombatMedic3.java | 52 ++++++++++++++ .../mage/sets/fallenempires/CombatMedic4.java | 52 ++++++++++++++ .../sets/fallenempires/ElvenFortress1.java | 67 +++++++++++++++++ .../sets/fallenempires/ElvenFortress2.java | 51 +++++++++++++ .../sets/fallenempires/ElvenFortress3.java | 51 +++++++++++++ .../sets/fallenempires/ElvenFortress4.java | 51 +++++++++++++ .../sets/fallenempires/RingOfRenewal.java | 52 ++++++++++++++ .../mage/sets/mastersedition/BasalThrull.java | 52 ++++++++++++++ .../sets/masterseditionii/CombatMedic.java | 72 +++++++++++++++++++ .../sets/masterseditioniv/RingOfRenewal.java | 70 ++++++++++++++++++ 16 files changed, 897 insertions(+) create mode 100644 Mage.Sets/src/mage/sets/fallenempires/BasalThrull1.java create mode 100644 Mage.Sets/src/mage/sets/fallenempires/BasalThrull2.java create mode 100644 Mage.Sets/src/mage/sets/fallenempires/BasalThrull3.java create mode 100644 Mage.Sets/src/mage/sets/fallenempires/BasalThrull4.java create mode 100644 Mage.Sets/src/mage/sets/fallenempires/CombatMedic1.java create mode 100644 Mage.Sets/src/mage/sets/fallenempires/CombatMedic2.java create mode 100644 Mage.Sets/src/mage/sets/fallenempires/CombatMedic3.java create mode 100644 Mage.Sets/src/mage/sets/fallenempires/CombatMedic4.java create mode 100644 Mage.Sets/src/mage/sets/fallenempires/ElvenFortress1.java create mode 100644 Mage.Sets/src/mage/sets/fallenempires/ElvenFortress2.java create mode 100644 Mage.Sets/src/mage/sets/fallenempires/ElvenFortress3.java create mode 100644 Mage.Sets/src/mage/sets/fallenempires/ElvenFortress4.java create mode 100644 Mage.Sets/src/mage/sets/fallenempires/RingOfRenewal.java create mode 100644 Mage.Sets/src/mage/sets/mastersedition/BasalThrull.java create mode 100644 Mage.Sets/src/mage/sets/masterseditionii/CombatMedic.java create mode 100644 Mage.Sets/src/mage/sets/masterseditioniv/RingOfRenewal.java diff --git a/Mage.Sets/src/mage/sets/fallenempires/BasalThrull1.java b/Mage.Sets/src/mage/sets/fallenempires/BasalThrull1.java new file mode 100644 index 00000000000..efef91c76aa --- /dev/null +++ b/Mage.Sets/src/mage/sets/fallenempires/BasalThrull1.java @@ -0,0 +1,70 @@ +/* + * 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.fallenempires; + +import java.util.UUID; +import mage.MageInt; +import mage.Mana; +import mage.abilities.Ability; +import mage.abilities.costs.common.SacrificeSourceCost; +import mage.abilities.costs.common.TapSourceCost; +import mage.abilities.effects.common.BasicManaEffect; +import mage.abilities.mana.SimpleManaAbility; +import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.Rarity; +import mage.constants.Zone; + +/** + * + * @author LoneFox + */ +public class BasalThrull1 extends CardImpl { + + public BasalThrull1(UUID ownerId) { + super(ownerId, 5, "Basal Thrull", Rarity.COMMON, new CardType[]{CardType.CREATURE}, "{B}{B}"); + this.expansionSetCode = "FEM"; + this.subtype.add("Thrull"); + this.power = new MageInt(1); + this.toughness = new MageInt(2); + + // {T}, Sacrifice Basal Thrull: Add {B}{B} to your mana pool. + Ability ability = new SimpleManaAbility(Zone.BATTLEFIELD, new BasicManaEffect(new Mana(0, 0, 0, 0, 2, 0, 0)), new TapSourceCost()); + ability.addCost(new SacrificeSourceCost()); + this.addAbility(ability); + } + + public BasalThrull1(final BasalThrull1 card) { + super(card); + } + + @Override + public BasalThrull1 copy() { + return new BasalThrull1(this); + } +} diff --git a/Mage.Sets/src/mage/sets/fallenempires/BasalThrull2.java b/Mage.Sets/src/mage/sets/fallenempires/BasalThrull2.java new file mode 100644 index 00000000000..93ab2baea70 --- /dev/null +++ b/Mage.Sets/src/mage/sets/fallenempires/BasalThrull2.java @@ -0,0 +1,51 @@ +/* + * 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.fallenempires; + +import java.util.UUID; + +/** + * + * @author LoneFox + */ +public class BasalThrull2 extends BasalThrull1 { + + public BasalThrull2(UUID ownerId) { + super(ownerId); + this.cardNumber = 6; + } + + public BasalThrull2(final BasalThrull2 card) { + super(card); + } + + @Override + public BasalThrull2 copy() { + return new BasalThrull2(this); + } +} diff --git a/Mage.Sets/src/mage/sets/fallenempires/BasalThrull3.java b/Mage.Sets/src/mage/sets/fallenempires/BasalThrull3.java new file mode 100644 index 00000000000..27a36274d83 --- /dev/null +++ b/Mage.Sets/src/mage/sets/fallenempires/BasalThrull3.java @@ -0,0 +1,51 @@ +/* + * 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.fallenempires; + +import java.util.UUID; + +/** + * + * @author LoneFox + */ +public class BasalThrull3 extends BasalThrull1 { + + public BasalThrull3(UUID ownerId) { + super(ownerId); + this.cardNumber = 7; + } + + public BasalThrull3(final BasalThrull3 card) { + super(card); + } + + @Override + public BasalThrull3 copy() { + return new BasalThrull3(this); + } +} diff --git a/Mage.Sets/src/mage/sets/fallenempires/BasalThrull4.java b/Mage.Sets/src/mage/sets/fallenempires/BasalThrull4.java new file mode 100644 index 00000000000..d2441b5dc52 --- /dev/null +++ b/Mage.Sets/src/mage/sets/fallenempires/BasalThrull4.java @@ -0,0 +1,51 @@ +/* + * 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.fallenempires; + +import java.util.UUID; + +/** + * + * @author LoneFox + */ +public class BasalThrull4 extends BasalThrull1 { + + public BasalThrull4(UUID ownerId) { + super(ownerId); + this.cardNumber = 8; + } + + public BasalThrull4(final BasalThrull4 card) { + super(card); + } + + @Override + public BasalThrull4 copy() { + return new BasalThrull4(this); + } +} diff --git a/Mage.Sets/src/mage/sets/fallenempires/CombatMedic1.java b/Mage.Sets/src/mage/sets/fallenempires/CombatMedic1.java new file mode 100644 index 00000000000..c564b342fa9 --- /dev/null +++ b/Mage.Sets/src/mage/sets/fallenempires/CombatMedic1.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.fallenempires; + +import java.util.UUID; + +/** + * + * @author LoneFox + */ +public class CombatMedic1 extends mage.sets.masterseditionii.CombatMedic { + + public CombatMedic1(UUID ownerId) { + super(ownerId); + this.cardNumber = 133; + this.expansionSetCode = "FEM"; + } + + public CombatMedic1(final CombatMedic1 card) { + super(card); + } + + @Override + public CombatMedic1 copy() { + return new CombatMedic1(this); + } +} diff --git a/Mage.Sets/src/mage/sets/fallenempires/CombatMedic2.java b/Mage.Sets/src/mage/sets/fallenempires/CombatMedic2.java new file mode 100644 index 00000000000..9234cc19515 --- /dev/null +++ b/Mage.Sets/src/mage/sets/fallenempires/CombatMedic2.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.fallenempires; + +import java.util.UUID; + +/** + * + * @author LoneFox + */ +public class CombatMedic2 extends mage.sets.masterseditionii.CombatMedic { + + public CombatMedic2(UUID ownerId) { + super(ownerId); + this.cardNumber = 134; + this.expansionSetCode = "FEM"; + } + + public CombatMedic2(final CombatMedic2 card) { + super(card); + } + + @Override + public CombatMedic2 copy() { + return new CombatMedic2(this); + } +} diff --git a/Mage.Sets/src/mage/sets/fallenempires/CombatMedic3.java b/Mage.Sets/src/mage/sets/fallenempires/CombatMedic3.java new file mode 100644 index 00000000000..d6efe570e65 --- /dev/null +++ b/Mage.Sets/src/mage/sets/fallenempires/CombatMedic3.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.fallenempires; + +import java.util.UUID; + +/** + * + * @author LoneFox + */ +public class CombatMedic3 extends mage.sets.masterseditionii.CombatMedic { + + public CombatMedic3(UUID ownerId) { + super(ownerId); + this.cardNumber = 135; + this.expansionSetCode = "FEM"; + } + + public CombatMedic3(final CombatMedic3 card) { + super(card); + } + + @Override + public CombatMedic3 copy() { + return new CombatMedic3(this); + } +} diff --git a/Mage.Sets/src/mage/sets/fallenempires/CombatMedic4.java b/Mage.Sets/src/mage/sets/fallenempires/CombatMedic4.java new file mode 100644 index 00000000000..33028ae3b51 --- /dev/null +++ b/Mage.Sets/src/mage/sets/fallenempires/CombatMedic4.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.fallenempires; + +import java.util.UUID; + +/** + * + * @author LoneFox + */ +public class CombatMedic4 extends mage.sets.masterseditionii.CombatMedic { + + public CombatMedic4(UUID ownerId) { + super(ownerId); + this.cardNumber = 136; + this.expansionSetCode = "FEM"; + } + + public CombatMedic4(final CombatMedic4 card) { + super(card); + } + + @Override + public CombatMedic4 copy() { + return new CombatMedic4(this); + } +} diff --git a/Mage.Sets/src/mage/sets/fallenempires/ElvenFortress1.java b/Mage.Sets/src/mage/sets/fallenempires/ElvenFortress1.java new file mode 100644 index 00000000000..2e5618016c8 --- /dev/null +++ b/Mage.Sets/src/mage/sets/fallenempires/ElvenFortress1.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.fallenempires; + +import java.util.UUID; +import mage.abilities.Ability; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.costs.mana.ManaCostsImpl; +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.constants.Zone; +import mage.filter.common.FilterBlockingCreature; +import mage.target.common.TargetCreaturePermanent; + +/** + * + * @author LoneFox + */ +public class ElvenFortress1 extends CardImpl { + + public ElvenFortress1(UUID ownerId) { + super(ownerId, 67, "Elven Fortress", Rarity.COMMON, new CardType[]{CardType.ENCHANTMENT}, "{G}"); + this.expansionSetCode = "FEM"; + + // {1}{G}: Target blocking creature gets +0/+1 until end of turn. + Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new BoostTargetEffect(0, 1, Duration.EndOfTurn), new ManaCostsImpl("{1}{G}")); + ability.addTarget(new TargetCreaturePermanent(new FilterBlockingCreature())); + this.addAbility(ability); + } + + public ElvenFortress1(final ElvenFortress1 card) { + super(card); + } + + @Override + public ElvenFortress1 copy() { + return new ElvenFortress1(this); + } +} diff --git a/Mage.Sets/src/mage/sets/fallenempires/ElvenFortress2.java b/Mage.Sets/src/mage/sets/fallenempires/ElvenFortress2.java new file mode 100644 index 00000000000..c454d76e92c --- /dev/null +++ b/Mage.Sets/src/mage/sets/fallenempires/ElvenFortress2.java @@ -0,0 +1,51 @@ +/* + * 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.fallenempires; + +import java.util.UUID; + +/** + * + * @author LoneFox + */ +public class ElvenFortress2 extends ElvenFortress1 { + + public ElvenFortress2(UUID ownerId) { + super(ownerId); + this.cardNumber = 68; + } + + public ElvenFortress2(final ElvenFortress2 card) { + super(card); + } + + @Override + public ElvenFortress2 copy() { + return new ElvenFortress2(this); + } +} diff --git a/Mage.Sets/src/mage/sets/fallenempires/ElvenFortress3.java b/Mage.Sets/src/mage/sets/fallenempires/ElvenFortress3.java new file mode 100644 index 00000000000..2af6a0b26af --- /dev/null +++ b/Mage.Sets/src/mage/sets/fallenempires/ElvenFortress3.java @@ -0,0 +1,51 @@ +/* + * 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.fallenempires; + +import java.util.UUID; + +/** + * + * @author LoneFox + */ +public class ElvenFortress3 extends ElvenFortress1 { + + public ElvenFortress3(UUID ownerId) { + super(ownerId); + this.cardNumber = 69; + } + + public ElvenFortress3(final ElvenFortress3 card) { + super(card); + } + + @Override + public ElvenFortress3 copy() { + return new ElvenFortress3(this); + } +} diff --git a/Mage.Sets/src/mage/sets/fallenempires/ElvenFortress4.java b/Mage.Sets/src/mage/sets/fallenempires/ElvenFortress4.java new file mode 100644 index 00000000000..70e5a5e6ac7 --- /dev/null +++ b/Mage.Sets/src/mage/sets/fallenempires/ElvenFortress4.java @@ -0,0 +1,51 @@ +/* + * 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.fallenempires; + +import java.util.UUID; + +/** + * + * @author LoneFox + */ +public class ElvenFortress4 extends ElvenFortress1 { + + public ElvenFortress4(UUID ownerId) { + super(ownerId); + this.cardNumber = 70; + } + + public ElvenFortress4(final ElvenFortress4 card) { + super(card); + } + + @Override + public ElvenFortress4 copy() { + return new ElvenFortress4(this); + } +} diff --git a/Mage.Sets/src/mage/sets/fallenempires/RingOfRenewal.java b/Mage.Sets/src/mage/sets/fallenempires/RingOfRenewal.java new file mode 100644 index 00000000000..4d9b13c8182 --- /dev/null +++ b/Mage.Sets/src/mage/sets/fallenempires/RingOfRenewal.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.fallenempires; + +import java.util.UUID; + +/** + * + * @author LoneFox + */ +public class RingOfRenewal extends mage.sets.masterseditioniv.RingOfRenewal { + + public RingOfRenewal(UUID ownerId) { + super(ownerId); + this.cardNumber = 174; + this.expansionSetCode = "FEM"; + } + + public RingOfRenewal(final RingOfRenewal card) { + super(card); + } + + @Override + public RingOfRenewal copy() { + return new RingOfRenewal(this); + } +} diff --git a/Mage.Sets/src/mage/sets/mastersedition/BasalThrull.java b/Mage.Sets/src/mage/sets/mastersedition/BasalThrull.java new file mode 100644 index 00000000000..a2cc39602c0 --- /dev/null +++ b/Mage.Sets/src/mage/sets/mastersedition/BasalThrull.java @@ -0,0 +1,52 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.sets.mastersedition; + +import java.util.UUID; + +/** + * + * @author LoneFox + */ +public class BasalThrull extends mage.sets.fallenempires.BasalThrull1 { + + public BasalThrull(UUID ownerId) { + super(ownerId); + this.cardNumber = 59; + this.expansionSetCode = "MED"; + } + + public BasalThrull(final BasalThrull card) { + super(card); + } + + @Override + public BasalThrull copy() { + return new BasalThrull(this); + } +} diff --git a/Mage.Sets/src/mage/sets/masterseditionii/CombatMedic.java b/Mage.Sets/src/mage/sets/masterseditionii/CombatMedic.java new file mode 100644 index 00000000000..6708aa9d2c7 --- /dev/null +++ b/Mage.Sets/src/mage/sets/masterseditionii/CombatMedic.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.masterseditionii; + +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.PreventDamageToTargetEffect; +import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.Rarity; +import mage.constants.Zone; +import mage.target.common.TargetCreatureOrPlayer; + +/** + * + * @author LoneFox + */ +public class CombatMedic extends CardImpl { + + public CombatMedic(UUID ownerId) { + super(ownerId, 9, "Combat Medic", Rarity.COMMON, new CardType[]{CardType.CREATURE}, "{2}{W}"); + this.expansionSetCode = "ME2"; + this.subtype.add("Human"); + this.subtype.add("Cleric"); + this.subtype.add("Soldier"); + this.power = new MageInt(0); + this.toughness = new MageInt(2); + + // {1}{W}: Prevent the next 1 damage that would be dealt to target creature or player this turn. + Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new PreventDamageToTargetEffect(Duration.EndOfTurn, 1), new ManaCostsImpl("{1}{W}")); + ability.addTarget(new TargetCreatureOrPlayer()); + this.addAbility(ability); + } + + public CombatMedic(final CombatMedic card) { + super(card); + } + + @Override + public CombatMedic copy() { + return new CombatMedic(this); + } +} diff --git a/Mage.Sets/src/mage/sets/masterseditioniv/RingOfRenewal.java b/Mage.Sets/src/mage/sets/masterseditioniv/RingOfRenewal.java new file mode 100644 index 00000000000..61ac07d1299 --- /dev/null +++ b/Mage.Sets/src/mage/sets/masterseditioniv/RingOfRenewal.java @@ -0,0 +1,70 @@ +/* + * 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.masterseditioniv; + +import java.util.UUID; +import mage.abilities.Ability; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.costs.common.TapSourceCost; +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.effects.Effect; +import mage.abilities.effects.common.DrawCardSourceControllerEffect; +import mage.abilities.effects.common.discard.DiscardControllerEffect; +import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.Rarity; +import mage.constants.Zone; + +/** + * + * @author LoneFox + */ +public class RingOfRenewal extends CardImpl { + + public RingOfRenewal(UUID ownerId) { + super(ownerId, 224, "Ring of Renewal", Rarity.RARE, new CardType[]{CardType.ARTIFACT}, "{5}"); + this.expansionSetCode = "ME4"; + + // {5}, {tap}: Discard a card at random, then draw two cards. + Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new DiscardControllerEffect(1, true), new ManaCostsImpl("{5}")); + ability.addCost(new TapSourceCost()); + Effect effect = new DrawCardSourceControllerEffect(2); + effect.setText(", then draw two cards"); + ability.addEffect(effect); + this.addAbility(ability); + } + + public RingOfRenewal(final RingOfRenewal card) { + super(card); + } + + @Override + public RingOfRenewal copy() { + return new RingOfRenewal(this); + } +} From fd7bf5d7900f84a6ee36682b3900c0cb39e3f568 Mon Sep 17 00:00:00 2001 From: LoneFox Date: Mon, 12 Oct 2015 22:19:13 +0300 Subject: [PATCH 122/268] Kill a few DamageTargetControllerEffect implementations --- .../riseoftheeldrazi/GrotagSiegeRunner.java | 47 +++------------- .../sets/scarsofmirrodin/MeltTerrain.java | 52 +++--------------- .../mage/sets/shadowmoor/PoisonTheWell.java | 45 +++------------ .../sets/shadowmoor/SmashToSmithereens.java | 51 +++-------------- .../src/mage/sets/tenthedition/Cryoclasm.java | 55 +++---------------- .../src/mage/sets/theros/PeakEruption.java | 53 +++--------------- 6 files changed, 47 insertions(+), 256 deletions(-) diff --git a/Mage.Sets/src/mage/sets/riseoftheeldrazi/GrotagSiegeRunner.java b/Mage.Sets/src/mage/sets/riseoftheeldrazi/GrotagSiegeRunner.java index 4c8578d6096..e3407fb0dec 100644 --- a/Mage.Sets/src/mage/sets/riseoftheeldrazi/GrotagSiegeRunner.java +++ b/Mage.Sets/src/mage/sets/riseoftheeldrazi/GrotagSiegeRunner.java @@ -28,24 +28,21 @@ package mage.sets.riseoftheeldrazi; import java.util.UUID; -import mage.constants.CardType; -import mage.constants.Outcome; -import mage.constants.Rarity; -import mage.constants.Zone; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.SimpleActivatedAbility; import mage.abilities.costs.common.SacrificeSourceCost; import mage.abilities.costs.mana.ManaCostsImpl; -import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.Effect; +import mage.abilities.effects.common.DamageTargetControllerEffect; import mage.abilities.effects.common.DestroyTargetEffect; import mage.abilities.keyword.DefenderAbility; import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.Rarity; +import mage.constants.Zone; import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.mageobject.AbilityPredicate; -import mage.game.Game; -import mage.game.permanent.Permanent; -import mage.players.Player; import mage.target.common.TargetCreaturePermanent; /** @@ -70,10 +67,12 @@ public class GrotagSiegeRunner extends CardImpl { this.toughness = new MageInt(1); // {R}, Sacrifice Grotag Siege-Runner: Destroy target creature with defender. Grotag Siege-Runner deals 2 damage to that creature's controller. - SimpleActivatedAbility ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new DestroyTargetEffect(), new ManaCostsImpl("{R}")); + Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new DestroyTargetEffect(), new ManaCostsImpl("{R}")); ability.addCost(new SacrificeSourceCost()); + Effect effect = new DamageTargetControllerEffect(2); + effect.setText("{this} deals 2 damage to that creature's controller"); + ability.addEffect(effect); ability.addTarget(new TargetCreaturePermanent(filter)); - ability.addEffect(new GrotageSiegeRunnerEffect()); this.addAbility(ability); } @@ -86,31 +85,3 @@ public class GrotagSiegeRunner extends CardImpl { return new GrotagSiegeRunner(this); } } - -class GrotageSiegeRunnerEffect extends OneShotEffect { - - public GrotageSiegeRunnerEffect() { - super(Outcome.Damage); - this.staticText = "{this} deals 2 damage to that creature's controller"; - } - - public GrotageSiegeRunnerEffect(final GrotageSiegeRunnerEffect effect) { - super(effect); - } - - @Override - public GrotageSiegeRunnerEffect copy() { - return new GrotageSiegeRunnerEffect(this); - } - - @Override - public boolean apply(Game game, Ability source) { - Permanent permanent = (Permanent) game.getLastKnownInformation(source.getFirstTarget(), Zone.BATTLEFIELD); - if (permanent != null) { - Player controller = game.getPlayer(permanent.getControllerId()); - controller.damage(2, source.getSourceId(), game, false, true); - return true; - } - return false; - } -} diff --git a/Mage.Sets/src/mage/sets/scarsofmirrodin/MeltTerrain.java b/Mage.Sets/src/mage/sets/scarsofmirrodin/MeltTerrain.java index 8c95d5de0b3..0524d95acd6 100644 --- a/Mage.Sets/src/mage/sets/scarsofmirrodin/MeltTerrain.java +++ b/Mage.Sets/src/mage/sets/scarsofmirrodin/MeltTerrain.java @@ -29,18 +29,12 @@ package mage.sets.scarsofmirrodin; import java.util.UUID; - -import mage.constants.CardType; -import mage.constants.Rarity; -import mage.constants.Zone; -import mage.abilities.Ability; -import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.Effect; +import mage.abilities.effects.common.DamageTargetControllerEffect; import mage.abilities.effects.common.DestroyTargetEffect; import mage.cards.CardImpl; -import mage.constants.Outcome; -import mage.game.Game; -import mage.game.permanent.Permanent; -import mage.players.Player; +import mage.constants.CardType; +import mage.constants.Rarity; import mage.target.common.TargetLandPermanent; /** @@ -53,8 +47,11 @@ public class MeltTerrain extends CardImpl { super(ownerId, 97, "Melt Terrain", Rarity.COMMON, new CardType[]{CardType.SORCERY}, "{2}{R}{R}"); this.expansionSetCode = "SOM"; + // Destroy target land. Melt Terrain deals 2 damage to that land's controller. this.getSpellAbility().addEffect(new DestroyTargetEffect()); - this.getSpellAbility().addEffect(new MeltTerrainEffect()); + Effect effect = new DamageTargetControllerEffect(2); + effect.setText("{this} deals 2 damage to that land's controller"); + this.getSpellAbility().addEffect(effect); this.getSpellAbility().addTarget(new TargetLandPermanent()); } @@ -66,37 +63,4 @@ public class MeltTerrain extends CardImpl { public MeltTerrain copy() { return new MeltTerrain(this); } - } - -class MeltTerrainEffect extends OneShotEffect { - MeltTerrainEffect() { - super(Outcome.Damage); - staticText = "{this} deals 2 damage to that land's controller"; - } - - MeltTerrainEffect(final MeltTerrainEffect effect) { - super(effect); - } - - @Override - public boolean apply(Game game, Ability source) { - Permanent p = game.getBattlefield().getPermanent(source.getFirstTarget()); - if (p == null) { - p = (Permanent) game.getLastKnownInformation(source.getFirstTarget(), Zone.BATTLEFIELD); - } - if (p != null) { - Player player = game.getPlayer(p.getControllerId()); - if (player != null) { - player.damage(2, source.getSourceId(), game, false, true); - } - } - return false; - } - - @Override - public MeltTerrainEffect copy() { - return new MeltTerrainEffect(this); - } - -} \ No newline at end of file diff --git a/Mage.Sets/src/mage/sets/shadowmoor/PoisonTheWell.java b/Mage.Sets/src/mage/sets/shadowmoor/PoisonTheWell.java index cb515b66693..1b8d897cfed 100644 --- a/Mage.Sets/src/mage/sets/shadowmoor/PoisonTheWell.java +++ b/Mage.Sets/src/mage/sets/shadowmoor/PoisonTheWell.java @@ -28,15 +28,12 @@ package mage.sets.shadowmoor; import java.util.UUID; -import mage.abilities.Ability; -import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.Effect; +import mage.abilities.effects.common.DamageTargetControllerEffect; +import mage.abilities.effects.common.DestroyTargetEffect; 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.players.Player; import mage.target.common.TargetLandPermanent; /** @@ -50,7 +47,10 @@ public class PoisonTheWell extends CardImpl { this.expansionSetCode = "SHM"; // Destroy target land. Poison the Well deals 2 damage to that land's controller. - this.getSpellAbility().addEffect(new PoisonTheWellEffect()); + this.getSpellAbility().addEffect(new DestroyTargetEffect()); + Effect effect = new DamageTargetControllerEffect(2); + effect.setText("{this} deals 2 damage to that land's controller"); + this.getSpellAbility().addEffect(effect); this.getSpellAbility().addTarget(new TargetLandPermanent()); } @@ -63,34 +63,3 @@ public class PoisonTheWell extends CardImpl { return new PoisonTheWell(this); } } - -class PoisonTheWellEffect extends OneShotEffect { - - public PoisonTheWellEffect() { - super(Outcome.DestroyPermanent); - this.staticText = "Destroy target land. {this} deals 2 damage to that land's controller"; - } - - public PoisonTheWellEffect(final PoisonTheWellEffect effect) { - super(effect); - } - - @Override - public PoisonTheWellEffect copy() { - return new PoisonTheWellEffect(this); - } - - @Override - public boolean apply(Game game, Ability source) { - Permanent targetedLand = game.getPermanent(source.getFirstTarget()); - if (targetedLand != null) { - targetedLand.destroy(source.getSourceId(), game, true); - Player controller = game.getPlayer(targetedLand.getControllerId()); - if (controller != null) { - controller.damage(2, source.getSourceId(), game, false, true); - } - return true; - } - return false; - } -} diff --git a/Mage.Sets/src/mage/sets/shadowmoor/SmashToSmithereens.java b/Mage.Sets/src/mage/sets/shadowmoor/SmashToSmithereens.java index 98ff75dc2bc..113b83d9f7e 100644 --- a/Mage.Sets/src/mage/sets/shadowmoor/SmashToSmithereens.java +++ b/Mage.Sets/src/mage/sets/shadowmoor/SmashToSmithereens.java @@ -28,17 +28,12 @@ package mage.sets.shadowmoor; import java.util.UUID; -import mage.constants.CardType; -import mage.constants.Outcome; -import mage.constants.Rarity; -import mage.constants.Zone; -import mage.abilities.Ability; -import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.Effect; +import mage.abilities.effects.common.DamageTargetControllerEffect; import mage.abilities.effects.common.DestroyTargetEffect; import mage.cards.CardImpl; -import mage.game.Game; -import mage.game.permanent.Permanent; -import mage.players.Player; +import mage.constants.CardType; +import mage.constants.Rarity; import mage.target.common.TargetArtifactPermanent; /** @@ -52,9 +47,11 @@ public class SmashToSmithereens extends CardImpl { this.expansionSetCode = "SHM"; // Destroy target artifact. Smash to Smithereens deals 3 damage to that artifact's controller. - this.getSpellAbility().addTarget(new TargetArtifactPermanent()); this.getSpellAbility().addEffect(new DestroyTargetEffect()); - this.getSpellAbility().addEffect(new SmashToSmithereensEffect()); + Effect effect = new DamageTargetControllerEffect(3); + effect.setText("{this} deals 3 damage to that artifact's controller"); + this.getSpellAbility().addEffect(effect); + this.getSpellAbility().addTarget(new TargetArtifactPermanent()); } public SmashToSmithereens(final SmashToSmithereens card) { @@ -66,35 +63,3 @@ public class SmashToSmithereens extends CardImpl { return new SmashToSmithereens(this); } } - -class SmashToSmithereensEffect extends OneShotEffect { - - SmashToSmithereensEffect() { - super(Outcome.Damage); - staticText = "{this} deals 3 damage to that artifact's controller"; - } - - SmashToSmithereensEffect(final SmashToSmithereensEffect effect) { - super(effect); - } - - @Override - public boolean apply(Game game, Ability source) { - Permanent permanent = game.getBattlefield().getPermanent(source.getFirstTarget()); - if (permanent == null) { - permanent = (Permanent) game.getLastKnownInformation(source.getFirstTarget(), Zone.BATTLEFIELD); - } - if (permanent != null) { - Player player = game.getPlayer(permanent.getControllerId()); - if (player != null) { - player.damage(3, source.getSourceId(), game, false, true); - } - } - return false; - } - - @Override - public SmashToSmithereensEffect copy() { - return new SmashToSmithereensEffect(this); - } -} diff --git a/Mage.Sets/src/mage/sets/tenthedition/Cryoclasm.java b/Mage.Sets/src/mage/sets/tenthedition/Cryoclasm.java index f76c044baa2..c9c1cff99b5 100644 --- a/Mage.Sets/src/mage/sets/tenthedition/Cryoclasm.java +++ b/Mage.Sets/src/mage/sets/tenthedition/Cryoclasm.java @@ -28,23 +28,15 @@ package mage.sets.tenthedition; import java.util.UUID; - -import mage.MageObject; -import mage.abilities.Ability; -import mage.abilities.effects.OneShotEffect; -import mage.abilities.effects.common.DamageTargetEffect; +import mage.abilities.effects.Effect; +import mage.abilities.effects.common.DamageTargetControllerEffect; import mage.abilities.effects.common.DestroyTargetEffect; import mage.cards.CardImpl; import mage.constants.CardType; -import mage.constants.Outcome; import mage.constants.Rarity; -import mage.constants.Zone; import mage.filter.common.FilterLandPermanent; import mage.filter.predicate.Predicates; import mage.filter.predicate.mageobject.SubtypePredicate; -import mage.game.Game; -import mage.game.permanent.Permanent; -import mage.players.Player; import mage.target.common.TargetLandPermanent; /** @@ -54,20 +46,20 @@ import mage.target.common.TargetLandPermanent; public class Cryoclasm extends CardImpl { private static final FilterLandPermanent filter = new FilterLandPermanent("Plains or Island"); + static { - filter.add(Predicates.or( - new SubtypePredicate("Plains"), - new SubtypePredicate("Island"))); + filter.add(Predicates.or(new SubtypePredicate("Plains"), new SubtypePredicate("Island"))); } public Cryoclasm(UUID ownerId) { super(ownerId, 195, "Cryoclasm", Rarity.UNCOMMON, new CardType[]{CardType.SORCERY}, "{2}{R}"); this.expansionSetCode = "10E"; - // Destroy target Plains or Island. Cryoclasm deals 3 damage to that land's controller. this.getSpellAbility().addEffect(new DestroyTargetEffect()); - this.getSpellAbility().addEffect(new CryoclasmEffect()); + Effect effect = new DamageTargetControllerEffect(3); + effect.setText("{this} deals 3 damage to that land's controller"); + this.getSpellAbility().addEffect(effect); this.getSpellAbility().addTarget(new TargetLandPermanent(filter)); } @@ -81,36 +73,3 @@ public class Cryoclasm extends CardImpl { return new Cryoclasm(this); } } - -class CryoclasmEffect extends OneShotEffect { - - public CryoclasmEffect() { - super(Outcome.Damage); - this.staticText = "{this} deals 3 damage to that land's controller"; - } - - public CryoclasmEffect(final CryoclasmEffect effect) { - super(effect); - } - - @Override - public CryoclasmEffect copy() { - return new CryoclasmEffect(this); - } - - @Override - public boolean apply(Game game, Ability source) { - UUID targetId = getTargetPointer().getFirst(game, source); - if (targetId != null) { - Permanent permanent = game.getPermanentOrLKIBattlefield(targetId); - if (permanent != null) { - Player controller = game.getPlayer(permanent.getControllerId()); - if (controller != null) { - controller.damage(3, source.getSourceId(), game, false, false); - return true; - } - } - } - return false; - } -} \ No newline at end of file diff --git a/Mage.Sets/src/mage/sets/theros/PeakEruption.java b/Mage.Sets/src/mage/sets/theros/PeakEruption.java index 4aa27c573a4..0b8e9796eb1 100644 --- a/Mage.Sets/src/mage/sets/theros/PeakEruption.java +++ b/Mage.Sets/src/mage/sets/theros/PeakEruption.java @@ -28,19 +28,14 @@ package mage.sets.theros; import java.util.UUID; -import mage.abilities.Ability; -import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.Effect; +import mage.abilities.effects.common.DamageTargetControllerEffect; import mage.abilities.effects.common.DestroyTargetEffect; import mage.cards.CardImpl; import mage.constants.CardType; -import mage.constants.Outcome; import mage.constants.Rarity; -import mage.constants.Zone; import mage.filter.common.FilterLandPermanent; import mage.filter.predicate.mageobject.SubtypePredicate; -import mage.game.Game; -import mage.game.permanent.Permanent; -import mage.players.Player; import mage.target.common.TargetLandPermanent; /** @@ -50,20 +45,21 @@ import mage.target.common.TargetLandPermanent; public class PeakEruption extends CardImpl { private static final FilterLandPermanent filter = new FilterLandPermanent("Mountain"); + static{ filter.add(new SubtypePredicate(("Mountain"))); } - - + public PeakEruption(UUID ownerId) { super(ownerId, 132, "Peak Eruption", Rarity.UNCOMMON, new CardType[]{CardType.SORCERY}, "{2}{R}"); this.expansionSetCode = "THS"; - // Destroy target Mountain. Peak Eruption deals 3 damage to that land's controller. - this.getSpellAbility().addTarget(new TargetLandPermanent(filter)); this.getSpellAbility().addEffect(new DestroyTargetEffect()); - this.getSpellAbility().addEffect(new PeakEruptionEffect()); + Effect effect = new DamageTargetControllerEffect(3); + effect.setText("{this} deals 3 damage to that land's controller"); + this.getSpellAbility().addEffect(effect); + this.getSpellAbility().addTarget(new TargetLandPermanent(filter)); } public PeakEruption(final PeakEruption card) { @@ -75,36 +71,3 @@ public class PeakEruption extends CardImpl { return new PeakEruption(this); } } - - -class PeakEruptionEffect extends OneShotEffect { - - PeakEruptionEffect() { - super(Outcome.Damage); - staticText = "{this} deals 3 damage to that land's controller"; - } - - PeakEruptionEffect(final PeakEruptionEffect effect) { - super(effect); - } - - @Override - public boolean apply(Game game, Ability source) { - Permanent permanent = game.getBattlefield().getPermanent(source.getFirstTarget()); - if (permanent == null) { - permanent = (Permanent) game.getLastKnownInformation(source.getFirstTarget(), Zone.BATTLEFIELD); - } - if (permanent != null) { - Player player = game.getPlayer(permanent.getControllerId()); - if (player != null) { - player.damage(3, source.getSourceId(), game, false, true); - } - } - return false; - } - - @Override - public PeakEruptionEffect copy() { - return new PeakEruptionEffect(this); - } -} From 3076ebd5ad38491ad237bf452cf1d3497ec8936f Mon Sep 17 00:00:00 2001 From: Jeff Date: Mon, 12 Oct 2015 15:15:29 -0500 Subject: [PATCH 123/268] - Simple text fixes. --- Mage/src/mage/abilities/keyword/ConspireAbility.java | 2 +- Mage/src/mage/watchers/common/FirstTimeStepWatcher.java | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Mage/src/mage/abilities/keyword/ConspireAbility.java b/Mage/src/mage/abilities/keyword/ConspireAbility.java index cef23120fe0..a655b31721d 100644 --- a/Mage/src/mage/abilities/keyword/ConspireAbility.java +++ b/Mage/src/mage/abilities/keyword/ConspireAbility.java @@ -68,7 +68,7 @@ import mage.target.common.TargetControlledPermanent; * 702.77b If a spell has multiple instances of conspire, each is paid separately and triggers * based on its own payment, not any other instance of conspire. * * - * @author jeffwadsworth heavily based off the replicate keyword by LevelX + * @author LevelX */ public class ConspireAbility extends StaticAbility implements OptionalAdditionalSourceCosts { diff --git a/Mage/src/mage/watchers/common/FirstTimeStepWatcher.java b/Mage/src/mage/watchers/common/FirstTimeStepWatcher.java index 911a3ecf93f..028e77e1209 100644 --- a/Mage/src/mage/watchers/common/FirstTimeStepWatcher.java +++ b/Mage/src/mage/watchers/common/FirstTimeStepWatcher.java @@ -34,8 +34,8 @@ import mage.game.events.GameEvent.EventType; import mage.watchers.Watcher; /** - * The wachter checks if a specific phase event has already happened during the - * current turn. If not it returns false, otheriwsed true. + * The watcher checks if a specific phase event has already happened during the + * current turn. If not it returns false, otherwise true. * * @author LevelX2 */ From f13ca0c87d4744a98ffaac671c066c3a5122af06 Mon Sep 17 00:00:00 2001 From: LevelX2 Date: Mon, 12 Oct 2015 23:10:16 +0200 Subject: [PATCH 124/268] * Oath of Lieges - Fixed target handling (fixes #1312). --- .../src/mage/sets/exodus/OathOfLieges.java | 22 ++-- .../cards/enchantments/OathOfLiegesTest.java | 124 ++++++++++++++++++ .../java/org/mage/test/player/TestPlayer.java | 29 +++- Mage/src/mage/game/GameImpl.java | 2 +- 4 files changed, 163 insertions(+), 14 deletions(-) create mode 100644 Mage.Tests/src/test/java/org/mage/test/cards/enchantments/OathOfLiegesTest.java diff --git a/Mage.Sets/src/mage/sets/exodus/OathOfLieges.java b/Mage.Sets/src/mage/sets/exodus/OathOfLieges.java index b7a8d637588..f11e6b7823e 100644 --- a/Mage.Sets/src/mage/sets/exodus/OathOfLieges.java +++ b/Mage.Sets/src/mage/sets/exodus/OathOfLieges.java @@ -31,7 +31,7 @@ import java.util.UUID; import mage.abilities.Ability; import mage.abilities.common.BeginningOfUpkeepTriggeredAbility; import mage.abilities.effects.Effect; -import mage.abilities.effects.common.search.SearchLibraryPutInPlayEffect; +import mage.abilities.effects.common.search.SearchLibraryPutInPlayTargetPlayerEffect; import mage.cards.CardImpl; import mage.constants.CardType; import mage.constants.Outcome; @@ -46,14 +46,16 @@ import mage.game.Game; import mage.players.Player; import mage.target.TargetPlayer; import mage.target.common.TargetCardInLibrary; +import mage.target.targetpointer.FixedTarget; /** * * @author emerald000 */ public class OathOfLieges extends CardImpl { - - private static final FilterPlayer filter = new FilterPlayer(); + + private static final FilterPlayer filter = new FilterPlayer("player who controls more lands than you do and is his your opponent"); + static { filter.add(new OathOfLiegesPredicate()); } @@ -62,9 +64,8 @@ public class OathOfLieges extends CardImpl { super(ownerId, 11, "Oath of Lieges", Rarity.RARE, new CardType[]{CardType.ENCHANTMENT}, "{1}{W}"); this.expansionSetCode = "EXO"; - // At the beginning of each player's upkeep, that player chooses target player who controls more lands than he or she does and is his or her opponent. The first player may search his or her library for a basic land card, put that card onto the battlefield, then shuffle his or her library. - Effect effect = new SearchLibraryPutInPlayEffect(new TargetCardInLibrary(new FilterBasicLandCard()), false, Outcome.PutLandInPlay); + Effect effect = new SearchLibraryPutInPlayTargetPlayerEffect(new TargetCardInLibrary(new FilterBasicLandCard()), false, Outcome.PutLandInPlay); effect.setText("that player chooses target player who controls more lands than he or she does and is his or her opponent. The first player may search his or her library for a basic land card, put that card onto the battlefield, then shuffle his or her library"); Ability ability = new BeginningOfUpkeepTriggeredAbility(effect, TargetController.ANY, true); ability.addTarget(new TargetPlayer(1, 1, false, filter)); @@ -74,16 +75,21 @@ public class OathOfLieges extends CardImpl { public OathOfLieges(final OathOfLieges card) { super(card); } - + @Override public void adjustTargets(Ability ability, Game game) { if (ability instanceof BeginningOfUpkeepTriggeredAbility) { Player activePlayer = game.getPlayer(game.getActivePlayerId()); if (activePlayer != null) { - ability.setControllerId(activePlayer.getId()); ability.getTargets().clear(); TargetPlayer target = new TargetPlayer(1, 1, false, filter); + target.setTargetController(activePlayer.getId()); ability.getTargets().add(target); + for (Effect effect : ability.getEffects()) { + if (effect instanceof SearchLibraryPutInPlayTargetPlayerEffect) { + effect.setTargetPointer(new FixedTarget(activePlayer.getId())); + } + } } } } @@ -119,4 +125,4 @@ class OathOfLiegesPredicate implements ObjectSourcePlayerPredicate abilities, Game game) { if (!choices.isEmpty()) { @@ -1891,11 +1915,6 @@ public class TestPlayer implements Player { return computerPlayer.choose(outcome, cards, target, game); } - @Override - public boolean chooseTarget(Outcome outcome, Cards cards, TargetCard target, Ability source, Game game) { - return computerPlayer.chooseTarget(outcome, cards, target, source, game); - } - @Override public boolean chooseTargetAmount(Outcome outcome, TargetAmount target, Ability source, Game game) { return computerPlayer.chooseTargetAmount(outcome, target, source, game); diff --git a/Mage/src/mage/game/GameImpl.java b/Mage/src/mage/game/GameImpl.java index 27abfa58db1..f67b6387437 100644 --- a/Mage/src/mage/game/GameImpl.java +++ b/Mage/src/mage/game/GameImpl.java @@ -1467,7 +1467,7 @@ public abstract class GameImpl implements Game, Serializable { } else { TriggeredAbility newAbility = ability.copy(); newAbility.newId(); - // Too early, becuase no targets set yet !!!!!!!!!!! + // Too early, because no targets set yet !!!!!!!!!!! for (Effect effect : newAbility.getEffects()) { effect.getTargetPointer().init(this, newAbility); } From dc7fee86df8e69fe090f85f2ab73734167ab3599 Mon Sep 17 00:00:00 2001 From: LevelX2 Date: Mon, 12 Oct 2015 23:50:29 +0200 Subject: [PATCH 125/268] Added test. --- .../sets/avacynrestored/DevastationTide.java | 27 ++++--- .../abilities/other/DevastationTideTest.java | 77 +++++++++++++++++++ 2 files changed, 95 insertions(+), 9 deletions(-) create mode 100644 Mage.Tests/src/test/java/org/mage/test/cards/abilities/other/DevastationTideTest.java diff --git a/Mage.Sets/src/mage/sets/avacynrestored/DevastationTide.java b/Mage.Sets/src/mage/sets/avacynrestored/DevastationTide.java index 2a13b1ecf80..126fc303e65 100644 --- a/Mage.Sets/src/mage/sets/avacynrestored/DevastationTide.java +++ b/Mage.Sets/src/mage/sets/avacynrestored/DevastationTide.java @@ -27,20 +27,23 @@ */ package mage.sets.avacynrestored; +import java.util.LinkedHashSet; +import java.util.Set; import java.util.UUID; -import mage.constants.CardType; -import mage.constants.Outcome; -import mage.constants.Rarity; -import mage.constants.Zone; import mage.abilities.Ability; import mage.abilities.costs.mana.ManaCostsImpl; import mage.abilities.effects.OneShotEffect; import mage.abilities.keyword.MiracleAbility; +import mage.cards.Card; import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.Outcome; +import mage.constants.Rarity; +import mage.constants.Zone; import mage.filter.common.FilterNonlandPermanent; import mage.game.Game; import mage.game.permanent.Permanent; - +import mage.players.Player; /** * @@ -52,7 +55,6 @@ public class DevastationTide extends CardImpl { super(ownerId, 48, "Devastation Tide", Rarity.RARE, new CardType[]{CardType.SORCERY}, "{3}{U}{U}"); this.expansionSetCode = "AVR"; - // Return all nonland permanents to their owners' hands. this.getSpellAbility().addEffect(new DevastationTideEffect()); @@ -83,10 +85,17 @@ class DevastationTideEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { - for (Permanent creature : game.getBattlefield().getActivePermanents(new FilterNonlandPermanent(), source.getControllerId(), source.getSourceId(), game)) { - creature.moveToZone(Zone.HAND, source.getSourceId(), game, true); + Player controller = game.getPlayer(source.getControllerId()); + if (controller != null) { + Set cardsToHand = new LinkedHashSet<>(); + for (Permanent permanent : game.getBattlefield().getActivePermanents(new FilterNonlandPermanent(), source.getControllerId(), source.getSourceId(), game)) { + cardsToHand.add((Card) permanent); + } + controller.moveCards(cardsToHand, null, Zone.HAND, source, game); + return true; + } - return true; + return false; } @Override diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/abilities/other/DevastationTideTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/abilities/other/DevastationTideTest.java new file mode 100644 index 00000000000..e9ddc239d89 --- /dev/null +++ b/Mage.Tests/src/test/java/org/mage/test/cards/abilities/other/DevastationTideTest.java @@ -0,0 +1,77 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package org.mage.test.cards.abilities.other; + +import mage.constants.PhaseStep; +import mage.constants.Zone; +import org.junit.Test; +import org.mage.test.serverside.base.CardTestPlayerBase; + +/** + * + * @author LevelX2 + */ +public class DevastationTideTest extends CardTestPlayerBase { + + @Test + public void testReturnNonLandPermanents() { + addCard(Zone.BATTLEFIELD, playerA, "Island", 4); + addCard(Zone.HAND, playerA, "Devastation Tide"); // {3}{U}{U} + + addCard(Zone.BATTLEFIELD, playerA, "Silvercoat Lion"); // Creature + addCard(Zone.BATTLEFIELD, playerA, "Vampiric Rites"); // Enchantment + addCard(Zone.BATTLEFIELD, playerA, "Hedron Archive"); // Artifact + addCard(Zone.BATTLEFIELD, playerA, "Karn Liberated"); // Planeswalker + addCard(Zone.BATTLEFIELD, playerA, "Nimbus Maze", 1); // Land + + addCard(Zone.BATTLEFIELD, playerB, "Silvercoat Lion"); // Creature + addCard(Zone.BATTLEFIELD, playerB, "Vampiric Rites"); // Enchantment + addCard(Zone.BATTLEFIELD, playerB, "Hedron Archive"); // Artifact + addCard(Zone.BATTLEFIELD, playerB, "Karn Liberated"); // Planeswalker + addCard(Zone.BATTLEFIELD, playerB, "Nimbus Maze", 1); // Land + + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Devastation Tide"); + + setStopAt(1, PhaseStep.BEGIN_COMBAT); + execute(); + + assertHandCount(playerA, "Silvercoat Lion", 1); + assertHandCount(playerA, "Vampiric Rites", 1); + assertHandCount(playerA, "Hedron Archive", 1); + assertHandCount(playerA, "Karn Liberated", 1); + assertHandCount(playerA, "Nimbus Maze", 0); + + assertHandCount(playerB, "Silvercoat Lion", 1); + assertHandCount(playerB, "Vampiric Rites", 1); + assertHandCount(playerB, "Hedron Archive", 1); + assertHandCount(playerB, "Karn Liberated", 1); + assertHandCount(playerB, "Nimbus Maze", 0); + + } + +} From a6014cb4ab148aaa5036c02838cfec851993fb7f Mon Sep 17 00:00:00 2001 From: LevelX2 Date: Tue, 13 Oct 2015 00:28:05 +0200 Subject: [PATCH 126/268] Added Hostility card. --- .../anthologyjacevschandra/Hostility.java | 52 +++++++ .../mage/sets/jacevschandra/Hostility.java | 145 ++++++++++++++++++ Mage.Sets/src/mage/sets/lorwyn/Hostility.java | 52 +++++++ 3 files changed, 249 insertions(+) create mode 100644 Mage.Sets/src/mage/sets/anthologyjacevschandra/Hostility.java create mode 100644 Mage.Sets/src/mage/sets/jacevschandra/Hostility.java create mode 100644 Mage.Sets/src/mage/sets/lorwyn/Hostility.java diff --git a/Mage.Sets/src/mage/sets/anthologyjacevschandra/Hostility.java b/Mage.Sets/src/mage/sets/anthologyjacevschandra/Hostility.java new file mode 100644 index 00000000000..3c8621e98e7 --- /dev/null +++ b/Mage.Sets/src/mage/sets/anthologyjacevschandra/Hostility.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.anthologyjacevschandra; + +import java.util.UUID; + +/** + * + * @author LevelX2 + */ +public class Hostility extends mage.sets.jacevschandra.Hostility { + + public Hostility(UUID ownerId) { + super(ownerId); + this.cardNumber = 48; + this.expansionSetCode = "DD3"; + } + + public Hostility(final Hostility card) { + super(card); + } + + @Override + public Hostility copy() { + return new Hostility(this); + } +} diff --git a/Mage.Sets/src/mage/sets/jacevschandra/Hostility.java b/Mage.Sets/src/mage/sets/jacevschandra/Hostility.java new file mode 100644 index 00000000000..a4e68652263 --- /dev/null +++ b/Mage.Sets/src/mage/sets/jacevschandra/Hostility.java @@ -0,0 +1,145 @@ +/* + * 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.jacevschandra; + +import java.util.Arrays; +import java.util.UUID; +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.PutIntoGraveFromAnywhereSourceTriggeredAbility; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.effects.PreventionEffectData; +import mage.abilities.effects.PreventionEffectImpl; +import mage.abilities.effects.common.CreateTokenEffect; +import mage.abilities.effects.common.ShuffleIntoLibrarySourceEffect; +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.game.Game; +import mage.game.events.GameEvent; +import mage.game.permanent.token.Token; + +/** + * + * @author LevelX2 + */ +public class Hostility extends CardImpl { + + public Hostility(UUID ownerId) { + super(ownerId, 48, "Hostility", Rarity.RARE, new CardType[]{CardType.CREATURE}, "{3}{R}{R}{R}"); + this.expansionSetCode = "DD2"; + this.subtype.add("Elemental"); + this.subtype.add("Incarnation"); + this.power = new MageInt(6); + this.toughness = new MageInt(6); + + // Haste + this.addAbility(HasteAbility.getInstance()); + + // If a spell you control would deal damage to an opponent, prevent that damage. + // Put a 3/1 red Elemental Shaman creature token with haste onto the battlefield for each 1 damage prevented this way. + this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new HostilityEffect())); + + // When Hostility is put into a graveyard from anywhere, shuffle it into its owner's library. + this.addAbility(new PutIntoGraveFromAnywhereSourceTriggeredAbility(new ShuffleIntoLibrarySourceEffect())); + } + + public Hostility(final Hostility card) { + super(card); + } + + @Override + public Hostility copy() { + return new Hostility(this); + } +} + +class HostilityEffect extends PreventionEffectImpl { + + public HostilityEffect() { + super(Duration.WhileOnBattlefield, Integer.MAX_VALUE, false, false); + staticText = "If a spell you control would deal damage to an opponent, prevent that damage. Put a 3/1 red Elemental Shaman creature token with haste onto the battlefield for each 1 damage prevented this way."; + } + + public HostilityEffect(final HostilityEffect effect) { + super(effect); + } + + @Override + public HostilityEffect copy() { + return new HostilityEffect(this); + } + + @Override + public boolean checksEventType(GameEvent event, Game game) { + switch (event.getType()) { + case DAMAGE_PLAYER: + return true; + } + return false; + } + + @Override + public boolean applies(GameEvent event, Ability source, Game game) { + if (super.applies(event, source, game)) { + if (game.getOpponents(source.getControllerId()).contains(event.getTargetId())) { + return true; + } + } + return false; + } + + @Override + public boolean replaceEvent(GameEvent event, Ability source, Game game) { + PreventionEffectData preventionEffectData = preventDamageAction(event, source, game); + if (preventionEffectData.getPreventedDamage() > 0) { + new CreateTokenEffect(new HostilityElementalToken(), preventionEffectData.getPreventedDamage()).apply(game, source); + } + return true; + } +} + +class HostilityElementalToken extends Token { + + public HostilityElementalToken() { + super("Elemental Shaman", "3/1 red Elemental Shaman creature token with haste"); + availableImageSetCodes.addAll(Arrays.asList("LRW", "DD2")); + cardType.add(CardType.CREATURE); + color.setRed(true); + subtype.add("Elemental"); + subtype.add("Shaman"); + power = new MageInt(3); + toughness = new MageInt(1); + + addAbility(HasteAbility.getInstance()); + } + +} diff --git a/Mage.Sets/src/mage/sets/lorwyn/Hostility.java b/Mage.Sets/src/mage/sets/lorwyn/Hostility.java new file mode 100644 index 00000000000..b309e8f73ad --- /dev/null +++ b/Mage.Sets/src/mage/sets/lorwyn/Hostility.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.lorwyn; + +import java.util.UUID; + +/** + * + * @author LevelX2 + */ +public class Hostility extends mage.sets.jacevschandra.Hostility { + + public Hostility(UUID ownerId) { + super(ownerId); + this.cardNumber = 176; + this.expansionSetCode = "LRW"; + } + + public Hostility(final Hostility card) { + super(card); + } + + @Override + public Hostility copy() { + return new Hostility(this); + } +} From b902a099a130e4abe29638e2fa3a22af406d415d Mon Sep 17 00:00:00 2001 From: LoneFox Date: Tue, 13 Oct 2015 08:03:39 +0300 Subject: [PATCH 127/268] Fix ExileFromZoneTargetEffect text generation --- .../abilities/effects/common/ExileFromZoneTargetEffect.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Mage/src/mage/abilities/effects/common/ExileFromZoneTargetEffect.java b/Mage/src/mage/abilities/effects/common/ExileFromZoneTargetEffect.java index 028237b01cf..654c49ea41e 100644 --- a/Mage/src/mage/abilities/effects/common/ExileFromZoneTargetEffect.java +++ b/Mage/src/mage/abilities/effects/common/ExileFromZoneTargetEffect.java @@ -111,6 +111,6 @@ public class ExileFromZoneTargetEffect extends OneShotEffect { } private void setText() { - staticText = "target player exiles " + CardUtil.numberToText(exileName, "a") + filter.getMessage() + " from his or her " + zone.toString().toLowerCase(); + staticText = "target player exiles " + CardUtil.numberToText(amount, "a") + " " + filter.getMessage() + " from his or her " + zone.toString().toLowerCase(); } } From 769f61aa05bdbd79b62fec49e6daae0ac4da63d5 Mon Sep 17 00:00:00 2001 From: LoneFox Date: Tue, 13 Oct 2015 08:03:56 +0300 Subject: [PATCH 128/268] Fix a couple of incorrect set codes --- Mage.Sets/src/mage/sets/anthologyjacevschandra/Hostility.java | 2 +- Mage.Sets/src/mage/sets/anthologyjacevschandra/Ophidian.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Mage.Sets/src/mage/sets/anthologyjacevschandra/Hostility.java b/Mage.Sets/src/mage/sets/anthologyjacevschandra/Hostility.java index 3c8621e98e7..4769a6c8b3b 100644 --- a/Mage.Sets/src/mage/sets/anthologyjacevschandra/Hostility.java +++ b/Mage.Sets/src/mage/sets/anthologyjacevschandra/Hostility.java @@ -38,7 +38,7 @@ public class Hostility extends mage.sets.jacevschandra.Hostility { public Hostility(UUID ownerId) { super(ownerId); this.cardNumber = 48; - this.expansionSetCode = "DD3"; + this.expansionSetCode = "DD3D"; } public Hostility(final Hostility card) { diff --git a/Mage.Sets/src/mage/sets/anthologyjacevschandra/Ophidian.java b/Mage.Sets/src/mage/sets/anthologyjacevschandra/Ophidian.java index 3816fda1c85..bf513964994 100644 --- a/Mage.Sets/src/mage/sets/anthologyjacevschandra/Ophidian.java +++ b/Mage.Sets/src/mage/sets/anthologyjacevschandra/Ophidian.java @@ -38,7 +38,7 @@ public class Ophidian extends mage.sets.vintagemasters.Ophidian { public Ophidian(UUID ownerId) { super(ownerId); this.cardNumber = 9; - this.expansionSetCode = "DD3"; + this.expansionSetCode = "DD3D"; } public Ophidian(final Ophidian card) { From c1984b15d9ddd8220e6911d905d132c010d0d4ff Mon Sep 17 00:00:00 2001 From: LoneFox Date: Tue, 13 Oct 2015 10:02:42 +0300 Subject: [PATCH 129/268] Implement cards: Quicksilver Wall, Ribbon Snake, Vintara Elephant, and Zerapa Minotaur --- .../mage/sets/prophecy/QuicksilverWall.java | 75 +++++++++++++++++++ .../src/mage/sets/prophecy/RibbonSnake.java | 75 +++++++++++++++++++ .../mage/sets/prophecy/VintaraElephant.java | 75 +++++++++++++++++++ .../mage/sets/prophecy/ZerapaMinotaur.java | 75 +++++++++++++++++++ .../continuous/LoseAbilitySourceEffect.java | 16 ++-- 5 files changed, 308 insertions(+), 8 deletions(-) create mode 100644 Mage.Sets/src/mage/sets/prophecy/QuicksilverWall.java create mode 100644 Mage.Sets/src/mage/sets/prophecy/RibbonSnake.java create mode 100644 Mage.Sets/src/mage/sets/prophecy/VintaraElephant.java create mode 100644 Mage.Sets/src/mage/sets/prophecy/ZerapaMinotaur.java diff --git a/Mage.Sets/src/mage/sets/prophecy/QuicksilverWall.java b/Mage.Sets/src/mage/sets/prophecy/QuicksilverWall.java new file mode 100644 index 00000000000..21a43d9f3c0 --- /dev/null +++ b/Mage.Sets/src/mage/sets/prophecy/QuicksilverWall.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.prophecy; + +import java.util.UUID; +import mage.MageInt; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.effects.common.InfoEffect; +import mage.abilities.effects.common.ReturnToHandSourceEffect; +import mage.abilities.keyword.DefenderAbility; +import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.Rarity; +import mage.constants.TargetController; +import mage.constants.Zone; + +/** + * + * @author LoneFox + */ +public class QuicksilverWall extends CardImpl { + + public QuicksilverWall(UUID ownerId) { + super(ownerId, 41, "Quicksilver Wall", Rarity.UNCOMMON, new CardType[]{CardType.CREATURE}, "{2}{U}"); + this.expansionSetCode = "PCY"; + this.subtype.add("Wall"); + this.power = new MageInt(1); + this.toughness = new MageInt(6); + + // Defender + this.addAbility(DefenderAbility.getInstance()); + // {4}: Return Quicksilver Wall to its owner's hand. Any player may activate this ability. + SimpleActivatedAbility ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, + new ReturnToHandSourceEffect(true), new ManaCostsImpl("{4}")); + ability.setMayActivate(TargetController.ANY); + ability.addEffect(new InfoEffect("Any player may activate this ability")); + this.addAbility(ability); + } + + public QuicksilverWall(final QuicksilverWall card) { + super(card); + } + + @Override + public QuicksilverWall copy() { + return new QuicksilverWall(this); + } +} diff --git a/Mage.Sets/src/mage/sets/prophecy/RibbonSnake.java b/Mage.Sets/src/mage/sets/prophecy/RibbonSnake.java new file mode 100644 index 00000000000..4e4829f4dc6 --- /dev/null +++ b/Mage.Sets/src/mage/sets/prophecy/RibbonSnake.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.prophecy; + +import java.util.UUID; +import mage.MageInt; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.effects.common.InfoEffect; +import mage.abilities.effects.common.continuous.LoseAbilitySourceEffect; +import mage.abilities.keyword.FlyingAbility; +import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.Rarity; +import mage.constants.TargetController; +import mage.constants.Zone; + +/** + * + * @author LoneFox + */ +public class RibbonSnake extends CardImpl { + + public RibbonSnake(UUID ownerId) { + super(ownerId, 46, "Ribbon Snake", Rarity.COMMON, new CardType[]{CardType.CREATURE}, "{1}{U}{U}"); + this.expansionSetCode = "PCY"; + this.subtype.add("Snake"); + this.power = new MageInt(2); + this.toughness = new MageInt(3); + + // Flying + this.addAbility(FlyingAbility.getInstance()); + // {2}: Ribbon Snake loses flying until end of turn. Any player may activate this ability. + SimpleActivatedAbility ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new LoseAbilitySourceEffect( + FlyingAbility.getInstance(), Duration.EndOfTurn), new ManaCostsImpl("{2}")); + ability.setMayActivate(TargetController.ANY); + ability.addEffect(new InfoEffect("Any player may activate this ability")); + this.addAbility(ability); + } + + public RibbonSnake(final RibbonSnake card) { + super(card); + } + + @Override + public RibbonSnake copy() { + return new RibbonSnake(this); + } +} diff --git a/Mage.Sets/src/mage/sets/prophecy/VintaraElephant.java b/Mage.Sets/src/mage/sets/prophecy/VintaraElephant.java new file mode 100644 index 00000000000..1e70c6836b7 --- /dev/null +++ b/Mage.Sets/src/mage/sets/prophecy/VintaraElephant.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.prophecy; + +import java.util.UUID; +import mage.MageInt; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.effects.common.InfoEffect; +import mage.abilities.effects.common.continuous.LoseAbilitySourceEffect; +import mage.abilities.keyword.TrampleAbility; +import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.Rarity; +import mage.constants.TargetController; +import mage.constants.Zone; + +/** + * + * @author LoneFox + */ +public class VintaraElephant extends CardImpl { + + public VintaraElephant(UUID ownerId) { + super(ownerId, 131, "Vintara Elephant", Rarity.COMMON, new CardType[]{CardType.CREATURE}, "{4}{G}"); + this.expansionSetCode = "PCY"; + this.subtype.add("Elephant"); + this.power = new MageInt(4); + this.toughness = new MageInt(3); + + // Trample + this.addAbility(TrampleAbility.getInstance()); + // {3}: Vintara Elephant loses trample until end of turn. Any player may activate this ability. + SimpleActivatedAbility ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new LoseAbilitySourceEffect( + TrampleAbility.getInstance(), Duration.EndOfTurn), new ManaCostsImpl("{3}")); + ability.setMayActivate(TargetController.ANY); + ability.addEffect(new InfoEffect("Any player may activate this ability")); + this.addAbility(ability); + } + + public VintaraElephant(final VintaraElephant card) { + super(card); + } + + @Override + public VintaraElephant copy() { + return new VintaraElephant(this); + } +} diff --git a/Mage.Sets/src/mage/sets/prophecy/ZerapaMinotaur.java b/Mage.Sets/src/mage/sets/prophecy/ZerapaMinotaur.java new file mode 100644 index 00000000000..6000fde3df3 --- /dev/null +++ b/Mage.Sets/src/mage/sets/prophecy/ZerapaMinotaur.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.prophecy; + +import java.util.UUID; +import mage.MageInt; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.effects.common.InfoEffect; +import mage.abilities.effects.common.continuous.LoseAbilitySourceEffect; +import mage.abilities.keyword.FirstStrikeAbility; +import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.Rarity; +import mage.constants.TargetController; +import mage.constants.Zone; + +/** + * + * @author LoneFox + */ +public class ZerapaMinotaur extends CardImpl { + + public ZerapaMinotaur(UUID ownerId) { + super(ownerId, 108, "Zerapa Minotaur", Rarity.COMMON, new CardType[]{CardType.CREATURE}, "{2}{R}{R}"); + this.expansionSetCode = "PCY"; + this.subtype.add("Minotaur"); + this.power = new MageInt(3); + this.toughness = new MageInt(3); + + // First strike + this.addAbility(FirstStrikeAbility.getInstance()); + // {2}: Zerapa Minotaur loses first strike until end of turn. Any player may activate this ability. + SimpleActivatedAbility ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new LoseAbilitySourceEffect( + FirstStrikeAbility.getInstance(), Duration.EndOfTurn), new ManaCostsImpl("{2}")); + ability.setMayActivate(TargetController.ANY); + ability.addEffect(new InfoEffect("Any player may activate this ability")); + this.addAbility(ability); + } + + public ZerapaMinotaur(final ZerapaMinotaur card) { + super(card); + } + + @Override + public ZerapaMinotaur copy() { + return new ZerapaMinotaur(this); + } +} diff --git a/Mage/src/mage/abilities/effects/common/continuous/LoseAbilitySourceEffect.java b/Mage/src/mage/abilities/effects/common/continuous/LoseAbilitySourceEffect.java index 2c898399a06..785420e329c 100644 --- a/Mage/src/mage/abilities/effects/common/continuous/LoseAbilitySourceEffect.java +++ b/Mage/src/mage/abilities/effects/common/continuous/LoseAbilitySourceEffect.java @@ -17,36 +17,36 @@ import mage.game.permanent.Permanent; * @author Noahsark */ public class LoseAbilitySourceEffect extends ContinuousEffectImpl{ - + protected Ability ability; - + public LoseAbilitySourceEffect(Ability ability){ this(ability, Duration.WhileOnBattlefield); } - + public LoseAbilitySourceEffect(Ability ability, Duration duration){ super(duration, Layer.AbilityAddingRemovingEffects_6, SubLayer.NA, Outcome.LoseAbility); this.ability = ability; - staticText = "{this} loses " + ability.getRule() + duration.toString(); + staticText = "{this} loses " + ability.getRule() + " " + duration.toString(); } - + public LoseAbilitySourceEffect(final LoseAbilitySourceEffect effect){ super(effect); this.ability = effect.ability.copy(); } - + @Override public LoseAbilitySourceEffect copy(){ return new LoseAbilitySourceEffect(this); } - + @Override public boolean apply(Game game, Ability source){ Permanent permanent = game.getPermanent(source.getSourceId()); if (permanent != null){ // 112.10 while (permanent.getAbilities().remove(ability)) { - + } } return true; From 6dcfa0cee4c63bf5572f702ada84dee584ef99c8 Mon Sep 17 00:00:00 2001 From: LoneFox Date: Tue, 13 Oct 2015 10:29:08 +0300 Subject: [PATCH 130/268] Implement cards: Fen Stalker, Scoria Cat, Spur Grappler, and Vintara Snapper --- .../src/mage/sets/prophecy/FenStalker.java | 81 +++++++++++++++++++ .../src/mage/sets/prophecy/ScoriaCat.java | 80 ++++++++++++++++++ .../src/mage/sets/prophecy/SpurGrappler.java | 80 ++++++++++++++++++ .../mage/sets/prophecy/VintaraSnapper.java | 81 +++++++++++++++++++ 4 files changed, 322 insertions(+) create mode 100644 Mage.Sets/src/mage/sets/prophecy/FenStalker.java create mode 100644 Mage.Sets/src/mage/sets/prophecy/ScoriaCat.java create mode 100644 Mage.Sets/src/mage/sets/prophecy/SpurGrappler.java create mode 100644 Mage.Sets/src/mage/sets/prophecy/VintaraSnapper.java diff --git a/Mage.Sets/src/mage/sets/prophecy/FenStalker.java b/Mage.Sets/src/mage/sets/prophecy/FenStalker.java new file mode 100644 index 00000000000..9a573268b67 --- /dev/null +++ b/Mage.Sets/src/mage/sets/prophecy/FenStalker.java @@ -0,0 +1,81 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.sets.prophecy; + +import java.util.UUID; +import mage.MageInt; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.condition.InvertCondition; +import mage.abilities.condition.common.PermanentsOnTheBattlefieldCondition; +import mage.abilities.decorator.ConditionalContinuousEffect; +import mage.abilities.effects.common.continuous.GainAbilitySourceEffect; +import mage.abilities.keyword.FearAbility; +import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.Rarity; +import mage.constants.Zone; +import mage.filter.common.FilterControlledLandPermanent; +import mage.filter.predicate.Predicates; +import mage.filter.predicate.permanent.TappedPredicate; + +/** + * + * @author LoneFox + */ +public class FenStalker extends CardImpl { + + private static final FilterControlledLandPermanent filter = new FilterControlledLandPermanent(); + + static { + filter.add(Predicates.not(new TappedPredicate())); + } + + public FenStalker(UUID ownerId) { + super(ownerId, 64, "Fen Stalker", Rarity.COMMON, new CardType[]{CardType.CREATURE}, "{3}{B}"); + this.expansionSetCode = "PCY"; + this.subtype.add("Nightstalker"); + this.power = new MageInt(3); + this.toughness = new MageInt(2); + + // Fen Stalker has fear as long as you control no untapped lands. + this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, + new ConditionalContinuousEffect(new GainAbilitySourceEffect(FearAbility.getInstance(), + Duration.WhileOnBattlefield), new InvertCondition(new PermanentsOnTheBattlefieldCondition(filter)), + "{this} has fear as long as you control no untapped lands"))); + } + + public FenStalker(final FenStalker card) { + super(card); + } + + @Override + public FenStalker copy() { + return new FenStalker(this); + } +} diff --git a/Mage.Sets/src/mage/sets/prophecy/ScoriaCat.java b/Mage.Sets/src/mage/sets/prophecy/ScoriaCat.java new file mode 100644 index 00000000000..1d7e4438ddf --- /dev/null +++ b/Mage.Sets/src/mage/sets/prophecy/ScoriaCat.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.prophecy; + +import java.util.UUID; +import mage.MageInt; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.condition.InvertCondition; +import mage.abilities.condition.common.PermanentsOnTheBattlefieldCondition; +import mage.abilities.decorator.ConditionalContinuousEffect; +import mage.abilities.effects.common.continuous.BoostSourceEffect; +import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.Rarity; +import mage.constants.Zone; +import mage.filter.common.FilterControlledLandPermanent; +import mage.filter.predicate.Predicates; +import mage.filter.predicate.permanent.TappedPredicate; + +/** + * + * @author LoneFox + */ +public class ScoriaCat extends CardImpl { + + private static final FilterControlledLandPermanent filter = new FilterControlledLandPermanent(); + + static { + filter.add(Predicates.not(new TappedPredicate())); + } + + public ScoriaCat(UUID ownerId) { + super(ownerId, 101, "Scoria Cat", Rarity.UNCOMMON, new CardType[]{CardType.CREATURE}, "{3}{R}{R}"); + this.expansionSetCode = "PCY"; + this.subtype.add("Cat"); + this.power = new MageInt(3); + this.toughness = new MageInt(3); + + // Scoria Cat gets +3/+3 as long as you control no untapped lands. + this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, + new ConditionalContinuousEffect(new BoostSourceEffect(3, 3, Duration.WhileOnBattlefield), + new InvertCondition(new PermanentsOnTheBattlefieldCondition(filter)), + "{this} gets +3/+3 as long as you control no untapped lands"))); + } + + public ScoriaCat(final ScoriaCat card) { + super(card); + } + + @Override + public ScoriaCat copy() { + return new ScoriaCat(this); + } +} diff --git a/Mage.Sets/src/mage/sets/prophecy/SpurGrappler.java b/Mage.Sets/src/mage/sets/prophecy/SpurGrappler.java new file mode 100644 index 00000000000..204a883999c --- /dev/null +++ b/Mage.Sets/src/mage/sets/prophecy/SpurGrappler.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.prophecy; + +import java.util.UUID; +import mage.MageInt; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.condition.InvertCondition; +import mage.abilities.condition.common.PermanentsOnTheBattlefieldCondition; +import mage.abilities.decorator.ConditionalContinuousEffect; +import mage.abilities.effects.common.continuous.BoostSourceEffect; +import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.Rarity; +import mage.constants.Zone; +import mage.filter.common.FilterControlledLandPermanent; +import mage.filter.predicate.Predicates; +import mage.filter.predicate.permanent.TappedPredicate; + +/** + * + * @author LoneFox + */ +public class SpurGrappler extends CardImpl { + + private static final FilterControlledLandPermanent filter = new FilterControlledLandPermanent(); + + static { + filter.add(Predicates.not(new TappedPredicate())); + } + + public SpurGrappler(UUID ownerId) { + super(ownerId, 104, "Spur Grappler", Rarity.COMMON, new CardType[]{CardType.CREATURE}, "{2}{R}"); + this.expansionSetCode = "PCY"; + this.subtype.add("Beast"); + this.power = new MageInt(2); + this.toughness = new MageInt(1); + + // Spur Grappler gets +2/+1 as long as you control no untapped lands. + this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, + new ConditionalContinuousEffect(new BoostSourceEffect(2, 1, Duration.WhileOnBattlefield), + new InvertCondition(new PermanentsOnTheBattlefieldCondition(filter)), + "{this} gets +2/+1 as long as you control no untapped lands"))); + } + + public SpurGrappler(final SpurGrappler card) { + super(card); + } + + @Override + public SpurGrappler copy() { + return new SpurGrappler(this); + } +} diff --git a/Mage.Sets/src/mage/sets/prophecy/VintaraSnapper.java b/Mage.Sets/src/mage/sets/prophecy/VintaraSnapper.java new file mode 100644 index 00000000000..ba9f95908b0 --- /dev/null +++ b/Mage.Sets/src/mage/sets/prophecy/VintaraSnapper.java @@ -0,0 +1,81 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.sets.prophecy; + +import java.util.UUID; +import mage.MageInt; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.condition.InvertCondition; +import mage.abilities.condition.common.PermanentsOnTheBattlefieldCondition; +import mage.abilities.decorator.ConditionalContinuousEffect; +import mage.abilities.effects.common.continuous.GainAbilitySourceEffect; +import mage.abilities.keyword.ShroudAbility; +import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.Rarity; +import mage.constants.Zone; +import mage.filter.common.FilterControlledLandPermanent; +import mage.filter.predicate.Predicates; +import mage.filter.predicate.permanent.TappedPredicate; + +/** + * + * @author LoneFox + */ +public class VintaraSnapper extends CardImpl { + + private static final FilterControlledLandPermanent filter = new FilterControlledLandPermanent(); + + static { + filter.add(Predicates.not(new TappedPredicate())); + } + + public VintaraSnapper(UUID ownerId) { + super(ownerId, 132, "Vintara Snapper", Rarity.UNCOMMON, new CardType[]{CardType.CREATURE}, "{G}{G}"); + this.expansionSetCode = "PCY"; + this.subtype.add("Turtle"); + this.power = new MageInt(2); + this.toughness = new MageInt(2); + + // Vintara Snapper has shroud as long as you control no untapped lands. + this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, + new ConditionalContinuousEffect(new GainAbilitySourceEffect(ShroudAbility.getInstance(), + Duration.WhileOnBattlefield), new InvertCondition(new PermanentsOnTheBattlefieldCondition(filter)), + "{this} has shroud as long as you control no untapped lands"))); + } + + public VintaraSnapper(final VintaraSnapper card) { + super(card); + } + + @Override + public VintaraSnapper copy() { + return new VintaraSnapper(this); + } +} From 321c2e8b295c9310e262ace65c6e0db7daa96292 Mon Sep 17 00:00:00 2001 From: LoneFox Date: Tue, 13 Oct 2015 11:07:23 +0300 Subject: [PATCH 131/268] Implement cards: Devastate, Noxious Field, Silt Crawler, and Troublesome Spirit --- .../src/mage/sets/prophecy/Devastate.java | 62 ++++++++++++++ .../src/mage/sets/prophecy/NoxiousField.java | 82 +++++++++++++++++++ .../src/mage/sets/prophecy/SiltCrawler.java | 64 +++++++++++++++ .../mage/sets/prophecy/TroublesomeSpirit.java | 68 +++++++++++++++ 4 files changed, 276 insertions(+) create mode 100644 Mage.Sets/src/mage/sets/prophecy/Devastate.java create mode 100644 Mage.Sets/src/mage/sets/prophecy/NoxiousField.java create mode 100644 Mage.Sets/src/mage/sets/prophecy/SiltCrawler.java create mode 100644 Mage.Sets/src/mage/sets/prophecy/TroublesomeSpirit.java diff --git a/Mage.Sets/src/mage/sets/prophecy/Devastate.java b/Mage.Sets/src/mage/sets/prophecy/Devastate.java new file mode 100644 index 00000000000..20068f5e1bd --- /dev/null +++ b/Mage.Sets/src/mage/sets/prophecy/Devastate.java @@ -0,0 +1,62 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.sets.prophecy; + +import java.util.UUID; +import mage.abilities.effects.common.DamageEverythingEffect; +import mage.abilities.effects.common.DestroyTargetEffect; +import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.Rarity; +import mage.target.common.TargetLandPermanent; + +/** + * + * @author LoneFox + */ +public class Devastate extends CardImpl { + + public Devastate(UUID ownerId) { + super(ownerId, 87, "Devastate", Rarity.COMMON, new CardType[]{CardType.SORCERY}, "{3}{R}{R}"); + this.expansionSetCode = "PCY"; + + // Destroy target land. Devastate deals 1 damage to each creature and each player. + this.getSpellAbility().addEffect(new DestroyTargetEffect()); + this.getSpellAbility().addEffect(new DamageEverythingEffect(1)); + this.getSpellAbility().addTarget(new TargetLandPermanent()); + } + + public Devastate(final Devastate card) { + super(card); + } + + @Override + public Devastate copy() { + return new Devastate(this); + } +} diff --git a/Mage.Sets/src/mage/sets/prophecy/NoxiousField.java b/Mage.Sets/src/mage/sets/prophecy/NoxiousField.java new file mode 100644 index 00000000000..e3aa9bf82c0 --- /dev/null +++ b/Mage.Sets/src/mage/sets/prophecy/NoxiousField.java @@ -0,0 +1,82 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.sets.prophecy; + +import java.util.UUID; +import mage.abilities.Ability; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.costs.common.TapSourceCost; +import mage.abilities.effects.Effect; +import mage.abilities.effects.common.AttachEffect; +import mage.abilities.effects.common.DamageEverythingEffect; +import mage.abilities.effects.common.continuous.GainAbilityAttachedEffect; +import mage.abilities.keyword.EnchantAbility; +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.Zone; +import mage.target.TargetPermanent; +import mage.target.common.TargetLandPermanent; + +/** + * + * @author LoneFox + */ +public class NoxiousField extends CardImpl { + + public NoxiousField(UUID ownerId) { + super(ownerId, 70, "Noxious Field", Rarity.UNCOMMON, new CardType[]{CardType.ENCHANTMENT}, "{1}{B}{B}"); + this.expansionSetCode = "PCY"; + this.subtype.add("Aura"); + + // Enchant land + TargetPermanent auraTarget = new TargetLandPermanent(); + this.getSpellAbility().addTarget(auraTarget); + this.getSpellAbility().addEffect(new AttachEffect(Outcome.AddAbility)); + Ability ability = new EnchantAbility(auraTarget.getTargetName()); + this.addAbility(ability); + // Enchanted land has "{tap}: This land deals 1 damage to each creature and each player." + ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new DamageEverythingEffect(1), new TapSourceCost()); + Effect effect = new GainAbilityAttachedEffect(ability, AttachmentType.AURA); + effect.setText("Enchanted land has \"{T}: This land deals 1 damage to each creature and each player.\""); + this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, effect)); + } + + public NoxiousField(final NoxiousField card) { + super(card); + } + + @Override + public NoxiousField copy() { + return new NoxiousField(this); + } +} diff --git a/Mage.Sets/src/mage/sets/prophecy/SiltCrawler.java b/Mage.Sets/src/mage/sets/prophecy/SiltCrawler.java new file mode 100644 index 00000000000..177b90a0871 --- /dev/null +++ b/Mage.Sets/src/mage/sets/prophecy/SiltCrawler.java @@ -0,0 +1,64 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.sets.prophecy; + +import java.util.UUID; +import mage.MageInt; +import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.effects.common.TapAllEffect; +import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.Rarity; +import mage.filter.common.FilterControlledLandPermanent; + +/** + * + * @author LoneFox + */ +public class SiltCrawler extends CardImpl { + + public SiltCrawler(UUID ownerId) { + super(ownerId, 123, "Silt Crawler", Rarity.COMMON, new CardType[]{CardType.CREATURE}, "{2}{G}"); + this.expansionSetCode = "PCY"; + this.subtype.add("Beast"); + this.power = new MageInt(3); + this.toughness = new MageInt(3); + + // When Silt Crawler enters the battlefield, tap all lands you control. + this.addAbility(new EntersBattlefieldTriggeredAbility(new TapAllEffect(new FilterControlledLandPermanent("lands you control")), false)); + } + + public SiltCrawler(final SiltCrawler card) { + super(card); + } + + @Override + public SiltCrawler copy() { + return new SiltCrawler(this); + } +} diff --git a/Mage.Sets/src/mage/sets/prophecy/TroublesomeSpirit.java b/Mage.Sets/src/mage/sets/prophecy/TroublesomeSpirit.java new file mode 100644 index 00000000000..f3a6f6c58ce --- /dev/null +++ b/Mage.Sets/src/mage/sets/prophecy/TroublesomeSpirit.java @@ -0,0 +1,68 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.sets.prophecy; + +import java.util.UUID; +import mage.MageInt; +import mage.abilities.common.BeginningOfEndStepTriggeredAbility; +import mage.abilities.effects.common.TapAllEffect; +import mage.abilities.keyword.FlyingAbility; +import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.Rarity; +import mage.constants.TargetController; +import mage.filter.common.FilterControlledLandPermanent; + +/** + * + * @author LoneFox + */ +public class TroublesomeSpirit extends CardImpl { + + public TroublesomeSpirit(UUID ownerId) { + super(ownerId, 52, "Troublesome Spirit", Rarity.RARE, new CardType[]{CardType.CREATURE}, "{2}{U}{U}"); + this.expansionSetCode = "PCY"; + this.subtype.add("Spirit"); + this.power = new MageInt(3); + this.toughness = new MageInt(4); + + // Flying + this.addAbility(FlyingAbility.getInstance()); + // At the beginning of your end step, tap all lands you control. + this.addAbility(new BeginningOfEndStepTriggeredAbility(new TapAllEffect(new FilterControlledLandPermanent("lands you control")), TargetController.YOU, false)); + } + + public TroublesomeSpirit(final TroublesomeSpirit card) { + super(card); + } + + @Override + public TroublesomeSpirit copy() { + return new TroublesomeSpirit(this); + } +} From 5f74101fa53d539b65bb3cbb5ce64ca894ec6e66 Mon Sep 17 00:00:00 2001 From: LoneFox Date: Tue, 13 Oct 2015 11:58:12 +0300 Subject: [PATCH 132/268] Implement cards: Mine Bearer, Sunken Field, Well of Discovery, and Well of Life --- .../src/mage/sets/prophecy/MineBearer.java | 72 ++++++++++++++++ .../src/mage/sets/prophecy/SunkenField.java | 85 +++++++++++++++++++ .../mage/sets/prophecy/WellOfDiscovery.java | 75 ++++++++++++++++ .../src/mage/sets/prophecy/WellOfLife.java | 74 ++++++++++++++++ 4 files changed, 306 insertions(+) create mode 100644 Mage.Sets/src/mage/sets/prophecy/MineBearer.java create mode 100644 Mage.Sets/src/mage/sets/prophecy/SunkenField.java create mode 100644 Mage.Sets/src/mage/sets/prophecy/WellOfDiscovery.java create mode 100644 Mage.Sets/src/mage/sets/prophecy/WellOfLife.java diff --git a/Mage.Sets/src/mage/sets/prophecy/MineBearer.java b/Mage.Sets/src/mage/sets/prophecy/MineBearer.java new file mode 100644 index 00000000000..f74f6b1f0b3 --- /dev/null +++ b/Mage.Sets/src/mage/sets/prophecy/MineBearer.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.prophecy; + +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.costs.common.TapSourceCost; +import mage.abilities.effects.common.DestroyTargetEffect; +import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.Rarity; +import mage.constants.Zone; +import mage.target.common.TargetAttackingCreature; + +/** + * + * @author LoneFox + */ +public class MineBearer extends CardImpl { + + public MineBearer(UUID ownerId) { + super(ownerId, 16, "Mine Bearer", Rarity.COMMON, new CardType[]{CardType.CREATURE}, "{2}{W}"); + this.expansionSetCode = "PCY"; + this.subtype.add("Human"); + this.subtype.add("Soldier"); + this.power = new MageInt(1); + this.toughness = new MageInt(1); + + // {tap}, Sacrifice Mine Bearer: Destroy target attacking creature. + Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new DestroyTargetEffect(), new TapSourceCost()); + ability.addCost(new SacrificeSourceCost()); + ability.addTarget(new TargetAttackingCreature()); + this.addAbility(ability); + } + + public MineBearer(final MineBearer card) { + super(card); + } + + @Override + public MineBearer copy() { + return new MineBearer(this); + } +} diff --git a/Mage.Sets/src/mage/sets/prophecy/SunkenField.java b/Mage.Sets/src/mage/sets/prophecy/SunkenField.java new file mode 100644 index 00000000000..fca2a0bc868 --- /dev/null +++ b/Mage.Sets/src/mage/sets/prophecy/SunkenField.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.prophecy; + +import java.util.UUID; +import mage.abilities.Ability; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.costs.common.TapSourceCost; +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.effects.Effect; +import mage.abilities.effects.common.AttachEffect; +import mage.abilities.effects.common.CounterUnlessPaysEffect; +import mage.abilities.effects.common.continuous.GainAbilityAttachedEffect; +import mage.abilities.keyword.EnchantAbility; +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.Zone; +import mage.target.TargetPermanent; +import mage.target.TargetSpell; +import mage.target.common.TargetLandPermanent; + +/** + * + * @author LoneFox + */ +public class SunkenField extends CardImpl { + + public SunkenField(UUID ownerId) { + super(ownerId, 51, "Sunken Field", Rarity.UNCOMMON, new CardType[]{CardType.ENCHANTMENT}, "{1}{U}"); + this.expansionSetCode = "PCY"; + this.subtype.add("Aura"); + + // Enchant land + TargetPermanent auraTarget = new TargetLandPermanent(); + this.getSpellAbility().addTarget(auraTarget); + this.getSpellAbility().addEffect(new AttachEffect(Outcome.AddAbility)); + Ability ability = new EnchantAbility(auraTarget.getTargetName()); + this.addAbility(ability); + // Enchanted land has "{T}: Counter target spell unless its controller pays {1}." + ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new CounterUnlessPaysEffect(new ManaCostsImpl("{1}")), new TapSourceCost()); + ability.addTarget(new TargetSpell()); + Effect effect = new GainAbilityAttachedEffect(ability, AttachmentType.AURA); + effect.setText("Enchanted land has \"{T}: Counter target spell unless its controller pays {1}.\""); + this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, effect)); + } + + public SunkenField(final SunkenField card) { + super(card); + } + + @Override + public SunkenField copy() { + return new SunkenField(this); + } +} diff --git a/Mage.Sets/src/mage/sets/prophecy/WellOfDiscovery.java b/Mage.Sets/src/mage/sets/prophecy/WellOfDiscovery.java new file mode 100644 index 00000000000..d13f785e997 --- /dev/null +++ b/Mage.Sets/src/mage/sets/prophecy/WellOfDiscovery.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.prophecy; + +import java.util.UUID; +import mage.abilities.common.BeginningOfEndStepTriggeredAbility; +import mage.abilities.condition.InvertCondition; +import mage.abilities.condition.common.PermanentsOnTheBattlefieldCondition; +import mage.abilities.decorator.ConditionalTriggeredAbility; +import mage.abilities.effects.common.DrawCardSourceControllerEffect; +import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.Rarity; +import mage.constants.TargetController; +import mage.filter.common.FilterControlledLandPermanent; +import mage.filter.predicate.Predicates; +import mage.filter.predicate.permanent.TappedPredicate; + +/** + * + * @author LoneFox + */ +public class WellOfDiscovery extends CardImpl { + + private static final FilterControlledLandPermanent filter = new FilterControlledLandPermanent(); + + static { + filter.add(Predicates.not(new TappedPredicate())); + } + + public WellOfDiscovery(UUID ownerId) { + super(ownerId, 140, "Well of Discovery", Rarity.RARE, new CardType[]{CardType.ARTIFACT}, "{6}"); + this.expansionSetCode = "PCY"; + + // At the beginning of your end step, if you control no untapped lands, draw a card. + this.addAbility(new ConditionalTriggeredAbility(new BeginningOfEndStepTriggeredAbility( + new DrawCardSourceControllerEffect(1), TargetController.YOU, false), + new InvertCondition(new PermanentsOnTheBattlefieldCondition(filter)), + "At the beginning of your end step, if you control no untapped lands, draw a card.")); + } + + public WellOfDiscovery(final WellOfDiscovery card) { + super(card); + } + + @Override + public WellOfDiscovery copy() { + return new WellOfDiscovery(this); + } +} diff --git a/Mage.Sets/src/mage/sets/prophecy/WellOfLife.java b/Mage.Sets/src/mage/sets/prophecy/WellOfLife.java new file mode 100644 index 00000000000..82a2e24ad43 --- /dev/null +++ b/Mage.Sets/src/mage/sets/prophecy/WellOfLife.java @@ -0,0 +1,74 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.sets.prophecy; + +import java.util.UUID; +import mage.abilities.common.BeginningOfEndStepTriggeredAbility; +import mage.abilities.condition.InvertCondition; +import mage.abilities.condition.common.PermanentsOnTheBattlefieldCondition; +import mage.abilities.decorator.ConditionalTriggeredAbility; +import mage.abilities.effects.common.GainLifeEffect; +import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.Rarity; +import mage.constants.TargetController; +import mage.filter.common.FilterControlledLandPermanent; +import mage.filter.predicate.Predicates; +import mage.filter.predicate.permanent.TappedPredicate; + +/** + * + * @author LoneFox + */ +public class WellOfLife extends CardImpl { + + private static final FilterControlledLandPermanent filter = new FilterControlledLandPermanent(); + + static { + filter.add(Predicates.not(new TappedPredicate())); + } + + public WellOfLife(UUID ownerId) { + super(ownerId, 141, "Well of Life", Rarity.UNCOMMON, new CardType[]{CardType.ARTIFACT}, "{4}"); + this.expansionSetCode = "PCY"; + + // At the beginning of your end step, if you control no untapped lands, you gain 2 life. + this.addAbility(new ConditionalTriggeredAbility(new BeginningOfEndStepTriggeredAbility( + new GainLifeEffect(2), TargetController.YOU, false), new InvertCondition(new PermanentsOnTheBattlefieldCondition(filter)), + "At the beginning of your end step, if you control no untapped lands, you gain 2 life.")); + } + + public WellOfLife(final WellOfLife card) { + super(card); + } + + @Override + public WellOfLife copy() { + return new WellOfLife(this); + } +} From cfb10c869e7d6e8395d60d82a0a5ecbd3f142ae9 Mon Sep 17 00:00:00 2001 From: LevelX2 Date: Tue, 13 Oct 2015 17:11:10 +0200 Subject: [PATCH 133/268] Added 5 older cards. --- .../mage/sets/planarchaos/BrainGorgers.java | 114 ++++++++++++++++ .../src/mage/sets/planarchaos/DashHopes.java | 110 ++++++++++++++++ .../sets/planarchaos/Phantasmagorian.java | 19 +-- .../sets/planarchaos/TemporalExtortion.java | 104 +++++++++++++++ .../src/mage/sets/prophecy/AvatarOfMight.java | 122 ++++++++++++++++++ .../src/mage/sets/prophecy/AvatarOfWill.java | 120 +++++++++++++++++ .../mage/sets/tenthedition/AvatarOfMight.java | 52 ++++++++ 7 files changed, 633 insertions(+), 8 deletions(-) create mode 100644 Mage.Sets/src/mage/sets/planarchaos/BrainGorgers.java create mode 100644 Mage.Sets/src/mage/sets/planarchaos/DashHopes.java create mode 100644 Mage.Sets/src/mage/sets/planarchaos/TemporalExtortion.java create mode 100644 Mage.Sets/src/mage/sets/prophecy/AvatarOfMight.java create mode 100644 Mage.Sets/src/mage/sets/prophecy/AvatarOfWill.java create mode 100644 Mage.Sets/src/mage/sets/tenthedition/AvatarOfMight.java diff --git a/Mage.Sets/src/mage/sets/planarchaos/BrainGorgers.java b/Mage.Sets/src/mage/sets/planarchaos/BrainGorgers.java new file mode 100644 index 00000000000..9ba3c089df2 --- /dev/null +++ b/Mage.Sets/src/mage/sets/planarchaos/BrainGorgers.java @@ -0,0 +1,114 @@ +/* + * 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.planarchaos; + +import java.util.UUID; +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.costs.common.SacrificeTargetCost; +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.CastSourceTriggeredAbility; +import mage.abilities.keyword.MadnessAbility; +import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.Outcome; +import mage.constants.Rarity; +import mage.game.Game; +import mage.game.stack.Spell; +import mage.players.Player; +import mage.target.common.TargetControlledCreaturePermanent; + +/** + * + * @author LevelX2 + */ +public class BrainGorgers extends CardImpl { + + public BrainGorgers(UUID ownerId) { + super(ownerId, 65, "Brain Gorgers", Rarity.COMMON, new CardType[]{CardType.CREATURE}, "{3}{B}"); + this.expansionSetCode = "PLC"; + this.subtype.add("Zombie"); + this.power = new MageInt(4); + this.toughness = new MageInt(2); + + // When you cast Brain Gorgers, any player may sacrifice a creature. If a player does, counter Brain Gorgers. + this.addAbility(new CastSourceTriggeredAbility(new BrainGorgersCounterSourceEffect())); + + // Madness {1}{B} + this.addAbility(new MadnessAbility(this, new ManaCostsImpl<>("{1}{B}"))); + } + + public BrainGorgers(final BrainGorgers card) { + super(card); + } + + @Override + public BrainGorgers copy() { + return new BrainGorgers(this); + } +} + +class BrainGorgersCounterSourceEffect extends OneShotEffect { + + public BrainGorgersCounterSourceEffect() { + super(Outcome.AIDontUseIt); + staticText = "any player may sacrifice a creature. If a player does, counter {source}"; + } + + public BrainGorgersCounterSourceEffect(final BrainGorgersCounterSourceEffect effect) { + super(effect); + } + + @Override + public BrainGorgersCounterSourceEffect copy() { + return new BrainGorgersCounterSourceEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Spell spell = game.getStack().getSpell(source.getSourceId()); + if (spell != null) { + SacrificeTargetCost cost = new SacrificeTargetCost(new TargetControlledCreaturePermanent()); + for (UUID playerId : game.getState().getPlayerList(source.getControllerId())) { + cost.clearPaid(); + Player player = game.getPlayer(playerId); + if (cost.canPay(source, source.getSourceId(), player.getId(), game) + && player.chooseUse(outcome, "Sacrifice a creature to counter " + spell.getIdName() + "?", source, game)) { + if (cost.pay(source, game, source.getSourceId(), player.getId(), false)) { + game.informPlayers(player.getLogName() + " sacrifices a creature to counter " + spell.getIdName() + "."); + game.getStack().counter(spell.getId(), source.getSourceId(), game); + } + } + } + return true; + } + return false; + } + +} diff --git a/Mage.Sets/src/mage/sets/planarchaos/DashHopes.java b/Mage.Sets/src/mage/sets/planarchaos/DashHopes.java new file mode 100644 index 00000000000..561fbbc9e8b --- /dev/null +++ b/Mage.Sets/src/mage/sets/planarchaos/DashHopes.java @@ -0,0 +1,110 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.sets.planarchaos; + +import java.util.UUID; +import mage.abilities.Ability; +import mage.abilities.costs.common.PayLifeCost; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.CastSourceTriggeredAbility; +import mage.abilities.effects.common.CounterTargetEffect; +import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.Outcome; +import mage.constants.Rarity; +import mage.game.Game; +import mage.game.stack.Spell; +import mage.players.Player; +import mage.target.TargetSpell; + +/** + * + * @author LevelX2 + */ +public class DashHopes extends CardImpl { + + public DashHopes(UUID ownerId) { + super(ownerId, 68, "Dash Hopes", Rarity.COMMON, new CardType[]{CardType.INSTANT}, "{B}{B}"); + this.expansionSetCode = "PLC"; + + // When you cast Dash Hopes, any player may pay 5 life. If a player does, counter Dash Hopes. + this.addAbility(new CastSourceTriggeredAbility(new DashHopesCounterSourceEffect())); + + // Counter target spell. + this.getSpellAbility().addEffect(new CounterTargetEffect()); + this.getSpellAbility().addTarget(new TargetSpell()); + } + + public DashHopes(final DashHopes card) { + super(card); + } + + @Override + public DashHopes copy() { + return new DashHopes(this); + } +} + +class DashHopesCounterSourceEffect extends OneShotEffect { + + public DashHopesCounterSourceEffect() { + super(Outcome.AIDontUseIt); + staticText = "any player may pay 5 life. If a player does, counter {source}"; + } + + public DashHopesCounterSourceEffect(final DashHopesCounterSourceEffect effect) { + super(effect); + } + + @Override + public DashHopesCounterSourceEffect copy() { + return new DashHopesCounterSourceEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Spell spell = game.getStack().getSpell(source.getSourceId()); + if (spell != null) { + PayLifeCost cost = new PayLifeCost(5); + for (UUID playerId : game.getState().getPlayerList(source.getControllerId())) { + Player player = game.getPlayer(playerId); + cost.clearPaid(); + if (cost.canPay(source, source.getSourceId(), player.getId(), game) + && player.chooseUse(outcome, "Pay 5 life to counter " + spell.getIdName() + "?", source, game)) { + if (cost.pay(source, game, source.getSourceId(), player.getId(), false)) { + game.informPlayers(player.getLogName() + " pays 5 life to counter " + spell.getIdName() + "."); + game.getStack().counter(spell.getId(), source.getSourceId(), game); + } + } + } + return true; + } + return false; + } + +} diff --git a/Mage.Sets/src/mage/sets/planarchaos/Phantasmagorian.java b/Mage.Sets/src/mage/sets/planarchaos/Phantasmagorian.java index e8e99f9eb63..966f1d2a126 100644 --- a/Mage.Sets/src/mage/sets/planarchaos/Phantasmagorian.java +++ b/Mage.Sets/src/mage/sets/planarchaos/Phantasmagorian.java @@ -95,19 +95,22 @@ class CounterSourceEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { - + StackObject spell = null; - for(StackObject objet : game.getStack()){ - if(objet instanceof Spell && objet.getSourceId().equals(source.getSourceId())){ + for (StackObject objet : game.getStack()) { + if (objet instanceof Spell && objet.getSourceId().equals(source.getSourceId())) { spell = objet; } } - if(spell != null){ - for(UUID uuid : game.getPlayerList()){ + if (spell != null) { + DiscardTargetCost cost = new DiscardTargetCost(new TargetCardInHand(3, 3, new FilterCard())); + for (UUID uuid : game.getPlayerList()) { Player player = game.getPlayer(uuid); - if(player.chooseUse(Outcome.Detriment, "Discard three cards to counter " + spell.getName() + "?", source, game)){ - DiscardTargetCost cost = new DiscardTargetCost(new TargetCardInHand(3, 3, new FilterCard())); - if(cost.pay(source, game, source.getSourceId(), uuid, false)){ + cost.clearPaid(); + if (cost.canPay(source, source.getSourceId(), player.getId(), game) + && player.chooseUse(Outcome.Detriment, "Discard three cards to counter " + spell.getName() + "?", source, game)) { + + if (cost.pay(source, game, source.getSourceId(), uuid, false)) { game.informPlayers(player.getLogName() + " discards 3 cards to counter " + spell.getName() + "."); game.getStack().counter(spell.getId(), source.getSourceId(), game); return true; diff --git a/Mage.Sets/src/mage/sets/planarchaos/TemporalExtortion.java b/Mage.Sets/src/mage/sets/planarchaos/TemporalExtortion.java new file mode 100644 index 00000000000..ea806b61981 --- /dev/null +++ b/Mage.Sets/src/mage/sets/planarchaos/TemporalExtortion.java @@ -0,0 +1,104 @@ +/* + * 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.planarchaos; + +import java.util.UUID; +import mage.abilities.Ability; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.CastSourceTriggeredAbility; +import mage.abilities.effects.common.turn.AddExtraTurnControllerEffect; +import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.Outcome; +import mage.constants.Rarity; +import mage.game.Game; +import mage.game.stack.Spell; +import mage.players.Player; + +/** + * + * @author LevelX2 + */ +public class TemporalExtortion extends CardImpl { + + public TemporalExtortion(UUID ownerId) { + super(ownerId, 81, "Temporal Extortion", Rarity.RARE, new CardType[]{CardType.SORCERY}, "{B}{B}{B}{B}"); + this.expansionSetCode = "PLC"; + + // When you cast Temporal Extortion, any player may pay half his or her life, rounded up. If a player does, counter Temporal Extortion. + this.addAbility(new CastSourceTriggeredAbility(new TemporalExtortionCounterSourceEffect())); + + // Take an extra turn after this one. + this.getSpellAbility().addEffect(new AddExtraTurnControllerEffect()); + } + + public TemporalExtortion(final TemporalExtortion card) { + super(card); + } + + @Override + public TemporalExtortion copy() { + return new TemporalExtortion(this); + } +} + +class TemporalExtortionCounterSourceEffect extends OneShotEffect { + + public TemporalExtortionCounterSourceEffect() { + super(Outcome.AIDontUseIt); + staticText = "any player may pay half his or her life, rounded up. If a player does, counter {source}"; + } + + public TemporalExtortionCounterSourceEffect(final TemporalExtortionCounterSourceEffect effect) { + super(effect); + } + + @Override + public TemporalExtortionCounterSourceEffect copy() { + return new TemporalExtortionCounterSourceEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Spell spell = game.getStack().getSpell(source.getSourceId()); + if (spell != null) { + for (UUID playerId : game.getState().getPlayerList(source.getControllerId())) { + Player player = game.getPlayer(playerId); + if (player.chooseUse(outcome, "Pay half your life, rounded up to counter " + spell.getIdName() + "?", source, game)) { + Integer amount = (int) Math.ceil(player.getLife() / 2f); + player.loseLife(amount, game); + game.informPlayers(player.getLogName() + " pays half his or her life, rounded up to counter " + spell.getIdName() + "."); + game.getStack().counter(spell.getId(), source.getSourceId(), game); + } + } + return true; + } + return false; + } + +} diff --git a/Mage.Sets/src/mage/sets/prophecy/AvatarOfMight.java b/Mage.Sets/src/mage/sets/prophecy/AvatarOfMight.java new file mode 100644 index 00000000000..8008f96f3df --- /dev/null +++ b/Mage.Sets/src/mage/sets/prophecy/AvatarOfMight.java @@ -0,0 +1,122 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.sets.prophecy; + +import java.util.UUID; +import mage.MageInt; +import mage.Mana; +import mage.abilities.Ability; +import mage.abilities.SpellAbility; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.effects.common.cost.CostModificationEffectImpl; +import mage.abilities.keyword.TrampleAbility; +import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.CostModificationType; +import mage.constants.Duration; +import mage.constants.Outcome; +import mage.constants.Rarity; +import mage.constants.Zone; +import mage.filter.common.FilterCreaturePermanent; +import mage.game.Game; +import mage.players.Player; + +/** + * + * @author LevelX2 + */ +public class AvatarOfMight extends CardImpl { + + public AvatarOfMight(UUID ownerId) { + super(ownerId, 109, "Avatar of Might", Rarity.RARE, new CardType[]{CardType.CREATURE}, "{6}{G}{G}"); + this.expansionSetCode = "PCY"; + this.subtype.add("Avatar"); + this.power = new MageInt(8); + this.toughness = new MageInt(8); + + // If an opponent controls at least four more creatures than you, Avatar of Might costs {6} less to cast. + this.addAbility(new SimpleStaticAbility(Zone.STACK, new AvatarOfMightCostReductionEffect())); + + // Trample + this.addAbility(TrampleAbility.getInstance()); + } + + public AvatarOfMight(final AvatarOfMight card) { + super(card); + } + + @Override + public AvatarOfMight copy() { + return new AvatarOfMight(this); + } +} + +class AvatarOfMightCostReductionEffect extends CostModificationEffectImpl { + + AvatarOfMightCostReductionEffect() { + super(Duration.Custom, Outcome.Benefit, CostModificationType.REDUCE_COST); + staticText = "If an opponent controls at least four more creatures than you, {this} will costs {6} less to cast"; + } + + AvatarOfMightCostReductionEffect(final AvatarOfMightCostReductionEffect effect) { + super(effect); + } + + @Override + public boolean apply(Game game, Ability source, Ability abilityToModify) { + SpellAbility spellAbility = (SpellAbility) abilityToModify; + Mana mana = spellAbility.getManaCostsToPay().getMana(); + if (mana.getColorless() > 0) { + int newCount = mana.getColorless() - 6; + if (newCount < 0) { + newCount = 0; + } + mana.setColorless(newCount); + spellAbility.getManaCostsToPay().load(mana.toString()); + return true; + } + return false; + } + + @Override + public boolean applies(Ability abilityToModify, Ability source, Game game) { + int creatures = game.getBattlefield().countAll(new FilterCreaturePermanent(), source.getControllerId(), game); + for (UUID playerId : game.getOpponents(source.getControllerId())) { + Player opponent = game.getPlayer(playerId); + if (opponent != null && game.getBattlefield().countAll(new FilterCreaturePermanent(), opponent.getId(), game) >= creatures + 4) { + return true; + } + } + return false; + } + + @Override + public AvatarOfMightCostReductionEffect copy() { + return new AvatarOfMightCostReductionEffect(this); + } +} diff --git a/Mage.Sets/src/mage/sets/prophecy/AvatarOfWill.java b/Mage.Sets/src/mage/sets/prophecy/AvatarOfWill.java new file mode 100644 index 00000000000..2dbd76b18b1 --- /dev/null +++ b/Mage.Sets/src/mage/sets/prophecy/AvatarOfWill.java @@ -0,0 +1,120 @@ +/* + * 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.Mana; +import mage.abilities.Ability; +import mage.abilities.SpellAbility; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.effects.common.cost.CostModificationEffectImpl; +import mage.abilities.keyword.FlyingAbility; +import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.CostModificationType; +import mage.constants.Duration; +import mage.constants.Outcome; +import mage.constants.Rarity; +import mage.constants.Zone; +import mage.game.Game; +import mage.players.Player; + +/** + * + * @author LevelX2 + */ +public class AvatarOfWill extends CardImpl { + + public AvatarOfWill(UUID ownerId) { + super(ownerId, 30, "Avatar of Will", Rarity.RARE, new CardType[]{CardType.CREATURE}, "{6}{U}{U}"); + this.expansionSetCode = "PCY"; + this.subtype.add("Avatar"); + this.power = new MageInt(5); + this.toughness = new MageInt(6); + + // If an opponent has no cards in hand, Avatar of Will costs {6} less to cast. + this.addAbility(new SimpleStaticAbility(Zone.STACK, new AvatarOfWillCostReductionEffect())); + + // Flying + this.addAbility(FlyingAbility.getInstance()); + } + + public AvatarOfWill(final AvatarOfWill card) { + super(card); + } + + @Override + public AvatarOfWill copy() { + return new AvatarOfWill(this); + } +} + +class AvatarOfWillCostReductionEffect extends CostModificationEffectImpl { + + AvatarOfWillCostReductionEffect() { + super(Duration.Custom, Outcome.Benefit, CostModificationType.REDUCE_COST); + staticText = "If an opponent has no cards in hand, {this} will costs {6} less to cast"; + } + + AvatarOfWillCostReductionEffect(final AvatarOfWillCostReductionEffect effect) { + super(effect); + } + + @Override + public boolean apply(Game game, Ability source, Ability abilityToModify) { + SpellAbility spellAbility = (SpellAbility) abilityToModify; + Mana mana = spellAbility.getManaCostsToPay().getMana(); + if (mana.getColorless() > 0) { + int newCount = mana.getColorless() - 6; + if (newCount < 0) { + newCount = 0; + } + mana.setColorless(newCount); + spellAbility.getManaCostsToPay().load(mana.toString()); + return true; + } + return false; + } + + @Override + public boolean applies(Ability abilityToModify, Ability source, Game game) { + for (UUID playerId : game.getOpponents(source.getControllerId())) { + Player opponent = game.getPlayer(playerId); + if (opponent != null && opponent.getHand().isEmpty()) { + return true; + } + } + return false; + } + + @Override + public AvatarOfWillCostReductionEffect copy() { + return new AvatarOfWillCostReductionEffect(this); + } +} diff --git a/Mage.Sets/src/mage/sets/tenthedition/AvatarOfMight.java b/Mage.Sets/src/mage/sets/tenthedition/AvatarOfMight.java new file mode 100644 index 00000000000..3fb391e2810 --- /dev/null +++ b/Mage.Sets/src/mage/sets/tenthedition/AvatarOfMight.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.tenthedition; + +import java.util.UUID; + +/** + * + * @author LevelX2 + */ +public class AvatarOfMight extends mage.sets.prophecy.AvatarOfMight { + + public AvatarOfMight(UUID ownerId) { + super(ownerId); + this.cardNumber = 251; + this.expansionSetCode = "10E"; + } + + public AvatarOfMight(final AvatarOfMight card) { + super(card); + } + + @Override + public AvatarOfMight copy() { + return new AvatarOfMight(this); + } +} From 19e231e860685dc620cf5466c0c35987b3e0d0da Mon Sep 17 00:00:00 2001 From: LevelX2 Date: Tue, 13 Oct 2015 22:35:50 +0200 Subject: [PATCH 134/268] * Fixed that continuous effects were not yet applied to lands entering the battlefield (preventing Prismatic Omen and Valakut the Molten Pinnacle combo to work). --- .../mage/sets/shadowmoor/PrismaticOmen.java | 21 ++++--- .../enters/ValakutTheMoltenPinnacleTest.java | 56 +++++++++++++------ .../mage/game/permanent/PermanentImpl.java | 6 +- 3 files changed, 51 insertions(+), 32 deletions(-) diff --git a/Mage.Sets/src/mage/sets/shadowmoor/PrismaticOmen.java b/Mage.Sets/src/mage/sets/shadowmoor/PrismaticOmen.java index f3e7e5bc716..73b5b6ee1b3 100644 --- a/Mage.Sets/src/mage/sets/shadowmoor/PrismaticOmen.java +++ b/Mage.Sets/src/mage/sets/shadowmoor/PrismaticOmen.java @@ -30,13 +30,6 @@ package mage.sets.shadowmoor; import java.util.ArrayList; import java.util.Arrays; import java.util.UUID; -import mage.constants.CardType; -import mage.constants.Duration; -import mage.constants.Layer; -import mage.constants.Outcome; -import mage.constants.Rarity; -import mage.constants.SubLayer; -import mage.constants.Zone; import mage.Mana; import mage.abilities.Ability; import mage.abilities.common.SimpleStaticAbility; @@ -48,6 +41,13 @@ import mage.abilities.mana.GreenManaAbility; import mage.abilities.mana.RedManaAbility; import mage.abilities.mana.WhiteManaAbility; import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.Layer; +import mage.constants.Outcome; +import mage.constants.Rarity; +import mage.constants.SubLayer; +import mage.constants.Zone; import mage.filter.common.FilterLandPermanent; import mage.game.Game; import mage.game.permanent.Permanent; @@ -62,7 +62,6 @@ public class PrismaticOmen extends CardImpl { super(ownerId, 126, "Prismatic Omen", Rarity.RARE, new CardType[]{CardType.ENCHANTMENT}, "{1}{G}"); this.expansionSetCode = "SHM"; - // Lands you control are every basic land type in addition to their other types. this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new BecomesBasicLandTypeAllEffect("Swamp", "Mountain", "Forest", "Island", "Plains"))); } @@ -109,11 +108,11 @@ class BecomesBasicLandTypeAllEffect extends ContinuousEffectImpl { switch (layer) { case AbilityAddingRemovingEffects_6: Mana mana = new Mana(); - for (Ability ability : land.getAbilities()){ + for (Ability ability : land.getAbilities()) { if (ability instanceof BasicManaAbility) { - for (Mana netMana: ((BasicManaAbility)ability ).getNetMana(game)) { + for (Mana netMana : ((BasicManaAbility) ability).getNetMana(game)) { mana.add(netMana); - } + } } } if (mana.getGreen() == 0 && landTypes.contains("Forest")) { diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/abilities/enters/ValakutTheMoltenPinnacleTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/abilities/enters/ValakutTheMoltenPinnacleTest.java index c29cd7a736b..141e9951328 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/abilities/enters/ValakutTheMoltenPinnacleTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/abilities/enters/ValakutTheMoltenPinnacleTest.java @@ -26,13 +26,10 @@ * authors and should not be interpreted as representing official policies, either expressed * or implied, of BetaSteward_at_googlemail.com. */ - package org.mage.test.cards.abilities.enters; import mage.constants.PhaseStep; import mage.constants.Zone; -import mage.game.permanent.Permanent; -import org.junit.Assert; import org.junit.Test; import org.mage.test.serverside.base.CardTestPlayerBase; @@ -40,17 +37,15 @@ import org.mage.test.serverside.base.CardTestPlayerBase; * * @author LevelX2 */ - public class ValakutTheMoltenPinnacleTest extends CardTestPlayerBase { /** - * Valakut, the Molten Pinnacle - * Land - * Valakut, the Molten Pinnacle enters the battlefield tapped. - * Whenever a Mountain enters the battlefield under your control, if you control at least five other Mountains, you may have Valakut, the Molten Pinnacle deal 3 damage to target creature or player. - * {T}: Add {R} to your mana pool. + * Valakut, the Molten Pinnacle Land Valakut, the Molten Pinnacle enters the + * battlefield tapped. Whenever a Mountain enters the battlefield under your + * control, if you control at least five other Mountains, you may have + * Valakut, the Molten Pinnacle deal 3 damage to target creature or player. + * {T}: Add {R} to your mana pool. */ - @Test public void onlyFourMountainsNoDamage() { @@ -85,13 +80,11 @@ public class ValakutTheMoltenPinnacleTest extends CardTestPlayerBase { assertLife(playerA, 20); assertLife(playerB, 17); - } - // Scapeshift {2}{G}{G} - // Sorcery - // Sacrifice any number of lands. Search your library for that many land cards, put them onto the battlefield tapped, then shuffle your library. - + // Scapeshift {2}{G}{G} + // Sorcery + // Sacrifice any number of lands. Search your library for that many land cards, put them onto the battlefield tapped, then shuffle your library. @Test public void sixEnterWithScapeshiftDamageToPlayerB() { @@ -113,7 +106,6 @@ public class ValakutTheMoltenPinnacleTest extends CardTestPlayerBase { assertLife(playerA, 20); assertLife(playerB, 2); // 6 * 3 damage = 18 - } @Test @@ -166,4 +158,36 @@ public class ValakutTheMoltenPinnacleTest extends CardTestPlayerBase { assertLife(playerB, 2); // 6 * 3 damage = 18 } + + /** + * Some lands aren't triggering Valakut, the Molten Pinnacle with Prismatic + * Omen and 6+ lands in play. So far I've noticed that Misty Rainforest and + * basic Island did not trigger Valakut, but an additional copy of Valakut + * did. + */ + @Test + public void withPrismaticOmen() { + // Valakut, the Molten Pinnacle enters the battlefield tapped. + // Whenever a Mountain enters the battlefield under your control, if you control at least five other Mountains, + // you may have Valakut, the Molten Pinnacle deal 3 damage to target creature or player. + // {T}: Add {R} to your mana pool. + addCard(Zone.BATTLEFIELD, playerA, "Valakut, the Molten Pinnacle"); + addCard(Zone.BATTLEFIELD, playerA, "Forest", 4); + + addCard(Zone.HAND, playerA, "Forest", 1); + + // Lands you control are every basic land type in addition to their other types. + addCard(Zone.BATTLEFIELD, playerA, "Prismatic Omen"); + + playLand(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Forest"); + addTarget(playerA, playerB); + + setStopAt(1, PhaseStep.BEGIN_COMBAT); + execute(); + + assertLife(playerA, 20); + assertLife(playerB, 17); + + } + } diff --git a/Mage/src/mage/game/permanent/PermanentImpl.java b/Mage/src/mage/game/permanent/PermanentImpl.java index f5be69ff35f..783801dc7f2 100644 --- a/Mage/src/mage/game/permanent/PermanentImpl.java +++ b/Mage/src/mage/game/permanent/PermanentImpl.java @@ -916,11 +916,7 @@ public abstract class PermanentImpl extends CardImpl implements Permanent { EntersTheBattlefieldEvent event = new EntersTheBattlefieldEvent(this, sourceId, getControllerId(), fromZone); if (!game.replaceEvent(event)) { if (fireEvent) { - if (sourceId == null) { // play lands - game.fireEvent(event); - } else { // from effects - game.addSimultaneousEvent(event); - } + game.addSimultaneousEvent(event); } return true; } From 7e768e787a2d70d0e0734d920d1387d47a4ca7b5 Mon Sep 17 00:00:00 2001 From: LevelX2 Date: Tue, 13 Oct 2015 23:16:42 +0200 Subject: [PATCH 135/268] * Fixed some handling problems of all players asked to pay a cost to counter the spell with this ability. --- .../mage/sets/planarchaos/BrainGorgers.java | 16 ++++++---- .../src/mage/sets/planarchaos/DashHopes.java | 14 ++++++--- .../sets/planarchaos/Phantasmagorian.java | 31 ++++++++----------- .../sets/planarchaos/TemporalExtortion.java | 14 ++++++--- .../costs/common/DiscardTargetCost.java | 4 ++- 5 files changed, 44 insertions(+), 35 deletions(-) diff --git a/Mage.Sets/src/mage/sets/planarchaos/BrainGorgers.java b/Mage.Sets/src/mage/sets/planarchaos/BrainGorgers.java index 9ba3c089df2..53fd0d565b6 100644 --- a/Mage.Sets/src/mage/sets/planarchaos/BrainGorgers.java +++ b/Mage.Sets/src/mage/sets/planarchaos/BrainGorgers.java @@ -29,6 +29,7 @@ package mage.sets.planarchaos; import java.util.UUID; import mage.MageInt; +import mage.MageObject; import mage.abilities.Ability; import mage.abilities.costs.common.SacrificeTargetCost; import mage.abilities.costs.mana.ManaCostsImpl; @@ -92,23 +93,26 @@ class BrainGorgersCounterSourceEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { - Spell spell = game.getStack().getSpell(source.getSourceId()); - if (spell != null) { + MageObject sourceObject = source.getSourceObject(game); + if (sourceObject != null) { SacrificeTargetCost cost = new SacrificeTargetCost(new TargetControlledCreaturePermanent()); for (UUID playerId : game.getState().getPlayerList(source.getControllerId())) { cost.clearPaid(); Player player = game.getPlayer(playerId); if (cost.canPay(source, source.getSourceId(), player.getId(), game) - && player.chooseUse(outcome, "Sacrifice a creature to counter " + spell.getIdName() + "?", source, game)) { + && player.chooseUse(outcome, "Sacrifice a creature to counter " + sourceObject.getIdName() + "?", source, game)) { if (cost.pay(source, game, source.getSourceId(), player.getId(), false)) { - game.informPlayers(player.getLogName() + " sacrifices a creature to counter " + spell.getIdName() + "."); - game.getStack().counter(spell.getId(), source.getSourceId(), game); + game.informPlayers(player.getLogName() + " sacrifices a creature to counter " + sourceObject.getIdName() + "."); + Spell spell = game.getStack().getSpell(source.getSourceId()); + if (spell != null) { + game.getStack().counter(spell.getId(), source.getSourceId(), game); + } } } } return true; } return false; - } + } } diff --git a/Mage.Sets/src/mage/sets/planarchaos/DashHopes.java b/Mage.Sets/src/mage/sets/planarchaos/DashHopes.java index 561fbbc9e8b..d061e582a98 100644 --- a/Mage.Sets/src/mage/sets/planarchaos/DashHopes.java +++ b/Mage.Sets/src/mage/sets/planarchaos/DashHopes.java @@ -28,6 +28,7 @@ package mage.sets.planarchaos; import java.util.UUID; +import mage.MageObject; import mage.abilities.Ability; import mage.abilities.costs.common.PayLifeCost; import mage.abilities.effects.OneShotEffect; @@ -88,17 +89,20 @@ class DashHopesCounterSourceEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { - Spell spell = game.getStack().getSpell(source.getSourceId()); - if (spell != null) { + MageObject sourceObject = source.getSourceObject(game); + if (sourceObject != null) { PayLifeCost cost = new PayLifeCost(5); for (UUID playerId : game.getState().getPlayerList(source.getControllerId())) { Player player = game.getPlayer(playerId); cost.clearPaid(); if (cost.canPay(source, source.getSourceId(), player.getId(), game) - && player.chooseUse(outcome, "Pay 5 life to counter " + spell.getIdName() + "?", source, game)) { + && player.chooseUse(outcome, "Pay 5 life to counter " + sourceObject.getIdName() + "?", source, game)) { if (cost.pay(source, game, source.getSourceId(), player.getId(), false)) { - game.informPlayers(player.getLogName() + " pays 5 life to counter " + spell.getIdName() + "."); - game.getStack().counter(spell.getId(), source.getSourceId(), game); + game.informPlayers(player.getLogName() + " pays 5 life to counter " + sourceObject.getIdName() + "."); + Spell spell = game.getStack().getSpell(source.getSourceId()); + if (spell != null) { + game.getStack().counter(spell.getId(), source.getSourceId(), game); + } } } } diff --git a/Mage.Sets/src/mage/sets/planarchaos/Phantasmagorian.java b/Mage.Sets/src/mage/sets/planarchaos/Phantasmagorian.java index 966f1d2a126..31778c36699 100644 --- a/Mage.Sets/src/mage/sets/planarchaos/Phantasmagorian.java +++ b/Mage.Sets/src/mage/sets/planarchaos/Phantasmagorian.java @@ -29,6 +29,7 @@ package mage.sets.planarchaos; import java.util.UUID; import mage.MageInt; +import mage.MageObject; import mage.abilities.Ability; import mage.abilities.Mode; import mage.abilities.common.SimpleActivatedAbility; @@ -44,7 +45,6 @@ import mage.constants.Zone; import mage.filter.FilterCard; import mage.game.Game; import mage.game.stack.Spell; -import mage.game.stack.StackObject; import mage.players.Player; import mage.target.common.TargetCardInHand; @@ -81,7 +81,7 @@ public class Phantasmagorian extends CardImpl { class CounterSourceEffect extends OneShotEffect { public CounterSourceEffect() { - super(Outcome.Detriment); + super(Outcome.AIDontUseIt); } public CounterSourceEffect(final CounterSourceEffect effect) { @@ -95,25 +95,20 @@ class CounterSourceEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { - - StackObject spell = null; - for (StackObject objet : game.getStack()) { - if (objet instanceof Spell && objet.getSourceId().equals(source.getSourceId())) { - spell = objet; - } - } - if (spell != null) { + MageObject sourceObject = source.getSourceObject(game); + if (sourceObject != null) { DiscardTargetCost cost = new DiscardTargetCost(new TargetCardInHand(3, 3, new FilterCard())); - for (UUID uuid : game.getPlayerList()) { - Player player = game.getPlayer(uuid); + for (UUID playerId : game.getState().getPlayerList(source.getControllerId())) { + Player player = game.getPlayer(playerId); cost.clearPaid(); if (cost.canPay(source, source.getSourceId(), player.getId(), game) - && player.chooseUse(Outcome.Detriment, "Discard three cards to counter " + spell.getName() + "?", source, game)) { - - if (cost.pay(source, game, source.getSourceId(), uuid, false)) { - game.informPlayers(player.getLogName() + " discards 3 cards to counter " + spell.getName() + "."); - game.getStack().counter(spell.getId(), source.getSourceId(), game); - return true; + && player.chooseUse(outcome, "Discard three cards to counter " + sourceObject.getIdName() + "?", source, game)) { + if (cost.pay(source, game, source.getSourceId(), playerId, false)) { + game.informPlayers(player.getLogName() + " discards 3 cards to counter " + sourceObject.getIdName() + "."); + Spell spell = game.getStack().getSpell(source.getSourceId()); + if (spell != null) { + game.getStack().counter(spell.getId(), source.getSourceId(), game); + } } } } diff --git a/Mage.Sets/src/mage/sets/planarchaos/TemporalExtortion.java b/Mage.Sets/src/mage/sets/planarchaos/TemporalExtortion.java index ea806b61981..c1a25134a5a 100644 --- a/Mage.Sets/src/mage/sets/planarchaos/TemporalExtortion.java +++ b/Mage.Sets/src/mage/sets/planarchaos/TemporalExtortion.java @@ -28,6 +28,7 @@ package mage.sets.planarchaos; import java.util.UUID; +import mage.MageObject; import mage.abilities.Ability; import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.CastSourceTriggeredAbility; @@ -85,15 +86,18 @@ class TemporalExtortionCounterSourceEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { - Spell spell = game.getStack().getSpell(source.getSourceId()); - if (spell != null) { + MageObject sourceObject = source.getSourceObject(game); + if (sourceObject != null) { for (UUID playerId : game.getState().getPlayerList(source.getControllerId())) { Player player = game.getPlayer(playerId); - if (player.chooseUse(outcome, "Pay half your life, rounded up to counter " + spell.getIdName() + "?", source, game)) { + if (player.chooseUse(outcome, "Pay half your life, rounded up to counter " + sourceObject.getIdName() + "?", source, game)) { Integer amount = (int) Math.ceil(player.getLife() / 2f); player.loseLife(amount, game); - game.informPlayers(player.getLogName() + " pays half his or her life, rounded up to counter " + spell.getIdName() + "."); - game.getStack().counter(spell.getId(), source.getSourceId(), game); + game.informPlayers(player.getLogName() + " pays half his or her life, rounded up to counter " + sourceObject.getIdName() + "."); + Spell spell = game.getStack().getSpell(source.getSourceId()); + if (spell != null) { + game.getStack().counter(spell.getId(), source.getSourceId(), game); + } } } return true; diff --git a/Mage/src/mage/abilities/costs/common/DiscardTargetCost.java b/Mage/src/mage/abilities/costs/common/DiscardTargetCost.java index 3cb460452af..5ba87b81916 100644 --- a/Mage/src/mage/abilities/costs/common/DiscardTargetCost.java +++ b/Mage/src/mage/abilities/costs/common/DiscardTargetCost.java @@ -68,6 +68,7 @@ public class DiscardTargetCost extends CostImpl { @Override public boolean pay(Ability ability, Game game, UUID sourceId, UUID controllerId, boolean noMana) { this.cards.clear(); + this.targets.clear(); Player player = game.getPlayer(controllerId); if (player == null) { return false; @@ -94,7 +95,8 @@ public class DiscardTargetCost extends CostImpl { @Override public void clearPaid() { super.clearPaid(); - cards.clear(); + this.cards.clear(); + this.targets.clear(); } @Override From 3d66f662ec5db0d64543ef68e16fea4190cec704 Mon Sep 17 00:00:00 2001 From: LevelX2 Date: Tue, 13 Oct 2015 23:34:03 +0200 Subject: [PATCH 136/268] * Fixed possible null pointer exception of DiesAttachedTriggerAbility. --- .../src/mage/sets/conflux/MartialCoup.java | 71 ++++++++++--------- .../common/DiesAttachedTriggeredAbility.java | 3 +- 2 files changed, 39 insertions(+), 35 deletions(-) diff --git a/Mage.Sets/src/mage/sets/conflux/MartialCoup.java b/Mage.Sets/src/mage/sets/conflux/MartialCoup.java index 3344214c170..2b856325231 100644 --- a/Mage.Sets/src/mage/sets/conflux/MartialCoup.java +++ b/Mage.Sets/src/mage/sets/conflux/MartialCoup.java @@ -1,46 +1,45 @@ /* -* 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.sets.conflux; +import java.util.List; import java.util.UUID; -import mage.constants.CardType; -import mage.constants.Outcome; -import mage.constants.Rarity; import mage.abilities.Ability; import mage.abilities.effects.OneShotEffect; import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.Outcome; +import mage.constants.Rarity; import mage.filter.common.FilterCreaturePermanent; import mage.game.Game; import mage.game.permanent.Permanent; import mage.game.permanent.token.SoldierToken; - /** * * @author BetaSteward_at_googlemail.com @@ -51,6 +50,7 @@ public class MartialCoup extends CardImpl { super(ownerId, 11, "Martial Coup", Rarity.RARE, new CardType[]{CardType.SORCERY}, "{X}{W}{W}"); this.expansionSetCode = "CON"; + // Put X 1/1 white Soldier creature tokens onto the battlefield. If X is 5 or more, destroy all other creatures. this.getSpellAbility().addEffect(new MartialCoupEffect()); } @@ -85,12 +85,15 @@ class MartialCoupEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { int amount = source.getManaCostsToPay().getX(); + token.putOntoBattlefield(amount, game, source.getSourceId(), source.getControllerId()); + List tokens = token.getLastAddedTokenIds(); if (amount > 4) { - for (Permanent permanent: game.getBattlefield().getActivePermanents(new FilterCreaturePermanent(), source.getControllerId(), game)) { - permanent.destroy(source.getSourceId(), game, false); + for (Permanent permanent : game.getBattlefield().getActivePermanents(new FilterCreaturePermanent(), source.getControllerId(), game)) { + if (!tokens.contains(permanent.getId())) { + permanent.destroy(source.getSourceId(), game, false); + } } } - token.putOntoBattlefield(amount, game, source.getSourceId(), source.getControllerId()); return true; } diff --git a/Mage/src/mage/abilities/common/DiesAttachedTriggeredAbility.java b/Mage/src/mage/abilities/common/DiesAttachedTriggeredAbility.java index e22e9c56744..70113a4564a 100644 --- a/Mage/src/mage/abilities/common/DiesAttachedTriggeredAbility.java +++ b/Mage/src/mage/abilities/common/DiesAttachedTriggeredAbility.java @@ -59,7 +59,8 @@ public class DiesAttachedTriggeredAbility extends TriggeredAbilityImpl { // If both (attachment and attached went to graveyard at the same time, the attachemnets can be already removed from the attached object.) // So check here with the LKI of the enchantment Permanent attachment = game.getPermanentOrLKIBattlefield(getSourceId()); - if (attachment != null && attachment.getAttachedTo().equals(zEvent.getTargetId()) + if (attachment != null + && zEvent.getTargetId().equals(attachment.getAttachedTo()) && attachment.getAttachedToZoneChangeCounter() == zEvent.getTarget().getZoneChangeCounter(game) - 1) { triggered = true; } From c8ba5fc50ac06d343374e2fdad0783b2c54bedd2 Mon Sep 17 00:00:00 2001 From: LevelX2 Date: Wed, 14 Oct 2015 00:13:57 +0200 Subject: [PATCH 137/268] * Blinding Powder - Fixed check for source object. --- .../betrayersofkamigawa/BlindingPowder.java | 20 +++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/Mage.Sets/src/mage/sets/betrayersofkamigawa/BlindingPowder.java b/Mage.Sets/src/mage/sets/betrayersofkamigawa/BlindingPowder.java index d1030fbd9c8..727a67b0c6f 100644 --- a/Mage.Sets/src/mage/sets/betrayersofkamigawa/BlindingPowder.java +++ b/Mage.Sets/src/mage/sets/betrayersofkamigawa/BlindingPowder.java @@ -61,7 +61,7 @@ public class BlindingPowder extends CardImpl { // Equipped creature has "Unattach Blinding Powder: Prevent all combat damage that would be dealt to this creature this turn." Effect effect = new PreventCombatDamageToSourceEffect(Duration.EndOfTurn); effect.setText("Prevent all combat damage that would be dealt to this creature this turn"); - Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, effect, new BlindingPowderUnattachCost()); + Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, effect, new BlindingPowderUnattachCost(getName(), getId())); this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new GainAbilityAttachedEffect(ability, AttachmentType.EQUIPMENT, Duration.WhileOnBattlefield))); // Equip {2} this.addAbility(new EquipAbility(Outcome.PreventDamage, new GenericManaCost(2))); @@ -79,28 +79,32 @@ public class BlindingPowder extends CardImpl { class BlindingPowderUnattachCost extends CostImpl { - public BlindingPowderUnattachCost() { - this.text = "Unattach Blinding Powder"; + protected UUID sourceEquipmentId; + + public BlindingPowderUnattachCost(String name, UUID sourceId) { + this.text = "Unattach " + name; + this.sourceEquipmentId = sourceId; } public BlindingPowderUnattachCost(final BlindingPowderUnattachCost cost) { super(cost); + this.sourceEquipmentId = cost.sourceEquipmentId; } @Override public boolean pay(Ability ability, Game game, UUID sourceId, UUID controllerId, boolean noMana) { Permanent permanent = game.getPermanent(sourceId); if (permanent != null) { - for (UUID attachmentId :permanent.getAttachments()) { + for (UUID attachmentId : permanent.getAttachments()) { Permanent attachment = game.getPermanent(attachmentId); - if (attachment != null && attachment.getName().equals("Blinding Powder")) { + if (attachment != null && attachment.getId().equals(sourceEquipmentId)) { paid = permanent.removeAttachment(attachmentId, game); if (paid) { break; } } } - + } return paid; } @@ -109,9 +113,9 @@ class BlindingPowderUnattachCost extends CostImpl { public boolean canPay(Ability ability, UUID sourceId, UUID controllerId, Game game) { Permanent permanent = game.getPermanent(sourceId); if (permanent != null) { - for (UUID attachmentId :permanent.getAttachments()) { + for (UUID attachmentId : permanent.getAttachments()) { Permanent attachment = game.getPermanent(attachmentId); - if (attachment != null && attachment.getName().equals("Blinding Powder")) { + if (attachment != null && attachment.getId().equals(sourceEquipmentId)) { return true; } } From 2c01d86fc0f8baee6838039bfe390c3eda466401 Mon Sep 17 00:00:00 2001 From: LevelX2 Date: Wed, 14 Oct 2015 08:30:29 +0200 Subject: [PATCH 138/268] * Some fixed to card movement. --- ...LeaveReturnExiledToBattlefieldAbility.java | 19 ++++--------------- .../ReturnFromExileForSourceEffect.java | 12 +----------- Mage/src/mage/players/Player.java | 3 ++- Mage/src/mage/players/PlayerImpl.java | 8 +------- 4 files changed, 8 insertions(+), 34 deletions(-) diff --git a/Mage/src/mage/abilities/common/delayed/OnLeaveReturnExiledToBattlefieldAbility.java b/Mage/src/mage/abilities/common/delayed/OnLeaveReturnExiledToBattlefieldAbility.java index 62e94044571..e632bc96f7c 100644 --- a/Mage/src/mage/abilities/common/delayed/OnLeaveReturnExiledToBattlefieldAbility.java +++ b/Mage/src/mage/abilities/common/delayed/OnLeaveReturnExiledToBattlefieldAbility.java @@ -27,13 +27,12 @@ */ package mage.abilities.common.delayed; -import java.util.LinkedList; +import java.util.LinkedHashSet; import java.util.UUID; import mage.MageObject; import mage.abilities.Ability; import mage.abilities.DelayedTriggeredAbility; import mage.abilities.effects.OneShotEffect; -import mage.cards.Card; import mage.constants.Duration; import mage.constants.Outcome; import mage.constants.Zone; @@ -50,9 +49,9 @@ import mage.util.CardUtil; * Returns the exiled cards/permanents as source leaves battlefield * * Uses no stack + * * @author LevelX2 */ - public class OnLeaveReturnExiledToBattlefieldAbility extends DelayedTriggeredAbility { public OnLeaveReturnExiledToBattlefieldAbility() { @@ -108,22 +107,12 @@ class ReturnExiledPermanentsEffect extends OneShotEffect { Player controller = game.getPlayer(source.getControllerId()); MageObject sourceObject = source.getSourceObject(game); if (sourceObject != null && controller != null) { - int zoneChangeCounter = (sourceObject instanceof PermanentToken) ? source.getSourceObjectZoneChangeCounter() : source.getSourceObjectZoneChangeCounter() -1; + int zoneChangeCounter = (sourceObject instanceof PermanentToken) ? source.getSourceObjectZoneChangeCounter() : source.getSourceObjectZoneChangeCounter() - 1; UUID exileZone = CardUtil.getExileZoneId(game, source.getSourceId(), zoneChangeCounter); if (exileZone != null) { ExileZone exile = game.getExile().getExileZone(exileZone); if (exile != null) { - LinkedList cards = new LinkedList<>(exile); - for (UUID cardId : cards) { - Card card = game.getCard(cardId); - if (card != null) { - Player owner = game.getPlayer(card.getOwnerId()); - if (owner != null && owner.isInGame()) { - owner.putOntoBattlefieldWithInfo(card, game, Zone.EXILED, source.getSourceId()); - } - } - } - exile.clear(); + controller.moveCards(new LinkedHashSet<>(exile.getCards(game)), Zone.EXILED, source, game, false, false, true, null); } return true; } diff --git a/Mage/src/mage/abilities/effects/common/ReturnFromExileForSourceEffect.java b/Mage/src/mage/abilities/effects/common/ReturnFromExileForSourceEffect.java index 181bb35f94c..8d7b8a7c2be 100644 --- a/Mage/src/mage/abilities/effects/common/ReturnFromExileForSourceEffect.java +++ b/Mage/src/mage/abilities/effects/common/ReturnFromExileForSourceEffect.java @@ -30,7 +30,6 @@ package mage.abilities.effects.common; import mage.MageObject; import mage.abilities.Ability; import mage.abilities.effects.OneShotEffect; -import mage.cards.Card; import mage.constants.Outcome; import mage.constants.Zone; import static mage.constants.Zone.BATTLEFIELD; @@ -102,16 +101,7 @@ public class ReturnFromExileForSourceEffect extends OneShotEffect { } ExileZone exile = game.getExile().getExileZone(CardUtil.getExileZoneId(game, source.getSourceId(), zoneChangeCounter)); if (exile != null) { // null is valid if source left battlefield before enters the battlefield effect resolved - if (returnToZone.equals(Zone.BATTLEFIELD)) { - for (Card card : exile.getCards(game)) { - Player owner = game.getPlayer(card.getOwnerId()); - if (owner != null) { - owner.putOntoBattlefieldWithInfo(card, game, Zone.EXILED, source.getSourceId()); - } - } - } else { - controller.moveCards(exile, Zone.EXILED, returnToZone, source, game); - } + controller.moveCards(exile, null, returnToZone, source, game); } return true; } diff --git a/Mage/src/mage/players/Player.java b/Mage/src/mage/players/Player.java index fe56815b058..d00471867c3 100644 --- a/Mage/src/mage/players/Player.java +++ b/Mage/src/mage/players/Player.java @@ -644,7 +644,8 @@ public interface Player extends MageItem, Copyable { * @param tapped tha cards are tapped on the battlefield * @param faceDown the cards are face down in the to zone * @param byOwner the card is moved (or put onto battlefield) by the owner - * of the card (instead of the controller of the source) + * of the card and if target zone is battlefield controlls the permanent + * (instead of the controller of the source) * @return */ boolean moveCards(Set cards, Zone toZone, Ability source, Game game, boolean tapped, boolean faceDown, boolean byOwner, ArrayList appliedEffects); diff --git a/Mage/src/mage/players/PlayerImpl.java b/Mage/src/mage/players/PlayerImpl.java index f1efe5d3301..49e8ffb656a 100644 --- a/Mage/src/mage/players/PlayerImpl.java +++ b/Mage/src/mage/players/PlayerImpl.java @@ -3015,13 +3015,7 @@ public abstract class PlayerImpl implements Player, Serializable { } break; case BATTLEFIELD: - for (Card card : cards) { - fromZone = game.getState().getZone(card.getId()); - if (putOntoBattlefieldWithInfo(card, game, fromZone, source == null ? null : source.getSourceId(), false, card.isFaceDown(game))) { - successfulMovedCards.add(card); - } - } - break; + return moveCards(cards, toZone, source, game, false, false, false, null); case LIBRARY: for (Card card : cards) { fromZone = game.getState().getZone(card.getId()); From 8d8607d14318100126a6b3f637c1146ab5ba6526 Mon Sep 17 00:00:00 2001 From: LevelX2 Date: Wed, 14 Oct 2015 14:23:13 +0200 Subject: [PATCH 139/268] Fixed wrong target zone. --- .../common/delayed/OnLeaveReturnExiledToBattlefieldAbility.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Mage/src/mage/abilities/common/delayed/OnLeaveReturnExiledToBattlefieldAbility.java b/Mage/src/mage/abilities/common/delayed/OnLeaveReturnExiledToBattlefieldAbility.java index e632bc96f7c..3d61104c9ad 100644 --- a/Mage/src/mage/abilities/common/delayed/OnLeaveReturnExiledToBattlefieldAbility.java +++ b/Mage/src/mage/abilities/common/delayed/OnLeaveReturnExiledToBattlefieldAbility.java @@ -112,7 +112,7 @@ class ReturnExiledPermanentsEffect extends OneShotEffect { if (exileZone != null) { ExileZone exile = game.getExile().getExileZone(exileZone); if (exile != null) { - controller.moveCards(new LinkedHashSet<>(exile.getCards(game)), Zone.EXILED, source, game, false, false, true, null); + controller.moveCards(new LinkedHashSet<>(exile.getCards(game)), Zone.BATTLEFIELD, source, game, false, false, true, null); } return true; } From e3b45629db030df3d19b1b3066288e204689e8a0 Mon Sep 17 00:00:00 2001 From: LevelX2 Date: Wed, 14 Oct 2015 17:54:55 +0200 Subject: [PATCH 140/268] Fixed some problems with UUID comparing and some problems with card moving. --- .gitignore | 7 +- Mage.Common/src/mage/view/GameView.java | 2 +- .../mage/sets/alarareborn/Thraximundar.java | 8 +- .../mage/sets/apocalypse/DesolationAngel.java | 14 +-- .../UlamogTheCeaselessHunger.java | 22 ++-- .../sets/bornofthegods/SpitefulReturned.java | 5 +- .../HallOfTheBanditLord.java | 31 ++--- .../championsofkamigawa/NightDealings.java | 27 ++--- .../championsofkamigawa/SiftThroughSands.java | 8 +- .../mage/sets/coldsnap/HibernationsEnd.java | 7 +- .../sets/commander/ChorusOfTheConclave.java | 2 +- .../sets/commander2013/RubiniaSoulsinger.java | 6 +- .../sets/commander2014/InfernalOffering.java | 21 ++-- .../src/mage/sets/darksteel/LichsTomb.java | 14 +-- .../src/mage/sets/eventide/DreamThief.java | 7 +- .../mage/sets/eventide/EndlessHorizons.java | 50 +++++---- .../mage/sets/eventide/HotheadedGiant.java | 7 +- .../src/mage/sets/eventide/SoulReap.java | 16 ++- .../mage/sets/eventide/TalarasBattalion.java | 3 +- .../mage/sets/exodus/SoltariVisionary.java | 2 +- .../sets/fatereforged/MarduWoeReaper.java | 10 +- .../sets/fatereforged/WardscaleDragon.java | 7 +- .../mage/sets/fifthedition/InstillEnergy.java | 3 +- .../src/mage/sets/limitedalpha/Fastbond.java | 14 +-- .../mage/sets/magic2015/GeneratorServant.java | 20 ++-- .../mage/sets/magicorigins/SigilOfValor.java | 4 +- .../sets/masterseditionii/ThoughtLash.java | 26 ++--- .../src/mage/sets/planeshift/OrimsChant.java | 60 +++++----- .../sets/returntoravnica/VraskaTheUnseen.java | 16 ++- .../sets/scarsofmirrodin/RevokeExistence.java | 14 +-- .../mage/sets/shadowmoor/MossbridgeTroll.java | 14 +-- .../sets/shadowmoor/ThoughtweftGambit.java | 3 +- .../sets/shardsofalara/GatherSpecimens.java | 6 +- .../mage/sets/tempest/HelmOfPossession.java | 10 +- .../mage/sets/worldwake/TuktukScrapper.java | 2 +- .../sets/worldwake/WrexialTheRisenDeep.java | 28 ++--- .../test/cards/triggers/OblivionRingTest.java | 4 + .../common/EntersBattlefieldAbility.java | 90 ++++++++------- .../costs/common/DiscardTargetCost.java | 2 +- .../abilities/effects/ContinuousEffects.java | 4 +- .../ReturnFromExileForSourceEffect.java | 6 +- .../abilities/keyword/ReboundAbility.java | 106 +++++++++--------- Mage/src/mage/cards/CardImpl.java | 9 +- Mage/src/mage/game/Exile.java | 5 +- Mage/src/mage/players/PlayerImpl.java | 2 +- 45 files changed, 364 insertions(+), 360 deletions(-) diff --git a/.gitignore b/.gitignore index b129f38e3cb..ca85c840055 100644 --- a/.gitignore +++ b/.gitignore @@ -50,7 +50,7 @@ Mage.Updater/target mage.updater.client/target releases -Utils/author.txt +Utils/author.txt .DS_Store .metadata .project @@ -88,5 +88,6 @@ Mage.Server.Plugins/Mage.Draft.8PlayerBooster/target /Utils/*_unimplemented.txt *.netbeans_automatic_build *.txt -Mage.Client/serverlist.txt -/bin/ +Mage.Client/serverlist.txt +/bin/ +/target/ \ No newline at end of file diff --git a/Mage.Common/src/mage/view/GameView.java b/Mage.Common/src/mage/view/GameView.java index 80ce4867c59..15731967b2c 100644 --- a/Mage.Common/src/mage/view/GameView.java +++ b/Mage.Common/src/mage/view/GameView.java @@ -184,7 +184,7 @@ public class GameView implements Serializable { } if (isPlayer) { // has only to be set for active palyer with priority (e.g. pay mana by delve or Quenchable Fire special action) - if (state.getPriorityPlayerId() == createdForPlayerId && createdForPlayer != null) { + if (createdForPlayer != null && createdForPlayerId.equals(state.getPriorityPlayerId())) { this.special = state.getSpecialActions().getControlledBy(state.getPriorityPlayerId(), createdForPlayer.isInPayManaMode()).size() > 0; } } else { diff --git a/Mage.Sets/src/mage/sets/alarareborn/Thraximundar.java b/Mage.Sets/src/mage/sets/alarareborn/Thraximundar.java index 9fe05560f06..08898a2dcce 100644 --- a/Mage.Sets/src/mage/sets/alarareborn/Thraximundar.java +++ b/Mage.Sets/src/mage/sets/alarareborn/Thraximundar.java @@ -60,9 +60,6 @@ public class Thraximundar extends CardImpl { this.subtype.add("Zombie"); this.subtype.add("Assassin"); - - - this.power = new MageInt(6); this.toughness = new MageInt(6); @@ -116,7 +113,8 @@ class ThraximundarTriggeredAbility extends TriggeredAbilityImpl { @Override public boolean checkTrigger(GameEvent event, Game game) { - if (event.getSourceId() == this.getSourceId()) { + if (event.getSourceId() != null + && event.getSourceId().equals(this.getSourceId())) { UUID defender = game.getCombat().getDefendingPlayerId(this.getSourceId(), game); this.getEffects().get(0).setTargetPointer(new FixedTarget(defender)); return true; @@ -160,4 +158,4 @@ class PlayerSacrificesCreatureTriggeredAbility extends TriggeredAbilityImpl { public PlayerSacrificesCreatureTriggeredAbility copy() { return new PlayerSacrificesCreatureTriggeredAbility(this); } -} \ No newline at end of file +} diff --git a/Mage.Sets/src/mage/sets/apocalypse/DesolationAngel.java b/Mage.Sets/src/mage/sets/apocalypse/DesolationAngel.java index 4c32f5136e9..dd1b5db3a32 100644 --- a/Mage.Sets/src/mage/sets/apocalypse/DesolationAngel.java +++ b/Mage.Sets/src/mage/sets/apocalypse/DesolationAngel.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.apocalypse; import java.util.UUID; -import mage.constants.CardType; -import mage.constants.Outcome; -import mage.constants.Rarity; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.EntersBattlefieldTriggeredAbility; @@ -41,6 +37,9 @@ import mage.abilities.keyword.FlyingAbility; import mage.abilities.keyword.KickerAbility; import mage.cards.Card; import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.Outcome; +import mage.constants.Rarity; import mage.filter.common.FilterLandPermanent; import mage.game.Game; import mage.game.permanent.Permanent; @@ -79,6 +78,7 @@ public class DesolationAngel extends CardImpl { } class DesolationAngelEntersBattlefieldEffect extends OneShotEffect { + DesolationAngelEntersBattlefieldEffect() { super(Outcome.DestroyPermanent); staticText = "destroy all lands you control. If it was kicked, destroy all lands instead"; @@ -93,8 +93,8 @@ class DesolationAngelEntersBattlefieldEffect extends OneShotEffect { Card p = game.getCard(source.getSourceId()); boolean kicked = KickedCondition.getInstance().apply(game, source); for (Permanent permanent : game.getBattlefield().getActivePermanents(new FilterLandPermanent(), source.getControllerId(), source.getSourceId(), game)) { - if ((!kicked && permanent.getControllerId() == source.getControllerId()) - || kicked) { + if ((!kicked && permanent.getControllerId().equals(source.getControllerId())) + || kicked) { permanent.destroy(source.getSourceId(), game, false); } } @@ -106,4 +106,4 @@ class DesolationAngelEntersBattlefieldEffect extends OneShotEffect { return new DesolationAngelEntersBattlefieldEffect(this); } -} \ No newline at end of file +} diff --git a/Mage.Sets/src/mage/sets/battleforzendikar/UlamogTheCeaselessHunger.java b/Mage.Sets/src/mage/sets/battleforzendikar/UlamogTheCeaselessHunger.java index 5b6d8c45eb9..038df1a77e9 100644 --- a/Mage.Sets/src/mage/sets/battleforzendikar/UlamogTheCeaselessHunger.java +++ b/Mage.Sets/src/mage/sets/battleforzendikar/UlamogTheCeaselessHunger.java @@ -67,10 +67,10 @@ public class UlamogTheCeaselessHunger extends CardImpl { // When you cast Ulamog, the Ceaseless Hunger, exile two target permanents. this.addAbility(new UlamogExilePermanentsOnCastAbility()); - + // Indestructible this.addAbility(IndestructibleAbility.getInstance()); - + // Whenever Ulamog attacks, defending player exiles the top twenty cards of his or her library. Effect effect = new UlamogExileLibraryEffect(); effect.setText("defending player exiles the top twenty cards of his or her library"); @@ -139,18 +139,20 @@ class UlamogAttackTriggeredAbility extends TriggeredAbilityImpl { public boolean checkEventType(GameEvent event, Game game) { return event.getType() == EventType.ATTACKER_DECLARED; } - + @Override public boolean checkTrigger(GameEvent event, Game game) { Permanent sourcePermanent = game.getPermanent(this.getSourceId()); - if (sourcePermanent != null && event.getSourceId() == this.getSourceId()) { + if (sourcePermanent != null + && event.getSourceId() != null + && event.getSourceId().equals(this.getSourceId())) { UUID defender = game.getCombat().getDefendingPlayerId(this.getSourceId(), game); this.getEffects().get(0).setTargetPointer(new FixedTarget(defender)); return true; - } - return false; } - + return false; + } + @Override public String getRule() { return new StringBuilder("Whenever {this} attacks, ").append(super.getRule()).toString(); @@ -184,8 +186,8 @@ class UlamogExileLibraryEffect extends OneShotEffect { card.moveToExile(null, null, source.getSourceId(), game); } } - return true; + return true; } - return false; + return false; } -} \ No newline at end of file +} diff --git a/Mage.Sets/src/mage/sets/bornofthegods/SpitefulReturned.java b/Mage.Sets/src/mage/sets/bornofthegods/SpitefulReturned.java index 3f132ca5074..93a3d82a419 100644 --- a/Mage.Sets/src/mage/sets/bornofthegods/SpitefulReturned.java +++ b/Mage.Sets/src/mage/sets/bornofthegods/SpitefulReturned.java @@ -67,7 +67,7 @@ public class SpitefulReturned extends CardImpl { effect.setText("defending player loses 2 life"); this.addAbility(new SpitefulReturnedTriggeredAbility(effect)); // Enchanted creature gets +1/+1. - this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new BoostEnchantedEffect(1,1, Duration.WhileOnBattlefield))); + this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new BoostEnchantedEffect(1, 1, Duration.WhileOnBattlefield))); } public SpitefulReturned(final SpitefulReturned card) { @@ -105,7 +105,8 @@ class SpitefulReturnedTriggeredAbility extends TriggeredAbilityImpl { Permanent sourcePermanent = game.getPermanent(this.getSourceId()); if (sourcePermanent != null) { if (sourcePermanent.getCardType().contains(CardType.CREATURE)) { - if (event.getSourceId() == this.getSourceId()) { + if (event.getSourceId() != null + && event.getSourceId().equals(this.getSourceId())) { UUID defender = game.getCombat().getDefendingPlayerId(this.getSourceId(), game); this.getEffects().get(0).setTargetPointer(new FixedTarget(defender)); return true; diff --git a/Mage.Sets/src/mage/sets/championsofkamigawa/HallOfTheBanditLord.java b/Mage.Sets/src/mage/sets/championsofkamigawa/HallOfTheBanditLord.java index b07a5806979..a23e783906b 100644 --- a/Mage.Sets/src/mage/sets/championsofkamigawa/HallOfTheBanditLord.java +++ b/Mage.Sets/src/mage/sets/championsofkamigawa/HallOfTheBanditLord.java @@ -69,7 +69,7 @@ public class HallOfTheBanditLord extends CardImpl { // Hall of the Bandit Lord enters the battlefield tapped. this.addAbility(new EntersBattlefieldTappedAbility()); - + // {T}, Pay 3 life: Add {1} to your mana pool. If that mana is spent on a creature spell, it gains haste. Mana mana = Mana.ColorlessMana; mana.setFlag(true); @@ -94,12 +94,12 @@ class HallOfTheBanditLordWatcher extends Watcher { private final Ability source; private final List creatures = new ArrayList<>(); - + HallOfTheBanditLordWatcher(Ability source) { super("HallOfTheBanditLordWatcher", WatcherScope.CARD); this.source = source; } - + HallOfTheBanditLordWatcher(final HallOfTheBanditLordWatcher watcher) { super(watcher); this.creatures.addAll(watcher.creatures); @@ -110,22 +110,25 @@ class HallOfTheBanditLordWatcher extends Watcher { public HallOfTheBanditLordWatcher copy() { return new HallOfTheBanditLordWatcher(this); } - + @Override public void watch(GameEvent event, Game game) { if (event.getType() == EventType.MANA_PAYED) { MageObject target = game.getObject(event.getTargetId()); - if (event.getSourceId() == this.getSourceId() && target != null && target.getCardType().contains(CardType.CREATURE) && event.getFlag()) { + if (event.getSourceId() != null + && event.getSourceId().equals(this.getSourceId()) + && target != null && target.getCardType().contains(CardType.CREATURE) + && event.getFlag()) { if (target instanceof Spell) { this.creatures.add(((Spell) target).getCard().getId()); } } } if (event.getType() == EventType.COUNTERED) { - if (creatures.contains(event.getTargetId())) { + if (creatures.contains(event.getTargetId())) { creatures.remove(event.getSourceId()); - } - } + } + } if (event.getType() == EventType.ZONE_CHANGE) { if (creatures.contains(event.getSourceId())) { ZoneChangeEvent zEvent = (ZoneChangeEvent) event; @@ -133,22 +136,22 @@ class HallOfTheBanditLordWatcher extends Watcher { if (zEvent.getToZone() == Zone.STACK) { creatures.remove(event.getSourceId()); } - } - } + } + } if (event.getType() == EventType.ENTERS_THE_BATTLEFIELD) { - if (creatures.contains(event.getSourceId())) { + if (creatures.contains(event.getSourceId())) { ContinuousEffect effect = new GainAbilityTargetEffect(HasteAbility.getInstance(), Duration.Custom); effect.setTargetPointer(new FixedTarget(event.getSourceId())); game.addEffect(effect, source); creatures.remove(event.getSourceId()); - } + } } } - + @Override public void reset() { super.reset(); creatures.clear(); } - + } diff --git a/Mage.Sets/src/mage/sets/championsofkamigawa/NightDealings.java b/Mage.Sets/src/mage/sets/championsofkamigawa/NightDealings.java index 2a9ee7434df..79ca6d3680c 100644 --- a/Mage.Sets/src/mage/sets/championsofkamigawa/NightDealings.java +++ b/Mage.Sets/src/mage/sets/championsofkamigawa/NightDealings.java @@ -25,14 +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.constants.Zone; import mage.abilities.Ability; import mage.abilities.TriggeredAbilityImpl; import mage.abilities.common.SimpleActivatedAbility; @@ -44,7 +39,10 @@ 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.counters.CounterType; import mage.filter.Filter; import mage.filter.common.FilterNonlandCard; @@ -61,7 +59,7 @@ import mage.target.common.TargetCardInLibrary; */ public class NightDealings extends CardImpl { - public NightDealings (UUID ownerId) { + public NightDealings(UUID ownerId) { super(ownerId, 132, "Night Dealings", Rarity.RARE, new CardType[]{CardType.ENCHANTMENT}, "{2}{B}{B}"); this.expansionSetCode = "CHK"; @@ -74,7 +72,7 @@ public class NightDealings extends CardImpl { this.addAbility(ability); } - public NightDealings (final NightDealings card) { + public NightDealings(final NightDealings card) { super(card); } @@ -83,7 +81,6 @@ public class NightDealings extends CardImpl { return new NightDealings(this); } - private class NightDealingsTriggeredAbility extends TriggeredAbilityImpl { public NightDealingsTriggeredAbility() { @@ -106,17 +103,17 @@ public class NightDealings extends CardImpl { @Override public boolean checkTrigger(GameEvent event, Game game) { - // to another player + // to another player if (this.getControllerId() != event.getTargetId()) { // a source you control UUID sourceControllerId = game.getControllerId(event.getSourceId()); - if (sourceControllerId != null && sourceControllerId == this.getControllerId()) { + if (sourceControllerId != null && sourceControllerId.equals(this.getControllerId())) { // save amount of damage to effect this.getEffects().get(0).setValue("damageAmount", event.getAmount()); return true; } } - return false; + return false; } @Override @@ -181,9 +178,9 @@ public class NightDealings extends CardImpl { int cmc = 0; for (Cost cost : source.getCosts()) { if (cost instanceof RemoveVariableCountersSourceCost) { - cmc = ((RemoveVariableCountersSourceCost)cost).getAmount(); + cmc = ((RemoveVariableCountersSourceCost) cost).getAmount(); } - } + } FilterNonlandCard filter = new FilterNonlandCard("nonland card with converted mana cost X = " + cmc); filter.add(new ConvertedManaCostPredicate(Filter.ComparisonType.Equal, cmc)); @@ -192,8 +189,8 @@ public class NightDealings extends CardImpl { if (player.searchLibrary(target, game)) { Card card = player.getLibrary().getCard(target.getFirstTarget(), game); if (card != null) { - card.moveToZone(Zone.HAND, source.getSourceId(), game, false); - + card.moveToZone(Zone.HAND, source.getSourceId(), game, false); + String name = "Reveal"; Cards cards = new CardsImpl(); cards.add(card); diff --git a/Mage.Sets/src/mage/sets/championsofkamigawa/SiftThroughSands.java b/Mage.Sets/src/mage/sets/championsofkamigawa/SiftThroughSands.java index 58e84d068ab..2e2206feef0 100644 --- a/Mage.Sets/src/mage/sets/championsofkamigawa/SiftThroughSands.java +++ b/Mage.Sets/src/mage/sets/championsofkamigawa/SiftThroughSands.java @@ -32,8 +32,8 @@ import mage.abilities.Ability; import mage.abilities.condition.Condition; import mage.abilities.decorator.ConditionalOneShotEffect; import mage.abilities.effects.Effect; -import mage.abilities.effects.common.discard.DiscardControllerEffect; import mage.abilities.effects.common.DrawCardSourceControllerEffect; +import mage.abilities.effects.common.discard.DiscardControllerEffect; import mage.abilities.effects.common.search.SearchLibraryPutInPlayEffect; import mage.cards.CardImpl; import mage.constants.CardType; @@ -56,6 +56,7 @@ public class SiftThroughSands extends CardImpl { private static final String rule = "If you've cast a spell named Peer Through Depths and a spell named Reach Through Mists this turn, you may search your library for a card named The Unspeakable, put it onto the battlefield, then shuffle your library"; private static final FilterCreatureCard filter = new FilterCreatureCard("a card named The Unspeakable"); + static { filter.add(new NamePredicate("The Unspeakable")); } @@ -65,13 +66,12 @@ public class SiftThroughSands extends CardImpl { this.expansionSetCode = "CHK"; this.subtype.add("Arcane"); - // Draw two cards, then discard a card. this.getSpellAbility().addEffect(new DrawCardSourceControllerEffect(2)); Effect effect = new DiscardControllerEffect(1); effect.setText(", then discard a card"); this.getSpellAbility().addEffect(effect); - + // If you've cast a spell named Peer Through Depths and a spell named Reach Through Mists this turn, you may search your library for a card named The Unspeakable, put it onto the battlefield, then shuffle your library. this.getSpellAbility().addEffect(new ConditionalOneShotEffect(new SearchLibraryPutInPlayEffect(new TargetCardInLibrary(filter), false, true), new SiftThroughSandsCondition(), rule)); this.getSpellAbility().addWatcher(new SiftThroughSandsWatcher()); @@ -125,7 +125,7 @@ class SiftThroughSandsWatcher extends Watcher { return; } if (event.getType() == EventType.SPELL_CAST - && controllerId == event.getPlayerId()) { + && controllerId.equals(event.getPlayerId())) { Spell spell = game.getStack().getSpell(event.getTargetId()); if (spell.getCard().getName().equals("Peer Through Depths")) { castPeerThroughDepths = true; diff --git a/Mage.Sets/src/mage/sets/coldsnap/HibernationsEnd.java b/Mage.Sets/src/mage/sets/coldsnap/HibernationsEnd.java index e62a91d9b36..09d46b4974c 100644 --- a/Mage.Sets/src/mage/sets/coldsnap/HibernationsEnd.java +++ b/Mage.Sets/src/mage/sets/coldsnap/HibernationsEnd.java @@ -44,8 +44,8 @@ import mage.filter.FilterCard; import mage.filter.predicate.mageobject.CardTypePredicate; import mage.filter.predicate.mageobject.ConvertedManaCostPredicate; import mage.game.Game; -import mage.game.events.GameEvent.EventType; import mage.game.events.GameEvent; +import mage.game.events.GameEvent.EventType; import mage.game.permanent.Permanent; import mage.players.Player; import mage.target.common.TargetCardInLibrary; @@ -98,7 +98,7 @@ class HibernationsEndAbility extends TriggeredAbilityImpl { @Override public boolean checkTrigger(GameEvent event, Game game) { - return event.getSourceId() == this.getSourceId(); + return event.getSourceId() != null && event.getSourceId().equals(this.getSourceId()); } @Override @@ -127,7 +127,7 @@ class HibernationsEndEffect extends OneShotEffect { public boolean apply(Game game, Ability source) { Player player = game.getPlayer(source.getControllerId()); Permanent sourcePermanent = game.getPermanentOrLKIBattlefield(source.getSourceId()); - if(sourcePermanent != null && player != null) { + if (sourcePermanent != null && player != null) { int newConvertedCost = sourcePermanent.getCounters().getCount("age"); FilterCard filter = new FilterCard("creature card with converted mana cost " + newConvertedCost); filter.add(new ConvertedManaCostPredicate(Filter.ComparisonType.Equal, newConvertedCost)); @@ -138,4 +138,3 @@ class HibernationsEndEffect extends OneShotEffect { return false; } } - diff --git a/Mage.Sets/src/mage/sets/commander/ChorusOfTheConclave.java b/Mage.Sets/src/mage/sets/commander/ChorusOfTheConclave.java index 83774981509..70fc31b6951 100644 --- a/Mage.Sets/src/mage/sets/commander/ChorusOfTheConclave.java +++ b/Mage.Sets/src/mage/sets/commander/ChorusOfTheConclave.java @@ -135,7 +135,7 @@ class ChorusOfTheConclaveReplacementEffect extends ReplacementEffectImpl { @Override public boolean applies(GameEvent event, Ability source, Game game) { - if (event.getPlayerId() == source.getControllerId()) { + if (event.getPlayerId().equals(source.getControllerId())) { MageObject spellObject = game.getObject(event.getSourceId()); if (spellObject != null) { return spellObject.getCardType().contains(CardType.CREATURE); diff --git a/Mage.Sets/src/mage/sets/commander2013/RubiniaSoulsinger.java b/Mage.Sets/src/mage/sets/commander2013/RubiniaSoulsinger.java index 0580c020d38..26b8c62ebfa 100644 --- a/Mage.Sets/src/mage/sets/commander2013/RubiniaSoulsinger.java +++ b/Mage.Sets/src/mage/sets/commander2013/RubiniaSoulsinger.java @@ -92,9 +92,9 @@ class RubiniaSoulsingerCondition implements Condition { controllerId = source.getControllerId(); } Permanent permanent = game.getBattlefield().getPermanent(source.getSourceId()); - if (permanent != null){ - if (permanent.isTapped()){ - return controllerId == source.getControllerId(); + if (permanent != null) { + if (permanent.isTapped()) { + return controllerId.equals(source.getControllerId()); } } return false; diff --git a/Mage.Sets/src/mage/sets/commander2014/InfernalOffering.java b/Mage.Sets/src/mage/sets/commander2014/InfernalOffering.java index f0bb1741adc..18a0fef42cb 100644 --- a/Mage.Sets/src/mage/sets/commander2014/InfernalOffering.java +++ b/Mage.Sets/src/mage/sets/commander2014/InfernalOffering.java @@ -61,10 +61,9 @@ public class InfernalOffering extends CardImpl { super(ownerId, 24, "Infernal Offering", Rarity.RARE, new CardType[]{CardType.SORCERY}, "{4}{B}"); this.expansionSetCode = "C14"; - // Choose an opponent. You and that player each sacrifice a creature. Each player who sacrificed a creature this way draws two cards. this.getSpellAbility().addEffect(new InfernalOfferingSacrificeEffect()); - + // Choose an opponent. Return a creature card from your graveyard to the battlefield, then that player returns a creature card from his or her graveyard to the battlefield. this.getSpellAbility().addEffect(new InfernalOfferingReturnEffect()); } @@ -80,21 +79,21 @@ public class InfernalOffering extends CardImpl { } class InfernalOfferingSacrificeEffect extends OneShotEffect { - + InfernalOfferingSacrificeEffect() { super(Outcome.Sacrifice); this.staticText = "Choose an opponent. You and that player each sacrifice a creature. Each player who sacrificed a creature this way draws two cards"; } - + InfernalOfferingSacrificeEffect(final InfernalOfferingSacrificeEffect effect) { super(effect); } - + @Override public InfernalOfferingSacrificeEffect copy() { return new InfernalOfferingSacrificeEffect(this); } - + @Override public boolean apply(Game game, Ability source) { Player player = game.getPlayer(source.getControllerId()); @@ -106,7 +105,7 @@ class InfernalOfferingSacrificeEffect extends OneShotEffect { //Choose creatures to sacrifice Map toSacrifice = new HashMap<>(2); for (UUID playerId : player.getInRange()) { - if (playerId == player.getId() || playerId == opponent.getId()) { + if (playerId.equals(player.getId()) || playerId.equals(opponent.getId())) { target = new TargetControlledCreaturePermanent(1, 1, new FilterControlledCreaturePermanent(), true); if (target.choose(Outcome.Sacrifice, playerId, source.getControllerId(), game)) { toSacrifice.put(playerId, target.getFirstTarget()); @@ -138,21 +137,21 @@ class InfernalOfferingSacrificeEffect extends OneShotEffect { } class InfernalOfferingReturnEffect extends OneShotEffect { - + InfernalOfferingReturnEffect() { super(Outcome.PutCreatureInPlay); this.staticText = "Choose an opponent. Return a creature card from your graveyard to the battlefield, then that player returns a creature card from his or her graveyard to the battlefield"; } - + InfernalOfferingReturnEffect(final InfernalOfferingReturnEffect effect) { super(effect); } - + @Override public InfernalOfferingReturnEffect copy() { return new InfernalOfferingReturnEffect(this); } - + @Override public boolean apply(Game game, Ability source) { Player player = game.getPlayer(source.getControllerId()); diff --git a/Mage.Sets/src/mage/sets/darksteel/LichsTomb.java b/Mage.Sets/src/mage/sets/darksteel/LichsTomb.java index 3ec918d0114..33a0f45d56e 100644 --- a/Mage.Sets/src/mage/sets/darksteel/LichsTomb.java +++ b/Mage.Sets/src/mage/sets/darksteel/LichsTomb.java @@ -56,7 +56,7 @@ public class LichsTomb extends CardImpl { // You don't lose the game for having 0 or less life. this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new DontLoseByZeroOrLessLifeEffect(Duration.WhileOnBattlefield))); - + // Whenever you lose life, sacrifice a permanent for each 1 life you lost. this.addAbility(new LichsTombTriggeredAbility()); } @@ -72,15 +72,15 @@ public class LichsTomb extends CardImpl { } class LichsTombTriggeredAbility extends TriggeredAbilityImpl { - + LichsTombTriggeredAbility() { super(Zone.BATTLEFIELD, new SacrificeControllerEffect(new FilterPermanent(), 0, ""), false); } - + LichsTombTriggeredAbility(final LichsTombTriggeredAbility ability) { super(ability); } - + @Override public LichsTombTriggeredAbility copy() { return new LichsTombTriggeredAbility(this); @@ -90,16 +90,16 @@ class LichsTombTriggeredAbility extends TriggeredAbilityImpl { public boolean checkEventType(GameEvent event, Game game) { return event.getType() == EventType.LOST_LIFE; } - + @Override public boolean checkTrigger(GameEvent event, Game game) { - if (event.getPlayerId() == this.getControllerId()) { + if (event.getPlayerId().equals(this.getControllerId())) { ((SacrificeEffect) this.getEffects().get(0)).setAmount(new StaticValue(event.getAmount())); return true; } return false; } - + @Override public String getRule() { return "Whenever you lose life, sacrifice a permanent for each 1 life you lost."; diff --git a/Mage.Sets/src/mage/sets/eventide/DreamThief.java b/Mage.Sets/src/mage/sets/eventide/DreamThief.java index f0373c53ccf..a3dc86a47d3 100644 --- a/Mage.Sets/src/mage/sets/eventide/DreamThief.java +++ b/Mage.Sets/src/mage/sets/eventide/DreamThief.java @@ -53,7 +53,7 @@ import mage.watchers.Watcher; * @author jeffwadsworth */ public class DreamThief extends CardImpl { - + private static final String rule = "draw a card if you've cast another blue spell this turn"; public DreamThief(UUID ownerId) { @@ -70,7 +70,7 @@ public class DreamThief extends CardImpl { // When Dream Thief enters the battlefield, draw a card if you've cast another blue spell this turn. this.addAbility(new EntersBattlefieldTriggeredAbility(new ConditionalOneShotEffect(new DrawCardSourceControllerEffect(1), new CastBlueSpellThisTurnCondition(), rule)), new DreamThiefWatcher(this.getId())); - + } public DreamThief(final DreamThief card) { @@ -98,6 +98,7 @@ class CastBlueSpellThisTurnCondition implements Condition { class DreamThiefWatcher extends Watcher { private static final FilterSpell filter = new FilterSpell(); + static { filter.add(new ColorPredicate(ObjectColor.BLUE)); } @@ -125,7 +126,7 @@ class DreamThiefWatcher extends Watcher { return; } if (event.getType() == EventType.SPELL_CAST - && controllerId == event.getPlayerId()) { + && controllerId.equals(event.getPlayerId())) { Spell spell = game.getStack().getSpell(event.getTargetId()); if (!spell.getSourceId().equals(cardId) && filter.match(spell, game)) { condition = true; diff --git a/Mage.Sets/src/mage/sets/eventide/EndlessHorizons.java b/Mage.Sets/src/mage/sets/eventide/EndlessHorizons.java index 240c94a0218..17af8a3fdcf 100644 --- a/Mage.Sets/src/mage/sets/eventide/EndlessHorizons.java +++ b/Mage.Sets/src/mage/sets/eventide/EndlessHorizons.java @@ -40,11 +40,13 @@ import mage.constants.Outcome; import mage.constants.Rarity; import mage.constants.TargetController; import mage.constants.Zone; +import mage.filter.FilterCard; import mage.filter.common.FilterLandCard; import mage.filter.predicate.mageobject.SubtypePredicate; import mage.game.ExileZone; import mage.game.Game; import mage.players.Player; +import mage.target.TargetCard; import mage.target.common.TargetCardInLibrary; import mage.util.CardUtil; @@ -58,7 +60,6 @@ public class EndlessHorizons extends CardImpl { super(ownerId, 4, "Endless Horizons", Rarity.RARE, new CardType[]{CardType.ENCHANTMENT}, "{3}{W}"); this.expansionSetCode = "EVE"; - // When Endless Horizons enters the battlefield, search your library for any number of Plains cards and exile them. Then shuffle your library. this.addAbility(new EntersBattlefieldTriggeredAbility(new EndlessHorizonsEffect(), false)); @@ -122,34 +123,41 @@ class EndlessHorizonsEffect extends SearchEffect { } } - class EndlessHorizonsEffect2 extends OneShotEffect { +class EndlessHorizonsEffect2 extends OneShotEffect { - public EndlessHorizonsEffect2() { - super(Outcome.ReturnToHand); - this.staticText = "you may put a card you own exiled with {this} into your hand"; - } + public EndlessHorizonsEffect2() { + super(Outcome.ReturnToHand); + this.staticText = "you may put a card you own exiled with {this} into your hand"; + } - public EndlessHorizonsEffect2(final EndlessHorizonsEffect2 effect) { - super(effect); - } + public EndlessHorizonsEffect2(final EndlessHorizonsEffect2 effect) { + super(effect); + } - @Override - public EndlessHorizonsEffect2 copy() { - return new EndlessHorizonsEffect2(this); - } + @Override + public EndlessHorizonsEffect2 copy() { + return new EndlessHorizonsEffect2(this); + } - @Override - public boolean apply(Game game, Ability source) { + @Override + public boolean apply(Game game, Ability source) { + Player controller = game.getPlayer(source.getControllerId()); + if (controller != null) { ExileZone exZone = game.getExile().getExileZone(CardUtil.getCardExileZoneId(game, source)); if (exZone != null) { - for (Card card : exZone.getCards(game)) { - if (card.getOwnerId() == source.getControllerId()) { - card.moveToZone(Zone.HAND, source.getSourceId(), game, false); - break; // only one - } + Card card = null; + if (exZone.size() > 1) { + TargetCard target = new TargetCard(Zone.EXILED, new FilterCard()); + controller.choose(outcome, exZone, target, game); + card = game.getCard(target.getFirstTarget()); + } else { + card = exZone.getRandom(game); } + controller.moveCards(card, null, Zone.HAND, source, game); } return true; } - + return false; + } + } diff --git a/Mage.Sets/src/mage/sets/eventide/HotheadedGiant.java b/Mage.Sets/src/mage/sets/eventide/HotheadedGiant.java index 41c797b735b..1e099413f2b 100644 --- a/Mage.Sets/src/mage/sets/eventide/HotheadedGiant.java +++ b/Mage.Sets/src/mage/sets/eventide/HotheadedGiant.java @@ -67,11 +67,11 @@ public class HotheadedGiant extends CardImpl { // Haste this.addAbility(HasteAbility.getInstance()); - + // Hotheaded Giant enters the battlefield with two -1/-1 counters on it unless you've cast another red spell this turn. Condition condition = new CastRedSpellThisTurnCondition(); this.addAbility(new EntersBattlefieldAbility(new ConditionalOneShotEffect(new AddCountersSourceEffect(CounterType.M1M1.createInstance(2)), new InvertCondition(condition), ""), "with two -1/-1 counters on it unless you've cast another red spell this turn"), new HotHeadedGiantWatcher(this.getId())); - + } public HotheadedGiant(final HotheadedGiant card) { @@ -99,6 +99,7 @@ class CastRedSpellThisTurnCondition implements Condition { class HotHeadedGiantWatcher extends Watcher { private static final FilterSpell filter = new FilterSpell(); + static { filter.add(new ColorPredicate(ObjectColor.RED)); } @@ -126,7 +127,7 @@ class HotHeadedGiantWatcher extends Watcher { return; } if (event.getType() == EventType.SPELL_CAST - && controllerId == event.getPlayerId()) { + && controllerId.equals(event.getPlayerId())) { Spell spell = game.getStack().getSpell(event.getTargetId()); if (!spell.getSourceId().equals(cardId) && filter.match(spell, game)) { condition = true; diff --git a/Mage.Sets/src/mage/sets/eventide/SoulReap.java b/Mage.Sets/src/mage/sets/eventide/SoulReap.java index 8c47750a966..3bb073a7dbf 100644 --- a/Mage.Sets/src/mage/sets/eventide/SoulReap.java +++ b/Mage.Sets/src/mage/sets/eventide/SoulReap.java @@ -32,7 +32,6 @@ import mage.ObjectColor; import mage.abilities.Ability; import mage.abilities.condition.Condition; import mage.abilities.decorator.ConditionalOneShotEffect; -import mage.abilities.effects.Effect; import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.DestroyTargetEffect; import mage.cards.CardImpl; @@ -59,26 +58,25 @@ import mage.watchers.Watcher; * @author jeffwadsworth */ public class SoulReap extends CardImpl { - + private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("nongreen creature"); - + static { filter.add(Predicates.not(new ColorPredicate(ObjectColor.GREEN))); } - + private String rule = "Its controller loses 3 life if you've cast another black spell this turn"; public SoulReap(UUID ownerId) { super(ownerId, 44, "Soul Reap", Rarity.COMMON, new CardType[]{CardType.SORCERY}, "{1}{B}"); this.expansionSetCode = "EVE"; - // Destroy target nongreen creature. Its controller loses 3 life if you've cast another black spell this turn. this.getSpellAbility().addEffect(new DestroyTargetEffect()); this.getSpellAbility().addTarget(new TargetCreaturePermanent(filter)); this.getSpellAbility().addEffect(new ConditionalOneShotEffect(new SoulReapEffect(), new CastBlackSpellThisTurnCondition(), rule)); this.getSpellAbility().addWatcher(new SoulReapWatcher(this.getId())); - + } public SoulReap(final SoulReap card) { @@ -106,7 +104,7 @@ class CastBlackSpellThisTurnCondition implements Condition { class SoulReapWatcher extends Watcher { private static final FilterSpell filter = new FilterSpell(); - + static { filter.add(new ColorPredicate(ObjectColor.BLACK)); } @@ -134,7 +132,7 @@ class SoulReapWatcher extends Watcher { return; } if (event.getType() == EventType.SPELL_CAST - && controllerId == event.getPlayerId()) { + && controllerId.equals(event.getPlayerId())) { Spell spell = game.getStack().getSpell(event.getTargetId()); if (!spell.getSourceId().equals(cardId) && filter.match(spell, game)) { condition = true; @@ -177,4 +175,4 @@ class SoulReapEffect extends OneShotEffect { } return false; } -} \ No newline at end of file +} diff --git a/Mage.Sets/src/mage/sets/eventide/TalarasBattalion.java b/Mage.Sets/src/mage/sets/eventide/TalarasBattalion.java index 3220bda751d..190a6d3f5b8 100644 --- a/Mage.Sets/src/mage/sets/eventide/TalarasBattalion.java +++ b/Mage.Sets/src/mage/sets/eventide/TalarasBattalion.java @@ -34,7 +34,6 @@ import mage.abilities.Ability; import mage.abilities.common.SimpleStaticAbility; import mage.abilities.condition.Condition; import mage.abilities.effects.ContinuousRuleModifyingEffectImpl; -import mage.abilities.effects.ReplacementEffectImpl; import mage.abilities.keyword.TrampleAbility; import mage.cards.CardImpl; import mage.constants.CardType; @@ -159,7 +158,7 @@ class TalarasBattalionWatcher extends Watcher { return; } if (event.getType() == EventType.SPELL_CAST - && controllerId == event.getPlayerId()) { + && controllerId.equals(event.getPlayerId())) { Spell spell = game.getStack().getSpell(event.getTargetId()); if (!spell.getSourceId().equals(cardId) && filter.match(spell, game)) { condition = true; diff --git a/Mage.Sets/src/mage/sets/exodus/SoltariVisionary.java b/Mage.Sets/src/mage/sets/exodus/SoltariVisionary.java index 4e07f51447c..99d614dd6a5 100644 --- a/Mage.Sets/src/mage/sets/exodus/SoltariVisionary.java +++ b/Mage.Sets/src/mage/sets/exodus/SoltariVisionary.java @@ -99,7 +99,7 @@ class SoltariVisionaryTriggeredAbility extends TriggeredAbilityImpl { @Override public boolean checkTrigger(GameEvent event, Game game) { Permanent soltari = game.getPermanent(event.getSourceId()); - if (soltari != null && soltari.getId() == this.getSourceId()) { + if (soltari != null && soltari.getId().equals(this.getSourceId())) { FilterEnchantmentPermanent filter = new FilterEnchantmentPermanent("enchantment that player controls."); filter.add(new ControllerIdPredicate(event.getPlayerId())); filter.setMessage("enchantment controlled by " + game.getPlayer(event.getTargetId()).getLogName()); diff --git a/Mage.Sets/src/mage/sets/fatereforged/MarduWoeReaper.java b/Mage.Sets/src/mage/sets/fatereforged/MarduWoeReaper.java index 15a433d0ea6..4b594d31ca4 100644 --- a/Mage.Sets/src/mage/sets/fatereforged/MarduWoeReaper.java +++ b/Mage.Sets/src/mage/sets/fatereforged/MarduWoeReaper.java @@ -99,7 +99,7 @@ class MarduWoeReaperTriggeredAbility extends TriggeredAbilityImpl { public boolean checkTrigger(GameEvent event, Game game) { if (event.getPlayerId().equals(this.getControllerId())) { Permanent permanent = game.getPermanent(event.getTargetId()); - if (permanent != null && (permanent.getId() == this.getSourceId() || permanent.hasSubtype("Warrior"))) { + if (permanent != null && (permanent.getId().equals(this.getSourceId()) || permanent.hasSubtype("Warrior"))) { return true; } } @@ -113,21 +113,21 @@ class MarduWoeReaperTriggeredAbility extends TriggeredAbilityImpl { } class MarduWoeReaperEffect extends OneShotEffect { - + MarduWoeReaperEffect() { super(Outcome.GainLife); this.staticText = "you may exile target creature card from a graveyard. If you do, you gain 1 life"; } - + MarduWoeReaperEffect(final MarduWoeReaperEffect effect) { super(effect); } - + @Override public MarduWoeReaperEffect copy() { return new MarduWoeReaperEffect(this); } - + @Override public boolean apply(Game game, Ability source) { Player player = game.getPlayer(source.getControllerId()); diff --git a/Mage.Sets/src/mage/sets/fatereforged/WardscaleDragon.java b/Mage.Sets/src/mage/sets/fatereforged/WardscaleDragon.java index fadb7c5a883..61869d47454 100644 --- a/Mage.Sets/src/mage/sets/fatereforged/WardscaleDragon.java +++ b/Mage.Sets/src/mage/sets/fatereforged/WardscaleDragon.java @@ -58,11 +58,10 @@ public class WardscaleDragon extends CardImpl { // Flying this.addAbility(FlyingAbility.getInstance()); - + // As long as Wardscale Dragon is attacking, defending player can't cast spells. this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new WardscaleDragonRuleEffect())); - - + } public WardscaleDragon(final WardscaleDragon card) { @@ -105,7 +104,7 @@ class WardscaleDragonRuleEffect extends ContinuousRuleModifyingEffectImpl { public boolean applies(GameEvent event, Ability source, Game game) { Permanent sourcePermanent = game.getPermanent(source.getSourceId()); if (sourcePermanent != null && sourcePermanent.isAttacking()) { - return event.getPlayerId() == game.getCombat().getDefendingPlayerId(sourcePermanent.getId(), game); + return event.getPlayerId().equals(game.getCombat().getDefendingPlayerId(sourcePermanent.getId(), game)); } return false; } diff --git a/Mage.Sets/src/mage/sets/fifthedition/InstillEnergy.java b/Mage.Sets/src/mage/sets/fifthedition/InstillEnergy.java index 5c82efdeba2..9c0b8691038 100644 --- a/Mage.Sets/src/mage/sets/fifthedition/InstillEnergy.java +++ b/Mage.Sets/src/mage/sets/fifthedition/InstillEnergy.java @@ -92,6 +92,7 @@ public class InstillEnergy extends CardImpl { } class CanAttackAsThoughItHadHasteEnchantedEffect extends AsThoughEffectImpl { + public CanAttackAsThoughItHadHasteEnchantedEffect(Duration duration) { super(AsThoughEffectType.ATTACK, duration, Outcome.Benefit); staticText = "Enchanted creature can attack as though it had haste"; @@ -114,7 +115,7 @@ class CanAttackAsThoughItHadHasteEnchantedEffect extends AsThoughEffectImpl { @Override public boolean applies(UUID objectId, Ability source, UUID affectedControllerId, Game game) { Permanent enchantment = game.getPermanent(source.getSourceId()); - return enchantment != null && enchantment.getAttachedTo() != null && enchantment.getAttachedTo() == objectId; + return enchantment != null && enchantment.getAttachedTo() != null && enchantment.getAttachedTo().equals(objectId); } } diff --git a/Mage.Sets/src/mage/sets/limitedalpha/Fastbond.java b/Mage.Sets/src/mage/sets/limitedalpha/Fastbond.java index 3be02bbc3d2..ddcdabe0e99 100644 --- a/Mage.Sets/src/mage/sets/limitedalpha/Fastbond.java +++ b/Mage.Sets/src/mage/sets/limitedalpha/Fastbond.java @@ -52,13 +52,11 @@ public class Fastbond extends CardImpl { super(ownerId, 101, "Fastbond", Rarity.RARE, new CardType[]{CardType.ENCHANTMENT}, "{G}"); this.expansionSetCode = "LEA"; - // You may play any number of additional lands on each of your turns. this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new PlayAdditionalLandsControllerEffect(Integer.MAX_VALUE, Duration.WhileOnBattlefield))); // Whenever you play a land, if it wasn't the first land you played this turn, Fastbond deals 1 damage to you. this.addAbility(new PlayALandTriggeredAbility()); } - public Fastbond(final Fastbond card) { super(card); @@ -70,7 +68,6 @@ public class Fastbond extends CardImpl { } } - class PlayALandTriggeredAbility extends TriggeredAbilityImpl { public PlayALandTriggeredAbility() { @@ -88,14 +85,14 @@ class PlayALandTriggeredAbility extends TriggeredAbilityImpl { @Override public boolean checkTrigger(GameEvent event, Game game) { - return event.getPlayerId() == this.getControllerId(); + return event.getPlayerId().equals(this.getControllerId()); } @Override public boolean checkInterveningIfClause(Game game) { Player player = game.getPlayer(this.getControllerId()); - if (player != null){ - if (player.getLandsPlayed() != 1){ + if (player != null) { + if (player.getLandsPlayed() != 1) { return true; } } @@ -111,8 +108,5 @@ class PlayALandTriggeredAbility extends TriggeredAbilityImpl { public String getRule() { return "Whenever you play a land, if it wasn't the first land you played this turn, {source} deals 1 damage to you"; } - - + } - - diff --git a/Mage.Sets/src/mage/sets/magic2015/GeneratorServant.java b/Mage.Sets/src/mage/sets/magic2015/GeneratorServant.java index 1bda0be0091..898e79c6943 100644 --- a/Mage.Sets/src/mage/sets/magic2015/GeneratorServant.java +++ b/Mage.Sets/src/mage/sets/magic2015/GeneratorServant.java @@ -77,7 +77,7 @@ public class GeneratorServant extends CardImpl { ability.addCost(new SacrificeSourceCost()); ability.getEffects().get(0).setText("Add {2} to your mana pool. If that mana is spent on a creature spell, it gains haste until end of turn."); this.addAbility(ability); - + this.addAbility(new SimpleStaticAbility(Zone.ALL, new GeneratorServantHasteEffect()), new GeneratorServantWatcher()); } @@ -94,11 +94,11 @@ public class GeneratorServant extends CardImpl { class GeneratorServantWatcher extends Watcher { public List creatures = new ArrayList<>(); - + public GeneratorServantWatcher() { super("GeneratorServantWatcher", WatcherScope.CARD); } - + public GeneratorServantWatcher(final GeneratorServantWatcher watcher) { super(watcher); this.creatures.addAll(watcher.creatures); @@ -108,13 +108,13 @@ class GeneratorServantWatcher extends Watcher { public GeneratorServantWatcher copy() { return new GeneratorServantWatcher(this); } - + @Override public void watch(GameEvent event, Game game) { if (event.getType() == GameEvent.EventType.MANA_PAYED) { MageObject target = game.getObject(event.getTargetId()); - MageObject source = game.getObject(this.getSourceId()); - if (event.getSourceId() == this.getSourceId() && target != null && target.getCardType().contains(CardType.CREATURE) && event.getFlag()) { + if (event.getSourceId() != null + && event.getSourceId().equals(this.getSourceId()) && target != null && target.getCardType().contains(CardType.CREATURE) && event.getFlag()) { if (target instanceof Spell) { this.creatures.add(((Spell) target).getCard().getId()); } @@ -127,7 +127,7 @@ class GeneratorServantWatcher extends Watcher { super.reset(); creatures.clear(); } - + } class GeneratorServantHasteEffect extends ContinuousEffectImpl { @@ -135,7 +135,7 @@ class GeneratorServantHasteEffect extends ContinuousEffectImpl { public GeneratorServantHasteEffect() { super(Duration.EndOfGame, Layer.AbilityAddingRemovingEffects_6, SubLayer.NA, Outcome.AddAbility); } - + public GeneratorServantHasteEffect(final GeneratorServantHasteEffect effect) { super(effect); } @@ -144,7 +144,7 @@ class GeneratorServantHasteEffect extends ContinuousEffectImpl { public ContinuousEffect copy() { return new GeneratorServantHasteEffect(this); } - + @Override public boolean apply(Game game, Ability source) { GeneratorServantWatcher watcher = (GeneratorServantWatcher) game.getState().getWatchers().get("GeneratorServantWatcher", source.getSourceId()); @@ -158,5 +158,5 @@ class GeneratorServantHasteEffect extends ContinuousEffectImpl { } return false; } - + } diff --git a/Mage.Sets/src/mage/sets/magicorigins/SigilOfValor.java b/Mage.Sets/src/mage/sets/magicorigins/SigilOfValor.java index bc849bbcf50..be8c354a8ee 100644 --- a/Mage.Sets/src/mage/sets/magicorigins/SigilOfValor.java +++ b/Mage.Sets/src/mage/sets/magicorigins/SigilOfValor.java @@ -105,7 +105,9 @@ class SigilOfValorTriggeredAbility extends TriggeredAbilityImpl { if (game.getCombat().attacksAlone()) { Permanent equipment = game.getPermanent(getSourceId()); UUID attackerId = game.getCombat().getAttackers().get(0); - if (equipment != null && equipment.getAttachedTo() == attackerId) { + if (equipment != null + && equipment.getAttachedTo() != null + && equipment.getAttachedTo().equals(attackerId)) { this.getEffects().get(0).setTargetPointer(new FixedTarget(attackerId)); return true; } diff --git a/Mage.Sets/src/mage/sets/masterseditionii/ThoughtLash.java b/Mage.Sets/src/mage/sets/masterseditionii/ThoughtLash.java index e8a28e8196f..65a48ed577a 100644 --- a/Mage.Sets/src/mage/sets/masterseditionii/ThoughtLash.java +++ b/Mage.Sets/src/mage/sets/masterseditionii/ThoughtLash.java @@ -60,10 +60,10 @@ public class ThoughtLash extends CardImpl { // Cumulative upkeep - Exile the top card of your library. this.addAbility(new CumulativeUpkeepAbility(new ExileFromTopOfLibraryCost(1))); - + // When a player doesn't pay Thought Lash's cumulative upkeep, that player exiles all cards from his or her library. this.addAbility(new ThoughtLashTriggeredAbility()); - + // Exile the top card of your library: Prevent the next 1 damage that would be dealt to you this turn. this.addAbility(new SimpleActivatedAbility(Zone.BATTLEFIELD, new ThoughtLashPreventionEffect(), new ExileFromTopOfLibraryCost(1))); } @@ -79,30 +79,30 @@ public class ThoughtLash extends CardImpl { } class ThoughtLashTriggeredAbility extends TriggeredAbilityImpl { - + ThoughtLashTriggeredAbility() { super(Zone.BATTLEFIELD, new ThoughtLashExileLibraryEffect(), false); } - + ThoughtLashTriggeredAbility(final ThoughtLashTriggeredAbility ability) { super(ability); } - + @Override public ThoughtLashTriggeredAbility copy() { return new ThoughtLashTriggeredAbility(this); } - + @Override public boolean checkEventType(GameEvent event, Game game) { return event.getType() == EventType.DIDNT_PAY_CUMULATIVE_UPKEEP; } - + @Override public boolean checkTrigger(GameEvent event, Game game) { - return event.getSourceId() == this.getSourceId(); + return event.getSourceId() != null && event.getSourceId().equals(this.getSourceId()); } - + @Override public String getRule() { return "When a player doesn't pay {this}'s cumulative upkeep, that player exiles all cards from his or her library."; @@ -110,21 +110,21 @@ class ThoughtLashTriggeredAbility extends TriggeredAbilityImpl { } class ThoughtLashExileLibraryEffect extends OneShotEffect { - + ThoughtLashExileLibraryEffect() { super(Outcome.Detriment); this.staticText = "that player exiles all cards from his or her library"; } - + ThoughtLashExileLibraryEffect(final ThoughtLashExileLibraryEffect effect) { super(effect); } - + @Override public ThoughtLashExileLibraryEffect copy() { return new ThoughtLashExileLibraryEffect(this); } - + @Override public boolean apply(Game game, Ability source) { Player controller = game.getPlayer(source.getControllerId()); diff --git a/Mage.Sets/src/mage/sets/planeshift/OrimsChant.java b/Mage.Sets/src/mage/sets/planeshift/OrimsChant.java index 6c87841a9ef..5a35bbde4f3 100644 --- a/Mage.Sets/src/mage/sets/planeshift/OrimsChant.java +++ b/Mage.Sets/src/mage/sets/planeshift/OrimsChant.java @@ -1,31 +1,30 @@ /* -* Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. -* -* Redistribution and use in source and binary forms, with or without modification, are -* permitted provided that the following conditions are met: -* -* 1. Redistributions of source code must retain the above copyright notice, this list of -* conditions and the following disclaimer. -* -* 2. Redistributions in binary form must reproduce the above copyright notice, this list -* of conditions and the following disclaimer in the documentation and/or other materials -* provided with the distribution. -* -* THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED -* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND -* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR -* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR -* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON -* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING -* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF -* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -* -* The views and conclusions contained in the software and documentation are those of the -* authors and should not be interpreted as representing official policies, either expressed -* or implied, of BetaSteward_at_googlemail.com. -*/ - + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ package mage.sets.planeshift; import java.util.UUID; @@ -56,7 +55,6 @@ public class OrimsChant extends CardImpl { super(ownerId, 11, "Orim's Chant", Rarity.RARE, new CardType[]{CardType.INSTANT}, "{W}"); this.expansionSetCode = "PLS"; - // Kicker {W} (You may pay an additional {W} as you cast this spell.) this.addAbility(new KickerAbility("{W}")); @@ -81,7 +79,7 @@ public class OrimsChant extends CardImpl { class OrimsChantCantCastEffect extends ContinuousRuleModifyingEffectImpl { - public OrimsChantCantCastEffect() { + public OrimsChantCantCastEffect() { super(Duration.EndOfTurn, Outcome.Benefit); staticText = "Target player can't cast spells this turn"; } @@ -97,12 +95,12 @@ class OrimsChantCantCastEffect extends ContinuousRuleModifyingEffectImpl { @Override public boolean checksEventType(GameEvent event, Game game) { - return event.getType() == GameEvent.EventType.CAST_SPELL; + return GameEvent.EventType.CAST_SPELL.equals(event.getType()); } @Override public boolean applies(GameEvent event, Ability source, Game game) { - return event.getPlayerId() == getTargetPointer().getFirst(game, source); + return event.getPlayerId().equals(getTargetPointer().getFirst(game, source)); } } diff --git a/Mage.Sets/src/mage/sets/returntoravnica/VraskaTheUnseen.java b/Mage.Sets/src/mage/sets/returntoravnica/VraskaTheUnseen.java index e04c58658c0..3c890808dd2 100644 --- a/Mage.Sets/src/mage/sets/returntoravnica/VraskaTheUnseen.java +++ b/Mage.Sets/src/mage/sets/returntoravnica/VraskaTheUnseen.java @@ -66,7 +66,7 @@ import mage.target.targetpointer.FixedTarget; * Each Assassin token's triggered ability will trigger whenever it deals combat * damage to any player, including you. * - * + * * @author LevelX2 */ public class VraskaTheUnseen extends CardImpl { @@ -76,11 +76,10 @@ public class VraskaTheUnseen extends CardImpl { this.expansionSetCode = "RTR"; this.subtype.add("Vraska"); - this.addAbility(new EntersBattlefieldAbility(new AddCountersSourceEffect(CounterType.LOYALTY.createInstance(5)), false)); // +1: Until your next turn, whenever a creature deals combat damage to Vraska the Unseen, destroy that creature. - this.addAbility(new LoyaltyAbility(new VraskaTheUnseenGainAbilityEffect(new VraskaTheUnseenTriggeredAbility()),1)); + this.addAbility(new LoyaltyAbility(new VraskaTheUnseenGainAbilityEffect(new VraskaTheUnseenTriggeredAbility()), 1)); // -3: Destroy target nonland permanent. LoyaltyAbility ability = new LoyaltyAbility(new DestroyTargetEffect(), -3); @@ -101,7 +100,6 @@ public class VraskaTheUnseen extends CardImpl { } } - class VraskaTheUnseenGainAbilityEffect extends ContinuousEffectImpl { protected Ability ability; @@ -142,8 +140,7 @@ class VraskaTheUnseenGainAbilityEffect extends ContinuousEffectImpl { @Override public boolean isInactive(Ability source, Game game) { - if (startingTurn != 0 && game.getTurnNum() != startingTurn) - { + if (startingTurn != 0 && game.getTurnNum() != startingTurn) { if (game.getActivePlayerId().equals(source.getControllerId())) { return true; } @@ -153,6 +150,7 @@ class VraskaTheUnseenGainAbilityEffect extends ContinuousEffectImpl { } class AssassinToken extends Token { + AssassinToken() { super("Assassin", "1/1 black Assassin creature tokens with \"Whenever this creature deals combat damage to a player, that player loses the game.\""); cardType.add(CardType.CREATURE); @@ -160,7 +158,7 @@ class AssassinToken extends Token { subtype.add("Assassin"); power = new MageInt(1); toughness = new MageInt(1); - addAbility(new DealsCombatDamageToAPlayerTriggeredAbility(new LoseGameTargetPlayerEffect(),false, true)); + addAbility(new DealsCombatDamageToAPlayerTriggeredAbility(new LoseGameTargetPlayerEffect(), false, true)); } } @@ -186,7 +184,7 @@ class VraskaTheUnseenTriggeredAbility extends TriggeredAbilityImpl { @Override public boolean checkTrigger(GameEvent event, Game game) { - if (((DamagedPlaneswalkerEvent) event).isCombatDamage() && event.getTargetId() == sourceId) { + if (((DamagedPlaneswalkerEvent) event).isCombatDamage() && getSourceId().equals(event.getTargetId())) { Permanent sourceOfDamage = game.getPermanent(event.getSourceId()); if (sourceOfDamage != null && sourceOfDamage.getCardType().contains(CardType.CREATURE)) { Effect effect = this.getEffects().get(0); @@ -202,4 +200,4 @@ class VraskaTheUnseenTriggeredAbility extends TriggeredAbilityImpl { return "Until your next turn, whenever a creature deals combat damage to {this}, destroy that creature"; } -} \ No newline at end of file +} diff --git a/Mage.Sets/src/mage/sets/scarsofmirrodin/RevokeExistence.java b/Mage.Sets/src/mage/sets/scarsofmirrodin/RevokeExistence.java index 554cefc08b4..1186f719aec 100644 --- a/Mage.Sets/src/mage/sets/scarsofmirrodin/RevokeExistence.java +++ b/Mage.Sets/src/mage/sets/scarsofmirrodin/RevokeExistence.java @@ -25,25 +25,24 @@ * authors and should not be interpreted as representing official policies, either expressed * or implied, of BetaSteward_at_googlemail.com. */ - package mage.sets.scarsofmirrodin; -import mage.constants.CardType; -import mage.constants.Rarity; +import java.util.UUID; import mage.abilities.effects.common.ExileTargetEffect; 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; -import java.util.UUID; - /** * * @author Loki */ public class RevokeExistence extends CardImpl { + private static final FilterPermanent filter = new FilterPermanent("artifact or enchantment"); static { @@ -52,15 +51,16 @@ public class RevokeExistence extends CardImpl { new CardTypePredicate(CardType.ENCHANTMENT))); } - public RevokeExistence (UUID ownerId) { + public RevokeExistence(UUID ownerId) { super(ownerId, 18, "Revoke Existence", Rarity.COMMON, new CardType[]{CardType.SORCERY}, "{1}{W}"); this.expansionSetCode = "SOM"; + // Exile target artifact or enchantment. this.getSpellAbility().addEffect(new ExileTargetEffect()); this.getSpellAbility().addTarget(new TargetPermanent(filter)); } - public RevokeExistence (final RevokeExistence card) { + public RevokeExistence(final RevokeExistence card) { super(card); } diff --git a/Mage.Sets/src/mage/sets/shadowmoor/MossbridgeTroll.java b/Mage.Sets/src/mage/sets/shadowmoor/MossbridgeTroll.java index 539b8f9d3d0..bc44a0a95d4 100644 --- a/Mage.Sets/src/mage/sets/shadowmoor/MossbridgeTroll.java +++ b/Mage.Sets/src/mage/sets/shadowmoor/MossbridgeTroll.java @@ -56,7 +56,7 @@ import mage.target.common.TargetControlledCreaturePermanent; * @author jeffwadsworth */ public class MossbridgeTroll extends CardImpl { - + private static final FilterControlledCreaturePermanent filter = new FilterControlledCreaturePermanent("untapped creatures you control"); static { @@ -78,7 +78,7 @@ public class MossbridgeTroll extends CardImpl { Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new BoostSourceEffect(20, 20, Duration.EndOfTurn), new MossbridgeTrollCost()); ability.setAdditionalCostsRuleVisible(false); this.addAbility(ability); - + } public MossbridgeTroll(final MossbridgeTroll card) { @@ -115,10 +115,11 @@ class MossbridgeTrollReplacementEffect extends ReplacementEffectImpl { public boolean checksEventType(GameEvent event, Game game) { return event.getType() == GameEvent.EventType.DESTROY_PERMANENT; } - + @Override public boolean applies(GameEvent event, Ability source, Game game) { - return event.getTargetId() == source.getSourceId(); + return event.getTargetId() != null + && event.getTargetId().equals(source.getSourceId()); } @Override @@ -150,7 +151,7 @@ class MossbridgeTrollCost extends CostImpl { public boolean pay(Ability ability, Game game, UUID sourceId, UUID controllerId, boolean noMana) { int sumPower = 0; if (targets.choose(Outcome.Tap, controllerId, sourceId, game)) { - for (UUID targetId: targets.get(0).getTargets()) { + for (UUID targetId : targets.get(0).getTargets()) { Permanent permanent = game.getPermanent(targetId); if (permanent != null && permanent.tap(game)) { sumPower += permanent.getPower().getValue(); @@ -165,7 +166,7 @@ class MossbridgeTrollCost extends CostImpl { @Override public boolean canPay(Ability ability, UUID sourceId, UUID controllerId, Game game) { int sumPower = 0; - for (Permanent permanent :game.getBattlefield().getAllActivePermanents(new FilterCreaturePermanent(), controllerId, game)) { + for (Permanent permanent : game.getBattlefield().getAllActivePermanents(new FilterCreaturePermanent(), controllerId, game)) { if (!permanent.getId().equals(sourceId)) { sumPower += permanent.getPower().getValue(); } @@ -178,4 +179,3 @@ class MossbridgeTrollCost extends CostImpl { return new MossbridgeTrollCost(this); } } - diff --git a/Mage.Sets/src/mage/sets/shadowmoor/ThoughtweftGambit.java b/Mage.Sets/src/mage/sets/shadowmoor/ThoughtweftGambit.java index f6c0b113a1d..5246fd44592 100644 --- a/Mage.Sets/src/mage/sets/shadowmoor/ThoughtweftGambit.java +++ b/Mage.Sets/src/mage/sets/shadowmoor/ThoughtweftGambit.java @@ -50,7 +50,6 @@ public class ThoughtweftGambit extends CardImpl { super(ownerId, 154, "Thoughtweft Gambit", Rarity.UNCOMMON, new CardType[]{CardType.INSTANT}, "{4}{W/U}{W/U}"); this.expansionSetCode = "SHM"; - // Tap all creatures your opponents control and untap all creatures you control. this.getSpellAbility().addEffect(new ThoughtweftGambitEffect()); @@ -94,7 +93,7 @@ class ThoughtweftGambitEffect extends OneShotEffect { } if (controller != null) { for (Permanent creature : game.getBattlefield().getActivePermanents(filter, source.getControllerId(), game)) { - if (controller.getId() == creature.getControllerId()) { + if (controller.getId().equals(creature.getControllerId())) { creature.untap(game); } } diff --git a/Mage.Sets/src/mage/sets/shardsofalara/GatherSpecimens.java b/Mage.Sets/src/mage/sets/shardsofalara/GatherSpecimens.java index 1287b0fc327..f33ff12365e 100644 --- a/Mage.Sets/src/mage/sets/shardsofalara/GatherSpecimens.java +++ b/Mage.Sets/src/mage/sets/shardsofalara/GatherSpecimens.java @@ -52,10 +52,8 @@ public class GatherSpecimens extends CardImpl { super(ownerId, 45, "Gather Specimens", Rarity.RARE, new CardType[]{CardType.INSTANT}, "{3}{U}{U}{U}"); this.expansionSetCode = "ALA"; - // If a creature would enter the battlefield under an opponent's control this turn, it enters the battlefield under your control instead. this.getSpellAbility().addEffect(new GatherSpecimensReplacementEffect()); - } public GatherSpecimens(final GatherSpecimens card) { @@ -114,7 +112,7 @@ class GatherSpecimensReplacementEffect extends ReplacementEffectImpl { } return false; } - + @Override public boolean replaceEvent(GameEvent event, Ability source, Game game) { Player controller = game.getPlayer(source.getControllerId()); @@ -122,5 +120,5 @@ class GatherSpecimensReplacementEffect extends ReplacementEffectImpl { event.setPlayerId(controller.getId()); } return false; - } + } } diff --git a/Mage.Sets/src/mage/sets/tempest/HelmOfPossession.java b/Mage.Sets/src/mage/sets/tempest/HelmOfPossession.java index f80c7843013..b20810eabfc 100644 --- a/Mage.Sets/src/mage/sets/tempest/HelmOfPossession.java +++ b/Mage.Sets/src/mage/sets/tempest/HelmOfPossession.java @@ -59,7 +59,7 @@ public class HelmOfPossession extends CardImpl { // You may choose not to untap Helm of Possession during your untap step. this.addAbility(new SkipUntapOptionalAbility()); - + // {2}, {tap}, Sacrifice a creature: Gain control of target creature for as long as you control Helm of Possession and Helm of Possession remains tapped. ConditionalContinuousEffect effect = new ConditionalContinuousEffect( new GainControlTargetEffect(Duration.Custom), @@ -92,11 +92,11 @@ class HelmOfPossessionCondition implements Condition { controllerId = source.getControllerId(); } Permanent permanent = game.getBattlefield().getPermanent(source.getSourceId()); - if (permanent != null){ - if (permanent.isTapped()){ - return controllerId == source.getControllerId(); + if (permanent != null) { + if (permanent.isTapped()) { + return controllerId.equals(source.getControllerId()); } } return false; } -} \ No newline at end of file +} diff --git a/Mage.Sets/src/mage/sets/worldwake/TuktukScrapper.java b/Mage.Sets/src/mage/sets/worldwake/TuktukScrapper.java index f1476ca3aee..2a22757c2ef 100644 --- a/Mage.Sets/src/mage/sets/worldwake/TuktukScrapper.java +++ b/Mage.Sets/src/mage/sets/worldwake/TuktukScrapper.java @@ -100,7 +100,7 @@ class TuktukScrapperTriggeredAbility extends TriggeredAbilityImpl { public boolean checkTrigger(GameEvent event, Game game) { Permanent permanent = game.getPermanent(event.getTargetId()); if (permanent != null) { - if (permanent.getId() == this.getSourceId()) { + if (permanent.getId().equals(this.getSourceId())) { return true; } if (permanent.hasSubtype("Ally") diff --git a/Mage.Sets/src/mage/sets/worldwake/WrexialTheRisenDeep.java b/Mage.Sets/src/mage/sets/worldwake/WrexialTheRisenDeep.java index c0c76991785..678fbf386b4 100644 --- a/Mage.Sets/src/mage/sets/worldwake/WrexialTheRisenDeep.java +++ b/Mage.Sets/src/mage/sets/worldwake/WrexialTheRisenDeep.java @@ -28,11 +28,6 @@ package mage.sets.worldwake; 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.MageInt; import mage.abilities.Ability; import mage.abilities.common.DealsCombatDamageToAPlayerTriggeredAbility; @@ -42,6 +37,11 @@ import mage.abilities.keyword.IslandwalkAbility; import mage.abilities.keyword.SwampwalkAbility; import mage.cards.Card; import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.Outcome; +import mage.constants.Rarity; +import mage.constants.Zone; import mage.filter.FilterCard; import mage.filter.predicate.Predicates; import mage.filter.predicate.mageobject.CardTypePredicate; @@ -50,7 +50,6 @@ import mage.game.Game; import mage.game.events.GameEvent; import mage.game.events.GameEvent.EventType; import mage.game.events.ZoneChangeEvent; -import mage.game.stack.Spell; import mage.game.stack.StackObject; import mage.players.Player; import mage.target.Target; @@ -156,29 +155,22 @@ class WrexialReplacementEffect extends ReplacementEffectImpl { public boolean checksEventType(GameEvent event, Game game) { return event.getType() == EventType.ZONE_CHANGE; } - + @Override public boolean applies(GameEvent event, Ability source, Game game) { ZoneChangeEvent zEvent = (ZoneChangeEvent) event; - if (zEvent.getToZone() == Zone.GRAVEYARD - && ((ZoneChangeEvent) event).getTargetId() == cardid) { - return true; - } - return false; + return zEvent.getToZone() == Zone.GRAVEYARD + && ((ZoneChangeEvent) event).getTargetId().equals(cardid); } - + @Override public boolean replaceEvent(GameEvent event, Ability source, Game game) { UUID eventObject = ((ZoneChangeEvent) event).getTargetId(); StackObject card = game.getStack().getStackObject(eventObject); Player controller = game.getPlayer(source.getControllerId()); if (card != null && controller != null) { - if (card instanceof Spell) { - game.rememberLKI(card.getId(), Zone.STACK, (Spell) card); - } if (card instanceof Card) { - controller.moveCardToExileWithInfo((Card)card, null, "", source.getSourceId(), game, game.getState().getZone(event.getTargetId()), true); - return true; + return controller.moveCards((Card) card, null, Zone.EXILED, source, game); } } return false; diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/triggers/OblivionRingTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/triggers/OblivionRingTest.java index ef5dc6ae622..d09251969fc 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/triggers/OblivionRingTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/triggers/OblivionRingTest.java @@ -90,6 +90,7 @@ public class OblivionRingTest extends CardTestPlayerBase { addCard(Zone.BATTLEFIELD, playerA, "Plains", 5); addCard(Zone.HAND, playerA, "Oblivion Ring"); addCard(Zone.BATTLEFIELD, playerA, "Jace Beleren"); + // Exile target artifact or enchantment. addCard(Zone.HAND, playerA, "Revoke Existence"); activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "-1: Target player draws a card", playerA); @@ -100,7 +101,10 @@ public class OblivionRingTest extends CardTestPlayerBase { setStopAt(1, PhaseStep.END_TURN); execute(); + assertExileCount("Oblivion Ring", 1); + assertGraveyardCount(playerA, "Revoke Existence", 1); assertPermanentCount(playerA, "Oblivion Ring", 0); + assertGraveyardCount(playerA, "Jace Beleren", 0); assertPermanentCount(playerA, "Jace Beleren", 1); // returns back assertHandCount(playerA, 2); // can use ability twice } diff --git a/Mage/src/mage/abilities/common/EntersBattlefieldAbility.java b/Mage/src/mage/abilities/common/EntersBattlefieldAbility.java index fa51f390540..64bd2c40fe5 100644 --- a/Mage/src/mage/abilities/common/EntersBattlefieldAbility.java +++ b/Mage/src/mage/abilities/common/EntersBattlefieldAbility.java @@ -1,31 +1,30 @@ /* -* Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. -* -* Redistribution and use in source and binary forms, with or without modification, are -* permitted provided that the following conditions are met: -* -* 1. Redistributions of source code must retain the above copyright notice, this list of -* conditions and the following disclaimer. -* -* 2. Redistributions in binary form must reproduce the above copyright notice, this list -* of conditions and the following disclaimer in the documentation and/or other materials -* provided with the distribution. -* -* THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED -* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND -* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR -* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR -* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON -* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING -* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF -* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -* -* The views and conclusions contained in the software and documentation are those of the -* authors and should not be interpreted as representing official policies, either expressed -* or implied, of BetaSteward_at_googlemail.com. -*/ - + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ package mage.abilities.common; import mage.abilities.StaticAbility; @@ -41,15 +40,17 @@ import mage.constants.Zone; public class EntersBattlefieldAbility extends StaticAbility { protected String abilityRule; - + public EntersBattlefieldAbility(Effect effect) { this(effect, true); } -/** - * - * @param effect effect that happens when the permanent enters the battlefield - * @param showRule show the rule for this ability - */ + + /** + * + * @param effect effect that happens when the permanent enters the + * battlefield + * @param showRule show the rule for this ability + */ public EntersBattlefieldAbility(Effect effect, Boolean showRule) { this(effect, null, showRule, null, null); } @@ -57,16 +58,19 @@ public class EntersBattlefieldAbility extends StaticAbility { public EntersBattlefieldAbility(Effect effect, String effectText) { this(effect, null, true, null, effectText); } -/** - * - * @param effect effect that happens when the permanent enters the battlefield - * @param condition only if this condition is true, the effect will happen - * @param ruleVisible show the rule for this ability - * @param abilityRule rule for this ability (no text from effects will be added) - * @param effectText this text will be used for the EnterBattlefieldEffect - */ + + /** + * + * @param effect effect that happens when the permanent enters the + * battlefield + * @param condition only if this condition is true, the effect will happen + * @param ruleVisible show the rule for this ability + * @param abilityRule rule for this ability (no text from effects will be + * added) + * @param effectText this text will be used for the EnterBattlefieldEffect + */ public EntersBattlefieldAbility(Effect effect, Condition condition, Boolean ruleVisible, String abilityRule, String effectText) { - super(Zone.BATTLEFIELD, new EntersBattlefieldEffect(effect, condition, effectText)); + super(Zone.ALL, new EntersBattlefieldEffect(effect, condition, effectText)); this.setRuleVisible(ruleVisible); this.abilityRule = abilityRule; } @@ -96,7 +100,7 @@ public class EntersBattlefieldAbility extends StaticAbility { @Override public String getRule() { if (!ruleVisible) { - return ""; + return ""; } if (abilityRule != null && !abilityRule.isEmpty()) { return abilityRule; diff --git a/Mage/src/mage/abilities/costs/common/DiscardTargetCost.java b/Mage/src/mage/abilities/costs/common/DiscardTargetCost.java index 5ba87b81916..c62ecfc3953 100644 --- a/Mage/src/mage/abilities/costs/common/DiscardTargetCost.java +++ b/Mage/src/mage/abilities/costs/common/DiscardTargetCost.java @@ -68,7 +68,7 @@ public class DiscardTargetCost extends CostImpl { @Override public boolean pay(Ability ability, Game game, UUID sourceId, UUID controllerId, boolean noMana) { this.cards.clear(); - this.targets.clear(); + this.targets.clearChosen();; Player player = game.getPlayer(controllerId); if (player == null) { return false; diff --git a/Mage/src/mage/abilities/effects/ContinuousEffects.java b/Mage/src/mage/abilities/effects/ContinuousEffects.java index 241c3de5289..de323f1202b 100644 --- a/Mage/src/mage/abilities/effects/ContinuousEffects.java +++ b/Mage/src/mage/abilities/effects/ContinuousEffects.java @@ -1246,7 +1246,7 @@ public class ContinuousEffects implements Serializable { HashSet abilities = preventionEffects.getAbility(effect.getId()); for (Ability ability : abilities) { if (ability.getSourceId().equals(sourceId)) { - if (controllerFound == null || controllerFound == ability.getControllerId()) { + if (controllerFound == null || controllerFound.equals(ability.getControllerId())) { controllerFound = ability.getControllerId(); } else { // not unique controller - No solution yet @@ -1260,7 +1260,7 @@ public class ContinuousEffects implements Serializable { for (Ability ability : abilities) { if (ability.getSourceId() != null) { if (ability.getSourceId().equals(sourceId)) { - if (controllerFound == null || controllerFound == ability.getControllerId()) { + if (controllerFound == null || controllerFound.equals(ability.getControllerId())) { controllerFound = ability.getControllerId(); } else { // not unique controller - No solution yet diff --git a/Mage/src/mage/abilities/effects/common/ReturnFromExileForSourceEffect.java b/Mage/src/mage/abilities/effects/common/ReturnFromExileForSourceEffect.java index 8d7b8a7c2be..1276b0acdff 100644 --- a/Mage/src/mage/abilities/effects/common/ReturnFromExileForSourceEffect.java +++ b/Mage/src/mage/abilities/effects/common/ReturnFromExileForSourceEffect.java @@ -101,7 +101,11 @@ public class ReturnFromExileForSourceEffect extends OneShotEffect { } ExileZone exile = game.getExile().getExileZone(CardUtil.getExileZoneId(game, source.getSourceId(), zoneChangeCounter)); if (exile != null) { // null is valid if source left battlefield before enters the battlefield effect resolved - controller.moveCards(exile, null, returnToZone, source, game); + if (returnToZone.equals(Zone.BATTLEFIELD)) { + controller.moveCards(exile.getCards(game), returnToZone, source, game, false, false, true, null); + } else { + controller.moveCards(exile, null, returnToZone, source, game); + } } return true; } diff --git a/Mage/src/mage/abilities/keyword/ReboundAbility.java b/Mage/src/mage/abilities/keyword/ReboundAbility.java index 6bd8c0d6527..7ab46d546e0 100644 --- a/Mage/src/mage/abilities/keyword/ReboundAbility.java +++ b/Mage/src/mage/abilities/keyword/ReboundAbility.java @@ -1,31 +1,30 @@ /* -* Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. -* -* Redistribution and use in source and binary forms, with or without modification, are -* permitted provided that the following conditions are met: -* -* 1. Redistributions of source code must retain the above copyright notice, this list of -* conditions and the following disclaimer. -* -* 2. Redistributions in binary form must reproduce the above copyright notice, this list -* of conditions and the following disclaimer in the documentation and/or other materials -* provided with the distribution. -* -* THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED -* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND -* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR -* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR -* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON -* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING -* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF -* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -* -* The views and conclusions contained in the software and documentation are those of the -* authors and should not be interpreted as representing official policies, either expressed -* or implied, of BetaSteward_at_googlemail.com. -*/ - + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ package mage.abilities.keyword; import java.util.UUID; @@ -48,28 +47,29 @@ import mage.game.stack.Spell; import mage.players.Player; /** - * This ability has no effect by default and will always return false on the call - * to apply. This is because of how the {@link ReboundEffect} works. It will - * install the effect if and only if the spell was cast from the {@link Zone#HAND Hand}. + * This ability has no effect by default and will always return false on the + * call to apply. This is because of how the {@link ReboundEffect} works. It + * will install the effect if and only if the spell was cast from the + * {@link Zone#HAND Hand}. *

* 702.85. Rebound *

- * 702.85a Rebound appears on some instants and sorceries. It represents a static - * ability that functions while the spell is on the stack and may create a delayed - * triggered ability. "Rebound" means "If this spell was cast from your hand, - * instead of putting it into your graveyard as it resolves, exile it and, at - * the beginning of your next upkeep, you may cast this card from exile without - * paying its mana cost." + * 702.85a Rebound appears on some instants and sorceries. It represents a + * static ability that functions while the spell is on the stack and may create + * a delayed triggered ability. "Rebound" means "If this spell was cast from + * your hand, instead of putting it into your graveyard as it resolves, exile it + * and, at the beginning of your next upkeep, you may cast this card from exile + * without paying its mana cost." *

- * 702.85b Casting a card without paying its mana cost as the result of a rebound - * ability follows the rules for paying alternative costs in rules 601.2b and 601.2e-g. + * 702.85b Casting a card without paying its mana cost as the result of a + * rebound ability follows the rules for paying alternative costs in rules + * 601.2b and 601.2e-g. *

* 702.85c Multiple instances of rebound on the same spell are redundant. * * @author maurer.it_at_gmail.com, noxx */ - -public class ReboundAbility extends SimpleStaticAbility { +public class ReboundAbility extends SimpleStaticAbility { public ReboundAbility() { super(Zone.STACK, new ReboundCastFromHandReplacementEffect()); @@ -81,8 +81,8 @@ public class ReboundAbility extends SimpleStaticAbility { @Override public ReboundAbility copy() { - return new ReboundAbility(this); - } + return new ReboundAbility(this); + } } class ReboundCastFromHandReplacementEffect extends ReplacementEffectImpl { @@ -95,7 +95,7 @@ class ReboundCastFromHandReplacementEffect extends ReplacementEffectImpl { ReboundCastFromHandReplacementEffect(ReboundCastFromHandReplacementEffect effect) { super(effect); } - + @Override public boolean checksEventType(GameEvent event, Game game) { return event.getType() == GameEvent.EventType.ZONE_CHANGE; @@ -103,16 +103,18 @@ class ReboundCastFromHandReplacementEffect extends ReplacementEffectImpl { @Override public boolean applies(GameEvent event, Ability source, Game game) { - if (((ZoneChangeEvent) event).getFromZone() == Zone.STACK && - ((ZoneChangeEvent) event).getToZone() == Zone.GRAVEYARD && - event.getSourceId() == source.getSourceId()) { // if countered the source.sourceId is different or null if it fizzles + if (((ZoneChangeEvent) event).getFromZone() == Zone.STACK + && ((ZoneChangeEvent) event).getToZone() == Zone.GRAVEYARD + && event.getSourceId() != null + && event.getSourceId().equals(source.getSourceId())) { // if countered the source.sourceId is different or null if it fizzles Spell spell = game.getStack().getSpell(event.getTargetId()); if (spell != null && spell.getFromZone().equals(Zone.HAND)) { return true; - } + } } return false; } + @Override public boolean replaceEvent(GameEvent event, Ability source, Game game) { Spell sourceSpell = game.getStack().getSpell(source.getSourceId()); @@ -126,9 +128,9 @@ class ReboundCastFromHandReplacementEffect extends ReplacementEffectImpl { // Add the delayed triggered effect ReboundEffectCastFromExileDelayedTrigger trigger = new ReboundEffectCastFromExileDelayedTrigger(source.getSourceId(), source.getSourceId()); trigger.setControllerId(source.getControllerId()); - trigger.setSourceObject(source.getSourceObject(game), game); + trigger.setSourceObject(source.getSourceObject(game), game); game.addDelayedTriggeredAbility(trigger); - + player.moveCardToExileWithInfo(sourceCard, sourceCard.getId(), player.getName() + " Rebound", source.getSourceId(), game, Zone.STACK, true); return true; } @@ -144,7 +146,6 @@ class ReboundCastFromHandReplacementEffect extends ReplacementEffectImpl { } - class ReboundEffectCastFromExileDelayedTrigger extends DelayedTriggeredAbility { ReboundEffectCastFromExileDelayedTrigger(UUID cardId, UUID sourceId) { @@ -171,6 +172,7 @@ class ReboundEffectCastFromExileDelayedTrigger extends DelayedTriggeredAbility { public boolean checkTrigger(GameEvent event, Game game) { return MyTurnCondition.getInstance().apply(game, this); } + @Override public String getRule() { return "Rebound - You may cast {this} from exile without paying its mana cost."; @@ -178,8 +180,8 @@ class ReboundEffectCastFromExileDelayedTrigger extends DelayedTriggeredAbility { } /** - * Will be triggered by {@link ReboundEffectCastFromExileDelayedTrigger} and will - * simply cast the spell then remove it from its former home in exile. + * Will be triggered by {@link ReboundEffectCastFromExileDelayedTrigger} and + * will simply cast the spell then remove it from its former home in exile. * * @author maurer.it_at_gmail.com */ diff --git a/Mage/src/mage/cards/CardImpl.java b/Mage/src/mage/cards/CardImpl.java index d6dc1f58c7d..2d3fa165cfe 100644 --- a/Mage/src/mage/cards/CardImpl.java +++ b/Mage/src/mage/cards/CardImpl.java @@ -507,8 +507,8 @@ public abstract class CardImpl extends MageObjectImpl implements Card { break; case EXILED: if (game.getExile().getCard(getId(), game) != null) { - game.getExile().removeCard(this, game); - removed = true; + removed = game.getExile().removeCard(this, game); + } break; case STACK: @@ -552,8 +552,9 @@ public abstract class CardImpl extends MageObjectImpl implements Card { + "] source [" + (sourceObject != null ? sourceObject.getName() : "null") + "]"); break; } - game.rememberLKI(objectId, fromZone, lkiObject != null ? lkiObject : this); - if (!removed) { + if (removed) { + game.rememberLKI(objectId, fromZone, lkiObject != null ? lkiObject : this); + } else { logger.warn("Couldn't find card in fromZone, card=" + getIdName() + ", fromZone=" + fromZone); } return removed; diff --git a/Mage/src/mage/game/Exile.java b/Mage/src/mage/game/Exile.java index 42b513092f3..8abb6d4cb59 100644 --- a/Mage/src/mage/game/Exile.java +++ b/Mage/src/mage/game/Exile.java @@ -107,12 +107,13 @@ public class Exile implements Serializable, Copyable { return cards; } - public void removeCard(Card card, Game game) { + public boolean removeCard(Card card, Game game) { for (ExileZone exile : exileZones.values()) { if (exile.contains(card.getId())) { - exile.remove(card); + return exile.remove(card.getId()); } } + return false; } @Override diff --git a/Mage/src/mage/players/PlayerImpl.java b/Mage/src/mage/players/PlayerImpl.java index 49e8ffb656a..bb1250e1b5c 100644 --- a/Mage/src/mage/players/PlayerImpl.java +++ b/Mage/src/mage/players/PlayerImpl.java @@ -3052,7 +3052,7 @@ public abstract class PlayerImpl implements Player, Serializable { ZoneChangeEvent event = new ZoneChangeEvent(card.getId(), source.getSourceId(), controllingPlayerId, fromZone, Zone.BATTLEFIELD, appliedEffects, tapped); if (!game.replaceEvent(event)) { // get permanent - Permanent permanent = new PermanentCard(card, controllingPlayerId, game); + Permanent permanent = new PermanentCard(card, event.getPlayerId(), game);// controlling player can be replaced so use event player now permanents.add(permanent); card.checkForCountersToAdd(permanent, game); permanent.setTapped(tapped); From 7924d301bade5b9c06d82b12ca564f4cc95c7988 Mon Sep 17 00:00:00 2001 From: LoneFox Date: Wed, 14 Oct 2015 21:00:55 +0300 Subject: [PATCH 141/268] Implement cards: Alexi's Cloak; Barbed Field; Chilling Apparition; and Latulla, Keldon Overseer --- .../src/mage/sets/prophecy/AlexisCloak.java | 78 +++++++++++++++++ .../src/mage/sets/prophecy/BarbedField.java | 84 +++++++++++++++++++ .../sets/prophecy/ChillingApparition.java | 69 +++++++++++++++ .../sets/prophecy/LatullaKeldonOverseer.java | 78 +++++++++++++++++ 4 files changed, 309 insertions(+) create mode 100644 Mage.Sets/src/mage/sets/prophecy/AlexisCloak.java create mode 100644 Mage.Sets/src/mage/sets/prophecy/BarbedField.java create mode 100644 Mage.Sets/src/mage/sets/prophecy/ChillingApparition.java create mode 100644 Mage.Sets/src/mage/sets/prophecy/LatullaKeldonOverseer.java diff --git a/Mage.Sets/src/mage/sets/prophecy/AlexisCloak.java b/Mage.Sets/src/mage/sets/prophecy/AlexisCloak.java new file mode 100644 index 00000000000..f2616d74fd2 --- /dev/null +++ b/Mage.Sets/src/mage/sets/prophecy/AlexisCloak.java @@ -0,0 +1,78 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.sets.prophecy; + +import java.util.UUID; +import mage.abilities.Ability; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.effects.common.AttachEffect; +import mage.abilities.effects.common.continuous.GainAbilityAttachedEffect; +import mage.abilities.keyword.EnchantAbility; +import mage.abilities.keyword.FlashAbility; +import mage.abilities.keyword.ShroudAbility; +import mage.cards.CardImpl; +import mage.constants.AttachmentType; +import mage.constants.CardType; +import mage.constants.Outcome; +import mage.constants.Rarity; +import mage.constants.Zone; +import mage.target.TargetPermanent; +import mage.target.common.TargetCreaturePermanent; + +/** + * + * @author LoneFox + */ +public class AlexisCloak extends CardImpl { + + public AlexisCloak(UUID ownerId) { + super(ownerId, 29, "Alexi's Cloak", Rarity.COMMON, new CardType[]{CardType.ENCHANTMENT}, "{1}{U}"); + this.expansionSetCode = "PCY"; + this.subtype.add("Aura"); + + // Flash + this.addAbility(FlashAbility.getInstance()); + // Enchant creature + TargetPermanent auraTarget = new TargetCreaturePermanent(); + this.getSpellAbility().addTarget(auraTarget); + this.getSpellAbility().addEffect(new AttachEffect(Outcome.AddAbility)); + Ability ability = new EnchantAbility(auraTarget.getTargetName()); + this.addAbility(ability); + // Enchanted creature has shroud. + this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new GainAbilityAttachedEffect(ShroudAbility.getInstance(), AttachmentType.AURA))); + } + + public AlexisCloak(final AlexisCloak card) { + super(card); + } + + @Override + public AlexisCloak copy() { + return new AlexisCloak(this); + } +} diff --git a/Mage.Sets/src/mage/sets/prophecy/BarbedField.java b/Mage.Sets/src/mage/sets/prophecy/BarbedField.java new file mode 100644 index 00000000000..794f5688e29 --- /dev/null +++ b/Mage.Sets/src/mage/sets/prophecy/BarbedField.java @@ -0,0 +1,84 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.sets.prophecy; + +import java.util.UUID; +import mage.abilities.Ability; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.costs.common.TapSourceCost; +import mage.abilities.effects.Effect; +import mage.abilities.effects.common.AttachEffect; +import mage.abilities.effects.common.DamageTargetEffect; +import mage.abilities.effects.common.continuous.GainAbilityAttachedEffect; +import mage.abilities.keyword.EnchantAbility; +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.Zone; +import mage.target.TargetPermanent; +import mage.target.common.TargetCreatureOrPlayer; +import mage.target.common.TargetLandPermanent; + +/** + * + * @author LoneFox + */ +public class BarbedField extends CardImpl { + + public BarbedField(UUID ownerId) { + super(ownerId, 83, "Barbed Field", Rarity.UNCOMMON, new CardType[]{CardType.ENCHANTMENT}, "{2}{R}{R}"); + this.expansionSetCode = "PCY"; + this.subtype.add("Aura"); + + // Enchant land + TargetPermanent auraTarget = new TargetLandPermanent(); + this.getSpellAbility().addTarget(auraTarget); + this.getSpellAbility().addEffect(new AttachEffect(Outcome.AddAbility)); + Ability ability = new EnchantAbility(auraTarget.getTargetName()); + this.addAbility(ability); + // Enchanted land has "{tap}: This land deals 1 damage to target creature or player." + ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new DamageTargetEffect(1), new TapSourceCost()); + ability.addTarget(new TargetCreatureOrPlayer()); + Effect effect = new GainAbilityAttachedEffect(ability, AttachmentType.AURA); + effect.setText("Enchanted land has \"{T}: This land deals 1 damage to target creature or player.\""); + this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, effect)); + } + + public BarbedField(final BarbedField card) { + super(card); + } + + @Override + public BarbedField copy() { + return new BarbedField(this); + } +} diff --git a/Mage.Sets/src/mage/sets/prophecy/ChillingApparition.java b/Mage.Sets/src/mage/sets/prophecy/ChillingApparition.java new file mode 100644 index 00000000000..e47fc63331e --- /dev/null +++ b/Mage.Sets/src/mage/sets/prophecy/ChillingApparition.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.prophecy; + +import java.util.UUID; +import mage.MageInt; +import mage.abilities.common.DealsDamageToOpponentTriggeredAbility; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.effects.common.RegenerateSourceEffect; +import mage.abilities.effects.common.discard.DiscardTargetEffect; +import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.Rarity; +import mage.constants.Zone; + +/** + * + * @author LoneFox + */ +public class ChillingApparition extends CardImpl { + + public ChillingApparition(UUID ownerId) { + super(ownerId, 59, "Chilling Apparition", Rarity.UNCOMMON, new CardType[]{CardType.CREATURE}, "{2}{B}"); + this.expansionSetCode = "PCY"; + this.subtype.add("Spirit"); + this.power = new MageInt(1); + this.toughness = new MageInt(1); + + // {B}: Regenerate Chilling Apparition. + this.addAbility(new SimpleActivatedAbility(Zone.BATTLEFIELD, new RegenerateSourceEffect(), new ManaCostsImpl("{B}"))); + // Whenever Chilling Apparition deals combat damage to a player, that player discards a card. + this.addAbility(new DealsDamageToOpponentTriggeredAbility(new DiscardTargetEffect(1), false, true, true)); + } + + public ChillingApparition(final ChillingApparition card) { + super(card); + } + + @Override + public ChillingApparition copy() { + return new ChillingApparition(this); + } +} diff --git a/Mage.Sets/src/mage/sets/prophecy/LatullaKeldonOverseer.java b/Mage.Sets/src/mage/sets/prophecy/LatullaKeldonOverseer.java new file mode 100644 index 00000000000..5d7ca6f1de7 --- /dev/null +++ b/Mage.Sets/src/mage/sets/prophecy/LatullaKeldonOverseer.java @@ -0,0 +1,78 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.sets.prophecy; + +import java.util.UUID; +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.costs.common.DiscardTargetCost; +import mage.abilities.costs.common.TapSourceCost; +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.dynamicvalue.common.ManacostVariableValue; +import mage.abilities.effects.common.DamageTargetEffect; +import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.Rarity; +import mage.constants.Zone; +import mage.filter.FilterCard; +import mage.target.common.TargetCardInHand; +import mage.target.common.TargetCreatureOrPlayer; + +/** + * + * @author LoneFox + */ +public class LatullaKeldonOverseer extends CardImpl { + + public LatullaKeldonOverseer(UUID ownerId) { + super(ownerId, 95, "Latulla, Keldon Overseer", Rarity.RARE, new CardType[]{CardType.CREATURE}, "{3}{R}{R}"); + this.expansionSetCode = "PCY"; + this.supertype.add("Legendary"); + this.subtype.add("Human"); + this.subtype.add("Spellshaper"); + this.power = new MageInt(3); + this.toughness = new MageInt(3); + + // {X}{R}, {tap}, Discard two cards: Latulla, Keldon Overseer deals X damage to target creature or player. + Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new DamageTargetEffect(new ManacostVariableValue()), new ManaCostsImpl("{X}{R}")); + ability.addCost(new TapSourceCost()); + ability.addCost(new DiscardTargetCost(new TargetCardInHand(2, 2, new FilterCard("two cards")))); + ability.addTarget(new TargetCreatureOrPlayer()); + this.addAbility(ability); + } + + public LatullaKeldonOverseer(final LatullaKeldonOverseer card) { + super(card); + } + + @Override + public LatullaKeldonOverseer copy() { + return new LatullaKeldonOverseer(this); + } +} From 806a52c1c05c2ed241d4d20c85ff0ae56968b38d Mon Sep 17 00:00:00 2001 From: LoneFox Date: Wed, 14 Oct 2015 21:17:54 +0300 Subject: [PATCH 142/268] Fix Chilling Apparition to affect any player it damages --- Mage.Sets/src/mage/sets/prophecy/ChillingApparition.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Mage.Sets/src/mage/sets/prophecy/ChillingApparition.java b/Mage.Sets/src/mage/sets/prophecy/ChillingApparition.java index e47fc63331e..816f89bac48 100644 --- a/Mage.Sets/src/mage/sets/prophecy/ChillingApparition.java +++ b/Mage.Sets/src/mage/sets/prophecy/ChillingApparition.java @@ -29,7 +29,7 @@ package mage.sets.prophecy; import java.util.UUID; import mage.MageInt; -import mage.abilities.common.DealsDamageToOpponentTriggeredAbility; +import mage.abilities.common.DealsCombatDamageToAPlayerTriggeredAbility; import mage.abilities.common.SimpleActivatedAbility; import mage.abilities.costs.mana.ManaCostsImpl; import mage.abilities.effects.common.RegenerateSourceEffect; @@ -55,7 +55,7 @@ public class ChillingApparition extends CardImpl { // {B}: Regenerate Chilling Apparition. this.addAbility(new SimpleActivatedAbility(Zone.BATTLEFIELD, new RegenerateSourceEffect(), new ManaCostsImpl("{B}"))); // Whenever Chilling Apparition deals combat damage to a player, that player discards a card. - this.addAbility(new DealsDamageToOpponentTriggeredAbility(new DiscardTargetEffect(1), false, true, true)); + this.addAbility(new DealsCombatDamageToAPlayerTriggeredAbility(new DiscardTargetEffect(1), false, true)); } public ChillingApparition(final ChillingApparition card) { From c6ff078c09b38d4cc98592a35c0211cdeefcb0b9 Mon Sep 17 00:00:00 2001 From: Anton Date: Wed, 14 Oct 2015 20:34:10 +0200 Subject: [PATCH 143/268] Added Forgotten Ancient --- .../mage/sets/archenemy/ForgottenAncient.java | 52 ++++++ .../sets/planechase/ForgottenAncient.java | 52 ++++++ .../mage/sets/scourge/ForgottenAncient.java | 158 ++++++++++++++++++ 3 files changed, 262 insertions(+) create mode 100644 Mage.Sets/src/mage/sets/archenemy/ForgottenAncient.java create mode 100644 Mage.Sets/src/mage/sets/planechase/ForgottenAncient.java create mode 100644 Mage.Sets/src/mage/sets/scourge/ForgottenAncient.java diff --git a/Mage.Sets/src/mage/sets/archenemy/ForgottenAncient.java b/Mage.Sets/src/mage/sets/archenemy/ForgottenAncient.java new file mode 100644 index 00000000000..0ac189d66b9 --- /dev/null +++ b/Mage.Sets/src/mage/sets/archenemy/ForgottenAncient.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.archenemy; + +import java.util.UUID; + +/** + * + * @author Blinke + */ +public class ForgottenAncient extends mage.sets.scourge.ForgottenAncient { + + public ForgottenAncient(UUID ownerId) { + super(ownerId); + this.cardNumber = 57; + this.expansionSetCode = "ARC"; + } + + public ForgottenAncient(final ForgottenAncient card) { + super(card); + } + + @Override + public ForgottenAncient copy() { + return new ForgottenAncient(this); + } +} diff --git a/Mage.Sets/src/mage/sets/planechase/ForgottenAncient.java b/Mage.Sets/src/mage/sets/planechase/ForgottenAncient.java new file mode 100644 index 00000000000..e8b9b7dfc5c --- /dev/null +++ b/Mage.Sets/src/mage/sets/planechase/ForgottenAncient.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.planechase; + +import java.util.UUID; + +/** + * + * @author Blinke + */ +public class ForgottenAncient extends mage.sets.scourge.ForgottenAncient { + + public ForgottenAncient(UUID ownerId) { + super(ownerId); + this.cardNumber = 73; + this.expansionSetCode = "HOP"; + } + + public ForgottenAncient(final ForgottenAncient card) { + super(card); + } + + @Override + public ForgottenAncient copy() { + return new ForgottenAncient(this); + } +} diff --git a/Mage.Sets/src/mage/sets/scourge/ForgottenAncient.java b/Mage.Sets/src/mage/sets/scourge/ForgottenAncient.java new file mode 100644 index 00000000000..8107c48a39c --- /dev/null +++ b/Mage.Sets/src/mage/sets/scourge/ForgottenAncient.java @@ -0,0 +1,158 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.sets.scourge; + +import java.util.ArrayList; +import java.util.UUID; +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.BeginningOfUpkeepTriggeredAbility; +import mage.abilities.common.SpellCastAllTriggeredAbility; +import mage.abilities.effects.Effect; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.counter.AddCountersSourceEffect; +import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.Outcome; +import mage.constants.Rarity; +import mage.constants.TargetController; +import mage.constants.Zone; +import mage.counters.CounterType; +import mage.filter.common.FilterCreaturePermanent; +import mage.filter.predicate.permanent.AnotherPredicate; +import mage.game.Game; +import mage.game.permanent.Permanent; +import mage.players.Player; +import mage.target.Target; +import mage.target.common.TargetCreaturePermanent; + +/** + * + * @author Blinke + */ +public class ForgottenAncient extends CardImpl { + private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("another creature"); + static { + filter.add(new AnotherPredicate()); + } + + public ForgottenAncient(UUID ownerId) { + super(ownerId, 120, "Forgotten Ancient", Rarity.RARE, new CardType[]{CardType.CREATURE}, "{3}{G}"); + this.expansionSetCode = "SCG"; + this.subtype.add("Elemental"); + this.power = new MageInt(0); + this.toughness = new MageInt(3); + + // Whenever a player casts a spell, you may put a +1/+1 counter on Forgotten Ancient. + Effect effect = new AddCountersSourceEffect(CounterType.P1P1.createInstance()); + Ability ability = new SpellCastAllTriggeredAbility(effect, true); + this.addAbility(ability); + + // At the beginning of your upkeep, you may move any number of +1/+1 counters from Forgotten Ancient onto other creatures. + this.addAbility(new BeginningOfUpkeepTriggeredAbility(Zone.BATTLEFIELD, new ForgottenAncientEffect(), TargetController.YOU, true)); + } + + public ForgottenAncient(final ForgottenAncient card) { + super(card); + } + + @Override + public ForgottenAncient copy() { + return new ForgottenAncient(this); + } + + class CounterMovement { + public UUID target; + public int counters; + } + + class ForgottenAncientEffect extends OneShotEffect { + + public ForgottenAncientEffect() { + super(Outcome.Benefit); + this.staticText = "you may move any number of +1/+1 counters from Forgotten Ancient onto other creatures."; + } + + public ForgottenAncientEffect(final ForgottenAncientEffect effect) { + super(effect); + } + + @Override + public ForgottenAncientEffect copy() { + return new ForgottenAncientEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player controller = game.getPlayer(source.getControllerId()); + Permanent sourcePermanent = game.getPermanent(source.getSourceId()); + + if(controller == null || sourcePermanent == null) { + return false; + } + + int numCounters = sourcePermanent.getCounters().getCount(CounterType.P1P1); + ArrayList counterMovements = new ArrayList<>(); + + do { + Target target = new TargetCreaturePermanent(1, 1, filter, true); + if(numCounters == 0 || !target.choose(Outcome.Benefit, source.getControllerId(), source.getSourceId(), game)) { + continue; + } + + int amountToMove = controller.getAmount(0, numCounters, "How many counters do you want to move? " + "(" + numCounters + ")" + " counters remaining.", game); + if(amountToMove > 0) + { + boolean previouslyChosen = false; + for (CounterMovement cm : counterMovements) { + if(cm.target.equals(target.getFirstTarget())) + { + cm.counters += amountToMove; + previouslyChosen = true; + } + } + if(!previouslyChosen) { + CounterMovement cm = new CounterMovement(); + cm.target = target.getFirstTarget(); + cm.counters = amountToMove; + counterMovements.add(cm); + } + + numCounters -= amountToMove; + } + } while(numCounters > 0 && controller.chooseUse(Outcome.Benefit, "Move additonal counters?", source, game)); + + //Move all the counters for each chosen creature + for(CounterMovement cm: counterMovements) { + sourcePermanent.removeCounters(CounterType.P1P1.createInstance(cm.counters), game); + game.getPermanent(cm.target).addCounters(CounterType.P1P1.createInstance(cm.counters), game); + } + return true; + } + } +} From 058650d7315feeaf74a5d86c349805e1d58dfded Mon Sep 17 00:00:00 2001 From: Plopman Date: Wed, 14 Oct 2015 21:19:44 +0200 Subject: [PATCH 144/268] Small changes to sylvan Library and Chrome Mox.It's now possible to select cards directly in the hand instead of in an other window --- .../mage/sets/fifthedition/SylvanLibrary.java | 35 +- .../src/mage/sets/mirrodin/ChromeMox.java | 408 +++++++++--------- 2 files changed, 237 insertions(+), 206 deletions(-) diff --git a/Mage.Sets/src/mage/sets/fifthedition/SylvanLibrary.java b/Mage.Sets/src/mage/sets/fifthedition/SylvanLibrary.java index e6d7c57a60e..afa1cd28900 100644 --- a/Mage.Sets/src/mage/sets/fifthedition/SylvanLibrary.java +++ b/Mage.Sets/src/mage/sets/fifthedition/SylvanLibrary.java @@ -30,6 +30,7 @@ package mage.sets.fifthedition; import java.util.HashSet; import java.util.Set; import java.util.UUID; +import mage.MageObject; import mage.abilities.Ability; import mage.abilities.common.BeginningOfDrawTriggeredAbility; import mage.abilities.effects.OneShotEffect; @@ -44,6 +45,7 @@ import mage.constants.TargetController; import mage.constants.WatcherScope; import mage.constants.Zone; import mage.filter.FilterCard; +import mage.filter.predicate.Predicate; import mage.game.Game; import mage.game.events.GameEvent; import mage.players.Player; @@ -110,8 +112,10 @@ class SylvanLibraryEffect extends OneShotEffect { } int numberOfTargets = Math.min(2, cards.size()); if (numberOfTargets > 0) { - TargetCardInHand target = new TargetCardInHand(numberOfTargets, new FilterCard(numberOfTargets + " cards of cards drawn this turn")); - controller.chooseTarget(outcome, cards, target, source, game); + FilterCard filter = new FilterCard(numberOfTargets + " cards of cards drawn this turn"); + filter.add(new CardIdPredicate(cards)); + TargetCardInHand target = new TargetCardInHand(numberOfTargets, filter); + controller.choose(outcome, target, source.getSourceId(), game); Cards cardsPutBack = new CardsImpl(); for (UUID cardId : target.getTargets()) { @@ -190,3 +194,30 @@ class CardsDrawnThisTurnWatcher extends Watcher { return new CardsDrawnThisTurnWatcher(this); } } + + +class CardIdPredicate implements Predicate { + + private final Cards cardsId; + + public CardIdPredicate(Cards cardsId) { + this.cardsId = cardsId; + } + + @Override + public boolean apply(MageObject input, Game game) { + for(UUID uuid : cardsId) + { + if(uuid.equals(input.getId())) + { + return true; + } + } + return false; + } + + @Override + public String toString() { + return "CardsId"; + } +} diff --git a/Mage.Sets/src/mage/sets/mirrodin/ChromeMox.java b/Mage.Sets/src/mage/sets/mirrodin/ChromeMox.java index af94a37a999..73fff870bc8 100644 --- a/Mage.Sets/src/mage/sets/mirrodin/ChromeMox.java +++ b/Mage.Sets/src/mage/sets/mirrodin/ChromeMox.java @@ -1,205 +1,205 @@ -/* - * 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.mirrodin; - -import java.util.List; -import java.util.UUID; -import mage.Mana; -import mage.ObjectColor; -import mage.abilities.Ability; -import mage.abilities.common.EntersBattlefieldTriggeredAbility; -import mage.abilities.costs.common.TapSourceCost; -import mage.abilities.effects.OneShotEffect; -import mage.abilities.effects.common.ManaEffect; -import mage.abilities.mana.SimpleManaAbility; -import mage.cards.Card; -import mage.cards.CardImpl; -import mage.choices.Choice; -import mage.choices.ChoiceImpl; -import mage.constants.CardType; -import mage.constants.Outcome; -import mage.constants.Rarity; -import mage.constants.Zone; -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.TargetCard; - -/** - * - * @author Plopman - */ -public class ChromeMox extends CardImpl { - - public ChromeMox(UUID ownerId) { - super(ownerId, 152, "Chrome Mox", Rarity.RARE, new CardType[]{CardType.ARTIFACT}, "{0}"); - this.expansionSetCode = "MRD"; - - // Imprint - When Chrome Mox enters the battlefield, you may exile a nonartifact, nonland card from your hand. - this.addAbility(new EntersBattlefieldTriggeredAbility(new ChromeMoxEffect(), true)); - // {tap}: Add one mana of any of the exiled card's colors to your mana pool. - this.addAbility(new SimpleManaAbility(Zone.BATTLEFIELD, new ChromeMoxManaEffect(), new TapSourceCost())); - } - - public ChromeMox(final ChromeMox card) { - super(card); - } - - @java.lang.Override - public ChromeMox copy() { - return new ChromeMox(this); - } -} - -class ChromeMoxEffect extends OneShotEffect { - - private static final FilterCard filter = new FilterCard("nonartifact, nonland card"); - static { - filter.add(Predicates.not(Predicates.or(new CardTypePredicate(CardType.LAND), new CardTypePredicate(CardType.ARTIFACT)))); - } - public ChromeMoxEffect() { - super(Outcome.Benefit); - staticText = "exile a nonartifact, nonland card from your hand"; - } - - public ChromeMoxEffect(ChromeMoxEffect effect) { - super(effect); - } - - @java.lang.Override - public boolean apply(Game game, Ability source) { - Player player = game.getPlayer(source.getControllerId()); - if (player.getHand().size() > 0) { - TargetCard target = new TargetCard(Zone.HAND, filter); - player.choose(Outcome.Benefit, player.getHand(), target, game); - Card card = player.getHand().get(target.getFirstTarget(), game); - if (card != null) { - card.moveToExile(getId(), "Chrome Mox (Imprint)", source.getSourceId(), game); - Permanent permanent = game.getPermanent(source.getSourceId()); - if (permanent != null) { - permanent.imprint(card.getId(), game); - } - return true; - } - } - return true; - } - - @java.lang.Override - public ChromeMoxEffect copy() { - return new ChromeMoxEffect(this); - } - - -} - -class ChromeMoxManaEffect extends ManaEffect { - - - ChromeMoxManaEffect() { - super(); - staticText = "Add one mana of any of the exiled card's colors to your mana pool"; - } - - ChromeMoxManaEffect(ChromeMoxManaEffect effect) { - super(effect); - } - - - - @java.lang.Override - public ChromeMoxManaEffect copy() { - return new ChromeMoxManaEffect(this); - } - - @java.lang.Override - public boolean apply(Game game, Ability source) { - Permanent permanent = game.getPermanent(source.getSourceId()); - Player player = game.getPlayer(source.getControllerId()); - if (permanent != null && player != null) { - List imprinted = permanent.getImprinted(); - if (imprinted.size() > 0) { - Card imprintedCard = game.getCard(imprinted.get(0)); - if (imprintedCard != null) { - Choice choice = new ChoiceImpl(true); - choice.setMessage("Pick a mana color"); - ObjectColor color = imprintedCard.getColor(game); - if (color.isBlack()) { - choice.getChoices().add("Black"); - } - if (color.isRed()) { - choice.getChoices().add("Red"); - } - if (color.isBlue()) { - choice.getChoices().add("Blue"); - } - if (color.isGreen()) { - choice.getChoices().add("Green"); - } - if (color.isWhite()) { - choice.getChoices().add("White"); - } - - if (choice.getChoices().size() > 0) { - Mana mana = new Mana(); - if (choice.getChoices().size() == 1) { - choice.setChoice(choice.getChoices().iterator().next()); - } else { - player.choose(outcome, choice, game); - } - if (choice.getChoice().equals("Black")) { - player.getManaPool().addMana(Mana.BlackMana, game, source); - } else if (choice.getChoice().equals("Blue")) { - player.getManaPool().addMana(Mana.BlueMana, game, source); - } else if (choice.getChoice().equals("Red")) { - player.getManaPool().addMana(Mana.RedMana, game, source); - } else if (choice.getChoice().equals("Green")) { - player.getManaPool().addMana(Mana.GreenMana, game, source); - } else if (choice.getChoice().equals("White")) { - player.getManaPool().addMana(Mana.WhiteMana, game, source); - } else if (choice.getChoice().equals("Colorless")) { - player.getManaPool().addMana(Mana.ColorlessMana, game, source); - } - checkToFirePossibleEvents(mana, game, source); - player.getManaPool().addMana(mana, game, source); - } - } - } - } - return true; - } - - @java.lang.Override - public Mana getMana(Game game, Ability source) { - return null; - } - +/* + * 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.mirrodin; + +import java.util.List; +import java.util.UUID; +import mage.Mana; +import mage.ObjectColor; +import mage.abilities.Ability; +import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.costs.common.TapSourceCost; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.ManaEffect; +import mage.abilities.mana.SimpleManaAbility; +import mage.cards.Card; +import mage.cards.CardImpl; +import mage.choices.Choice; +import mage.choices.ChoiceImpl; +import mage.constants.CardType; +import mage.constants.Outcome; +import mage.constants.Rarity; +import mage.constants.Zone; +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.TargetCard; + +/** + * + * @author Plopman + */ +public class ChromeMox extends CardImpl { + + public ChromeMox(UUID ownerId) { + super(ownerId, 152, "Chrome Mox", Rarity.RARE, new CardType[]{CardType.ARTIFACT}, "{0}"); + this.expansionSetCode = "MRD"; + + // Imprint - When Chrome Mox enters the battlefield, you may exile a nonartifact, nonland card from your hand. + this.addAbility(new EntersBattlefieldTriggeredAbility(new ChromeMoxEffect(), true)); + // {tap}: Add one mana of any of the exiled card's colors to your mana pool. + this.addAbility(new SimpleManaAbility(Zone.BATTLEFIELD, new ChromeMoxManaEffect(), new TapSourceCost())); + } + + public ChromeMox(final ChromeMox card) { + super(card); + } + + @java.lang.Override + public ChromeMox copy() { + return new ChromeMox(this); + } +} + +class ChromeMoxEffect extends OneShotEffect { + + private static final FilterCard filter = new FilterCard("nonartifact, nonland card"); + static { + filter.add(Predicates.not(Predicates.or(new CardTypePredicate(CardType.LAND), new CardTypePredicate(CardType.ARTIFACT)))); + } + public ChromeMoxEffect() { + super(Outcome.Benefit); + staticText = "exile a nonartifact, nonland card from your hand"; + } + + public ChromeMoxEffect(ChromeMoxEffect effect) { + super(effect); + } + + @java.lang.Override + public boolean apply(Game game, Ability source) { + Player player = game.getPlayer(source.getControllerId()); + if (player.getHand().size() > 0) { + TargetCard target = new TargetCard(Zone.HAND, filter); + player.choose(Outcome.Benefit, target, source.getSourceId(), game); + Card card = player.getHand().get(target.getFirstTarget(), game); + if (card != null) { + card.moveToExile(getId(), "Chrome Mox (Imprint)", source.getSourceId(), game); + Permanent permanent = game.getPermanent(source.getSourceId()); + if (permanent != null) { + permanent.imprint(card.getId(), game); + } + return true; + } + } + return true; + } + + @java.lang.Override + public ChromeMoxEffect copy() { + return new ChromeMoxEffect(this); + } + + +} + +class ChromeMoxManaEffect extends ManaEffect { + + + ChromeMoxManaEffect() { + super(); + staticText = "Add one mana of any of the exiled card's colors to your mana pool"; + } + + ChromeMoxManaEffect(ChromeMoxManaEffect effect) { + super(effect); + } + + + + @java.lang.Override + public ChromeMoxManaEffect copy() { + return new ChromeMoxManaEffect(this); + } + + @java.lang.Override + public boolean apply(Game game, Ability source) { + Permanent permanent = game.getPermanent(source.getSourceId()); + Player player = game.getPlayer(source.getControllerId()); + if (permanent != null && player != null) { + List imprinted = permanent.getImprinted(); + if (imprinted.size() > 0) { + Card imprintedCard = game.getCard(imprinted.get(0)); + if (imprintedCard != null) { + Choice choice = new ChoiceImpl(true); + choice.setMessage("Pick a mana color"); + ObjectColor color = imprintedCard.getColor(game); + if (color.isBlack()) { + choice.getChoices().add("Black"); + } + if (color.isRed()) { + choice.getChoices().add("Red"); + } + if (color.isBlue()) { + choice.getChoices().add("Blue"); + } + if (color.isGreen()) { + choice.getChoices().add("Green"); + } + if (color.isWhite()) { + choice.getChoices().add("White"); + } + + if (choice.getChoices().size() > 0) { + Mana mana = new Mana(); + if (choice.getChoices().size() == 1) { + choice.setChoice(choice.getChoices().iterator().next()); + } else { + player.choose(outcome, choice, game); + } + if (choice.getChoice().equals("Black")) { + player.getManaPool().addMana(Mana.BlackMana, game, source); + } else if (choice.getChoice().equals("Blue")) { + player.getManaPool().addMana(Mana.BlueMana, game, source); + } else if (choice.getChoice().equals("Red")) { + player.getManaPool().addMana(Mana.RedMana, game, source); + } else if (choice.getChoice().equals("Green")) { + player.getManaPool().addMana(Mana.GreenMana, game, source); + } else if (choice.getChoice().equals("White")) { + player.getManaPool().addMana(Mana.WhiteMana, game, source); + } else if (choice.getChoice().equals("Colorless")) { + player.getManaPool().addMana(Mana.ColorlessMana, game, source); + } + checkToFirePossibleEvents(mana, game, source); + player.getManaPool().addMana(mana, game, source); + } + } + } + } + return true; + } + + @java.lang.Override + public Mana getMana(Game game, Ability source) { + return null; + } + } \ No newline at end of file From 11efdcad789545fa0ecb3e46bc48c4e8a13d2b7f Mon Sep 17 00:00:00 2001 From: LoneFox Date: Wed, 14 Oct 2015 22:32:38 +0300 Subject: [PATCH 145/268] Add TargetsPermanentPredicate and use it for existing cards. Implement card: Hydromorph Gull --- .../sets/riseoftheeldrazi/NotOfThisWorld.java | 110 ++------------ .../mage/sets/scarsofmirrodin/TurnAside.java | 134 ++---------------- .../mage/sets/torment/HydromorphGuardian.java | 40 +----- .../src/mage/sets/torment/HydromorphGull.java | 85 +++++++++++ .../src/mage/sets/urzaslegacy/Intervene.java | 116 ++------------- .../other/TargetsPermanentPredicate.java | 76 ++++++++++ 6 files changed, 200 insertions(+), 361 deletions(-) create mode 100644 Mage.Sets/src/mage/sets/torment/HydromorphGull.java create mode 100644 Mage/src/mage/filter/predicate/other/TargetsPermanentPredicate.java diff --git a/Mage.Sets/src/mage/sets/riseoftheeldrazi/NotOfThisWorld.java b/Mage.Sets/src/mage/sets/riseoftheeldrazi/NotOfThisWorld.java index 558d240f739..1ee4a1ce987 100644 --- a/Mage.Sets/src/mage/sets/riseoftheeldrazi/NotOfThisWorld.java +++ b/Mage.Sets/src/mage/sets/riseoftheeldrazi/NotOfThisWorld.java @@ -27,8 +27,6 @@ */ package mage.sets.riseoftheeldrazi; -import java.util.HashSet; -import java.util.Set; import java.util.UUID; import mage.abilities.Ability; import mage.abilities.common.SimpleStaticAbility; @@ -40,18 +38,17 @@ import mage.constants.CardType; import mage.constants.Rarity; import mage.constants.TargetController; import mage.constants.Zone; -import mage.filter.Filter; +import mage.filter.FilterSpell; +import mage.filter.common.FilterControlledPermanent; import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.mageobject.PowerPredicate; +import mage.filter.predicate.other.TargetsPermanentPredicate; import mage.filter.predicate.permanent.ControllerPredicate; import mage.game.Game; import mage.game.permanent.Permanent; -import mage.game.stack.Spell; -import mage.game.stack.StackAbility; import mage.game.stack.StackObject; import mage.target.Target; -import mage.target.TargetObject; -import mage.target.Targets; +import mage.target.TargetSpell; /** * @@ -59,15 +56,19 @@ import mage.target.Targets; */ public class NotOfThisWorld extends CardImpl { + private final static FilterSpell filter = new FilterSpell("spell that targets a permanent you control"); + + static { + filter.add(new TargetsPermanentPredicate(new FilterControlledPermanent())); + } + public NotOfThisWorld(UUID ownerId) { - super(ownerId, 8, "Not of This World", Rarity.UNCOMMON, - new CardType[]{CardType.TRIBAL, CardType.INSTANT}, "{7}"); + super(ownerId, 8, "Not of This World", Rarity.UNCOMMON, new CardType[]{CardType.TRIBAL, CardType.INSTANT}, "{7}"); this.expansionSetCode = "ROE"; this.subtype.add("Eldrazi"); // Counter target spell or ability that targets a permanent you control. - this.getSpellAbility().addTarget( - new TargetStackObjectTargetingControlledPermanent()); + this.getSpellAbility().addTarget(new TargetSpell(filter)); this.getSpellAbility().addEffect(new CounterTargetEffect()); // Not of This World costs {7} less to cast if it targets a spell or ability that targets a creature you control with power 7 or greater. this.addAbility(new SimpleStaticAbility(Zone.STACK, new SpellCostReductionSourceEffect(7, NotOfThisWorldCondition.getInstance()))); @@ -83,93 +84,6 @@ public class NotOfThisWorld extends CardImpl { } } -class TargetStackObjectTargetingControlledPermanent extends TargetObject { - - - public TargetStackObjectTargetingControlledPermanent() { - this.minNumberOfTargets = 1; - this.maxNumberOfTargets = 1; - this.zone = Zone.STACK; - this.targetName = "spell or ability that targets a permanent you control"; - } - - public TargetStackObjectTargetingControlledPermanent(final TargetStackObjectTargetingControlledPermanent target) { - super(target); - } - - @Override - public Filter getFilter() { - throw new UnsupportedOperationException("Not supported."); //To change body of generated methods, choose Tools | Templates. - } - - @Override - public boolean canTarget(UUID id, Ability source, Game game) { - StackObject stackObject = game.getStack().getStackObject(id); - if ((stackObject instanceof Spell) || (stackObject instanceof StackAbility)) { - return true; - } - return false; - } - - @Override - public boolean canChoose(UUID sourceId, UUID sourceControllerId, Game game) { - return canChoose(sourceControllerId, game); - } - - @Override - public boolean canChoose(UUID sourceControllerId, Game game) { - for (StackObject stackObject : game.getStack()) { - if ((stackObject instanceof Spell) || (stackObject instanceof StackAbility)) { - Targets objectTargets = stackObject.getStackAbility().getTargets(); - if(!objectTargets.isEmpty()) { - for (Target target : objectTargets) { - for (UUID targetId : target.getTargets()) { - Permanent targetedPermanent = game.getPermanentOrLKIBattlefield(targetId); - if (targetedPermanent != null && targetedPermanent.getControllerId().equals(sourceControllerId)) { - return true; - } - } - } - } - } - } - return false; - } - - @Override - public Set possibleTargets(UUID sourceId, UUID sourceControllerId, - Game game) { - return possibleTargets(sourceControllerId, game); - } - - @Override - public Set possibleTargets(UUID sourceControllerId, Game game) { - Set possibleTargets = new HashSet<>(); - for (StackObject stackObject : game.getStack()) { - if ((stackObject instanceof Spell) || (stackObject instanceof StackAbility)) { - Targets objectTargets = stackObject.getStackAbility().getTargets(); - if(!objectTargets.isEmpty()) { - for (Target target : objectTargets) { - for (UUID targetId : target.getTargets()) { - Permanent targetedPermanent = game.getPermanentOrLKIBattlefield(targetId); - if (targetedPermanent != null && targetedPermanent.getControllerId().equals(sourceControllerId)) { - possibleTargets.add(stackObject.getId()); - } - } - } - } - } - } - return possibleTargets; - } - - @Override - public TargetStackObjectTargetingControlledPermanent copy() { - return new TargetStackObjectTargetingControlledPermanent(this); - } - -} - class NotOfThisWorldCondition implements Condition { private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("creature you control with power 7 or greater"); diff --git a/Mage.Sets/src/mage/sets/scarsofmirrodin/TurnAside.java b/Mage.Sets/src/mage/sets/scarsofmirrodin/TurnAside.java index f6f9cb5c4c9..a878638f92d 100644 --- a/Mage.Sets/src/mage/sets/scarsofmirrodin/TurnAside.java +++ b/Mage.Sets/src/mage/sets/scarsofmirrodin/TurnAside.java @@ -28,40 +28,35 @@ package mage.sets.scarsofmirrodin; -import mage.constants.CardType; -import mage.constants.Rarity; -import mage.abilities.Ability; +import java.util.UUID; import mage.abilities.effects.common.CounterTargetEffect; import mage.cards.CardImpl; -import mage.constants.Zone; -import mage.filter.Filter; +import mage.constants.CardType; +import mage.constants.Rarity; import mage.filter.FilterSpell; -import mage.game.Game; -import mage.game.permanent.Permanent; -import mage.game.stack.Spell; -import mage.game.stack.StackObject; -import mage.target.TargetObject; +import mage.filter.common.FilterControlledPermanent; +import mage.filter.predicate.other.TargetsPermanentPredicate; +import mage.target.TargetSpell; -import java.util.HashSet; -import java.util.Set; -import java.util.UUID; -import mage.target.Target; /** * @author ayratn */ public class TurnAside extends CardImpl { - private static FilterSpell filter = new FilterSpell("spell that targets a permanent you control"); + private final static FilterSpell filter = new FilterSpell("spell that targets a permanent you control"); + + static { + filter.add(new TargetsPermanentPredicate(new FilterControlledPermanent())); + } public TurnAside(UUID ownerId) { super(ownerId, 49, "Turn Aside", Rarity.COMMON, new CardType[]{CardType.INSTANT}, "{U}"); this.expansionSetCode = "SOM"; - // Counter target spell that targets a permanent you control. this.getSpellAbility().addEffect(new CounterTargetEffect()); - this.getSpellAbility().addTarget(new CustomTargetSpell(filter)); + this.getSpellAbility().addTarget(new TargetSpell(filter)); } public TurnAside(final TurnAside card) { @@ -72,109 +67,4 @@ public class TurnAside extends CardImpl { public TurnAside copy() { return new TurnAside(this); } - - private class CustomTargetSpell extends TargetObject { - - protected FilterSpell filter; - - public CustomTargetSpell() { - this(1, 1, new FilterSpell()); - } - - public CustomTargetSpell(FilterSpell filter) { - this(1, 1, filter); - } - - public CustomTargetSpell(int numTargets, FilterSpell filter) { - this(numTargets, numTargets, filter); - } - - public CustomTargetSpell(int minNumTargets, int maxNumTargets, FilterSpell filter) { - this.minNumberOfTargets = minNumTargets; - this.maxNumberOfTargets = maxNumTargets; - this.zone = Zone.STACK; - this.filter = filter; - this.targetName = filter.getMessage(); - } - - public CustomTargetSpell(final CustomTargetSpell target) { - super(target); - this.filter = target.filter.copy(); - } - - @Override - public boolean canChoose(UUID sourceId, UUID sourceControllerId, Game game) { - return canChoose(sourceControllerId, game); - } - - @Override - public Set possibleTargets(UUID sourceId, UUID sourceControllerId, Game game) { - return possibleTargets(sourceControllerId, game); - } - - @Override - public boolean canTarget(UUID id, Ability source, Game game) { - if (super.canTarget(id, source, game)) { - if (targetsMyPermanent(id, source.getControllerId(), game)) { - return true; - } - } - return false; - } - - @Override - public boolean canChoose(UUID sourceControllerId, Game game) { - int count = 0; - for (StackObject stackObject : game.getStack()) { - if (stackObject instanceof Spell && game.getPlayer(sourceControllerId).getInRange().contains(stackObject.getControllerId()) && filter.match((Spell) stackObject, game)) { - if (targetsMyPermanent(stackObject.getId(), sourceControllerId, game)) { - count++; - if (count >= this.minNumberOfTargets) - return true; - } - } - } - return false; - } - - @Override - public Set possibleTargets(UUID sourceControllerId, Game game) { - Set possibleTargets = new HashSet(); - for (StackObject stackObject : game.getStack()) { - if (stackObject instanceof Spell && game.getPlayer(sourceControllerId).getInRange().contains(stackObject.getControllerId()) && filter.match((Spell) stackObject, game)) { - if (targetsMyPermanent(stackObject.getId(), sourceControllerId, game)) { - - possibleTargets.add(stackObject.getId()); - } - } - } - return possibleTargets; - } - - @Override - public Filter getFilter() { - return filter; - } - - private boolean targetsMyPermanent(UUID id, UUID controllerId, Game game) { - StackObject spell = game.getStack().getStackObject(id); - if (spell != null) { - Ability ability = spell.getStackAbility(); - for (Target target : ability.getTargets()) { - for (UUID permanentId : target.getTargets()) { - Permanent permanent = game.getPermanent(permanentId); - if (permanent != null && permanent.getControllerId().equals(controllerId)) { - return true; - } - } - } - } - return false; - } - - @Override - public CustomTargetSpell copy() { - return new CustomTargetSpell(this); - } - } } diff --git a/Mage.Sets/src/mage/sets/torment/HydromorphGuardian.java b/Mage.Sets/src/mage/sets/torment/HydromorphGuardian.java index 261fc1c2e34..0eaaf30cd1f 100644 --- a/Mage.Sets/src/mage/sets/torment/HydromorphGuardian.java +++ b/Mage.Sets/src/mage/sets/torment/HydromorphGuardian.java @@ -29,9 +29,7 @@ package mage.sets.torment; import java.util.UUID; import mage.MageInt; -import mage.MageObject; import mage.abilities.Ability; -import mage.abilities.Mode; import mage.abilities.common.SimpleActivatedAbility; import mage.abilities.costs.common.SacrificeSourceCost; import mage.abilities.costs.mana.ColoredManaCost; @@ -42,12 +40,8 @@ import mage.constants.ColoredManaSymbol; import mage.constants.Rarity; import mage.constants.Zone; import mage.filter.FilterSpell; -import mage.filter.predicate.ObjectSourcePlayer; -import mage.filter.predicate.ObjectSourcePlayerPredicate; -import mage.game.Game; -import mage.game.permanent.Permanent; -import mage.game.stack.Spell; -import mage.target.Target; +import mage.filter.common.FilterControlledCreaturePermanent; +import mage.filter.predicate.other.TargetsPermanentPredicate; import mage.target.TargetSpell; /** @@ -59,7 +53,7 @@ public class HydromorphGuardian extends CardImpl { private final static FilterSpell filter = new FilterSpell("spell that targets one or more creatures you control"); static { - filter.add(new HydromorphGuardianPredicate()); + filter.add(new TargetsPermanentPredicate(new FilterControlledCreaturePermanent())); } public HydromorphGuardian(UUID ownerId) { @@ -85,31 +79,3 @@ public class HydromorphGuardian extends CardImpl { return new HydromorphGuardian(this); } } - -class HydromorphGuardianPredicate implements ObjectSourcePlayerPredicate> { - - @Override - public boolean apply(ObjectSourcePlayer input, Game game) { - Spell spell = game.getStack().getSpell(input.getObject().getId()); - if (spell != null) { - for (UUID modeId : spell.getSpellAbility().getModes().getSelectedModes()) { - Mode mode = spell.getSpellAbility().getModes().get(modeId); - for (Target target : mode.getTargets()) { - for (UUID targetId : target.getTargets()) { - Permanent permanent = game.getPermanent(targetId); - if (permanent.getCardType().contains(CardType.CREATURE) - && permanent.getControllerId().equals(input.getPlayerId())) { - return true; - } - } - } - } - } - return false; - } - - @Override - public String toString() { - return "that targets one or more creatures you control"; - } -} diff --git a/Mage.Sets/src/mage/sets/torment/HydromorphGull.java b/Mage.Sets/src/mage/sets/torment/HydromorphGull.java new file mode 100644 index 00000000000..c427837724d --- /dev/null +++ b/Mage.Sets/src/mage/sets/torment/HydromorphGull.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.torment; + +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.costs.mana.ColoredManaCost; +import mage.abilities.effects.common.CounterTargetEffect; +import mage.abilities.keyword.FlyingAbility; +import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.ColoredManaSymbol; +import mage.constants.Rarity; +import mage.constants.Zone; +import mage.filter.FilterSpell; +import mage.filter.common.FilterControlledCreaturePermanent; +import mage.filter.predicate.other.TargetsPermanentPredicate; +import mage.target.TargetSpell; + +/** + * + * @author LoneFox + */ +public class HydromorphGull extends CardImpl { + + private final static FilterSpell filter = new FilterSpell("spell that targets one or more creatures you control"); + + static { + filter.add(new TargetsPermanentPredicate(new FilterControlledCreaturePermanent())); + } + + public HydromorphGull(UUID ownerId) { + super(ownerId, 40, "Hydromorph Gull", Rarity.UNCOMMON, new CardType[]{CardType.CREATURE}, "{3}{U}{U}"); + this.expansionSetCode = "TOR"; + this.subtype.add("Elemental"); + this.subtype.add("Bird"); + this.power = new MageInt(3); + this.toughness = new MageInt(3); + + // Flying + this.addAbility(FlyingAbility.getInstance()); + // {U}, Sacrifice Hydromorph Gull: Counter target spell that targets one or more creatures you control. + Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new CounterTargetEffect(), new ColoredManaCost(ColoredManaSymbol.U)); + ability.addCost(new SacrificeSourceCost()); + ability.addTarget(new TargetSpell(filter)); + this.addAbility(ability); + } + + public HydromorphGull(final HydromorphGull card) { + super(card); + } + + @Override + public HydromorphGull copy() { + return new HydromorphGull(this); + } +} diff --git a/Mage.Sets/src/mage/sets/urzaslegacy/Intervene.java b/Mage.Sets/src/mage/sets/urzaslegacy/Intervene.java index 2713856744f..aa35fd116bd 100644 --- a/Mage.Sets/src/mage/sets/urzaslegacy/Intervene.java +++ b/Mage.Sets/src/mage/sets/urzaslegacy/Intervene.java @@ -27,24 +27,15 @@ */ package mage.sets.urzaslegacy; -import java.util.HashSet; -import java.util.Set; import java.util.UUID; - -import mage.constants.CardType; -import mage.constants.Rarity; -import mage.abilities.Ability; import mage.abilities.effects.common.CounterTargetEffect; import mage.cards.CardImpl; -import mage.constants.Zone; -import mage.filter.Filter; +import mage.constants.CardType; +import mage.constants.Rarity; import mage.filter.FilterSpell; -import mage.game.Game; -import mage.game.permanent.Permanent; -import mage.game.stack.Spell; -import mage.game.stack.StackObject; -import mage.target.Target; -import mage.target.TargetObject; +import mage.filter.common.FilterCreaturePermanent; +import mage.filter.predicate.other.TargetsPermanentPredicate; +import mage.target.TargetSpell; /** * @@ -52,13 +43,19 @@ import mage.target.TargetObject; */ public class Intervene extends CardImpl { + private final static FilterSpell filter = new FilterSpell("spell that targets a creature"); + + static { + filter.add(new TargetsPermanentPredicate(new FilterCreaturePermanent())); + } + public Intervene(UUID ownerId) { super(ownerId, 33, "Intervene", Rarity.COMMON, new CardType[]{CardType.INSTANT}, "{U}"); this.expansionSetCode = "ULG"; // Counter target spell that targets a creature. - this.getSpellAbility().addTarget(new InterveneTargetSpell()); + this.getSpellAbility().addTarget(new TargetSpell(filter)); this.getSpellAbility().addEffect(new CounterTargetEffect()); } @@ -70,93 +67,4 @@ public class Intervene extends CardImpl { public Intervene copy() { return new Intervene(this); } - - private class InterveneTargetSpell extends TargetObject { - - - public InterveneTargetSpell() { - super(1, Zone.STACK); - this.targetName = "spell that targets a creature"; - } - - public InterveneTargetSpell(final InterveneTargetSpell target) { - super(target); - } - - @Override - public boolean canChoose(UUID sourceId, UUID sourceControllerId, Game game) { - return canChoose(sourceControllerId, game); - } - - @Override - public Set possibleTargets(UUID sourceId, UUID sourceControllerId, Game game) { - return possibleTargets(sourceControllerId, game); - } - - @Override - public boolean canTarget(UUID id, Ability source, Game game) { - if (super.canTarget(id, source, game)) { - if (targetsCreature(id, game)) { - return true; - } - } - return false; - } - - @Override - public boolean canChoose(UUID sourceControllerId, Game game) { - for (StackObject stackObject : game.getStack()) { - if (stackObject instanceof Spell) { - if (targetsCreature(stackObject.getId(), game)) { - return true; - } - } - } - return false; - } - - @Override - public Set possibleTargets(UUID sourceControllerId, Game game) { - Set possibleTargets = new HashSet(); - for (StackObject stackObject : game.getStack()) { - if (stackObject instanceof Spell) { - if (targetsCreature(stackObject.getId(), game)) { - possibleTargets.add(stackObject.getId()); - } - } - } - return possibleTargets; - } - - - private boolean targetsCreature(UUID id, Game game) { - StackObject spell = game.getStack().getStackObject(id); - if (spell != null) { - Ability ability = spell.getStackAbility(); - if (ability != null && !ability.getTargets().isEmpty()) { - for (Target target : ability.getTargets()) { - for (UUID targetId : target.getTargets()) { - Permanent permanent = game.getPermanent(targetId); - if (permanent != null && permanent.getCardType().contains(CardType.CREATURE)) { - return true; - } - } - } - } - } - return false; - } - - @Override - public InterveneTargetSpell copy() { - return new InterveneTargetSpell(this); - } - - @Override - public Filter getFilter() { - return new FilterSpell(); - } - } } - - diff --git a/Mage/src/mage/filter/predicate/other/TargetsPermanentPredicate.java b/Mage/src/mage/filter/predicate/other/TargetsPermanentPredicate.java new file mode 100644 index 00000000000..0cf864bbc42 --- /dev/null +++ b/Mage/src/mage/filter/predicate/other/TargetsPermanentPredicate.java @@ -0,0 +1,76 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.filter.predicate.other; + +import java.util.UUID; +import mage.MageObject; +import mage.abilities.Mode; +import mage.filter.FilterPermanent; +import mage.filter.predicate.ObjectSourcePlayer; +import mage.filter.predicate.ObjectSourcePlayerPredicate; +import mage.game.Game; +import mage.game.permanent.Permanent; +import mage.game.stack.StackObject; +import mage.target.Target; + +/** + * + * @author LoneFox + */ +public class TargetsPermanentPredicate implements ObjectSourcePlayerPredicate> { + + private final FilterPermanent targetFilter; + + public TargetsPermanentPredicate(FilterPermanent targetFilter) { + this.targetFilter = targetFilter; + } + + @Override + public boolean apply(ObjectSourcePlayer input, Game game) { + StackObject object = game.getStack().getStackObject(input.getObject().getId()); + if(object != null) { + for(UUID modeId : object.getStackAbility().getModes().getSelectedModes()) { + Mode mode = object.getStackAbility().getModes().get(modeId); + for(Target target : mode.getTargets()) { + for(UUID targetId : target.getTargets()) { + Permanent permanent = game.getPermanentOrLKIBattlefield(targetId); + if(permanent != null) { + return targetFilter.match(permanent, input.getSourceId(), input.getPlayerId(), game); + } + } + } + } + } + return false; + } + + @Override + public String toString() { + return "that targets " + targetFilter.getMessage(); + } +} From f801477ab5ab8fec98e64d5f144db4ae88b991af Mon Sep 17 00:00:00 2001 From: LoneFox Date: Wed, 14 Oct 2015 22:58:43 +0300 Subject: [PATCH 146/268] Fix TargetStackObject not handling some predicate types correctly. Implement card to test it: Diplomatic Escort --- .../mercadianmasques/DiplomaticEscort.java | 83 +++++++++++++++++++ Mage/src/mage/target/TargetStackObject.java | 32 +++---- 2 files changed, 99 insertions(+), 16 deletions(-) create mode 100644 Mage.Sets/src/mage/sets/mercadianmasques/DiplomaticEscort.java diff --git a/Mage.Sets/src/mage/sets/mercadianmasques/DiplomaticEscort.java b/Mage.Sets/src/mage/sets/mercadianmasques/DiplomaticEscort.java new file mode 100644 index 00000000000..0abf5537b9e --- /dev/null +++ b/Mage.Sets/src/mage/sets/mercadianmasques/DiplomaticEscort.java @@ -0,0 +1,83 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.sets.mercadianmasques; + +import java.util.UUID; +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.costs.common.DiscardCardCost; +import mage.abilities.costs.common.TapSourceCost; +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.effects.common.CounterTargetEffect; +import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.Rarity; +import mage.constants.Zone; +import mage.filter.FilterStackObject; +import mage.filter.common.FilterCreaturePermanent; +import mage.filter.predicate.other.TargetsPermanentPredicate; +import mage.target.TargetStackObject; + +/** + * + * @author LoneFox + */ +public class DiplomaticEscort extends CardImpl { + + private final static FilterStackObject filter = new FilterStackObject("spell or ability that targets a creature"); + + static { + filter.add(new TargetsPermanentPredicate(new FilterCreaturePermanent())); + } + + public DiplomaticEscort(UUID ownerId) { + super(ownerId, 74, "Diplomatic Escort", Rarity.UNCOMMON, new CardType[]{CardType.CREATURE}, "{1}{U}"); + this.expansionSetCode = "MMQ"; + this.subtype.add("Human"); + this.subtype.add("Spellshaper"); + this.power = new MageInt(1); + this.toughness = new MageInt(1); + + // {U}, {tap}, Discard a card: Counter target spell or ability that targets a creature. + Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new CounterTargetEffect(), new ManaCostsImpl("{U}")); + ability.addCost(new TapSourceCost()); + ability.addCost(new DiscardCardCost()); + ability.addTarget(new TargetStackObject(filter)); + this.addAbility(ability); + } + + public DiplomaticEscort(final DiplomaticEscort card) { + super(card); + } + + @Override + public DiplomaticEscort copy() { + return new DiplomaticEscort(this); + } +} diff --git a/Mage/src/mage/target/TargetStackObject.java b/Mage/src/mage/target/TargetStackObject.java index 0a8e91a4e9a..467565ee72d 100644 --- a/Mage/src/mage/target/TargetStackObject.java +++ b/Mage/src/mage/target/TargetStackObject.java @@ -1,16 +1,16 @@ /* * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. - * + * * Redistribution and use in source and binary forms, with or without modification, are * permitted provided that the following conditions are met: - * + * * 1. Redistributions of source code must retain the above copyright notice, this list of * conditions and the following disclaimer. - * + * * 2. Redistributions in binary form must reproduce the above copyright notice, this list * of conditions and the following disclaimer in the documentation and/or other materials * provided with the distribution. - * + * * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR @@ -20,7 +20,7 @@ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * + * * The views and conclusions contained in the software and documentation are those of the * authors and should not be interpreted as representing official policies, either expressed * or implied, of BetaSteward_at_googlemail.com. @@ -80,21 +80,16 @@ public class TargetStackObject extends TargetObject { public boolean canTarget(UUID id, Ability source, Game game) { StackObject stackObject = game.getStack().getStackObject(id); if (stackObject != null) { - return filter.match(stackObject, game); + return filter.match(stackObject, source.getSourceId(), source.getControllerId(), game); } return false; } @Override public boolean canChoose(UUID sourceId, UUID sourceControllerId, Game game) { - return canChoose(sourceControllerId, game); - } - - @Override - public boolean canChoose(UUID sourceControllerId, Game game) { int count = 0; for (StackObject stackObject: game.getStack()) { - if (game.getPlayer(sourceControllerId).getInRange().contains(stackObject.getControllerId()) && filter.match(stackObject, game)) { + if (game.getPlayer(sourceControllerId).getInRange().contains(stackObject.getControllerId()) && filter.match(stackObject, sourceId, sourceControllerId, game)) { count++; if (count >= this.minNumberOfTargets) { return true; @@ -105,21 +100,26 @@ public class TargetStackObject extends TargetObject { } @Override - public Set possibleTargets(UUID sourceId, UUID sourceControllerId, Game game) { - return possibleTargets(sourceControllerId, game); + public boolean canChoose(UUID sourceControllerId, Game game) { + return canChoose(null, sourceControllerId, game); } @Override - public Set possibleTargets(UUID sourceControllerId, Game game) { + public Set possibleTargets(UUID sourceId, UUID sourceControllerId, Game game) { Set possibleTargets = new HashSet<>(); for (StackObject stackObject: game.getStack()) { - if (game.getPlayer(sourceControllerId).getInRange().contains(stackObject.getControllerId()) && filter.match(stackObject, game)) { + if (game.getPlayer(sourceControllerId).getInRange().contains(stackObject.getControllerId()) && filter.match(stackObject, sourceId, sourceControllerId, game)) { possibleTargets.add(stackObject.getId()); } } return possibleTargets; } + @Override + public Set possibleTargets(UUID sourceControllerId, Game game) { + return this.possibleTargets(null, sourceControllerId, game); + } + @Override public TargetStackObject copy() { return new TargetStackObject(this); From 7cee34be546ab123d73f12b9585b1bfce76211d7 Mon Sep 17 00:00:00 2001 From: LevelX2 Date: Thu, 15 Oct 2015 08:32:58 +0200 Subject: [PATCH 147/268] * Some changed to card moving (not finished) --- .../avacynrestored/InfiniteReflection.java | 5 +- .../sets/timespiral/ScionOfTheUrDragon.java | 12 +-- .../cards/copy/InfiniteReflectionTest.java | 69 ++++++++++++++ .../org/mage/test/cards/copy/VesuvaTest.java | 22 ++--- .../java/org/mage/test/player/TestPlayer.java | 5 + .../common/AsEntersBattlefieldAbility.java | 7 +- .../abilities/effects/ContinuousEffects.java | 4 +- .../effects/EntersBattlefieldEffect.java | 6 +- .../effects/common/ChooseColorEffect.java | 9 +- .../abilities/effects/common/CopyEffect.java | 91 ++++++++++--------- ...romGraveyardToBattlefieldTargetEffect.java | 2 +- .../counter/AddCountersSourceEffect.java | 27 +++--- Mage/src/mage/game/stack/Spell.java | 5 + Mage/src/mage/players/Player.java | 3 + Mage/src/mage/players/PlayerImpl.java | 39 ++++---- 15 files changed, 202 insertions(+), 104 deletions(-) create mode 100644 Mage.Tests/src/test/java/org/mage/test/cards/copy/InfiniteReflectionTest.java diff --git a/Mage.Sets/src/mage/sets/avacynrestored/InfiniteReflection.java b/Mage.Sets/src/mage/sets/avacynrestored/InfiniteReflection.java index 1744100e918..e2b81f4ec57 100644 --- a/Mage.Sets/src/mage/sets/avacynrestored/InfiniteReflection.java +++ b/Mage.Sets/src/mage/sets/avacynrestored/InfiniteReflection.java @@ -46,6 +46,7 @@ import mage.constants.Zone; import mage.filter.FilterPermanent; import mage.filter.common.FilterControlledCreaturePermanent; import mage.game.Game; +import mage.game.events.EntersTheBattlefieldEvent; import mage.game.events.GameEvent; import mage.game.permanent.Permanent; import mage.game.permanent.PermanentToken; @@ -141,7 +142,7 @@ class InfiniteReflectionEntersBattlefieldEffect extends ReplacementEffectImpl { @Override public boolean applies(GameEvent event, Ability source, Game game) { - Permanent permanent = game.getPermanent(event.getTargetId()); + Permanent permanent = ((EntersTheBattlefieldEvent) event).getTarget(); return permanent != null && permanent.getControllerId().equals(source.getControllerId()) && permanent.getCardType().contains(CardType.CREATURE) && !(permanent instanceof PermanentToken); @@ -149,7 +150,7 @@ class InfiniteReflectionEntersBattlefieldEffect extends ReplacementEffectImpl { @Override public boolean replaceEvent(GameEvent event, Ability source, Game game) { - MageObject toCopyToObject = game.getObject(event.getTargetId()); + MageObject toCopyToObject = ((EntersTheBattlefieldEvent) event).getTarget(); Permanent sourcePermanent = game.getPermanent(source.getSourceId()); if (sourcePermanent != null && toCopyToObject != null && sourcePermanent.getAttachedTo() != null) { Permanent toCopyFromPermanent = game.getPermanent(sourcePermanent.getAttachedTo()); diff --git a/Mage.Sets/src/mage/sets/timespiral/ScionOfTheUrDragon.java b/Mage.Sets/src/mage/sets/timespiral/ScionOfTheUrDragon.java index 3112e6b86b7..1a3700f00b2 100644 --- a/Mage.Sets/src/mage/sets/timespiral/ScionOfTheUrDragon.java +++ b/Mage.Sets/src/mage/sets/timespiral/ScionOfTheUrDragon.java @@ -53,7 +53,6 @@ import mage.target.common.TargetCardInLibrary; /** * @author duncant */ - public class ScionOfTheUrDragon extends CardImpl { public ScionOfTheUrDragon(UUID ownerId) { @@ -69,8 +68,8 @@ public class ScionOfTheUrDragon extends CardImpl { // {2}: Search your library for a Dragon permanent card and put it into your graveyard. If you do, Scion of the Ur-Dragon becomes a copy of that card until end of turn. Then shuffle your library. this.addAbility(new SimpleActivatedAbility(Zone.BATTLEFIELD, - new ScionOfTheUrDragonEffect(), - new ManaCostsImpl("{2}"))); + new ScionOfTheUrDragonEffect(), + new ManaCostsImpl("{2}"))); } public ScionOfTheUrDragon(final ScionOfTheUrDragon card) { @@ -84,15 +83,16 @@ public class ScionOfTheUrDragon extends CardImpl { } class ScionOfTheUrDragonEffect extends SearchEffect { + private static final FilterCard filter = new FilterPermanentCard("Dragon permanent card"); - + static { filter.add(new SubtypePredicate("Dragon")); } - + public ScionOfTheUrDragonEffect() { super(new TargetCardInLibrary(filter), Outcome.Copy); - staticText = "Search your library for a Dragon permanent card and put it into your graveyard. If you do, Scion of the Ur-Dragon becomes a copy of that card until end of turn. Then shuffle your library."; + staticText = "Search your library for a Dragon permanent card and put it into your graveyard. If you do, {this} becomes a copy of that card until end of turn. Then shuffle your library."; } ScionOfTheUrDragonEffect(final ScionOfTheUrDragonEffect effect) { diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/copy/InfiniteReflectionTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/copy/InfiniteReflectionTest.java new file mode 100644 index 00000000000..c60f7e912b9 --- /dev/null +++ b/Mage.Tests/src/test/java/org/mage/test/cards/copy/InfiniteReflectionTest.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 org.mage.test.cards.copy; + +import mage.constants.PhaseStep; +import mage.constants.Zone; +import org.junit.Test; +import org.mage.test.serverside.base.CardTestPlayerBase; + +/** + * + * @author LevelX2 + */ +public class InfiniteReflectionTest extends CardTestPlayerBase { + + /** + * + */ + @Test + public void testCopyAsEnters() { + addCard(Zone.BATTLEFIELD, playerA, "Island", 1); + addCard(Zone.BATTLEFIELD, playerA, "Swamp", 9); + addCard(Zone.BATTLEFIELD, playerA, "Silvercoat Lion", 1); +// addCard(Zone.BATTLEFIELD, playerA, "Birds of Paradise", 1); +// addCard(Zone.HAND, playerA, "Nantuko Husk", 1);// {2}{B} + addCard(Zone.GRAVEYARD, playerA, "Pillarfield Ox", 1); + // Put target creature card from a graveyard onto the battlefield under your control. You lose life equal to its converted mana cost. + addCard(Zone.HAND, playerA, "Reanimate", 1); // {B} + + // Enchant creature + // When Infinite Reflection enters the battlefield attached to a creature, each other nontoken creature you control becomes a copy of that creature. + // Nontoken creatures you control enter the battlefield as a copy of enchanted creature. + addCard(Zone.HAND, playerA, "Infinite Reflection", 1); // {5}{U} + + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Infinite Reflection", "Silvercoat Lion"); +// castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Nantuko Husk"); + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Reanimate", "Pillarfield Ox"); + setStopAt(1, PhaseStep.BEGIN_COMBAT); + execute(); + + assertPermanentCount(playerA, "Silvercoat Lion", 2); + } + +} diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/copy/VesuvaTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/copy/VesuvaTest.java index 601be2d21f4..48fc3962b1f 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/copy/VesuvaTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/copy/VesuvaTest.java @@ -60,12 +60,11 @@ public class VesuvaTest extends CardTestPlayerBase { addCard(Zone.HAND, playerB, "Glimmerpost", 1); - playLand(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Glimmerpost"); playLand(2, PhaseStep.PRECOMBAT_MAIN, playerB, "Glimmerpost"); playLand(3, PhaseStep.PRECOMBAT_MAIN, playerA, "Vesuva"); setChoice(playerA, "Glimmerpost"); - + setStopAt(3, PhaseStep.BEGIN_COMBAT); execute(); @@ -75,31 +74,32 @@ public class VesuvaTest extends CardTestPlayerBase { assertLife(playerA, 24); // 20 + 1 + 3 assertLife(playerB, 22); // 20 + 2 } - + @Test public void testDarkDepth() { // Dark Depths enters the battlefield with ten ice counters on it. // {3}: Remove an ice counter from Dark Depths. // When Dark Depths has no ice counters on it, sacrifice it. If you do, put a legendary 20/20 black Avatar creature token with flying and "This creature is indestructible" named Marit Lage onto the battlefield. addCard(Zone.BATTLEFIELD, playerB, "Dark Depths", 1); - + // You may have Vesuva enter the battlefield tapped as a copy of any land on the battlefield. - addCard(Zone.HAND, playerA, "Vesuva", 1); - + addCard(Zone.HAND, playerA, "Vesuva", 1); + playLand(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Vesuva"); setChoice(playerA, "Dark Depths"); - + setStopAt(1, PhaseStep.BEGIN_COMBAT); execute(); - assertPermanentCount(playerA, "Dark Depths", 1); assertPermanentCount(playerB, "Dark Depths", 1); - + assertPermanentCount(playerA, "Vesuva", 0); + assertPermanentCount(playerA, "Dark Depths", 1); + Permanent darkDepth = getPermanent("Dark Depths", playerA); if (darkDepth != null) { - Assert.assertEquals(darkDepth.getCounters().getCount("ice"), 10); + Assert.assertEquals(10, darkDepth.getCounters().getCount("ice")); } - + assertTappedCount("Dark Depths", true, 1); } } diff --git a/Mage.Tests/src/test/java/org/mage/test/player/TestPlayer.java b/Mage.Tests/src/test/java/org/mage/test/player/TestPlayer.java index 55ebad8d17f..5d0df67f11a 100644 --- a/Mage.Tests/src/test/java/org/mage/test/player/TestPlayer.java +++ b/Mage.Tests/src/test/java/org/mage/test/player/TestPlayer.java @@ -1970,6 +1970,11 @@ public class TestPlayer implements Player { return computerPlayer.scry(value, source, game); } + @Override + public boolean moveCards(Card card, Zone toZone, Ability source, Game game, boolean tapped, boolean faceDown, boolean byOwner, ArrayList appliedEffects) { + return computerPlayer.moveCards(card, toZone, source, game, tapped, faceDown, byOwner, appliedEffects); + } + @Override public boolean moveCards(Set cards, Zone toZone, Ability source, Game game, boolean tapped, boolean faceDown, boolean byOwner, ArrayList appliedEffects) { return computerPlayer.moveCards(cards, toZone, source, game, tapped, faceDown, byOwner, appliedEffects); diff --git a/Mage/src/mage/abilities/common/AsEntersBattlefieldAbility.java b/Mage/src/mage/abilities/common/AsEntersBattlefieldAbility.java index e41774bf772..d6f0e0fea6a 100644 --- a/Mage/src/mage/abilities/common/AsEntersBattlefieldAbility.java +++ b/Mage/src/mage/abilities/common/AsEntersBattlefieldAbility.java @@ -39,11 +39,11 @@ import mage.constants.Zone; public class AsEntersBattlefieldAbility extends StaticAbility { public AsEntersBattlefieldAbility(Effect effect) { - super(Zone.BATTLEFIELD, new EntersBattlefieldEffect(effect)); + super(Zone.ALL, new EntersBattlefieldEffect(effect)); } public AsEntersBattlefieldAbility(Effect effect, String text) { - super(Zone.BATTLEFIELD, new EntersBattlefieldEffect(effect, text)); + super(Zone.ALL, new EntersBattlefieldEffect(effect, text)); } public AsEntersBattlefieldAbility(AsEntersBattlefieldAbility ability) { @@ -59,10 +59,9 @@ public class AsEntersBattlefieldAbility extends StaticAbility { return; } } - super.addEffect(effect); + super.addEffect(effect); } - @Override public AsEntersBattlefieldAbility copy() { return new AsEntersBattlefieldAbility(this); diff --git a/Mage/src/mage/abilities/effects/ContinuousEffects.java b/Mage/src/mage/abilities/effects/ContinuousEffects.java index de323f1202b..c5b4661816b 100644 --- a/Mage/src/mage/abilities/effects/ContinuousEffects.java +++ b/Mage/src/mage/abilities/effects/ContinuousEffects.java @@ -876,7 +876,9 @@ public class ContinuousEffects implements Serializable { } } // Must be called here for some effects to be able to work correctly - // TODO: add info which effects need that call + // For example: Vesuva copying a Dark Depth (VesuvaTest:testDarkDepth) + // This call should be removed if possible as replacement effects of EntersTheBattlefield events + // do no longer work correctly because the entering permanents are not yet on the battlefield (before they were). game.applyEffects(); } while (true); return caught; diff --git a/Mage/src/mage/abilities/effects/EntersBattlefieldEffect.java b/Mage/src/mage/abilities/effects/EntersBattlefieldEffect.java index 5a03cbcf339..ef6bb795d16 100644 --- a/Mage/src/mage/abilities/effects/EntersBattlefieldEffect.java +++ b/Mage/src/mage/abilities/effects/EntersBattlefieldEffect.java @@ -34,6 +34,7 @@ import mage.abilities.condition.Condition; import mage.constants.Duration; import mage.constants.Zone; import mage.game.Game; +import mage.game.events.EntersTheBattlefieldEvent; import mage.game.events.GameEvent; import mage.game.events.GameEvent.EventType; import mage.game.stack.Spell; @@ -51,6 +52,7 @@ public class EntersBattlefieldEffect extends ReplacementEffectImpl { protected Condition condition; protected boolean optional; + public static final String ENTERING_PERMANENT = "enteringPermanent"; public static final String SOURCE_CAST_SPELL_ABILITY = "sourceCastSpellAbility"; public EntersBattlefieldEffect(Effect baseEffect) { @@ -112,7 +114,7 @@ public class EntersBattlefieldEffect extends ReplacementEffectImpl { if (controller == null || object == null) { return false; } - if (!controller.chooseUse(outcome, new StringBuilder("Use effect of ").append(object.getLogName()).append("?").toString(), source, game)) { + if (!controller.chooseUse(outcome, "Use effect of " + object.getLogName() + "?", source, game)) { return false; } } @@ -131,6 +133,8 @@ public class EntersBattlefieldEffect extends ReplacementEffectImpl { if (spell != null) { effect.setValue(SOURCE_CAST_SPELL_ABILITY, spell.getSpellAbility()); } + // Because the permanent is not on the battlefield yet, it has to be taken from the event + effect.setValue(ENTERING_PERMANENT, ((EntersTheBattlefieldEvent) event).getTarget()); effect.apply(game, source); } } diff --git a/Mage/src/mage/abilities/effects/common/ChooseColorEffect.java b/Mage/src/mage/abilities/effects/common/ChooseColorEffect.java index 8f22a961ad7..43836dd2f74 100644 --- a/Mage/src/mage/abilities/effects/common/ChooseColorEffect.java +++ b/Mage/src/mage/abilities/effects/common/ChooseColorEffect.java @@ -25,10 +25,10 @@ * authors and should not be interpreted as representing official policies, either expressed * or implied, of BetaSteward_at_googlemail.com. */ - package mage.abilities.effects.common; import mage.abilities.Ability; +import mage.abilities.effects.EntersBattlefieldEffect; import mage.abilities.effects.OneShotEffect; import mage.choices.ChoiceColor; import mage.constants.Outcome; @@ -56,6 +56,9 @@ public class ChooseColorEffect extends OneShotEffect { public boolean apply(Game game, Ability source) { Player controller = game.getPlayer(source.getControllerId()); Permanent permanent = game.getPermanent(source.getSourceId()); + if (permanent == null) { + permanent = (Permanent) getValue(EntersBattlefieldEffect.ENTERING_PERMANENT); + } if (controller != null && permanent != null) { ChoiceColor choice = new ChoiceColor(); while (!choice.isChosen()) { @@ -65,7 +68,7 @@ public class ChooseColorEffect extends OneShotEffect { } } if (!game.isSimulation()) { - game.informPlayers(permanent.getLogName()+": "+controller.getLogName()+" has chosen "+choice.getChoice()); + game.informPlayers(permanent.getLogName() + ": " + controller.getLogName() + " has chosen " + choice.getChoice()); } game.getState().setValue(source.getSourceId() + "_color", choice.getColor()); permanent.addInfo("chosen color", CardUtil.addToolTipMarkTags("Chosen color: " + choice.getChoice()), game); @@ -79,4 +82,4 @@ public class ChooseColorEffect extends OneShotEffect { return new ChooseColorEffect(this); } -} \ No newline at end of file +} diff --git a/Mage/src/mage/abilities/effects/common/CopyEffect.java b/Mage/src/mage/abilities/effects/common/CopyEffect.java index 9d1194fda2a..86bc3f060fb 100644 --- a/Mage/src/mage/abilities/effects/common/CopyEffect.java +++ b/Mage/src/mage/abilities/effects/common/CopyEffect.java @@ -1,16 +1,16 @@ /* * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. - * + * * Redistribution and use in source and binary forms, with or without modification, are * permitted provided that the following conditions are met: - * + * * 1. Redistributions of source code must retain the above copyright notice, this list of * conditions and the following disclaimer. - * + * * 2. Redistributions in binary form must reproduce the above copyright notice, this list * of conditions and the following disclaimer in the documentation and/or other materials * provided with the distribution. - * + * * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR @@ -20,15 +20,13 @@ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * + * * The views and conclusions contained in the software and documentation are those of the * authors and should not be interpreted as representing official policies, either expressed * or implied, of BetaSteward_at_googlemail.com. */ - package mage.abilities.effects.common; - import java.util.UUID; import mage.MageObject; import mage.MageObjectReference; @@ -56,39 +54,42 @@ public class CopyEffect extends ContinuousEffectImpl { /** * Object we copy from */ - private MageObject target; - - private UUID sourceId; + private MageObject copyFromObject; + + private UUID copyToObjectId; private ApplyToPermanent applier; - - public CopyEffect(MageObject target, UUID sourceId) { - this(Duration.Custom, target, sourceId); + + public CopyEffect(MageObject copyFromObject, UUID copyToObjectId) { + this(Duration.Custom, copyFromObject, copyToObjectId); } - - public CopyEffect(Duration duration, MageObject target, UUID sourceId) { + + public CopyEffect(Duration duration, MageObject copyFromObject, UUID copyToObjectId) { super(duration, Layer.CopyEffects_1, SubLayer.NA, Outcome.BecomeCreature); - this.target = target; - this.sourceId = sourceId; + this.copyFromObject = copyFromObject; + this.copyToObjectId = copyToObjectId; } public CopyEffect(final CopyEffect effect) { super(effect); - this.target = effect.target.copy(); - this.sourceId = effect.sourceId; + this.copyFromObject = effect.copyFromObject.copy(); + this.copyToObjectId = effect.copyToObjectId; this.applier = effect.applier; } @Override public void init(Ability source, Game game) { super.init(source, game); - if (!(target instanceof Permanent) && (target instanceof Card)) { - this.target = new PermanentCard((Card)target, source.getControllerId(), game); + if (!(copyFromObject instanceof Permanent) && (copyFromObject instanceof Card)) { + this.copyFromObject = new PermanentCard((Card) copyFromObject, source.getControllerId(), game); } - affectedObjectList.add(new MageObjectReference(getSourceId(), game)); + } @Override public boolean apply(Game game, Ability source) { + if (affectedObjectList.isEmpty()) { + affectedObjectList.add(new MageObjectReference(getSourceId(), game)); + } Permanent permanent = affectedObjectList.get(0).getPermanent(game); if (permanent == null) { permanent = (Permanent) game.getLastKnownInformation(getSourceId(), Zone.BATTLEFIELD, source.getSourceObjectZoneChangeCounter()); @@ -99,31 +100,31 @@ public class CopyEffect extends ContinuousEffectImpl { } } permanent.setCopy(true); - permanent.setName(target.getName()); - permanent.getColor(game).setColor(target.getColor(game)); + permanent.setName(copyFromObject.getName()); + permanent.getColor(game).setColor(copyFromObject.getColor(game)); permanent.getManaCost().clear(); - permanent.getManaCost().add(target.getManaCost()); + permanent.getManaCost().add(copyFromObject.getManaCost()); permanent.getCardType().clear(); - for (CardType type: target.getCardType()) { + for (CardType type : copyFromObject.getCardType()) { permanent.getCardType().add(type); } permanent.getSubtype().clear(); - for (String type: target.getSubtype()) { + for (String type : copyFromObject.getSubtype()) { permanent.getSubtype().add(type); } permanent.getSupertype().clear(); - for (String type: target.getSupertype()) { + for (String type : copyFromObject.getSupertype()) { permanent.getSupertype().add(type); } permanent.removeAllAbilities(source.getSourceId(), game); - for (Ability ability: target.getAbilities()) { - permanent.addAbility(ability, getSourceId(), game, false); // no new Id so consumed replacement effects are known while new continuousEffects.apply happen. + for (Ability ability : copyFromObject.getAbilities()) { + permanent.addAbility(ability, getSourceId(), game, false); // no new Id so consumed replacement effects are known while new continuousEffects.apply happen. } - permanent.getPower().setValue(target.getPower().getValue()); - permanent.getToughness().setValue(target.getToughness().getValue()); - if (target instanceof Permanent) { - Permanent targetPermanent = (Permanent) target; + permanent.getPower().setValue(copyFromObject.getPower().getValue()); + permanent.getToughness().setValue(copyFromObject.getToughness().getValue()); + if (copyFromObject instanceof Permanent) { + Permanent targetPermanent = (Permanent) copyFromObject; permanent.setTransformed(targetPermanent.isTransformed()); permanent.setSecondCardFace(targetPermanent.getSecondCardFace()); permanent.setFlipCard(targetPermanent.isFlipCard()); @@ -131,13 +132,13 @@ public class CopyEffect extends ContinuousEffectImpl { } // to get the image of the copied permanent copy number und expansionCode - if (target instanceof PermanentCard) { - permanent.setCardNumber(((PermanentCard) target).getCard().getCardNumber()); - permanent.setExpansionSetCode(((PermanentCard) target).getCard().getExpansionSetCode()); - } else if (target instanceof PermanentToken || target instanceof Card) { - permanent.setCardNumber(((Card) target).getCardNumber()); - permanent.setExpansionSetCode(((Card) target).getExpansionSetCode()); - } + if (copyFromObject instanceof PermanentCard) { + permanent.setCardNumber(((PermanentCard) copyFromObject).getCard().getCardNumber()); + permanent.setExpansionSetCode(((PermanentCard) copyFromObject).getCard().getExpansionSetCode()); + } else if (copyFromObject instanceof PermanentToken || copyFromObject instanceof Card) { + permanent.setCardNumber(((Card) copyFromObject).getCardNumber()); + permanent.setExpansionSetCode(((Card) copyFromObject).getExpansionSetCode()); + } return true; } @@ -147,15 +148,15 @@ public class CopyEffect extends ContinuousEffectImpl { } public MageObject getTarget() { - return target; + return copyFromObject; } public void setTarget(MageObject target) { - this.target = target; + this.copyFromObject = target; } public UUID getSourceId() { - return sourceId; + return copyToObjectId; } public ApplyToPermanent getApplier() { @@ -165,5 +166,5 @@ public class CopyEffect extends ContinuousEffectImpl { public void setApplier(ApplyToPermanent applier) { this.applier = applier; } - + } diff --git a/Mage/src/mage/abilities/effects/common/ReturnFromGraveyardToBattlefieldTargetEffect.java b/Mage/src/mage/abilities/effects/common/ReturnFromGraveyardToBattlefieldTargetEffect.java index da7960e7437..dd2e2797041 100644 --- a/Mage/src/mage/abilities/effects/common/ReturnFromGraveyardToBattlefieldTargetEffect.java +++ b/Mage/src/mage/abilities/effects/common/ReturnFromGraveyardToBattlefieldTargetEffect.java @@ -73,7 +73,7 @@ public class ReturnFromGraveyardToBattlefieldTargetEffect extends OneShotEffect for (UUID targetId : getTargetPointer().getTargets(game, source)) { Card card = game.getCard(targetId); if (card != null) { - controller.putOntoBattlefieldWithInfo(card, game, Zone.GRAVEYARD, source.getSourceId(), tapped); + controller.moveCards(card, Zone.BATTLEFIELD, source, game, tapped, false, false, null); } } return true; diff --git a/Mage/src/mage/abilities/effects/common/counter/AddCountersSourceEffect.java b/Mage/src/mage/abilities/effects/common/counter/AddCountersSourceEffect.java index 82c14c0cdb9..0633ff60c63 100644 --- a/Mage/src/mage/abilities/effects/common/counter/AddCountersSourceEffect.java +++ b/Mage/src/mage/abilities/effects/common/counter/AddCountersSourceEffect.java @@ -1,16 +1,16 @@ /* * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. - * + * * Redistribution and use in source and binary forms, with or without modification, are * permitted provided that the following conditions are met: - * + * * 1. Redistributions of source code must retain the above copyright notice, this list of * conditions and the following disclaimer. - * + * * 2. Redistributions in binary form must reproduce the above copyright notice, this list * of conditions and the following disclaimer in the documentation and/or other materials * provided with the distribution. - * + * * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR @@ -20,20 +20,20 @@ * 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.counter; -import mage.constants.Outcome; import mage.abilities.Ability; import mage.abilities.dynamicvalue.DynamicValue; import mage.abilities.dynamicvalue.common.StaticValue; +import mage.abilities.effects.EntersBattlefieldEffect; import mage.abilities.effects.OneShotEffect; import mage.cards.Card; +import mage.constants.Outcome; import mage.counters.Counter; import mage.game.Game; import mage.game.permanent.Permanent; @@ -63,11 +63,12 @@ public class AddCountersSourceEffect extends OneShotEffect { } /** - * + * * @param counter * @param amount this amount will be added to the counter instances * @param informPlayers - * @param putOnCard - counters have to be put on a card instead of a permanent + * @param putOnCard - counters have to be put on a card instead of a + * permanent */ public AddCountersSourceEffect(Counter counter, DynamicValue amount, boolean informPlayers, boolean putOnCard) { super(Outcome.Benefit); @@ -106,7 +107,7 @@ public class AddCountersSourceEffect extends OneShotEffect { if (informPlayers && !game.isSimulation()) { Player player = game.getPlayer(source.getControllerId()); if (player != null) { - game.informPlayers(new StringBuilder(player.getLogName()).append(" puts ").append(newCounter.getCount()).append(" ").append(newCounter.getName().toLowerCase()).append(" counter on ").append(card.getLogName()).toString()); + game.informPlayers(player.getLogName() + " puts " + newCounter.getCount() + " " + newCounter.getName().toLowerCase() + " counter on " + card.getLogName()); } } } @@ -114,6 +115,9 @@ public class AddCountersSourceEffect extends OneShotEffect { } } else { Permanent permanent = game.getPermanent(source.getSourceId()); + if (permanent == null) { + permanent = (Permanent) getValue(EntersBattlefieldEffect.ENTERING_PERMANENT); + } if (permanent != null) { if (counter != null) { Counter newCounter = counter.copy(); @@ -129,7 +133,7 @@ public class AddCountersSourceEffect extends OneShotEffect { int amountAdded = permanent.getCounters().getCount(newCounter.getName()) - before; Player player = game.getPlayer(source.getControllerId()); if (player != null) { - game.informPlayers(player.getLogName()+" puts "+amountAdded+" "+newCounter.getName().toLowerCase()+" counter on "+permanent.getLogName()); + game.informPlayers(player.getLogName() + " puts " + amountAdded + " " + newCounter.getName().toLowerCase() + " counter on " + permanent.getLogName()); } } } @@ -165,5 +169,4 @@ public class AddCountersSourceEffect extends OneShotEffect { return new AddCountersSourceEffect(this); } - } diff --git a/Mage/src/mage/game/stack/Spell.java b/Mage/src/mage/game/stack/Spell.java index 2972b65d2de..482bfb8451e 100644 --- a/Mage/src/mage/game/stack/Spell.java +++ b/Mage/src/mage/game/stack/Spell.java @@ -167,6 +167,10 @@ public class Spell extends StackObjImpl implements Card { @Override public boolean resolve(Game game) { boolean result; + Player controller = game.getPlayer(getControllerId()); + if (controller == null) { + return false; + } if (this.getCardType().contains(CardType.INSTANT) || this.getCardType().contains(CardType.SORCERY)) { int index = 0; result = false; @@ -261,6 +265,7 @@ public class Spell extends StackObjImpl implements Card { } } else { updateOptionalCosts(0); +// return controller.moveCards(card, Zone.BATTLEFIELD, ability, game, false, faceDown, false, null); result = card.putOntoBattlefield(game, Zone.STACK, ability.getSourceId(), controllerId, false, faceDown); return result; } diff --git a/Mage/src/mage/players/Player.java b/Mage/src/mage/players/Player.java index d00471867c3..b484fb8ccf9 100644 --- a/Mage/src/mage/players/Player.java +++ b/Mage/src/mage/players/Player.java @@ -635,6 +635,8 @@ public interface Player extends MageItem, Copyable { boolean moveCards(Set cards, Zone fromZone, Zone toZone, Ability source, Game game); + boolean moveCards(Card card, Zone toZone, Ability source, Game game, boolean tapped, boolean faceDown, boolean byOwner, ArrayList appliedEffects); + /** * * @param cards @@ -646,6 +648,7 @@ public interface Player extends MageItem, Copyable { * @param byOwner the card is moved (or put onto battlefield) by the owner * of the card and if target zone is battlefield controlls the permanent * (instead of the controller of the source) + * @param appliedEffects * @return */ boolean moveCards(Set cards, Zone toZone, Ability source, Game game, boolean tapped, boolean faceDown, boolean byOwner, ArrayList appliedEffects); diff --git a/Mage/src/mage/players/PlayerImpl.java b/Mage/src/mage/players/PlayerImpl.java index bb1250e1b5c..011d716acd2 100644 --- a/Mage/src/mage/players/PlayerImpl.java +++ b/Mage/src/mage/players/PlayerImpl.java @@ -1022,7 +1022,7 @@ public abstract class PlayerImpl implements Player, Serializable { game.fireEvent(GameEvent.getEvent(GameEvent.EventType.LAND_PLAYED, card.getId(), card.getId(), playerId)); game.fireInformEvent(getLogName() + " plays " + card.getLogName()); // game.removeBookmark(bookmark); - resetStoredBookmark(game); + resetStoredBookmark(game); // prevent undo after playing a land return true; } // putOntoBattlefield retured false if putOntoBattlefield was replaced by replacement effect (e.g. Kjeldorian Outpost). @@ -2998,22 +2998,6 @@ public abstract class PlayerImpl implements Player, Serializable { successfulMovedCards = moveCardsToGraveyardWithInfo(cards, source, game, fromZone); break; case HAND: - for (Card card : cards) { - fromZone = game.getState().getZone(card.getId()); -// if (fromZone == Zone.STACK) { -// // If a spell is returned to its owner's hand, it's removed from the stack and thus will not resolve -// Spell spell = game.getStack().getSpell(card.getId()); -// if (spell != null) { -// game.getStack().remove(spell); -// } -// } - boolean hideCard = fromZone.equals(Zone.LIBRARY) - || (card.isFaceDown(game) && !fromZone.equals(Zone.STACK) && !fromZone.equals(Zone.BATTLEFIELD)); - if (moveCardToHandWithInfo(card, source == null ? null : source.getSourceId(), game, !hideCard)) { - successfulMovedCards.add(card); - } - } - break; case BATTLEFIELD: return moveCards(cards, toZone, source, game, false, false, false, null); case LIBRARY: @@ -3032,6 +3016,15 @@ public abstract class PlayerImpl implements Player, Serializable { return successfulMovedCards.size() > 0; } + @Override + public boolean moveCards(Card card, Zone toZone, Ability source, Game game, boolean tapped, boolean faceDown, boolean byOwner, ArrayList appliedEffects) { + Set cardList = new HashSet<>(); + if (card != null) { + cardList.add(card); + } + return moveCards(cardList, toZone, source, game, tapped, faceDown, byOwner, appliedEffects); + } + @Override public boolean moveCards(Set cards, Zone toZone, Ability source, Game game, boolean tapped, boolean faceDown, boolean byOwner, ArrayList appliedEffects) { if (cards.isEmpty()) { @@ -3070,7 +3063,6 @@ public abstract class PlayerImpl implements Player, Serializable { } } game.setScopeRelevant(false); - game.applyEffects(); for (Permanent permanent : permanentsEntered) { fromZone = game.getState().getZone(permanent.getId()); if (((Card) permanent).removeFromZone(game, fromZone, source.getSourceId())) { @@ -3086,6 +3078,17 @@ public abstract class PlayerImpl implements Player, Serializable { game.addSimultaneousEvent(new ZoneChangeEvent(permanent, permanent.getControllerId(), fromZone, Zone.BATTLEFIELD)); } } + game.applyEffects(); + break; + case HAND: + for (Card card : cards) { + fromZone = game.getState().getZone(card.getId()); + boolean hideCard = fromZone.equals(Zone.LIBRARY) + || (card.isFaceDown(game) && !fromZone.equals(Zone.STACK) && !fromZone.equals(Zone.BATTLEFIELD)); + if (moveCardToHandWithInfo(card, source == null ? null : source.getSourceId(), game, !hideCard)) { + successfulMovedCards.add(card); + } + } break; default: throw new UnsupportedOperationException("to Zone not supported yet"); From b88884b4ab3682fe8486d636f66f1be60ff5e628 Mon Sep 17 00:00:00 2001 From: LoneFox Date: Thu, 15 Oct 2015 09:51:59 +0300 Subject: [PATCH 148/268] Fix compilation (But why did it work before? I tested it...) --- Mage.Sets/src/mage/sets/riseoftheeldrazi/NotOfThisWorld.java | 1 + 1 file changed, 1 insertion(+) diff --git a/Mage.Sets/src/mage/sets/riseoftheeldrazi/NotOfThisWorld.java b/Mage.Sets/src/mage/sets/riseoftheeldrazi/NotOfThisWorld.java index 1ee4a1ce987..97363cb0aa8 100644 --- a/Mage.Sets/src/mage/sets/riseoftheeldrazi/NotOfThisWorld.java +++ b/Mage.Sets/src/mage/sets/riseoftheeldrazi/NotOfThisWorld.java @@ -38,6 +38,7 @@ import mage.constants.CardType; import mage.constants.Rarity; import mage.constants.TargetController; import mage.constants.Zone; +import mage.filter.Filter; import mage.filter.FilterSpell; import mage.filter.common.FilterControlledPermanent; import mage.filter.common.FilterCreaturePermanent; From 4ec6164c86f04121057985389f3a80253c0cf59f Mon Sep 17 00:00:00 2001 From: LoneFox Date: Thu, 15 Oct 2015 09:53:24 +0300 Subject: [PATCH 149/268] Check all targets if necessary and not just the first one --- .../filter/predicate/other/TargetsPermanentPredicate.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Mage/src/mage/filter/predicate/other/TargetsPermanentPredicate.java b/Mage/src/mage/filter/predicate/other/TargetsPermanentPredicate.java index 0cf864bbc42..5471eae280c 100644 --- a/Mage/src/mage/filter/predicate/other/TargetsPermanentPredicate.java +++ b/Mage/src/mage/filter/predicate/other/TargetsPermanentPredicate.java @@ -59,8 +59,8 @@ public class TargetsPermanentPredicate implements ObjectSourcePlayerPredicate Date: Thu, 15 Oct 2015 09:28:02 +0200 Subject: [PATCH 150/268] Added Spoils of Evil --- .../src/mage/sets/iceage/SpoilsOfEvil.java | 105 ++++++++++++++++++ .../mage/sets/scourge/ForgottenAncient.java | 2 +- 2 files changed, 106 insertions(+), 1 deletion(-) create mode 100644 Mage.Sets/src/mage/sets/iceage/SpoilsOfEvil.java diff --git a/Mage.Sets/src/mage/sets/iceage/SpoilsOfEvil.java b/Mage.Sets/src/mage/sets/iceage/SpoilsOfEvil.java new file mode 100644 index 00000000000..731676b24a4 --- /dev/null +++ b/Mage.Sets/src/mage/sets/iceage/SpoilsOfEvil.java @@ -0,0 +1,105 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.sets.iceage; + +import java.util.UUID; +import mage.Mana; +import mage.abilities.Ability; +import mage.abilities.effects.OneShotEffect; +import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.Outcome; +import mage.constants.Rarity; +import mage.filter.FilterCard; +import mage.filter.predicate.Predicates; +import mage.filter.predicate.mageobject.CardTypePredicate; +import mage.game.Game; +import mage.players.Player; +import mage.target.common.TargetOpponent; + +/** + * + * @author Blinke + */ +public class SpoilsOfEvil extends CardImpl { + private static final FilterCard filter = new FilterCard("artifact or creature card in target opponents graveyard"); + static { + filter.add(Predicates.or( + new CardTypePredicate(CardType.ARTIFACT), + new CardTypePredicate(CardType.CREATURE))); + } + + public SpoilsOfEvil(UUID ownerId) { + super(ownerId, 51, "Spoils of Evil", Rarity.RARE, new CardType[]{CardType.INSTANT}, "{2}{B}"); + this.expansionSetCode = "ICE"; + + // For each artifact or creature card in target opponent's graveyard, add {1} to your mana pool and you gain 1 life. + this.getSpellAbility().addEffect(new SpoilsOfEvilEffect()); + this.getSpellAbility().addTarget(new TargetOpponent()); + } + + public SpoilsOfEvil(final SpoilsOfEvil card) { + super(card); + } + + @Override + public SpoilsOfEvil copy() { + return new SpoilsOfEvil(this); + } + + class SpoilsOfEvilEffect extends OneShotEffect { + + public SpoilsOfEvilEffect() { + super(Outcome.GainLife); + this.staticText = "For each artifact or creature card in target opponent's graveyard, add {1} to your mana pool and you gain 1 life."; + } + + public SpoilsOfEvilEffect(final SpoilsOfEvilEffect effect) { + super(effect); + } + + @Override + public SpoilsOfEvilEffect copy() { + return new SpoilsOfEvilEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player targetOpponent = game.getPlayer(targetPointer.getFirst(game, source)); + Player controller = game.getPlayer(source.getControllerId()); + + if(targetOpponent != null && controller != null) { + int cardCount = targetOpponent.getGraveyard().count(filter, game); + controller.gainLife(cardCount, game); + controller.getManaPool().addMana(Mana.ColorlessMana(cardCount), game, source); + return true; + } + return false; + } + } +} diff --git a/Mage.Sets/src/mage/sets/scourge/ForgottenAncient.java b/Mage.Sets/src/mage/sets/scourge/ForgottenAncient.java index 8107c48a39c..b6ad87f8e20 100644 --- a/Mage.Sets/src/mage/sets/scourge/ForgottenAncient.java +++ b/Mage.Sets/src/mage/sets/scourge/ForgottenAncient.java @@ -95,7 +95,7 @@ public class ForgottenAncient extends CardImpl { public ForgottenAncientEffect() { super(Outcome.Benefit); - this.staticText = "you may move any number of +1/+1 counters from Forgotten Ancient onto other creatures."; + this.staticText = "you may move any number of +1/+1 counters from {this} onto other creatures."; } public ForgottenAncientEffect(final ForgottenAncientEffect effect) { From a0e824134751b6c665dcd3e33339c9158438eb75 Mon Sep 17 00:00:00 2001 From: LevelX2 Date: Thu, 15 Oct 2015 17:19:34 +0200 Subject: [PATCH 151/268] Minor change. --- Mage/src/mage/abilities/common/DiesAttachedTriggeredAbility.java | 1 + 1 file changed, 1 insertion(+) diff --git a/Mage/src/mage/abilities/common/DiesAttachedTriggeredAbility.java b/Mage/src/mage/abilities/common/DiesAttachedTriggeredAbility.java index 70113a4564a..963df6092bc 100644 --- a/Mage/src/mage/abilities/common/DiesAttachedTriggeredAbility.java +++ b/Mage/src/mage/abilities/common/DiesAttachedTriggeredAbility.java @@ -60,6 +60,7 @@ public class DiesAttachedTriggeredAbility extends TriggeredAbilityImpl { // So check here with the LKI of the enchantment Permanent attachment = game.getPermanentOrLKIBattlefield(getSourceId()); if (attachment != null + && zEvent.getTargetId() != null && attachment.getAttachedTo() != null && zEvent.getTargetId().equals(attachment.getAttachedTo()) && attachment.getAttachedToZoneChangeCounter() == zEvent.getTarget().getZoneChangeCounter(game) - 1) { triggered = true; From 7274f9a8ac1782fb60825fb610c097a18bc27dee Mon Sep 17 00:00:00 2001 From: LevelX2 Date: Thu, 15 Oct 2015 21:56:03 +0200 Subject: [PATCH 152/268] Replaced some custom classes by ChooseCreatureTypeEffect. --- .../sets/avacynrestored/CavernOfSouls.java | 70 ++++--------------- .../sets/avacynrestored/RidersOfGavony.java | 63 ++++------------- .../mage/sets/magic2014/DoorOfDestinies.java | 47 +------------ .../src/mage/sets/magic2015/ObeliskOfUrd.java | 52 ++------------ .../src/mage/sets/newphyrexia/Xenograft.java | 58 +++------------ .../tempestremastered/VolrathsLaboratory.java | 15 ++-- 6 files changed, 50 insertions(+), 255 deletions(-) diff --git a/Mage.Sets/src/mage/sets/avacynrestored/CavernOfSouls.java b/Mage.Sets/src/mage/sets/avacynrestored/CavernOfSouls.java index 00e88453cb5..5ff7b12ef69 100644 --- a/Mage.Sets/src/mage/sets/avacynrestored/CavernOfSouls.java +++ b/Mage.Sets/src/mage/sets/avacynrestored/CavernOfSouls.java @@ -38,15 +38,12 @@ import mage.abilities.common.AsEntersBattlefieldAbility; import mage.abilities.common.SimpleStaticAbility; import mage.abilities.costs.common.TapSourceCost; import mage.abilities.effects.ContinuousRuleModifyingEffectImpl; -import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.ChooseCreatureTypeEffect; import mage.abilities.mana.ColorlessManaAbility; import mage.abilities.mana.ConditionalAnyColorManaAbility; import mage.abilities.mana.builder.ConditionalManaBuilder; import mage.abilities.mana.conditional.CreatureCastManaCondition; import mage.cards.CardImpl; -import mage.cards.repository.CardRepository; -import mage.choices.Choice; -import mage.choices.ChoiceImpl; import mage.constants.CardType; import mage.constants.Duration; import mage.constants.Outcome; @@ -55,10 +52,8 @@ import mage.constants.WatcherScope; import mage.constants.Zone; import mage.game.Game; import mage.game.events.GameEvent; -import mage.game.permanent.Permanent; import mage.game.stack.Spell; import mage.players.Player; -import mage.util.CardUtil; import mage.watchers.Watcher; /** @@ -67,14 +62,12 @@ import mage.watchers.Watcher; */ public class CavernOfSouls extends CardImpl { - private static final String ruleText = "choose a creature type"; - public CavernOfSouls(UUID ownerId) { super(ownerId, 226, "Cavern of Souls", Rarity.RARE, new CardType[]{CardType.LAND}, ""); this.expansionSetCode = "AVR"; // As Cavern of Souls enters the battlefield, choose a creature type. - this.addAbility(new AsEntersBattlefieldAbility(new CavernOfSoulsEffect(), ruleText)); + this.addAbility(new AsEntersBattlefieldAbility(new ChooseCreatureTypeEffect(Outcome.BoostCreature))); // {T}: Add {1} to your mana pool. this.addAbility(new ColorlessManaAbility()); @@ -82,7 +75,7 @@ public class CavernOfSouls extends CardImpl { // {T}: Add one mana of any color to your mana pool. Spend this mana only to cast a creature spell of the chosen type, and that spell can't be countered. Ability ability = new ConditionalAnyColorManaAbility(new TapSourceCost(), 1, new CavernOfSoulsManaBuilder(), true); this.addAbility(ability, new CavernOfSoulsWatcher(ability.getOriginalId())); - this.addAbility(new SimpleStaticAbility(Zone.ALL, new CavernOfSoulsCantCounterEffect())); + this.addAbility(new SimpleStaticAbility(Zone.ALL, new CavernOfSoulsCantCounterEffect())); } public CavernOfSouls(final CavernOfSouls card) { @@ -95,60 +88,23 @@ public class CavernOfSouls extends CardImpl { } } -class CavernOfSoulsEffect extends OneShotEffect { - - public CavernOfSoulsEffect() { - super(Outcome.Benefit); - staticText = "As {this} enters the battlefield, choose a creature type"; - } - - public CavernOfSoulsEffect(final CavernOfSoulsEffect effect) { - super(effect); - } - - @Override - public boolean apply(Game game, Ability source) { - Player player = game.getPlayer(source.getControllerId()); - Permanent permanent = game.getPermanent(source.getSourceId()); - if (player != null && permanent != null) { - Choice typeChoice = new ChoiceImpl(true); - typeChoice.setMessage("Choose creature type"); - typeChoice.setChoices(CardRepository.instance.getCreatureTypes()); - while (!player.choose(Outcome.Benefit, typeChoice, game)) { - if (!player.canRespond()) { - return false; - } - } - game.informPlayers(permanent.getName() + ": " + player.getLogName() + " has chosen " + typeChoice.getChoice()); - game.getState().setValue(permanent.getId() + "_type", typeChoice.getChoice()); - permanent.addInfo("chosen type", CardUtil.addToolTipMarkTags("Chosen type: " + typeChoice.getChoice()), game); - } - return false; - } - - @Override - public CavernOfSoulsEffect copy() { - return new CavernOfSoulsEffect(this); - } -} - class CavernOfSoulsManaBuilder extends ConditionalManaBuilder { String creatureType; - + @Override public ConditionalManaBuilder setMana(Mana mana, Ability source, Game game) { Object value = game.getState().getValue(source.getSourceId() + "_type"); if (value != null && value instanceof String) { creatureType = (String) value; - } + } Player controller = game.getPlayer(source.getControllerId()); MageObject sourceObject = game.getObject(source.getSourceId()); if (controller != null && sourceObject != null) { - game.informPlayers(controller.getLogName() + " produces " + mana.toString() + " with " + sourceObject.getLogName() + - " (can only be spend to cast for creatures of type " + creatureType + " and that spell can't be countered)"); - } - return super.setMana(mana, source, game); + game.informPlayers(controller.getLogName() + " produces " + mana.toString() + " with " + sourceObject.getLogName() + + " (can only be spend to cast for creatures of type " + creatureType + " and that spell can't be countered)"); + } + return super.setMana(mana, source, game); } @Override @@ -174,11 +130,11 @@ class CavernOfSoulsConditionalMana extends ConditionalMana { class CavernOfSoulsManaCondition extends CreatureCastManaCondition { String creatureType; - + CavernOfSoulsManaCondition(String creatureType) { this.creatureType = creatureType; } - + @Override public boolean apply(Game game, Ability source, UUID manaProducer) { // check: ... to cast a creature spell @@ -197,7 +153,7 @@ class CavernOfSoulsWatcher extends Watcher { private List spells = new ArrayList<>(); private final String originalId; - + public CavernOfSoulsWatcher(UUID originalId) { super("ManaPaidFromCavernOfSoulsWatcher", WatcherScope.CARD); this.originalId = originalId.toString(); @@ -222,7 +178,7 @@ class CavernOfSoulsWatcher extends Watcher { } } } - + public boolean spellCantBeCountered(UUID spellId) { return spells.contains(spellId); } diff --git a/Mage.Sets/src/mage/sets/avacynrestored/RidersOfGavony.java b/Mage.Sets/src/mage/sets/avacynrestored/RidersOfGavony.java index 8a0ead3bfc9..2f687150aa7 100644 --- a/Mage.Sets/src/mage/sets/avacynrestored/RidersOfGavony.java +++ b/Mage.Sets/src/mage/sets/avacynrestored/RidersOfGavony.java @@ -27,27 +27,28 @@ */ package mage.sets.avacynrestored; -import mage.constants.*; +import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.AsEntersBattlefieldAbility; import mage.abilities.common.SimpleStaticAbility; import mage.abilities.effects.ContinuousEffectImpl; -import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.ChooseCreatureTypeEffect; import mage.abilities.keyword.ProtectionAbility; import mage.abilities.keyword.VigilanceAbility; import mage.cards.CardImpl; -import mage.cards.repository.CardRepository; -import mage.choices.Choice; -import mage.choices.ChoiceImpl; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.Layer; +import mage.constants.Outcome; +import mage.constants.Rarity; +import mage.constants.SubLayer; +import mage.constants.Zone; import mage.filter.FilterPermanent; import mage.filter.common.FilterControlledCreaturePermanent; import mage.filter.predicate.mageobject.SubtypePredicate; import mage.game.Game; import mage.game.permanent.Permanent; -import mage.players.Player; - -import java.util.UUID; /** * @author noxx @@ -66,7 +67,7 @@ public class RidersOfGavony extends CardImpl { this.addAbility(VigilanceAbility.getInstance()); // As Riders of Gavony enters the battlefield, choose a creature type. - this.addAbility(new AsEntersBattlefieldAbility(new RidersOfGavonyEffect())); + this.addAbility(new AsEntersBattlefieldAbility(new ChooseCreatureTypeEffect(Outcome.Protect))); // Human creatures you control have protection from creatures of the chosen type. this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new RidersOfGavonyGainAbilityControlledEffect())); @@ -82,46 +83,6 @@ public class RidersOfGavony extends CardImpl { } } -class RidersOfGavonyEffect extends OneShotEffect { - - public RidersOfGavonyEffect() { - super(Outcome.BoostCreature); - staticText = "choose a creature type"; - } - - public RidersOfGavonyEffect(final RidersOfGavonyEffect effect) { - super(effect); - } - - @Override - public boolean apply(Game game, Ability source) { - Player player = game.getPlayer(source.getControllerId()); - Permanent permanent = game.getPermanent(source.getSourceId()); - if (player != null && permanent != null) { - Choice typeChoice = new ChoiceImpl(true); - typeChoice.setMessage("Choose creature type"); - typeChoice.setChoices(CardRepository.instance.getCreatureTypes()); - while (!player.choose(Outcome.BoostCreature, typeChoice, game)) { - if (!player.canRespond()) { - return false; - } - } - if (typeChoice.getChoice() != null) { - game.informPlayers(permanent.getName() + ": " + player.getLogName() + " has chosen " + typeChoice.getChoice()); - game.getState().setValue(permanent.getId() + "_type", typeChoice.getChoice()); - permanent.addInfo("chosen type", "Chosen type: " + typeChoice.getChoice() + "", game); - } - } - return false; - } - - @Override - public RidersOfGavonyEffect copy() { - return new RidersOfGavonyEffect(this); - } - -} - class RidersOfGavonyGainAbilityControlledEffect extends ContinuousEffectImpl { private static final FilterControlledCreaturePermanent filter = new FilterControlledCreaturePermanent("Human creatures you control"); @@ -154,13 +115,13 @@ class RidersOfGavonyGainAbilityControlledEffect extends ContinuousEffectImpl { if (permanent != null) { String subtype = (String) game.getState().getValue(permanent.getId() + "_type"); if (subtype != null) { - protectionFilter = new FilterPermanent(subtype+"s"); + protectionFilter = new FilterPermanent(subtype + "s"); protectionFilter.add(new SubtypePredicate(subtype)); } } } if (protectionFilter != null) { - for (Permanent perm: game.getBattlefield().getAllActivePermanents(filter, source.getControllerId(), game)) { + for (Permanent perm : game.getBattlefield().getAllActivePermanents(filter, source.getControllerId(), game)) { perm.addAbility(new ProtectionAbility(protectionFilter), source.getSourceId(), game); } return true; diff --git a/Mage.Sets/src/mage/sets/magic2014/DoorOfDestinies.java b/Mage.Sets/src/mage/sets/magic2014/DoorOfDestinies.java index 95ef1ee6103..d1aab901884 100644 --- a/Mage.Sets/src/mage/sets/magic2014/DoorOfDestinies.java +++ b/Mage.Sets/src/mage/sets/magic2014/DoorOfDestinies.java @@ -33,12 +33,9 @@ import mage.abilities.TriggeredAbilityImpl; import mage.abilities.common.AsEntersBattlefieldAbility; import mage.abilities.common.SimpleStaticAbility; import mage.abilities.effects.ContinuousEffectImpl; -import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.ChooseCreatureTypeEffect; import mage.abilities.effects.common.counter.AddCountersSourceEffect; import mage.cards.CardImpl; -import mage.cards.repository.CardRepository; -import mage.choices.Choice; -import mage.choices.ChoiceImpl; import mage.constants.CardType; import mage.constants.Duration; import mage.constants.Layer; @@ -57,7 +54,6 @@ import mage.game.events.GameEvent; import mage.game.events.GameEvent.EventType; import mage.game.permanent.Permanent; import mage.game.stack.Spell; -import mage.players.Player; /** * @@ -70,7 +66,8 @@ public class DoorOfDestinies extends CardImpl { this.expansionSetCode = "M14"; // As Door of Destinies enters the battlefield, choose a creature type. - this.addAbility(new AsEntersBattlefieldAbility(new ChooseCreatureTypeEffect())); + this.addAbility(new AsEntersBattlefieldAbility(new ChooseCreatureTypeEffect(Outcome.BoostCreature))); + // Whenever you cast a spell of the chosen type, put a charge counter on Door of Destinies. this.addAbility(new AddCounterAbility()); // Creatures you control of the chosen type get +1/+1 for each charge counter on Door of Destinies. @@ -87,44 +84,6 @@ public class DoorOfDestinies extends CardImpl { } } -class ChooseCreatureTypeEffect extends OneShotEffect { - - public ChooseCreatureTypeEffect() { - super(Outcome.BoostCreature); - staticText = "choose a creature type"; - } - - public ChooseCreatureTypeEffect(final ChooseCreatureTypeEffect effect) { - super(effect); - } - - @Override - public boolean apply(Game game, Ability source) { - Player player = game.getPlayer(source.getControllerId()); - Permanent permanent = game.getPermanent(source.getSourceId()); - if (player != null && permanent != null) { - Choice typeChoice = new ChoiceImpl(true); - typeChoice.setMessage("Choose creature type"); - typeChoice.setChoices(CardRepository.instance.getCreatureTypes()); - while (!player.choose(Outcome.BoostCreature, typeChoice, game)) { - if (!player.canRespond()) { - return false; - } - } - game.informPlayers(permanent.getName() + ": " + player.getLogName() + " has chosen " + typeChoice.getChoice()); - game.getState().setValue(permanent.getId() + "_type", typeChoice.getChoice()); - permanent.addInfo("chosen type", "Chosen type: " + typeChoice.getChoice().toString() + "", game); - } - return false; - } - - @Override - public ChooseCreatureTypeEffect copy() { - return new ChooseCreatureTypeEffect(this); - } - -} - class AddCounterAbility extends TriggeredAbilityImpl { public AddCounterAbility() { diff --git a/Mage.Sets/src/mage/sets/magic2015/ObeliskOfUrd.java b/Mage.Sets/src/mage/sets/magic2015/ObeliskOfUrd.java index d4a6c4f3a15..7a20f8d5867 100644 --- a/Mage.Sets/src/mage/sets/magic2015/ObeliskOfUrd.java +++ b/Mage.Sets/src/mage/sets/magic2015/ObeliskOfUrd.java @@ -32,12 +32,9 @@ import mage.abilities.Ability; import mage.abilities.common.AsEntersBattlefieldAbility; import mage.abilities.common.SimpleStaticAbility; import mage.abilities.effects.ContinuousEffectImpl; -import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.ChooseCreatureTypeEffect; import mage.abilities.keyword.ConvokeAbility; import mage.cards.CardImpl; -import mage.cards.repository.CardRepository; -import mage.choices.Choice; -import mage.choices.ChoiceImpl; import mage.constants.CardType; import mage.constants.Duration; import mage.constants.Layer; @@ -48,8 +45,6 @@ import mage.constants.Zone; import mage.filter.common.FilterCreaturePermanent; import mage.game.Game; import mage.game.permanent.Permanent; -import mage.players.Player; -import mage.util.CardUtil; /** * @@ -63,10 +58,10 @@ public class ObeliskOfUrd extends CardImpl { // Convoke this.addAbility(new ConvokeAbility()); - + // As Obelisk of Urd enters the battlefield, choose a creature type. - this.addAbility(new AsEntersBattlefieldAbility(new ObeliskOfUrdEnterBattlefieldEffect())); - + this.addAbility(new AsEntersBattlefieldAbility(new ChooseCreatureTypeEffect(Outcome.BoostCreature))); + // Creatures you control of the chosen type get +2/+2. this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new ObeliskOfUrdBoostEffect())); } @@ -81,43 +76,6 @@ public class ObeliskOfUrd extends CardImpl { } } -class ObeliskOfUrdEnterBattlefieldEffect extends OneShotEffect { - - ObeliskOfUrdEnterBattlefieldEffect() { - super(Outcome.BoostCreature); - staticText = "choose a creature type"; - } - - ObeliskOfUrdEnterBattlefieldEffect(final ObeliskOfUrdEnterBattlefieldEffect effect) { - super(effect); - } - - @Override - public ObeliskOfUrdEnterBattlefieldEffect copy() { - return new ObeliskOfUrdEnterBattlefieldEffect(this); - } - - @Override - public boolean apply(Game game, Ability source) { - Player player = game.getPlayer(source.getControllerId()); - Permanent permanent = game.getPermanent(source.getSourceId()); - if (player != null && permanent != null) { - Choice typeChoice = new ChoiceImpl(true); - typeChoice.setMessage("Choose a creature type:"); - typeChoice.setChoices(CardRepository.instance.getCreatureTypes()); - while (!player.choose(Outcome.BoostCreature, typeChoice, game)) { - if (!player.canRespond()) { - return false; - } - } - game.informPlayers(permanent.getName() + ": " + player.getLogName() + " has chosen " + typeChoice.getChoice()); - game.getState().setValue(permanent.getId() + "_type", typeChoice.getChoice()); - permanent.addInfo("chosen type", CardUtil.addToolTipMarkTags("Chosen type: " + typeChoice.getChoice()), game); - } - return false; - } -} - class ObeliskOfUrdBoostEffect extends ContinuousEffectImpl { private static final FilterCreaturePermanent filter = new FilterCreaturePermanent(); @@ -142,7 +100,7 @@ class ObeliskOfUrdBoostEffect extends ContinuousEffectImpl { if (permanent != null) { String subtype = (String) game.getState().getValue(permanent.getId() + "_type"); if (subtype != null) { - for (Permanent perm: game.getBattlefield().getAllActivePermanents(filter, source.getControllerId(), game)) { + for (Permanent perm : game.getBattlefield().getAllActivePermanents(filter, source.getControllerId(), game)) { if (perm.hasSubtype(subtype)) { perm.addPower(2); perm.addToughness(2); diff --git a/Mage.Sets/src/mage/sets/newphyrexia/Xenograft.java b/Mage.Sets/src/mage/sets/newphyrexia/Xenograft.java index df7da676226..0bcb89be3a9 100644 --- a/Mage.Sets/src/mage/sets/newphyrexia/Xenograft.java +++ b/Mage.Sets/src/mage/sets/newphyrexia/Xenograft.java @@ -29,6 +29,12 @@ package mage.sets.newphyrexia; import java.util.List; import java.util.UUID; +import mage.abilities.Ability; +import mage.abilities.common.AsEntersBattlefieldAbility; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.effects.ContinuousEffectImpl; +import mage.abilities.effects.common.ChooseCreatureTypeEffect; +import mage.cards.CardImpl; import mage.constants.CardType; import mage.constants.Duration; import mage.constants.Layer; @@ -36,19 +42,9 @@ import mage.constants.Outcome; import mage.constants.Rarity; import mage.constants.SubLayer; import mage.constants.Zone; -import mage.abilities.Ability; -import mage.abilities.common.AsEntersBattlefieldAbility; -import mage.abilities.common.SimpleStaticAbility; -import mage.abilities.effects.ContinuousEffectImpl; -import mage.abilities.effects.OneShotEffect; -import mage.cards.CardImpl; -import mage.cards.repository.CardRepository; -import mage.choices.Choice; -import mage.choices.ChoiceImpl; import mage.filter.common.FilterCreaturePermanent; import mage.game.Game; import mage.game.permanent.Permanent; -import mage.players.Player; /** * @@ -60,9 +56,8 @@ public class Xenograft extends CardImpl { super(ownerId, 51, "Xenograft", Rarity.RARE, new CardType[]{CardType.ENCHANTMENT}, "{4}{U}"); this.expansionSetCode = "NPH"; - // As Xenograft enters the battlefield, choose a creature type. - this.addAbility(new AsEntersBattlefieldAbility(new XenograftEffect())); + this.addAbility(new AsEntersBattlefieldAbility(new ChooseCreatureTypeEffect(Outcome.Detriment))); // Each creature you control is the chosen type in addition to its other types. this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new XenograftAddSubtypeEffect())); } @@ -77,43 +72,6 @@ public class Xenograft extends CardImpl { } } -class XenograftEffect extends OneShotEffect { - - public XenograftEffect() { - super(Outcome.DrawCard); - staticText = "choose a creature type"; - } - - public XenograftEffect(final XenograftEffect effect) { - super(effect); - } - - @Override - public boolean apply(Game game, Ability source) { - Player player = game.getPlayer(source.getControllerId()); - Permanent permanent = game.getPermanent(source.getSourceId()); - if (player != null && permanent != null) { - Choice typeChoice = new ChoiceImpl(true); - typeChoice.setMessage("Choose creature type"); - typeChoice.setChoices(CardRepository.instance.getCreatureTypes()); - while (!player.choose(Outcome.BoostCreature, typeChoice, game)) { - if (!player.canRespond()) { - return false; - } - } - game.informPlayers(permanent.getName() + ": " + player.getLogName() + " has chosen " + typeChoice.getChoice()); - game.getState().setValue(source.getSourceId() + "_XenograftType", typeChoice.getChoice()); - permanent.addInfo("chosen type", "Chosen type: " + typeChoice.getChoice().toString() + "", game); - } - return false; - } - - @Override - public XenograftEffect copy() { - return new XenograftEffect(this); - } -} - class XenograftAddSubtypeEffect extends ContinuousEffectImpl { public XenograftAddSubtypeEffect() { @@ -127,7 +85,7 @@ class XenograftAddSubtypeEffect extends ContinuousEffectImpl { @Override public boolean apply(Game game, Ability source) { - String subtype = (String) game.getState().getValue(source.getSourceId() + "_XenograftType"); + String subtype = (String) game.getState().getValue(source.getSourceId() + "_type"); if (subtype != null) { List permanents = game.getBattlefield().getAllActivePermanents(new FilterCreaturePermanent(), source.getControllerId(), game); for (Permanent permanent : permanents) { diff --git a/Mage.Sets/src/mage/sets/tempestremastered/VolrathsLaboratory.java b/Mage.Sets/src/mage/sets/tempestremastered/VolrathsLaboratory.java index 10b1208bbe7..70f4a27f8c7 100644 --- a/Mage.Sets/src/mage/sets/tempestremastered/VolrathsLaboratory.java +++ b/Mage.Sets/src/mage/sets/tempestremastered/VolrathsLaboratory.java @@ -35,6 +35,7 @@ import mage.abilities.common.EntersBattlefieldAbility; import mage.abilities.common.SimpleActivatedAbility; import mage.abilities.costs.common.TapSourceCost; import mage.abilities.costs.mana.GenericManaCost; +import mage.abilities.effects.Effect; import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.ChooseColorEffect; import mage.abilities.effects.common.ChooseCreatureTypeEffect; @@ -57,10 +58,12 @@ public class VolrathsLaboratory extends CardImpl { this.expansionSetCode = "TPR"; // As Volrath's Laboratory enters the battlefield, choose a color and a creature type. - Ability ability = new EntersBattlefieldAbility(new ChooseColorEffect(Outcome.Neutral), null, true, "As Volrath's Laboratory enters the battlefield, choose a color and a creature type.", ""); + Ability ability = new EntersBattlefieldAbility(new ChooseColorEffect(Outcome.Neutral)); + Effect effect = new ChooseColorEffect(Outcome.Neutral); + effect.setText("and a creature type"); ability.addEffect(new ChooseCreatureTypeEffect(Outcome.Neutral)); this.addAbility(ability); - + // {5}, {T}: Put a 2/2 creature token of the chosen color and type onto the battlefield. ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new VolrathsLaboratoryEffect(), new GenericManaCost(5)); ability.addCost(new TapSourceCost()); @@ -78,21 +81,21 @@ public class VolrathsLaboratory extends CardImpl { } class VolrathsLaboratoryEffect extends OneShotEffect { - + VolrathsLaboratoryEffect() { super(Outcome.PutCreatureInPlay); this.staticText = "Put a 2/2 creature token of the chosen color and type onto the battlefield"; } - + VolrathsLaboratoryEffect(final VolrathsLaboratoryEffect effect) { super(effect); } - + @Override public VolrathsLaboratoryEffect copy() { return new VolrathsLaboratoryEffect(this); } - + @Override public boolean apply(Game game, Ability source) { ObjectColor color = (ObjectColor) game.getState().getValue(source.getSourceId() + "_color"); From 328f7dd7a356b28e20710f4f3f20c350fbc31bf5 Mon Sep 17 00:00:00 2001 From: LevelX2 Date: Thu, 15 Oct 2015 22:02:04 +0200 Subject: [PATCH 153/268] * Phylactery Lich - Fixed that the replacement effect to select an artifact was handled targeted. --- .../mage/sets/magic2011/PhylacteryLich.java | 32 +++++++++++-------- 1 file changed, 18 insertions(+), 14 deletions(-) diff --git a/Mage.Sets/src/mage/sets/magic2011/PhylacteryLich.java b/Mage.Sets/src/mage/sets/magic2011/PhylacteryLich.java index a42e28768db..6cf3a7c7243 100644 --- a/Mage.Sets/src/mage/sets/magic2011/PhylacteryLich.java +++ b/Mage.Sets/src/mage/sets/magic2011/PhylacteryLich.java @@ -1,16 +1,16 @@ /* * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. - * + * * Redistribution and use in source and binary forms, with or without modification, are * permitted provided that the following conditions are met: - * + * * 1. Redistributions of source code must retain the above copyright notice, this list of * conditions and the following disclaimer. - * + * * 2. Redistributions in binary form must reproduce the above copyright notice, this list * of conditions and the following disclaimer in the documentation and/or other materials * provided with the distribution. - * + * * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR @@ -20,19 +20,14 @@ * 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.magic2011; import java.util.UUID; -import mage.constants.CardType; -import mage.constants.Outcome; -import mage.constants.Rarity; -import mage.constants.Zone; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.StateTriggeredAbility; @@ -41,6 +36,10 @@ import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.SacrificeSourceEffect; import mage.abilities.keyword.IndestructibleAbility; import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.Outcome; +import mage.constants.Rarity; +import mage.constants.Zone; import mage.counters.Counter; import mage.filter.common.FilterControlledPermanent; import mage.filter.predicate.mageobject.CardTypePredicate; @@ -64,8 +63,13 @@ public class PhylacteryLich extends CardImpl { this.power = new MageInt(5); this.toughness = new MageInt(5); - this.addAbility(new AsEntersBattlefieldAbility(new PhylacteryLichEffect(), "put a phylactery counter on an artifact you control")); + // Indestructible this.addAbility(IndestructibleAbility.getInstance()); + + // As Phylactery Lich enters the battlefield, put a phylactery counter on an artifact you control. + this.addAbility(new AsEntersBattlefieldAbility(new PhylacteryLichEffect(), "put a phylactery counter on an artifact you control")); + + // When you control no permanents with phylactery counters on them, sacrifice Phylactery Lich. this.addAbility(new PhylacteryLichAbility()); } @@ -95,7 +99,7 @@ public class PhylacteryLich extends CardImpl { @Override public boolean checkTrigger(GameEvent event, Game game) { - for (Permanent perm: game.getBattlefield().getAllActivePermanents(controllerId)) { + for (Permanent perm : game.getBattlefield().getAllActivePermanents(controllerId)) { if (perm.getCounters().getCount("phylactery") > 0) { return false; } @@ -133,7 +137,7 @@ class PhylacteryLichEffect extends OneShotEffect { public boolean apply(Game game, Ability source) { Player player = game.getPlayer(source.getControllerId()); if (player != null) { - TargetControlledPermanent target = new TargetControlledPermanent(filter); + TargetControlledPermanent target = new TargetControlledPermanent(1, 1, filter, true); if (target.canChoose(source.getControllerId(), game)) { if (player.choose(Outcome.Neutral, target, source.getSourceId(), game)) { Permanent permanent = game.getPermanent(target.getFirstTarget()); @@ -151,4 +155,4 @@ class PhylacteryLichEffect extends OneShotEffect { return new PhylacteryLichEffect(this); } -} \ No newline at end of file +} From 3c8a9a75fb7a028b415b39f6283655f834d2b9c9 Mon Sep 17 00:00:00 2001 From: LevelX2 Date: Thu, 15 Oct 2015 22:15:23 +0200 Subject: [PATCH 154/268] * Replaced some custom choose player effects. --- .../src/mage/sets/commander/SewerNemesis.java | 42 +------------ .../sets/commander2013/TrueNameNemesis.java | 62 ++++--------------- .../src/mage/sets/timespiral/StuffyDoll.java | 42 +------------ .../effects/common/ChoosePlayerEffect.java | 55 ++++++++++++++++ 4 files changed, 73 insertions(+), 128 deletions(-) create mode 100644 Mage/src/mage/abilities/effects/common/ChoosePlayerEffect.java diff --git a/Mage.Sets/src/mage/sets/commander/SewerNemesis.java b/Mage.Sets/src/mage/sets/commander/SewerNemesis.java index fa7df34d3fa..e8955959eee 100644 --- a/Mage.Sets/src/mage/sets/commander/SewerNemesis.java +++ b/Mage.Sets/src/mage/sets/commander/SewerNemesis.java @@ -35,7 +35,7 @@ import mage.abilities.common.AsEntersBattlefieldAbility; import mage.abilities.common.SimpleStaticAbility; import mage.abilities.dynamicvalue.DynamicValue; import mage.abilities.effects.Effect; -import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.ChoosePlayerEffect; import mage.abilities.effects.common.PutTopCardOfLibraryIntoGraveTargetEffect; import mage.abilities.effects.common.continuous.SetPowerToughnessSourceEffect; import mage.cards.CardImpl; @@ -47,9 +47,7 @@ import mage.constants.Zone; import mage.game.Game; import mage.game.events.GameEvent; import mage.game.events.GameEvent.EventType; -import mage.game.permanent.Permanent; import mage.players.Player; -import mage.target.TargetPlayer; import mage.target.targetpointer.FixedTarget; /** @@ -67,7 +65,7 @@ public class SewerNemesis extends CardImpl { this.toughness = new MageInt(0); // As Sewer Nemesis enters the battlefield, choose a player. - this.addAbility(new AsEntersBattlefieldAbility(new SewerNemesisChoosePlayerEffect())); + this.addAbility(new AsEntersBattlefieldAbility(new ChoosePlayerEffect(Outcome.Detriment))); // Sewer Nemesis's power and toughness are each equal to the number of cards in the chosen player's graveyard. this.addAbility(new SimpleStaticAbility(Zone.ALL, new SetPowerToughnessSourceEffect(new CardsInTargetOpponentsGraveyardCount(), Duration.WhileOnBattlefield))); // Whenever the chosen player casts a spell, that player puts the top card of his or her library into his or her graveyard. @@ -85,42 +83,8 @@ public class SewerNemesis extends CardImpl { } } -class SewerNemesisChoosePlayerEffect extends OneShotEffect { - - public SewerNemesisChoosePlayerEffect() { - super(Outcome.Detriment); - this.staticText = "choose a player"; - } - - public SewerNemesisChoosePlayerEffect(final SewerNemesisChoosePlayerEffect effect) { - super(effect); - } - - @Override - public SewerNemesisChoosePlayerEffect copy() { - return new SewerNemesisChoosePlayerEffect(this); - } - - @Override - public boolean apply(Game game, Ability source) { - Player player = game.getPlayer(source.getControllerId()); - Permanent permanent = game.getPermanent(source.getSourceId()); - if (player != null && permanent != null) { - TargetPlayer target = new TargetPlayer(1,1,true); - if (player.choose(this.outcome, target, source.getSourceId(), game)) { - Player chosenPlayer = game.getPlayer(target.getFirstTarget()); - if (chosenPlayer != null) { - game.informPlayers(permanent.getLogName() + ": " + player.getLogName() + " has chosen " + chosenPlayer.getLogName()); - game.getState().setValue(permanent.getId() + "_player", target.getFirstTarget()); - return true; - } - } - } - return false; - } -} - class CardsInTargetOpponentsGraveyardCount implements DynamicValue { + @Override public int calculate(Game game, Ability sourceAbility, Effect effect) { if (sourceAbility != null) { diff --git a/Mage.Sets/src/mage/sets/commander2013/TrueNameNemesis.java b/Mage.Sets/src/mage/sets/commander2013/TrueNameNemesis.java index 18c7db6b708..6c3967a3e6d 100644 --- a/Mage.Sets/src/mage/sets/commander2013/TrueNameNemesis.java +++ b/Mage.Sets/src/mage/sets/commander2013/TrueNameNemesis.java @@ -30,9 +30,8 @@ package mage.sets.commander2013; import java.util.UUID; import mage.MageInt; import mage.MageObject; -import mage.abilities.Ability; import mage.abilities.common.AsEntersBattlefieldAbility; -import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.ChoosePlayerEffect; import mage.abilities.keyword.ProtectionAbility; import mage.cards.Card; import mage.cards.CardImpl; @@ -44,18 +43,19 @@ import mage.game.Game; import mage.game.permanent.Permanent; import mage.game.stack.Spell; import mage.game.stack.StackObject; -import mage.players.Player; -import mage.target.TargetPlayer; /** - * Protection from a player is a new variant of the protection ability. It means the following: - * -- True-Name Nemesis can’t be the target of spells or abilities controlled by the chosen player. - * -- True-Name Nemesis can’t be enchanted by Auras or equipped by Equipment controlled - * by the chosen player. (The same is true for Fortifications controlled by the chosen player, - * if True-Name Nemesis becomes a land.) - * -- True-Name Nemesis can’t be blocked by creatures controlled by the chosen player. - * -- All damage that would be dealt to True-Name Nemesis by sources controlled by the chosen player - * is prevented. (The same is true for sources owned by the chosen player that don’t have controllers.) + * Protection from a player is a new variant of the protection ability. It means + * the following: -- True-Name Nemesis can’t be the target of spells or + * abilities controlled by the chosen player. -- True-Name Nemesis can’t be + * enchanted by Auras or equipped by Equipment controlled by the chosen player. + * (The same is true for Fortifications controlled by the chosen player, if + * True-Name Nemesis becomes a land.) -- True-Name Nemesis can’t be blocked by + * creatures controlled by the chosen player. -- All damage that would be dealt + * to True-Name Nemesis by sources controlled by the chosen player is prevented. + * (The same is true for sources owned by the chosen player that don’t have + * controllers.) + * * @author LevelX2 */ public class TrueNameNemesis extends CardImpl { @@ -70,7 +70,7 @@ public class TrueNameNemesis extends CardImpl { this.toughness = new MageInt(1); // As True-Name Nemesis enters the battlefield, choose a player. - this.addAbility(new AsEntersBattlefieldAbility(new TrueNameNemesisChoosePlayerEffect())); + this.addAbility(new AsEntersBattlefieldAbility(new ChoosePlayerEffect(Outcome.Protect))); // True-Name Nemesis has protection from the chosen player. this.addAbility(new ProtectionFromPlayerAbility()); } @@ -85,42 +85,6 @@ public class TrueNameNemesis extends CardImpl { } } -class TrueNameNemesisChoosePlayerEffect extends OneShotEffect { - - public TrueNameNemesisChoosePlayerEffect() { - super(Outcome.Detriment); - this.staticText = "choose a player"; - } - - public TrueNameNemesisChoosePlayerEffect(final TrueNameNemesisChoosePlayerEffect effect) { - super(effect); - } - - @Override - public TrueNameNemesisChoosePlayerEffect copy() { - return new TrueNameNemesisChoosePlayerEffect(this); - } - - @Override - public boolean apply(Game game, Ability source) { - Player player = game.getPlayer(source.getControllerId()); - Permanent permanent = game.getPermanent(source.getSourceId()); - if (player != null && permanent != null) { - TargetPlayer target = new TargetPlayer(1,1,true); - if (player.choose(this.outcome, target, source.getSourceId(), game)) { - Player chosenPlayer = game.getPlayer(target.getFirstTarget()); - if (chosenPlayer != null) { - game.informPlayers(permanent.getName() + ": " + player.getLogName() + " has chosen " + chosenPlayer.getLogName()); - game.getState().setValue(permanent.getId() + "_player", target.getFirstTarget()); - permanent.addInfo("chosen player", "Chosen player: " + chosenPlayer.getLogName() + "", game); - return true; - } - } - } - return false; - } -} - class ProtectionFromPlayerAbility extends ProtectionAbility { public ProtectionFromPlayerAbility() { diff --git a/Mage.Sets/src/mage/sets/timespiral/StuffyDoll.java b/Mage.Sets/src/mage/sets/timespiral/StuffyDoll.java index 7927019a7b4..2a30d327984 100644 --- a/Mage.Sets/src/mage/sets/timespiral/StuffyDoll.java +++ b/Mage.Sets/src/mage/sets/timespiral/StuffyDoll.java @@ -35,6 +35,7 @@ import mage.abilities.common.AsEntersBattlefieldAbility; import mage.abilities.common.SimpleActivatedAbility; import mage.abilities.costs.common.TapSourceCost; import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.ChoosePlayerEffect; import mage.abilities.effects.common.DamageSelfEffect; import mage.abilities.keyword.IndestructibleAbility; import mage.cards.CardImpl; @@ -45,10 +46,7 @@ import mage.constants.Zone; import mage.game.Game; import mage.game.events.GameEvent; import mage.game.events.GameEvent.EventType; -import mage.game.permanent.Permanent; import mage.players.Player; -import mage.target.TargetPlayer; - /** * @@ -64,7 +62,7 @@ public class StuffyDoll extends CardImpl { this.toughness = new MageInt(1); // As Stuffy Doll enters the battlefield, choose a player. - this.addAbility(new AsEntersBattlefieldAbility(new StuffyDollChoosePlayerEffect())); + this.addAbility(new AsEntersBattlefieldAbility(new ChoosePlayerEffect(Outcome.Damage))); // Stuffy Doll is indestructible. this.addAbility(IndestructibleAbility.getInstance()); // Whenever Stuffy Doll is dealt damage, it deals that much damage to the chosen player. @@ -83,41 +81,6 @@ public class StuffyDoll extends CardImpl { } } -class StuffyDollChoosePlayerEffect extends OneShotEffect { - - public StuffyDollChoosePlayerEffect() { - super(Outcome.Detriment); - this.staticText = "choose a player"; - } - - public StuffyDollChoosePlayerEffect(final StuffyDollChoosePlayerEffect effect) { - super(effect); - } - - @Override - public StuffyDollChoosePlayerEffect copy() { - return new StuffyDollChoosePlayerEffect(this); - } - - @Override - public boolean apply(Game game, Ability source) { - Player player = game.getPlayer(source.getControllerId()); - Permanent permanent = game.getPermanent(source.getSourceId()); - if (player != null && permanent != null) { - TargetPlayer target = new TargetPlayer(); - if (player.choose(this.outcome, target, source.getSourceId(), game)) { - Player chosenPlayer = game.getPlayer(target.getFirstTarget()); - if (chosenPlayer != null) { - game.informPlayers(permanent.getName() + ": " + player.getLogName() + " has chosen " + chosenPlayer.getLogName()); - game.getState().setValue(permanent.getId() + "_player", target.getFirstTarget()); - return true; - } - } - } - return false; - } -} - class StuffyDollTriggeredAbility extends TriggeredAbilityImpl { public StuffyDollTriggeredAbility() { @@ -179,4 +142,3 @@ class StuffyDollGainLifeEffect extends OneShotEffect { return true; } } - diff --git a/Mage/src/mage/abilities/effects/common/ChoosePlayerEffect.java b/Mage/src/mage/abilities/effects/common/ChoosePlayerEffect.java new file mode 100644 index 00000000000..9f4481515c5 --- /dev/null +++ b/Mage/src/mage/abilities/effects/common/ChoosePlayerEffect.java @@ -0,0 +1,55 @@ +/* + * To change this license header, choose License Headers in Project Properties. + * To change this template file, choose Tools | Templates + * and open the template in the editor. + */ +package mage.abilities.effects.common; + +import mage.abilities.Ability; +import mage.abilities.effects.OneShotEffect; +import mage.constants.Outcome; +import mage.game.Game; +import mage.game.permanent.Permanent; +import mage.players.Player; +import mage.target.TargetPlayer; +import mage.util.CardUtil; + +/** + * + * @author LevelX2 + */ +public class ChoosePlayerEffect extends OneShotEffect { + + public ChoosePlayerEffect(Outcome outcome) { + super(outcome); + this.staticText = "choose a player"; + } + + public ChoosePlayerEffect(final ChoosePlayerEffect effect) { + super(effect); + } + + @Override + public ChoosePlayerEffect copy() { + return new ChoosePlayerEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player player = game.getPlayer(source.getControllerId()); + Permanent permanent = game.getPermanent(source.getSourceId()); + if (player != null && permanent != null) { + TargetPlayer target = new TargetPlayer(1, 1, true); + if (player.choose(this.outcome, target, source.getSourceId(), game)) { + Player chosenPlayer = game.getPlayer(target.getFirstTarget()); + if (chosenPlayer != null) { + game.informPlayers(permanent.getName() + ": " + player.getLogName() + " has chosen " + chosenPlayer.getLogName()); + game.getState().setValue(permanent.getId() + "_player", target.getFirstTarget()); + permanent.addInfo("chosen player", CardUtil.addToolTipMarkTags("Chosen player: " + chosenPlayer.getLogName()), game); + return true; + } + } + } + return false; + } +} From ff0aace404d30a4f89daabdc7ab2bd7e65918e56 Mon Sep 17 00:00:00 2001 From: LevelX2 Date: Thu, 15 Oct 2015 22:25:52 +0200 Subject: [PATCH 155/268] * Replaced some custom name a card effects. --- .../src/mage/sets/innistrad/Nevermore.java | 67 +++---------------- .../mirrodinbesieged/PhyrexianRevoker.java | 65 +++--------------- .../sets/planarchaos/VoidstoneGargoyle.java | 11 +-- .../effects/common/NameACardEffect.java | 6 +- 4 files changed, 31 insertions(+), 118 deletions(-) diff --git a/Mage.Sets/src/mage/sets/innistrad/Nevermore.java b/Mage.Sets/src/mage/sets/innistrad/Nevermore.java index dee67c6f07f..dee1d81fe79 100644 --- a/Mage.Sets/src/mage/sets/innistrad/Nevermore.java +++ b/Mage.Sets/src/mage/sets/innistrad/Nevermore.java @@ -1,16 +1,16 @@ /* * Copyright 2011 BetaSteward_at_googlemail.com. All rights reserved. - * + * * Redistribution and use in source and binary forms, with or without modification, are * permitted provided that the following conditions are met: - * + * * 1. Redistributions of source code must retain the above copyright notice, this list of * conditions and the following disclaimer. - * + * * 2. Redistributions in binary form must reproduce the above copyright notice, this list * of conditions and the following disclaimer in the documentation and/or other materials * provided with the distribution. - * + * * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR @@ -20,7 +20,7 @@ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * + * * The views and conclusions contained in the software and documentation are those of the * authors and should not be interpreted as representing official policies, either expressed * or implied, of BetaSteward_at_googlemail.com. @@ -33,11 +33,8 @@ import mage.abilities.Ability; import mage.abilities.common.AsEntersBattlefieldAbility; import mage.abilities.common.SimpleStaticAbility; import mage.abilities.effects.ContinuousRuleModifyingEffectImpl; -import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.NameACardEffect; import mage.cards.CardImpl; -import mage.cards.repository.CardRepository; -import mage.choices.Choice; -import mage.choices.ChoiceImpl; import mage.constants.CardType; import mage.constants.Duration; import mage.constants.Outcome; @@ -46,9 +43,6 @@ import mage.constants.Zone; import mage.game.Game; import mage.game.events.GameEvent; import mage.game.events.GameEvent.EventType; -import mage.game.permanent.Permanent; -import mage.players.Player; -import mage.util.CardUtil; /** * @@ -60,11 +54,10 @@ public class Nevermore extends CardImpl { super(ownerId, 25, "Nevermore", Rarity.RARE, new CardType[]{CardType.ENCHANTMENT}, "{1}{W}{W}"); this.expansionSetCode = "ISD"; + // As Nevermore enters the battlefield, name a nonland card. + this.addAbility(new AsEntersBattlefieldAbility(new NameACardEffect(NameACardEffect.TypeOfName.NON_LAND_NAME))); - //As Nevermore enters the battlefield, name a nonland card. - this.addAbility(new AsEntersBattlefieldAbility(new NevermoreEffect1())); - - //The named card can't be cast. + // The named card can't be cast. this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new NevermoreEffect2())); } @@ -80,46 +73,6 @@ public class Nevermore extends CardImpl { } -class NevermoreEffect1 extends OneShotEffect { - - public NevermoreEffect1() { - super(Outcome.Detriment); - staticText = "name a nonland card"; - } - - public NevermoreEffect1(final NevermoreEffect1 effect) { - super(effect); - } - - @Override - public boolean apply(Game game, Ability source) { - Player controller = game.getPlayer(source.getControllerId()); - Permanent permanent = game.getPermanent(source.getSourceId()); - if (controller != null && permanent != null) { - Choice cardChoice = new ChoiceImpl(); - cardChoice.setChoices(CardRepository.instance.getNonLandNames()); - cardChoice.clearChoice(); - while (!controller.choose(Outcome.Detriment, cardChoice, game)) { - if (!controller.canRespond()) { - return false; - } - } - String cardName = cardChoice.getChoice(); - game.informPlayers(permanent.getLogName() + ", named card: [" + cardName + "]"); - game.getState().setValue(source.getSourceId().toString(), cardName); - permanent.addInfo("named card", CardUtil.addToolTipMarkTags("Named card: [" + cardName +"]"), game); - return true; - } - return false; - } - - @Override - public NevermoreEffect1 copy() { - return new NevermoreEffect1(this); - } - -} - class NevermoreEffect2 extends ContinuousRuleModifyingEffectImpl { public NevermoreEffect2() { @@ -145,7 +98,7 @@ class NevermoreEffect2 extends ContinuousRuleModifyingEffectImpl { public boolean applies(GameEvent event, Ability source, Game game) { if (event.getType() == EventType.CAST_SPELL) { MageObject object = game.getObject(event.getSourceId()); - if (object != null && object.getName().equals(game.getState().getValue(source.getSourceId().toString()))) { + if (object != null && object.getName().equals(game.getState().getValue(source.getSourceId().toString() + NameACardEffect.INFO_KEY))) { return true; } } diff --git a/Mage.Sets/src/mage/sets/mirrodinbesieged/PhyrexianRevoker.java b/Mage.Sets/src/mage/sets/mirrodinbesieged/PhyrexianRevoker.java index 279bd693526..6a51fef04bc 100644 --- a/Mage.Sets/src/mage/sets/mirrodinbesieged/PhyrexianRevoker.java +++ b/Mage.Sets/src/mage/sets/mirrodinbesieged/PhyrexianRevoker.java @@ -25,32 +25,25 @@ * authors and should not be interpreted as representing official policies, either expressed * or implied, of BetaSteward_at_googlemail.com. */ - package mage.sets.mirrodinbesieged; 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.MageInt; import mage.MageObject; import mage.abilities.Ability; import mage.abilities.common.AsEntersBattlefieldAbility; import mage.abilities.common.SimpleStaticAbility; import mage.abilities.effects.ContinuousRuleModifyingEffectImpl; -import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.NameACardEffect; import mage.cards.CardImpl; -import mage.cards.repository.CardRepository; -import mage.choices.Choice; -import mage.choices.ChoiceImpl; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.Outcome; +import mage.constants.Rarity; +import mage.constants.Zone; import mage.game.Game; import mage.game.events.GameEvent; import mage.game.events.GameEvent.EventType; -import mage.game.permanent.Permanent; -import mage.players.Player; -import mage.util.CardUtil; /** * @@ -66,7 +59,7 @@ public class PhyrexianRevoker extends CardImpl { this.toughness = new MageInt(1); // As Phyrexian Revoker enters the battlefield, name a nonland card. - this.addAbility(new AsEntersBattlefieldAbility(new PhyrexianRevokerEffect1())); + this.addAbility(new AsEntersBattlefieldAbility(new NameACardEffect(NameACardEffect.TypeOfName.NON_LAND_NAME))); // Activated abilities of sources with the chosen name can't be activated. this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new PhyrexianRevokerEffect2())); @@ -83,46 +76,6 @@ public class PhyrexianRevoker extends CardImpl { } -class PhyrexianRevokerEffect1 extends OneShotEffect { - - public PhyrexianRevokerEffect1() { - super(Outcome.Detriment); - staticText = "name a nonland card"; - } - - public PhyrexianRevokerEffect1(final PhyrexianRevokerEffect1 effect) { - super(effect); - } - - @Override - public boolean apply(Game game, Ability source) { - Player controller = game.getPlayer(source.getControllerId()); - Permanent permanent = game.getPermanent(source.getSourceId()); - if (controller != null && permanent != null) { - Choice cardChoice = new ChoiceImpl(); - cardChoice.setChoices(CardRepository.instance.getNonLandNames()); - cardChoice.clearChoice(); - while (!controller.choose(Outcome.Detriment, cardChoice, game)) { - if (!controller.canRespond()) { - return false; - } - } - String cardName = cardChoice.getChoice(); - game.informPlayers(permanent.getLogName() + ", named card: [" + cardName + "]"); - game.getState().setValue(source.getSourceId().toString(), cardName); - permanent.addInfo("named card", CardUtil.addToolTipMarkTags("Named card: [" + cardName +"]"), game); - return true; - } - return false; - } - - @Override - public PhyrexianRevokerEffect1 copy() { - return new PhyrexianRevokerEffect1(this); - } - -} - class PhyrexianRevokerEffect2 extends ContinuousRuleModifyingEffectImpl { public PhyrexianRevokerEffect2() { @@ -143,7 +96,7 @@ class PhyrexianRevokerEffect2 extends ContinuousRuleModifyingEffectImpl { public PhyrexianRevokerEffect2 copy() { return new PhyrexianRevokerEffect2(this); } - + @Override public String getInfoMessage(Ability source, GameEvent event, Game game) { MageObject mageObject = game.getObject(source.getSourceId()); @@ -157,7 +110,7 @@ class PhyrexianRevokerEffect2 extends ContinuousRuleModifyingEffectImpl { public boolean applies(GameEvent event, Ability source, Game game) { if (event.getType() == EventType.ACTIVATE_ABILITY) { MageObject object = game.getObject(event.getSourceId()); - if (object != null && object.getName().equals(game.getState().getValue(source.getSourceId().toString()))) { + if (object != null && object.getName().equals(game.getState().getValue(source.getSourceId().toString() + NameACardEffect.INFO_KEY))) { return true; } } diff --git a/Mage.Sets/src/mage/sets/planarchaos/VoidstoneGargoyle.java b/Mage.Sets/src/mage/sets/planarchaos/VoidstoneGargoyle.java index 9292efe16a6..4505e346779 100644 --- a/Mage.Sets/src/mage/sets/planarchaos/VoidstoneGargoyle.java +++ b/Mage.Sets/src/mage/sets/planarchaos/VoidstoneGargoyle.java @@ -34,7 +34,9 @@ import mage.abilities.Ability; import mage.abilities.common.AsEntersBattlefieldAbility; import mage.abilities.common.SimpleStaticAbility; import mage.abilities.effects.ContinuousRuleModifyingEffectImpl; +import mage.abilities.effects.EntersBattlefieldEffect; import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.NameACardEffect; import mage.abilities.keyword.FlyingAbility; import mage.cards.CardImpl; import mage.cards.repository.CardRepository; @@ -69,7 +71,7 @@ public class VoidstoneGargoyle extends CardImpl { // Flying this.addAbility(FlyingAbility.getInstance()); // As Voidstone Gargoyle enters the battlefield, name a nonland card. - this.addAbility(new AsEntersBattlefieldAbility(new VoidstoneGargoyleChooseCardEffect())); + this.addAbility(new AsEntersBattlefieldAbility(new NameACardEffect(NameACardEffect.TypeOfName.NON_LAND_NAME))); // The named card can't be cast. this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new VoidstoneGargoyleReplacementEffect1())); // Activated abilities of sources with the chosen name can't be activated. @@ -100,7 +102,7 @@ class VoidstoneGargoyleChooseCardEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { Player controller = game.getPlayer(source.getControllerId()); - Permanent permanent = game.getPermanent(source.getSourceId()); + Permanent permanent = (Permanent) getValue(EntersBattlefieldEffect.ENTERING_PERMANENT); if (controller != null && permanent != null) { Choice cardChoice = new ChoiceImpl(); cardChoice.setChoices(CardRepository.instance.getNonLandNames()); @@ -160,7 +162,8 @@ class VoidstoneGargoyleReplacementEffect1 extends ContinuousRuleModifyingEffectI public boolean applies(GameEvent event, Ability source, Game game) { if (event.getType() == GameEvent.EventType.CAST_SPELL) { MageObject object = game.getObject(event.getSourceId()); - if (object != null && object.getName().equals(game.getState().getValue(source.getSourceId().toString()))) { + if (object != null + && object.getName().equals(game.getState().getValue(source.getSourceId().toString() + NameACardEffect.INFO_KEY))) { return true; } } @@ -203,7 +206,7 @@ class VoidstoneGargoyleRuleModifyingEffect2 extends ContinuousRuleModifyingEffec public boolean applies(GameEvent event, Ability source, Game game) { if (event.getType() == EventType.ACTIVATE_ABILITY) { MageObject object = game.getObject(event.getSourceId()); - if (object != null && object.getName().equals(game.getState().getValue(source.getSourceId().toString()))) { + if (object != null && object.getName().equals(game.getState().getValue(source.getSourceId().toString() + NameACardEffect.INFO_KEY))) { return true; } } diff --git a/Mage/src/mage/abilities/effects/common/NameACardEffect.java b/Mage/src/mage/abilities/effects/common/NameACardEffect.java index 0123f9fd6f6..b75279a993f 100644 --- a/Mage/src/mage/abilities/effects/common/NameACardEffect.java +++ b/Mage/src/mage/abilities/effects/common/NameACardEffect.java @@ -29,6 +29,7 @@ package mage.abilities.effects.common; import mage.MageObject; import mage.abilities.Ability; +import mage.abilities.effects.EntersBattlefieldEffect; import mage.abilities.effects.OneShotEffect; import mage.cards.repository.CardRepository; import mage.choices.Choice; @@ -71,7 +72,10 @@ public class NameACardEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { Player controller = game.getPlayer(source.getControllerId()); - MageObject sourceObject = game.getObject(source.getSourceId()); + MageObject sourceObject = (Permanent) getValue(EntersBattlefieldEffect.ENTERING_PERMANENT); + if (sourceObject == null) { + game.getObject(source.getSourceId()); + } if (controller != null && sourceObject != null) { Choice cardChoice = new ChoiceImpl(); switch (typeOfName) { From 9ab99883079c6af0dc84f433b0b91637e1907dda Mon Sep 17 00:00:00 2001 From: LevelX2 Date: Thu, 15 Oct 2015 23:47:06 +0200 Subject: [PATCH 156/268] * Replaced some custom card effects. Updated enters battlefield replacement effects for new handling. --- .../sets/alarareborn/ArsenalThresher.java | 25 +++---- .../mage/sets/commander/TheMimeoplasm.java | 15 ++-- .../mage/sets/commander2014/BitterFeud.java | 3 +- Mage.Sets/src/mage/sets/conflux/Nyxathid.java | 53 +++----------- .../mage/sets/eventide/CankerAbomination.java | 28 ++++---- .../src/mage/sets/exodus/EntropicSpecter.java | 60 ++++------------ .../src/mage/sets/fourthedition/TheRack.java | 44 +----------- .../src/mage/sets/futuresight/CloudKey.java | 17 +++-- .../src/mage/sets/gatecrash/Realmwright.java | 63 ++++------------ .../mage/sets/guildpact/StompingGround.java | 13 ++-- .../sets/journeyintonyx/HallOfTriumph.java | 48 +------------ .../src/mage/sets/limitedalpha/BlackVise.java | 47 ++---------- .../sets/limitedalpha/PhantasmalTerrain.java | 58 +++------------ .../mage/sets/magic2010/ConvincingMirage.java | 72 +++++-------------- .../src/mage/sets/magic2012/SuturedGhoul.java | 46 ++++++------ .../returntoravnica/TabletOfTheGuilds.java | 16 ++--- .../riseoftheeldrazi/CurseOfWizardry.java | 40 +---------- .../sets/shadowmoor/LureboundScarecrow.java | 4 +- .../mage/sets/shadowmoor/PaintersServant.java | 43 ++--------- .../cards/single/avr/CavernOfSoulsTest.java | 55 +++++++------- .../common/ChooseBasicLandTypeEffect.java | 68 ++++++++++++++++++ .../effects/common/ChooseColorEffect.java | 17 +++-- .../common/ChooseCreatureTypeEffect.java | 18 +++-- .../effects/common/ChooseLandTypeEffect.java | 17 +++-- .../common/ChooseNewTargetsTargetEffect.java | 63 ++++++++-------- .../effects/common/ChooseOpponentEffect.java | 64 +++++++++++++++++ .../effects/common/ChoosePlayerEffect.java | 21 ++++-- .../common/TapSourceUnlessPaysEffect.java | 18 ++--- .../abilities/keyword/ModularAbility.java | 33 +++++---- 29 files changed, 437 insertions(+), 632 deletions(-) create mode 100644 Mage/src/mage/abilities/effects/common/ChooseBasicLandTypeEffect.java create mode 100644 Mage/src/mage/abilities/effects/common/ChooseOpponentEffect.java diff --git a/Mage.Sets/src/mage/sets/alarareborn/ArsenalThresher.java b/Mage.Sets/src/mage/sets/alarareborn/ArsenalThresher.java index 16bc181405a..f4203cb0d58 100644 --- a/Mage.Sets/src/mage/sets/alarareborn/ArsenalThresher.java +++ b/Mage.Sets/src/mage/sets/alarareborn/ArsenalThresher.java @@ -31,6 +31,7 @@ import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.AsEntersBattlefieldAbility; +import mage.abilities.effects.EntersBattlefieldEffect; import mage.abilities.effects.OneShotEffect; import mage.cards.CardImpl; import mage.cards.Cards; @@ -41,7 +42,6 @@ import mage.constants.Rarity; import mage.counters.CounterType; import mage.filter.common.FilterArtifactCard; import mage.filter.predicate.mageobject.AnotherCardPredicate; -import mage.filter.predicate.permanent.AnotherPredicate; import mage.game.Game; import mage.game.permanent.Permanent; import mage.players.Player; @@ -62,7 +62,8 @@ public class ArsenalThresher extends CardImpl { this.toughness = new MageInt(2); // As Arsenal Thresher enters the battlefield, you may reveal any number of other artifact cards from your hand. Arsenal Thresher enters the battlefield with a +1/+1 counter on it for each card revealed this way. - this.addAbility(new AsEntersBattlefieldAbility(new ArsenalThresherEffect(), "you may reveal any number of other artifact cards from your hand. {this} enters the battlefield with a +1/+1 counter on it for each card revealed this way")); + this.addAbility(new AsEntersBattlefieldAbility(new ArsenalThresherEffect(), + "you may reveal any number of other artifact cards from your hand. {this} enters the battlefield with a +1/+1 counter on it for each card revealed this way")); } public ArsenalThresher(final ArsenalThresher card) { @@ -92,29 +93,29 @@ class ArsenalThresherEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { - Player you = game.getPlayer(source.getControllerId()); - if (you == null) { + Player controller = game.getPlayer(source.getControllerId()); + if (controller == null) { return false; } - Permanent arsenalThresher = game.getPermanent(source.getSourceId()); + Permanent arsenalThresher = (Permanent) getValue(EntersBattlefieldEffect.ENTERING_PERMANENT); FilterArtifactCard filter = new FilterArtifactCard(); filter.add(new AnotherCardPredicate()); - if (you.chooseUse(Outcome.Benefit, "Do you want to reveal other artifacts in your hand?", source, game)) { + if (controller.chooseUse(Outcome.Benefit, "Do you want to reveal other artifacts in your hand?", source, game)) { Cards cards = new CardsImpl(); - if (you.getHand().count(filter, source.getSourceId(), source.getControllerId(), game) > 0) { + if (controller.getHand().count(filter, source.getSourceId(), source.getControllerId(), game) > 0) { TargetCardInHand target = new TargetCardInHand(0, Integer.MAX_VALUE, filter); - if (you.choose(Outcome.Benefit, target, source.getSourceId(), game)) { + if (controller.choose(Outcome.Benefit, target, source.getSourceId(), game)) { for (UUID uuid : target.getTargets()) { - cards.add(you.getHand().get(uuid, game)); + cards.add(controller.getHand().get(uuid, game)); } - you.revealCards("Revealed cards", cards, game); if (arsenalThresher != null) { + controller.revealCards(arsenalThresher.getIdName(), cards, game); arsenalThresher.addCounters(CounterType.P1P1.createInstance(cards.size()), game); - return true; } } } + return true; } return false; } -} \ No newline at end of file +} diff --git a/Mage.Sets/src/mage/sets/commander/TheMimeoplasm.java b/Mage.Sets/src/mage/sets/commander/TheMimeoplasm.java index 5be1bed0a24..238bb1bc6c3 100644 --- a/Mage.Sets/src/mage/sets/commander/TheMimeoplasm.java +++ b/Mage.Sets/src/mage/sets/commander/TheMimeoplasm.java @@ -32,6 +32,7 @@ import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.AsEntersBattlefieldAbility; import mage.abilities.dynamicvalue.common.CardsInAllGraveyardsCount; +import mage.abilities.effects.EntersBattlefieldEffect; import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.CopyEffect; import mage.cards.Card; @@ -80,27 +81,27 @@ public class TheMimeoplasm extends CardImpl { } class TheMimeoplasmEffect extends OneShotEffect { - + TheMimeoplasmEffect() { super(Outcome.Copy); } - + TheMimeoplasmEffect(final TheMimeoplasmEffect effect) { super(effect); } - + @Override public TheMimeoplasmEffect copy() { return new TheMimeoplasmEffect(this); } - + @Override public boolean apply(Game game, Ability source) { Player controller = game.getPlayer(source.getControllerId()); - Permanent permanent = game.getPermanent(source.getSourceId()); + Permanent permanent = (Permanent) getValue(EntersBattlefieldEffect.ENTERING_PERMANENT); if (controller != null && permanent != null) { if (new CardsInAllGraveyardsCount(new FilterCreatureCard()).calculate(game, source, this) >= 2) { - if (controller.chooseUse(Outcome.Benefit, "Do you want to exile two creature cards from graveyards?", source, game)) { + if (controller.chooseUse(Outcome.Benefit, "Do you want to exile two creature cards from graveyards?", source, game)) { TargetCardInGraveyard targetCopy = new TargetCardInGraveyard(new FilterCreatureCard("creature card to become a copy of")); TargetCardInGraveyard targetCounters = new TargetCardInGraveyard(new FilterCreatureCard("creature card to determine amount of additional +1/+1 counters")); if (controller.choose(Outcome.Copy, targetCopy, source.getSourceId(), game)) { @@ -122,7 +123,7 @@ class TheMimeoplasmEffect extends OneShotEffect { } } } - return true; + return true; } return false; } diff --git a/Mage.Sets/src/mage/sets/commander2014/BitterFeud.java b/Mage.Sets/src/mage/sets/commander2014/BitterFeud.java index 7ba41f23715..22d87b793ea 100644 --- a/Mage.Sets/src/mage/sets/commander2014/BitterFeud.java +++ b/Mage.Sets/src/mage/sets/commander2014/BitterFeud.java @@ -32,6 +32,7 @@ import mage.MageObject; import mage.abilities.Ability; import mage.abilities.common.AsEntersBattlefieldAbility; import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.effects.EntersBattlefieldEffect; import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.ReplacementEffectImpl; import mage.cards.Card; @@ -91,7 +92,7 @@ class BitterFeudEntersBattlefieldEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { Player controller = game.getPlayer(source.getControllerId()); - Permanent permanent = game.getPermanent(source.getSourceId()); + Permanent permanent = (Permanent) getValue(EntersBattlefieldEffect.ENTERING_PERMANENT); if (controller != null && permanent != null) { TargetPlayer target = new TargetPlayer(2, 2, true); controller.chooseTarget(outcome, target, source, game); diff --git a/Mage.Sets/src/mage/sets/conflux/Nyxathid.java b/Mage.Sets/src/mage/sets/conflux/Nyxathid.java index 22fb19bcede..0a7e5fee51a 100644 --- a/Mage.Sets/src/mage/sets/conflux/Nyxathid.java +++ b/Mage.Sets/src/mage/sets/conflux/Nyxathid.java @@ -27,6 +27,7 @@ */ package mage.sets.conflux; +import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.AsEntersBattlefieldAbility; @@ -34,16 +35,16 @@ import mage.abilities.common.SimpleStaticAbility; import mage.abilities.dynamicvalue.DynamicValue; import mage.abilities.dynamicvalue.common.SignInversionDynamicValue; import mage.abilities.effects.Effect; -import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.ChooseOpponentEffect; import mage.abilities.effects.common.continuous.BoostSourceEffect; import mage.cards.CardImpl; -import mage.constants.*; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.Outcome; +import mage.constants.Rarity; +import mage.constants.Zone; import mage.game.Game; -import mage.game.permanent.Permanent; import mage.players.Player; -import mage.target.common.TargetOpponent; - -import java.util.UUID; /** * @@ -60,7 +61,7 @@ public class Nyxathid extends CardImpl { this.toughness = new MageInt(7); // As Nyxathid enters the battlefield, choose an opponent. - this.addAbility(new AsEntersBattlefieldAbility(new ChooseOpponent())); + this.addAbility(new AsEntersBattlefieldAbility(new ChooseOpponentEffect(Outcome.Detriment))); // Nyxathid gets -1/-1 for each card in the chosen player's hand. DynamicValue chosenPlayerHand = new SignInversionDynamicValue(new CardsInChosenPlayerHandCount()); @@ -78,48 +79,12 @@ public class Nyxathid extends CardImpl { } } -class ChooseOpponent extends OneShotEffect { - - public ChooseOpponent() { - super(Outcome.Neutral); - this.staticText = "choose an opponent"; - } - - public ChooseOpponent(final ChooseOpponent effect) { - super(effect); - } - - @Override - public ChooseOpponent copy() { - return new ChooseOpponent(this); - } - - @Override - public boolean apply(Game game, Ability source) { - Player player = game.getPlayer(source.getControllerId()); - Permanent permanent = game.getPermanent(source.getSourceId()); - if (player != null && permanent != null) { - TargetOpponent target = new TargetOpponent(); - target.setNotTarget(true); - if (player.choose(this.outcome, target, source.getSourceId(), game)) { - Player chosenPlayer = game.getPlayer(target.getFirstTarget()); - if (chosenPlayer != null) { - game.informPlayers(permanent.getName() + ": " + player.getLogName() + " has chosen " + chosenPlayer.getLogName()); - game.getState().setValue(permanent.getId() + "_player", target.getFirstTarget()); - return true; - } - } - } - return false; - } -} - class CardsInChosenPlayerHandCount implements DynamicValue { @Override public int calculate(Game game, Ability sourceAbility, Effect effect) { if (sourceAbility != null) { - UUID playerId = (UUID) game.getState().getValue(sourceAbility.getSourceId() + "_player"); + UUID playerId = (UUID) game.getState().getValue(sourceAbility.getSourceId() + ChooseOpponentEffect.VALUE_KEY); Player chosenPlayer = game.getPlayer(playerId); if (chosenPlayer != null) { return chosenPlayer.getHand().size(); diff --git a/Mage.Sets/src/mage/sets/eventide/CankerAbomination.java b/Mage.Sets/src/mage/sets/eventide/CankerAbomination.java index 5b8107dd5f1..812f571064a 100644 --- a/Mage.Sets/src/mage/sets/eventide/CankerAbomination.java +++ b/Mage.Sets/src/mage/sets/eventide/CankerAbomination.java @@ -31,6 +31,7 @@ import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.AsEntersBattlefieldAbility; +import mage.abilities.effects.EntersBattlefieldEffect; import mage.abilities.effects.OneShotEffect; import mage.cards.CardImpl; import mage.constants.CardType; @@ -61,11 +62,7 @@ public class CankerAbomination extends CardImpl { this.toughness = new MageInt(6); // As Canker Abomination enters the battlefield, choose an opponent. Canker Abomination enters the battlefield with a -1/-1 counter on it for each creature that player controls. - Ability ability = new AsEntersBattlefieldAbility(new CankerAbominationEffect()); - Target target = new TargetOpponent(); - target.setNotTarget(true); - ability.addTarget(target); - this.addAbility(ability); + this.addAbility(new AsEntersBattlefieldAbility(new CankerAbominationEffect())); } @@ -97,14 +94,19 @@ class CankerAbominationEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { - Player player = game.getPlayer(source.getControllerId()); - Permanent CankerAbomination = game.getPermanent(source.getSourceId()); - if (player != null && CankerAbomination != null) { - Player chosenPlayer = game.getPlayer(source.getFirstTarget()); - if (chosenPlayer != null) { - game.informPlayers(CankerAbomination.getName() + ": " + player.getLogName() + " has chosen " + chosenPlayer.getLogName()); - int amount = game.getBattlefield().getAllActivePermanents(new FilterCreaturePermanent(), chosenPlayer.getId(), game).size(); - CankerAbomination.addCounters(CounterType.M1M1.createInstance(amount), game); + Player controller = game.getPlayer(source.getControllerId()); + Permanent cankerAbomination = (Permanent) getValue(EntersBattlefieldEffect.ENTERING_PERMANENT); + if (controller != null && cankerAbomination != null) { + Target target = new TargetOpponent(); + target.setNotTarget(true); + controller.choose(outcome, target, source.getSourceId(), game); + Player opponent = game.getPlayer(target.getFirstTarget()); + if (opponent != null) { + game.informPlayers(cankerAbomination.getName() + ": " + controller.getLogName() + " has chosen " + opponent.getLogName()); + int amount = game.getBattlefield().getAllActivePermanents(new FilterCreaturePermanent(), opponent.getId(), game).size(); + if (amount > 0) { + cankerAbomination.addCounters(CounterType.M1M1.createInstance(amount), game); + } return true; } } diff --git a/Mage.Sets/src/mage/sets/exodus/EntropicSpecter.java b/Mage.Sets/src/mage/sets/exodus/EntropicSpecter.java index 1e5348392f8..b2e6ebf7cca 100644 --- a/Mage.Sets/src/mage/sets/exodus/EntropicSpecter.java +++ b/Mage.Sets/src/mage/sets/exodus/EntropicSpecter.java @@ -27,6 +27,7 @@ */ package mage.sets.exodus; +import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.AsEntersBattlefieldAbility; @@ -34,18 +35,18 @@ import mage.abilities.common.DealsDamageToAPlayerTriggeredAbility; import mage.abilities.common.SimpleStaticAbility; import mage.abilities.dynamicvalue.DynamicValue; import mage.abilities.effects.Effect; -import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.ChooseOpponentEffect; import mage.abilities.effects.common.continuous.SetPowerToughnessSourceEffect; import mage.abilities.effects.common.discard.DiscardTargetEffect; import mage.abilities.keyword.FlyingAbility; import mage.cards.CardImpl; -import mage.constants.*; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.Outcome; +import mage.constants.Rarity; +import mage.constants.Zone; import mage.game.Game; -import mage.game.permanent.Permanent; import mage.players.Player; -import mage.target.common.TargetOpponent; - -import java.util.UUID; /** * @@ -64,13 +65,13 @@ public class EntropicSpecter extends CardImpl { // Flying this.addAbility(FlyingAbility.getInstance()); - + // As Entropic Specter enters the battlefield, choose an opponent. - this.addAbility(new AsEntersBattlefieldAbility(new ChooseOpponent())); - + this.addAbility(new AsEntersBattlefieldAbility(new ChooseOpponentEffect(Outcome.Detriment))); + // Entropic Specter's power and toughness are each equal to the number of cards in the chosen player's hand. this.addAbility(new SimpleStaticAbility(Zone.ALL, new SetPowerToughnessSourceEffect(new CardsInTargetPlayerHandCount(), Duration.WhileOnBattlefield))); - + // Whenever Entropic Specter deals damage to a player, that player discards a card. this.addAbility(new DealsDamageToAPlayerTriggeredAbility(new DiscardTargetEffect(1, false), false, true)); } @@ -85,47 +86,12 @@ public class EntropicSpecter extends CardImpl { } } -class ChooseOpponent extends OneShotEffect { - - public ChooseOpponent() { - super(Outcome.Neutral); - this.staticText = "choose an opponent"; - } - - public ChooseOpponent(final ChooseOpponent effect) { - super(effect); - } - - @Override - public ChooseOpponent copy() { - return new ChooseOpponent(this); - } - - @Override - public boolean apply(Game game, Ability source) { - Player player = game.getPlayer(source.getControllerId()); - Permanent permanent = game.getPermanent(source.getSourceId()); - if (player != null && permanent != null) { - TargetOpponent target = new TargetOpponent(); - target.setNotTarget(true); - if (player.choose(this.outcome, target, source.getSourceId(), game)) { - Player chosenPlayer = game.getPlayer(target.getFirstTarget()); - if (chosenPlayer != null) { - game.informPlayers(permanent.getName() + ": " + player.getLogName() + " has chosen " + chosenPlayer.getLogName()); - game.getState().setValue(permanent.getId() + "_player", target.getFirstTarget()); - return true; - } - } - } - return false; - } -} - class CardsInTargetPlayerHandCount implements DynamicValue { + @Override public int calculate(Game game, Ability sourceAbility, Effect effect) { if (sourceAbility != null) { - UUID playerId = (UUID) game.getState().getValue(sourceAbility.getSourceId() + "_player"); + UUID playerId = (UUID) game.getState().getValue(sourceAbility.getSourceId() + ChooseOpponentEffect.VALUE_KEY); Player chosenPlayer = game.getPlayer(playerId); if (chosenPlayer != null) { return chosenPlayer.getHand().size(); diff --git a/Mage.Sets/src/mage/sets/fourthedition/TheRack.java b/Mage.Sets/src/mage/sets/fourthedition/TheRack.java index 98b564a6bbf..a99f13634fa 100644 --- a/Mage.Sets/src/mage/sets/fourthedition/TheRack.java +++ b/Mage.Sets/src/mage/sets/fourthedition/TheRack.java @@ -32,6 +32,7 @@ import mage.abilities.Ability; import mage.abilities.TriggeredAbilityImpl; import mage.abilities.common.AsEntersBattlefieldAbility; import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.ChooseOpponentEffect; import mage.cards.CardImpl; import mage.constants.CardType; import mage.constants.Outcome; @@ -40,9 +41,7 @@ import mage.constants.Zone; import mage.game.Game; import mage.game.events.GameEvent; import mage.game.events.GameEvent.EventType; -import mage.game.permanent.Permanent; import mage.players.Player; -import mage.target.common.TargetOpponent; /** * @@ -55,7 +54,7 @@ public class TheRack extends CardImpl { this.expansionSetCode = "4ED"; // As The Rack enters the battlefield, choose an opponent. - this.addAbility(new AsEntersBattlefieldAbility(new ChooseOpponent())); + this.addAbility(new AsEntersBattlefieldAbility(new ChooseOpponentEffect(Outcome.Detriment))); // At the beginning of the chosen player's upkeep, The Rack deals X damage to that player, where X is 3 minus the number of cards in his or her hand. this.addAbility(new TheRackTriggeredAbility()); } @@ -72,7 +71,6 @@ public class TheRack extends CardImpl { class TheRackTriggeredAbility extends TriggeredAbilityImpl { - public TheRackTriggeredAbility() { super(Zone.BATTLEFIELD, new TheRackEffect(), false); } @@ -93,7 +91,7 @@ class TheRackTriggeredAbility extends TriggeredAbilityImpl { @Override public boolean checkTrigger(GameEvent event, Game game) { - return event.getPlayerId().equals((UUID) game.getState().getValue(new StringBuilder(this.getSourceId().toString()).append("_player").toString())); + return event.getPlayerId().equals((UUID) game.getState().getValue(this.getSourceId().toString() + ChooseOpponentEffect.VALUE_KEY)); } @Override @@ -103,42 +101,6 @@ class TheRackTriggeredAbility extends TriggeredAbilityImpl { } -class ChooseOpponent extends OneShotEffect { - - public ChooseOpponent() { - super(Outcome.Neutral); - this.staticText = "choose an opponent"; - } - - public ChooseOpponent(final ChooseOpponent effect) { - super(effect); - } - - @Override - public ChooseOpponent copy() { - return new ChooseOpponent(this); - } - - @Override - public boolean apply(Game game, Ability source) { - Player player = game.getPlayer(source.getControllerId()); - Permanent permanent = game.getPermanent(source.getSourceId()); - if (player != null && permanent != null) { - TargetOpponent target = new TargetOpponent(); - target.setNotTarget(true); - if (player.choose(this.outcome, target, source.getSourceId(), game)) { - Player chosenPlayer = game.getPlayer(target.getFirstTarget()); - if (chosenPlayer != null) { - game.informPlayers(permanent.getName() + ": " + player.getLogName() + " has chosen " + chosenPlayer.getLogName()); - game.getState().setValue(permanent.getId() + "_player", target.getFirstTarget()); - return true; - } - } - } - return false; - } -} - class TheRackEffect extends OneShotEffect { public TheRackEffect() { diff --git a/Mage.Sets/src/mage/sets/futuresight/CloudKey.java b/Mage.Sets/src/mage/sets/futuresight/CloudKey.java index 7fc55b94457..33e946d9393 100644 --- a/Mage.Sets/src/mage/sets/futuresight/CloudKey.java +++ b/Mage.Sets/src/mage/sets/futuresight/CloudKey.java @@ -11,6 +11,7 @@ import mage.abilities.Ability; import mage.abilities.SpellAbility; import mage.abilities.common.AsEntersBattlefieldAbility; import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.effects.EntersBattlefieldEffect; import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.cost.CostModificationEffectImpl; import mage.cards.Card; @@ -23,6 +24,7 @@ import mage.constants.Outcome; import mage.constants.Rarity; import mage.constants.Zone; import mage.game.Game; +import mage.game.permanent.Permanent; import mage.players.Player; import mage.util.CardUtil; @@ -73,8 +75,11 @@ class CloudKeyChooseTypeEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { Player controller = game.getPlayer(source.getControllerId()); - MageObject sourceObject = source.getSourceObject(game); - if (sourceObject != null && controller != null) { + MageObject mageObject = (Permanent) getValue(EntersBattlefieldEffect.ENTERING_PERMANENT); + if (mageObject == null) { + mageObject = game.getObject(source.getSourceId()); + } + if (mageObject != null && controller != null) { ChoiceImpl choices = new ChoiceImpl(true); choices.setMessage("Choose a spell type"); choices.getChoices().add(CardType.ARTIFACT.toString()); @@ -82,9 +87,12 @@ class CloudKeyChooseTypeEffect extends OneShotEffect { choices.getChoices().add(CardType.ENCHANTMENT.toString()); choices.getChoices().add(CardType.INSTANT.toString()); choices.getChoices().add(CardType.SORCERY.toString()); - if(controller.choose(Outcome.Neutral, choices, game)) { - game.informPlayers(sourceObject.getLogName() + ": chosen spell type is " + choices.getChoice()); + if (controller.choose(Outcome.Neutral, choices, game)) { + game.informPlayers(mageObject.getLogName() + ": chosen spell type is " + choices.getChoice()); game.getState().setValue(source.getSourceId().toString() + "_CloudKey", choices.getChoice()); + if (mageObject instanceof Permanent) { + ((Permanent) mageObject).addInfo("chosenCardType", CardUtil.addToolTipMarkTags("Chosen card type: " + choices.getChoice()), game); + } return true; } } @@ -129,4 +137,3 @@ class CloudKeyCostModificationEffect extends CostModificationEffectImpl { return false; } } - diff --git a/Mage.Sets/src/mage/sets/gatecrash/Realmwright.java b/Mage.Sets/src/mage/sets/gatecrash/Realmwright.java index dfb670e3dd7..f0707af005d 100644 --- a/Mage.Sets/src/mage/sets/gatecrash/Realmwright.java +++ b/Mage.Sets/src/mage/sets/gatecrash/Realmwright.java @@ -29,6 +29,18 @@ package mage.sets.gatecrash; import java.util.List; import java.util.UUID; +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.AsEntersBattlefieldAbility; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.effects.ContinuousEffectImpl; +import mage.abilities.effects.common.ChooseBasicLandTypeEffect; +import mage.abilities.mana.BlackManaAbility; +import mage.abilities.mana.BlueManaAbility; +import mage.abilities.mana.GreenManaAbility; +import mage.abilities.mana.RedManaAbility; +import mage.abilities.mana.WhiteManaAbility; +import mage.cards.CardImpl; import mage.constants.CardType; import mage.constants.Duration; import mage.constants.Layer; @@ -36,15 +48,6 @@ import mage.constants.Outcome; import mage.constants.Rarity; import mage.constants.SubLayer; import mage.constants.Zone; -import mage.MageInt; -import mage.abilities.Ability; -import mage.abilities.common.AsEntersBattlefieldAbility; -import mage.abilities.common.SimpleStaticAbility; -import mage.abilities.effects.ContinuousEffectImpl; -import mage.abilities.effects.OneShotEffect; -import mage.abilities.mana.*; -import mage.cards.CardImpl; -import mage.choices.ChoiceImpl; import mage.filter.common.FilterControlledLandPermanent; import mage.game.Game; import mage.game.permanent.Permanent; @@ -66,7 +69,7 @@ public class Realmwright extends CardImpl { this.toughness = new MageInt(1); // As Realmwright enters the battlefield, choose a basic land type. - this.addAbility(new AsEntersBattlefieldAbility(new RealmwrightEffect())); + this.addAbility(new AsEntersBattlefieldAbility(new ChooseBasicLandTypeEffect(Outcome.Neutral))); // Lands you control are the chosen type in addition to their other types. this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new RealmwrightEffect2())); @@ -82,44 +85,6 @@ public class Realmwright extends CardImpl { } } -class RealmwrightEffect extends OneShotEffect { - - public RealmwrightEffect() { - super(Outcome.Neutral); - this.staticText = "Choose a basic land type"; - } - - public RealmwrightEffect(final RealmwrightEffect effect) { - super(effect); - } - - @Override - public RealmwrightEffect copy() { - return new RealmwrightEffect(this); - } - - @Override - public boolean apply(Game game, Ability source) { - Player you = game.getPlayer(source.getControllerId()); - if (you != null) { - ChoiceImpl choices = new ChoiceImpl(true); - choices.setMessage("Choose basic land type"); - choices.isRequired(); - choices.getChoices().add("Forest"); - choices.getChoices().add("Plains"); - choices.getChoices().add("Mountain"); - choices.getChoices().add("Island"); - choices.getChoices().add("Swamp"); - if (you.choose(Outcome.Neutral, choices, game)) { - game.informPlayers(new StringBuilder("Realmwright: ").append(" Chosen basic land type is ").append(choices.getChoice()).toString()); - game.getState().setValue(source.getSourceId().toString() + "_Realmwright", choices.getChoice()); - return true; - } - } - return false; - } -} - class RealmwrightEffect2 extends ContinuousEffectImpl { public RealmwrightEffect2() { @@ -140,7 +105,7 @@ class RealmwrightEffect2 extends ContinuousEffectImpl { public boolean apply(Layer layer, SubLayer sublayer, Ability source, Game game) { Player you = game.getPlayer(source.getControllerId()); List lands = game.getBattlefield().getAllActivePermanents(new FilterControlledLandPermanent(), source.getControllerId(), game); - String choice = (String) game.getState().getValue(source.getSourceId().toString() + "_Realmwright"); + String choice = (String) game.getState().getValue(source.getSourceId().toString() + ChooseBasicLandTypeEffect.VALUE_KEY); if (you != null && choice != null) { for (Permanent land : lands) { if (land != null) { diff --git a/Mage.Sets/src/mage/sets/guildpact/StompingGround.java b/Mage.Sets/src/mage/sets/guildpact/StompingGround.java index 0bce0460177..85c8b2ce2d4 100644 --- a/Mage.Sets/src/mage/sets/guildpact/StompingGround.java +++ b/Mage.Sets/src/mage/sets/guildpact/StompingGround.java @@ -25,18 +25,17 @@ * authors and should not be interpreted as representing official policies, either expressed * or implied, of BetaSteward_at_googlemail.com. */ - package mage.sets.guildpact; import java.util.UUID; -import mage.constants.CardType; -import mage.constants.Rarity; import mage.abilities.common.AsEntersBattlefieldAbility; import mage.abilities.costs.common.PayLifeCost; import mage.abilities.effects.common.TapSourceUnlessPaysEffect; import mage.abilities.mana.GreenManaAbility; import mage.abilities.mana.RedManaAbility; import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.Rarity; /** * @@ -44,17 +43,19 @@ import mage.cards.CardImpl; */ public class StompingGround extends CardImpl { - public StompingGround (UUID ownerId) { + public StompingGround(UUID ownerId) { super(ownerId, 165, "Stomping Ground", Rarity.RARE, new CardType[]{CardType.LAND}, null); this.expansionSetCode = "GPT"; this.subtype.add("Mountain"); this.subtype.add("Forest"); + this.addAbility(new RedManaAbility()); this.addAbility(new GreenManaAbility()); - this.addAbility(new AsEntersBattlefieldAbility(new TapSourceUnlessPaysEffect(new PayLifeCost(2)), "you may pay 2 life. If you don't, Stomping Ground enters the battlefield tapped")); + this.addAbility(new AsEntersBattlefieldAbility(new TapSourceUnlessPaysEffect(new PayLifeCost(2)), + "you may pay 2 life. If you don't, {this} enters the battlefield tapped")); } - public StompingGround (final StompingGround card) { + public StompingGround(final StompingGround card) { super(card); } diff --git a/Mage.Sets/src/mage/sets/journeyintonyx/HallOfTriumph.java b/Mage.Sets/src/mage/sets/journeyintonyx/HallOfTriumph.java index 6fb34b789b2..6423e7622b4 100644 --- a/Mage.Sets/src/mage/sets/journeyintonyx/HallOfTriumph.java +++ b/Mage.Sets/src/mage/sets/journeyintonyx/HallOfTriumph.java @@ -33,9 +33,8 @@ import mage.abilities.Ability; import mage.abilities.common.AsEntersBattlefieldAbility; import mage.abilities.common.SimpleStaticAbility; import mage.abilities.effects.ContinuousEffectImpl; -import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.ChooseColorEffect; import mage.cards.CardImpl; -import mage.choices.ChoiceColor; import mage.constants.CardType; import mage.constants.Duration; import mage.constants.Layer; @@ -46,8 +45,6 @@ import mage.constants.Zone; import mage.filter.common.FilterCreaturePermanent; import mage.game.Game; import mage.game.permanent.Permanent; -import mage.players.Player; - /** * @@ -61,7 +58,7 @@ public class HallOfTriumph extends CardImpl { this.supertype.add("Legendary"); // As Hall of Triumph enters the battlefield choose a color. - this.addAbility(new AsEntersBattlefieldAbility(new HallOfTriumphEffect())); + this.addAbility(new AsEntersBattlefieldAbility(new ChooseColorEffect(Outcome.Neutral))); // Creatures you control of the chosen color get +1/+1. this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new HallOfTriumphBoostControlledEffect())); } @@ -76,45 +73,6 @@ public class HallOfTriumph extends CardImpl { } } -class HallOfTriumphEffect extends OneShotEffect { - - public HallOfTriumphEffect() { - super(Outcome.BoostCreature); - staticText = "choose a color"; - } - - public HallOfTriumphEffect(final HallOfTriumphEffect effect) { - super(effect); - } - - @Override - public boolean apply(Game game, Ability source) { - Player player = game.getPlayer(source.getControllerId()); - Permanent permanent = game.getPermanent(source.getSourceId()); - if (player != null && permanent != null) { - ChoiceColor colorChoice = new ChoiceColor(); - colorChoice.setMessage("Choose color"); - while (!player.choose(Outcome.BoostCreature, colorChoice, game)) { - if (!player.canRespond()) { - return false; - } - } - if (colorChoice.getChoice() != null) { - game.informPlayers(permanent.getName() + ": " + player.getLogName() + " has chosen " + colorChoice.getChoice()); - game.getState().setValue(permanent.getId() + "_color", colorChoice.getColor()); - permanent.addInfo("chosen color", "Chosen color: " + colorChoice.getColor().getDescription() + "", game); - } - } - return false; - } - - @Override - public HallOfTriumphEffect copy() { - return new HallOfTriumphEffect(this); - } - -} - class HallOfTriumphBoostControlledEffect extends ContinuousEffectImpl { private static final FilterCreaturePermanent filter = new FilterCreaturePermanent(); @@ -137,7 +95,7 @@ class HallOfTriumphBoostControlledEffect extends ContinuousEffectImpl { public boolean apply(Game game, Ability source) { ObjectColor color = (ObjectColor) game.getState().getValue(source.getSourceId() + "_color"); if (color != null) { - for (Permanent perm: game.getBattlefield().getAllActivePermanents(filter, source.getControllerId(), game)) { + for (Permanent perm : game.getBattlefield().getAllActivePermanents(filter, source.getControllerId(), game)) { if (perm.getColor(game).shares(color)) { perm.addPower(1); perm.addToughness(1); diff --git a/Mage.Sets/src/mage/sets/limitedalpha/BlackVise.java b/Mage.Sets/src/mage/sets/limitedalpha/BlackVise.java index 057ebaa541b..57732f49119 100644 --- a/Mage.Sets/src/mage/sets/limitedalpha/BlackVise.java +++ b/Mage.Sets/src/mage/sets/limitedalpha/BlackVise.java @@ -32,6 +32,7 @@ import mage.abilities.Ability; import mage.abilities.TriggeredAbilityImpl; import mage.abilities.common.AsEntersBattlefieldAbility; import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.ChooseOpponentEffect; import mage.cards.CardImpl; import mage.constants.CardType; import mage.constants.Outcome; @@ -40,9 +41,7 @@ import mage.constants.Zone; import mage.game.Game; import mage.game.events.GameEvent; import mage.game.events.GameEvent.EventType; -import mage.game.permanent.Permanent; import mage.players.Player; -import mage.target.common.TargetOpponent; /** * @@ -55,7 +54,7 @@ public class BlackVise extends CardImpl { this.expansionSetCode = "LEA"; // As Black Vise enters the battlefield, choose an opponent. - this.addAbility(new AsEntersBattlefieldAbility(new BlackViseChooseOpponent())); + this.addAbility(new AsEntersBattlefieldAbility(new ChooseOpponentEffect(Outcome.Detriment))); // At the beginning of the chosen player's upkeep, Black Vise deals X damage to that player, where X is the number of cards in his or her hand minus 4. this.addAbility(new BlackViseTriggeredAbility()); } @@ -70,42 +69,6 @@ public class BlackVise extends CardImpl { } } -class BlackViseChooseOpponent extends OneShotEffect { - - public BlackViseChooseOpponent() { - super(Outcome.Neutral); - this.staticText = "choose an opponent"; - } - - public BlackViseChooseOpponent(final BlackViseChooseOpponent effect) { - super(effect); - } - - @Override - public BlackViseChooseOpponent copy() { - return new BlackViseChooseOpponent(this); - } - - @Override - public boolean apply(Game game, Ability source) { - Player player = game.getPlayer(source.getControllerId()); - Permanent permanent = game.getPermanent(source.getSourceId()); - if (player != null && permanent != null) { - TargetOpponent target = new TargetOpponent(); - target.setNotTarget(true); - if (player.choose(this.outcome, target, source.getSourceId(), game)) { - Player chosenPlayer = game.getPlayer(target.getFirstTarget()); - if (chosenPlayer != null) { - game.informPlayers(permanent.getName() + ": " + player.getLogName() + " has chosen " + chosenPlayer.getLogName()); - game.getState().setValue(permanent.getId() + "_player", target.getFirstTarget()); - return true; - } - } - } - return false; - } -} - class BlackViseTriggeredAbility extends TriggeredAbilityImpl { public BlackViseTriggeredAbility() { @@ -128,12 +91,12 @@ class BlackViseTriggeredAbility extends TriggeredAbilityImpl { @Override public boolean checkTrigger(GameEvent event, Game game) { - return event.getPlayerId().equals(game.getState().getValue(getSourceId().toString() + "_player")); + return event.getPlayerId().equals(game.getState().getValue(getSourceId().toString() + ChooseOpponentEffect.VALUE_KEY)); } @Override public String getRule() { - return new StringBuilder("At the beginning of the chosen player's upkeep, ").append(super.getRule()).toString(); + return "At the beginning of the chosen player's upkeep, " + super.getRule(); } } @@ -155,7 +118,7 @@ class BlackViseEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { - UUID playerId = (UUID) game.getState().getValue(source.getSourceId().toString() + "_player"); + UUID playerId = (UUID) game.getState().getValue(source.getSourceId().toString() + ChooseOpponentEffect.VALUE_KEY); Player chosenPlayer = game.getPlayer(playerId); if (chosenPlayer != null) { int damage = chosenPlayer.getHand().size() - 4; diff --git a/Mage.Sets/src/mage/sets/limitedalpha/PhantasmalTerrain.java b/Mage.Sets/src/mage/sets/limitedalpha/PhantasmalTerrain.java index f38d3ea0f7d..d7de486907b 100644 --- a/Mage.Sets/src/mage/sets/limitedalpha/PhantasmalTerrain.java +++ b/Mage.Sets/src/mage/sets/limitedalpha/PhantasmalTerrain.java @@ -28,13 +28,12 @@ package mage.sets.limitedalpha; import java.util.UUID; -import mage.MageObject; import mage.abilities.Ability; import mage.abilities.common.AsEntersBattlefieldAbility; import mage.abilities.common.SimpleStaticAbility; import mage.abilities.effects.ContinuousEffectImpl; -import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.AttachEffect; +import mage.abilities.effects.common.ChooseBasicLandTypeEffect; import mage.abilities.keyword.EnchantAbility; import mage.abilities.mana.BlackManaAbility; import mage.abilities.mana.BlueManaAbility; @@ -42,7 +41,6 @@ import mage.abilities.mana.GreenManaAbility; import mage.abilities.mana.RedManaAbility; import mage.abilities.mana.WhiteManaAbility; import mage.cards.CardImpl; -import mage.choices.ChoiceImpl; import mage.constants.CardType; import mage.constants.Duration; import mage.constants.Layer; @@ -52,7 +50,6 @@ import mage.constants.SubLayer; import mage.constants.Zone; import mage.game.Game; import mage.game.permanent.Permanent; -import mage.players.Player; import mage.target.TargetPermanent; import mage.target.common.TargetLandPermanent; @@ -72,10 +69,10 @@ public class PhantasmalTerrain extends CardImpl { this.getSpellAbility().addTarget(auraTarget); this.getSpellAbility().addEffect(new AttachEffect(Outcome.Detriment)); this.addAbility(new EnchantAbility(auraTarget.getTargetName())); - + // As Phantasmal Terrain enters the battlefield, choose a basic land type. - this.addAbility(new AsEntersBattlefieldAbility(new PhantasmalTerrainChooseEffect())); - + this.addAbility(new AsEntersBattlefieldAbility(new ChooseBasicLandTypeEffect(Outcome.Neutral))); + // Enchanted land is the chosen type. this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new PhantasmalTerrainContinuousEffect())); } @@ -90,52 +87,13 @@ public class PhantasmalTerrain extends CardImpl { } } -class PhantasmalTerrainChooseEffect extends OneShotEffect { - - public PhantasmalTerrainChooseEffect() { - super(Outcome.Neutral); - this.staticText = "choose a basic land type"; - } - - public PhantasmalTerrainChooseEffect(final PhantasmalTerrainChooseEffect effect) { - super(effect); - } - - @Override - public PhantasmalTerrainChooseEffect copy() { - return new PhantasmalTerrainChooseEffect(this); - } - - @Override - public boolean apply(Game game, Ability source) { - Player controller = game.getPlayer(source.getControllerId()); - MageObject sourceObject = source.getSourceObject(game); - if (sourceObject != null && controller != null) { - ChoiceImpl choices = new ChoiceImpl(true); - choices.setMessage("Choose basic land type"); - choices.getChoices().add("Forest"); - choices.getChoices().add("Plains"); - choices.getChoices().add("Mountain"); - choices.getChoices().add("Island"); - choices.getChoices().add("Swamp"); - if (controller.choose(Outcome.Neutral, choices, game)) { - game.informPlayers(sourceObject.getLogName() + ": chosen basic land type is " + choices.getChoice()); - game.getState().setValue(source.getSourceId().toString() + "_PhantasmalTerrain", choices.getChoice()); - return true; - } - } - return false; - } - -} - class PhantasmalTerrainContinuousEffect extends ContinuousEffectImpl { - public PhantasmalTerrainContinuousEffect(){ + public PhantasmalTerrainContinuousEffect() { super(Duration.WhileOnBattlefield, Outcome.Neutral); this.staticText = "enchanted land is the chosen type"; } - + public PhantasmalTerrainContinuousEffect(final PhantasmalTerrainContinuousEffect effect) { super(effect); } @@ -148,7 +106,7 @@ class PhantasmalTerrainContinuousEffect extends ContinuousEffectImpl { @Override public boolean apply(Layer layer, SubLayer sublayer, Ability source, Game game) { Permanent enchantment = game.getPermanent(source.getSourceId()); - String choice = (String) game.getState().getValue(source.getSourceId().toString() + "_PhantasmalTerrain"); + String choice = (String) game.getState().getValue(source.getSourceId().toString() + ChooseBasicLandTypeEffect.VALUE_KEY); if (enchantment != null && enchantment.getAttachedTo() != null && choice != null) { Permanent land = game.getPermanent(enchantment.getAttachedTo()); if (land != null) { @@ -195,5 +153,5 @@ class PhantasmalTerrainContinuousEffect extends ContinuousEffectImpl { public boolean hasLayer(Layer layer) { return layer == Layer.AbilityAddingRemovingEffects_6 || layer == Layer.TypeChangingEffects_4; } - + } diff --git a/Mage.Sets/src/mage/sets/magic2010/ConvincingMirage.java b/Mage.Sets/src/mage/sets/magic2010/ConvincingMirage.java index 5ee4db516fb..9049656edd4 100644 --- a/Mage.Sets/src/mage/sets/magic2010/ConvincingMirage.java +++ b/Mage.Sets/src/mage/sets/magic2010/ConvincingMirage.java @@ -27,21 +27,13 @@ */ package mage.sets.magic2010; -import java.util.Set; import java.util.UUID; -import mage.constants.CardType; -import mage.constants.Duration; -import mage.constants.Layer; -import mage.constants.Outcome; -import mage.constants.Rarity; -import mage.constants.SubLayer; -import mage.constants.Zone; import mage.abilities.Ability; import mage.abilities.common.AsEntersBattlefieldAbility; import mage.abilities.common.SimpleStaticAbility; import mage.abilities.effects.ContinuousEffectImpl; -import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.AttachEffect; +import mage.abilities.effects.common.ChooseBasicLandTypeEffect; import mage.abilities.keyword.EnchantAbility; import mage.abilities.mana.BlackManaAbility; import mage.abilities.mana.BlueManaAbility; @@ -49,10 +41,15 @@ import mage.abilities.mana.GreenManaAbility; import mage.abilities.mana.RedManaAbility; import mage.abilities.mana.WhiteManaAbility; import mage.cards.CardImpl; -import mage.choices.ChoiceImpl; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.Layer; +import mage.constants.Outcome; +import mage.constants.Rarity; +import mage.constants.SubLayer; +import mage.constants.Zone; import mage.game.Game; import mage.game.permanent.Permanent; -import mage.players.Player; import mage.target.TargetPermanent; import mage.target.common.TargetLandPermanent; @@ -67,13 +64,12 @@ public class ConvincingMirage extends CardImpl { this.expansionSetCode = "M10"; this.subtype.add("Aura"); - // Enchant land TargetPermanent auraTarget = new TargetLandPermanent(); this.getSpellAbility().addTarget(auraTarget); this.getSpellAbility().addEffect(new AttachEffect(Outcome.Detriment)); // As Convincing Mirage enters the battlefield, choose a basic land type. - this.addAbility(new AsEntersBattlefieldAbility(new ConvincingMirageEffect())); + this.addAbility(new AsEntersBattlefieldAbility(new ChooseBasicLandTypeEffect(Outcome.Neutral))); // Enchanted land is the chosen type. Ability ability = new EnchantAbility(auraTarget.getTargetName()); this.addAbility(ability); @@ -90,42 +86,6 @@ public class ConvincingMirage extends CardImpl { } } -class ConvincingMirageEffect extends OneShotEffect { - - public ConvincingMirageEffect() { - super(Outcome.Neutral); - this.staticText = "choose a basic land type"; - } - - public ConvincingMirageEffect(final ConvincingMirageEffect effect) { - super(effect); - } - - @Override - public ConvincingMirageEffect copy() { - return new ConvincingMirageEffect(this); - } - - @Override - public boolean apply(Game game, Ability source) { - Player player = game.getPlayer(source.getControllerId()); - if (player != null) { - ChoiceImpl choices = new ChoiceImpl(true); - Set choicesSet = choices.getChoices(); - choicesSet.add("Forest"); - choicesSet.add("Plains"); - choicesSet.add("Mountain"); - choicesSet.add("Island"); - choicesSet.add("Swamp"); - if (player.choose(Outcome.Neutral, choices, game)) { - game.getState().setValue(source.getSourceId().toString() + "_ConvincingMirage", choices.getChoice()); - return true; - } - } - return false; - } -} - class ConvincingMirageContinousEffect extends ContinuousEffectImpl { public ConvincingMirageContinousEffect() { @@ -145,7 +105,7 @@ class ConvincingMirageContinousEffect extends ContinuousEffectImpl { @Override public boolean apply(Layer layer, SubLayer sublayer, Ability source, Game game) { Permanent enchantment = game.getPermanent(source.getSourceId()); - String choice = (String) game.getState().getValue(source.getSourceId().toString() + "_ConvincingMirage"); + String choice = (String) game.getState().getValue(source.getSourceId().toString() + ChooseBasicLandTypeEffect.VALUE_KEY); if (enchantment != null && enchantment.getAttachedTo() != null && choice != null) { Permanent land = game.getPermanent(enchantment.getAttachedTo()); if (land != null) { @@ -160,19 +120,19 @@ class ConvincingMirageContinousEffect extends ContinuousEffectImpl { if (sublayer == SubLayer.NA) { land.getAbilities().clear(); if (choice.equals("Forest")) { - land.addAbility(new GreenManaAbility(), game); + land.addAbility(new GreenManaAbility(), source.getSourceId(), game); } if (choice.equals("Plains")) { - land.addAbility(new WhiteManaAbility(), game); + land.addAbility(new WhiteManaAbility(), source.getSourceId(), game); } if (choice.equals("Mountain")) { - land.addAbility(new RedManaAbility(), game); + land.addAbility(new RedManaAbility(), source.getSourceId(), game); } if (choice.equals("Island")) { - land.addAbility(new BlueManaAbility(), game); + land.addAbility(new BlueManaAbility(), source.getSourceId(), game); } if (choice.equals("Swamp")) { - land.addAbility(new BlackManaAbility(), game); + land.addAbility(new BlackManaAbility(), source.getSourceId(), game); } } break; @@ -192,4 +152,4 @@ class ConvincingMirageContinousEffect extends ContinuousEffectImpl { public boolean hasLayer(Layer layer) { return layer == Layer.AbilityAddingRemovingEffects_6 || layer == Layer.TypeChangingEffects_4; } -} \ No newline at end of file +} diff --git a/Mage.Sets/src/mage/sets/magic2012/SuturedGhoul.java b/Mage.Sets/src/mage/sets/magic2012/SuturedGhoul.java index 42a2b16593f..44cc9264d27 100644 --- a/Mage.Sets/src/mage/sets/magic2012/SuturedGhoul.java +++ b/Mage.Sets/src/mage/sets/magic2012/SuturedGhoul.java @@ -27,26 +27,32 @@ */ package mage.sets.magic2012; +import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.AsEntersBattlefieldAbility; import mage.abilities.common.SimpleStaticAbility; import mage.abilities.dynamicvalue.DynamicValue; import mage.abilities.effects.Effect; +import mage.abilities.effects.EntersBattlefieldEffect; import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.continuous.BoostSourceEffect; import mage.abilities.keyword.TrampleAbility; import mage.cards.Card; import mage.cards.CardImpl; -import mage.constants.*; +import mage.cards.Cards; +import mage.cards.CardsImpl; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.Outcome; +import mage.constants.Rarity; +import mage.constants.Zone; import mage.filter.common.FilterCreatureCard; import mage.game.Game; import mage.game.permanent.Permanent; import mage.players.Player; import mage.target.common.TargetCardInYourGraveyard; -import java.util.UUID; - /** * @author nantuko */ @@ -97,30 +103,32 @@ class SuturedGhoulEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { - Player player = game.getPlayer(source.getControllerId()); - Permanent permanent = game.getPermanent(source.getSourceId()); - if (player.getGraveyard().size() > 0) { - + Player controller = game.getPlayer(source.getControllerId()); + Permanent permanent = (Permanent) getValue(EntersBattlefieldEffect.ENTERING_PERMANENT); + if (permanent == null) { + return false; + } + if (controller.getGraveyard().size() > 0) { TargetCardInYourGraveyard target = new TargetCardInYourGraveyard(0, Integer.MAX_VALUE, new FilterCreatureCard("creature cards from your graveyard")); - if (player.chooseTarget(Outcome.Benefit, target, source, game)) { + if (controller.chooseTarget(Outcome.Benefit, target, source, game)) { int count = 0; for (UUID uuid : target.getTargets()) { - Card card = player.getGraveyard().get(uuid, game); + Card card = controller.getGraveyard().get(uuid, game); if (card != null) { - card.moveToExile(getId(), "Sutured Ghoul", source.getSourceId(), game); - if (permanent != null) { - permanent.imprint(card.getId(), game); - count++; - } + card.moveToExile(getId(), permanent.getIdName(), source.getSourceId(), game); + permanent.imprint(card.getId(), game); + count++; } } + Cards cardsToExile = new CardsImpl(target.getTargets()); + controller.moveCards(cardsToExile, null, Zone.EXILED, source, game); String msg = count == 1 ? "1 card" : count + "cards"; - game.informPlayers("Sutured Ghoul: " + player.getLogName() + " exiled " + msg); + game.informPlayers(permanent.getLogName() + ": " + controller.getLogName() + " exiled " + msg); } } else { - game.informPlayers("Sutured Ghoul: No cards in graveyard."); + game.informPlayers(permanent.getLogName() + ": No cards in graveyard."); } return true; } @@ -147,7 +155,7 @@ class SuturedGhoulPowerCount implements DynamicValue { int amount = 0; Permanent permanent = game.getPermanent(sourceAbility.getSourceId()); if (permanent != null) { - for (UUID uuid: permanent.getImprinted()) { + for (UUID uuid : permanent.getImprinted()) { Card card = game.getCard(uuid); if (card != null) { amount += card.getPower().getValue(); @@ -189,7 +197,7 @@ class SuturedGhoulToughnessCount implements DynamicValue { int amount = 0; Permanent permanent = game.getPermanent(sourceAbility.getSourceId()); if (permanent != null) { - for (UUID uuid: permanent.getImprinted()) { + for (UUID uuid : permanent.getImprinted()) { Card card = game.getCard(uuid); if (card != null) { amount += card.getToughness().getValue(); @@ -214,5 +222,3 @@ class SuturedGhoulToughnessCount implements DynamicValue { return "the total toughness of the exiled cards"; } } - - diff --git a/Mage.Sets/src/mage/sets/returntoravnica/TabletOfTheGuilds.java b/Mage.Sets/src/mage/sets/returntoravnica/TabletOfTheGuilds.java index ffe0df331bd..c13d4cf6131 100644 --- a/Mage.Sets/src/mage/sets/returntoravnica/TabletOfTheGuilds.java +++ b/Mage.Sets/src/mage/sets/returntoravnica/TabletOfTheGuilds.java @@ -28,17 +28,17 @@ package mage.sets.returntoravnica; import java.util.UUID; - -import mage.constants.CardType; -import mage.constants.Outcome; -import mage.constants.Rarity; import mage.ObjectColor; import mage.abilities.Ability; import mage.abilities.common.AsEntersBattlefieldAbility; import mage.abilities.common.SpellCastControllerTriggeredAbility; +import mage.abilities.effects.EntersBattlefieldEffect; import mage.abilities.effects.OneShotEffect; import mage.cards.CardImpl; import mage.choices.ChoiceColor; +import mage.constants.CardType; +import mage.constants.Outcome; +import mage.constants.Rarity; import mage.filter.FilterSpell; import mage.game.Game; import mage.game.permanent.Permanent; @@ -59,7 +59,7 @@ public class TabletOfTheGuilds extends CardImpl { this.addAbility(new AsEntersBattlefieldAbility(new TabletOfTheGuildsEntersBattlefieldEffect())); // Whenever you cast a spell, if it's at least one of the chosen colors, you gain 1 life for each of the chosen colors it is. - this.addAbility(new SpellCastControllerTriggeredAbility(new TabletOfTheGuildsGainLifeEffect(), new FilterSpell("a spell"), false, true )); + this.addAbility(new SpellCastControllerTriggeredAbility(new TabletOfTheGuildsGainLifeEffect(), new FilterSpell("a spell"), false, true)); } public TabletOfTheGuilds(final TabletOfTheGuilds card) { @@ -86,7 +86,7 @@ class TabletOfTheGuildsEntersBattlefieldEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { Player player = game.getPlayer(source.getControllerId()); - Permanent permanent = game.getPermanent(source.getSourceId()); + Permanent permanent = (Permanent) getValue(EntersBattlefieldEffect.ENTERING_PERMANENT); if (player != null && permanent != null) { String colors; ChoiceColor colorChoice = new ChoiceColor(); @@ -101,7 +101,7 @@ class TabletOfTheGuildsEntersBattlefieldEffect extends OneShotEffect { colorChoice.getChoices().remove(colorChoice.getChoice()); colorChoice.setMessage("Choose the second color"); - while (!player.choose(Outcome.GainLife, colorChoice, game) && player.canRespond()) { + while (!player.choose(Outcome.GainLife, colorChoice, game) && player.canRespond()) { game.debugMessage("player canceled choosing type. retrying."); } game.getState().setValue(permanent.getId() + "_color2", colorChoice.getColor().toString()); @@ -157,4 +157,4 @@ class TabletOfTheGuildsGainLifeEffect extends OneShotEffect { public TabletOfTheGuildsGainLifeEffect copy() { return new TabletOfTheGuildsGainLifeEffect(this); } -} \ No newline at end of file +} diff --git a/Mage.Sets/src/mage/sets/riseoftheeldrazi/CurseOfWizardry.java b/Mage.Sets/src/mage/sets/riseoftheeldrazi/CurseOfWizardry.java index bd4d6e4b53f..db2d0e39027 100644 --- a/Mage.Sets/src/mage/sets/riseoftheeldrazi/CurseOfWizardry.java +++ b/Mage.Sets/src/mage/sets/riseoftheeldrazi/CurseOfWizardry.java @@ -29,13 +29,11 @@ package mage.sets.riseoftheeldrazi; import java.util.UUID; import mage.ObjectColor; -import mage.abilities.Ability; import mage.abilities.TriggeredAbilityImpl; import mage.abilities.common.AsEntersBattlefieldAbility; -import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.ChooseColorEffect; import mage.abilities.effects.common.LoseLifeTargetEffect; import mage.cards.CardImpl; -import mage.choices.ChoiceColor; import mage.constants.CardType; import mage.constants.Outcome; import mage.constants.Rarity; @@ -45,7 +43,6 @@ import mage.game.events.GameEvent; import mage.game.events.GameEvent.EventType; import mage.game.permanent.Permanent; import mage.game.stack.Spell; -import mage.players.Player; import mage.target.targetpointer.FixedTarget; /** @@ -57,9 +54,8 @@ public class CurseOfWizardry extends CardImpl { super(ownerId, 104, "Curse of Wizardry", Rarity.UNCOMMON, new CardType[]{CardType.ENCHANTMENT}, "{2}{B}{B}"); this.expansionSetCode = "ROE"; - // As Curse of Wizardry enters the battlefield, choose a color. - this.addAbility(new AsEntersBattlefieldAbility(new CurseOfWizardryChooseColorEffect())); + this.addAbility(new AsEntersBattlefieldAbility(new ChooseColorEffect(Outcome.Neutral))); // Whenever a player casts a spell of the chosen color, that player loses 1 life. this.addAbility(new CurseOfWizardryPlayerCastsSpellChosenColorTriggeredAbility()); @@ -76,38 +72,6 @@ public class CurseOfWizardry extends CardImpl { } } -class CurseOfWizardryChooseColorEffect extends OneShotEffect { - - public CurseOfWizardryChooseColorEffect() { - super(Outcome.Detriment); - staticText = "choose a color"; - } - - public CurseOfWizardryChooseColorEffect(final CurseOfWizardryChooseColorEffect effect) { - super(effect); - } - - @Override - public boolean apply(Game game, Ability source) { - Player player = game.getPlayer(source.getControllerId()); - Permanent curseOfWizardry = game.getPermanent(source.getSourceId()); - if (player != null && curseOfWizardry != null) { - ChoiceColor colorChoice = new ChoiceColor(); - if (player.choose(Outcome.Detriment, colorChoice, game)) { - game.informPlayers(curseOfWizardry.getName() + ": " + player.getLogName() + " has chosen " + colorChoice.getChoice()); - game.getState().setValue(curseOfWizardry.getId() + "_color", colorChoice.getColor()); - curseOfWizardry.addInfo("chosen color", "Chosen color: " + colorChoice.getColor().getDescription() + "", game); - } - } - return false; - } - - @Override - public CurseOfWizardryChooseColorEffect copy() { - return new CurseOfWizardryChooseColorEffect(this); - } -} - class CurseOfWizardryPlayerCastsSpellChosenColorTriggeredAbility extends TriggeredAbilityImpl { public CurseOfWizardryPlayerCastsSpellChosenColorTriggeredAbility() { diff --git a/Mage.Sets/src/mage/sets/shadowmoor/LureboundScarecrow.java b/Mage.Sets/src/mage/sets/shadowmoor/LureboundScarecrow.java index 1964cd1cc43..ba232975d03 100644 --- a/Mage.Sets/src/mage/sets/shadowmoor/LureboundScarecrow.java +++ b/Mage.Sets/src/mage/sets/shadowmoor/LureboundScarecrow.java @@ -32,9 +32,11 @@ import mage.MageInt; import mage.ObjectColor; import mage.abilities.StateTriggeredAbility; import mage.abilities.common.AsEntersBattlefieldAbility; +import mage.abilities.effects.common.ChooseColorEffect; import mage.abilities.effects.common.SacrificeSourceEffect; import mage.cards.CardImpl; import mage.constants.CardType; +import mage.constants.Outcome; import mage.constants.Rarity; import mage.constants.Zone; import mage.game.Game; @@ -56,7 +58,7 @@ public class LureboundScarecrow extends CardImpl { this.toughness = new MageInt(4); // As Lurebound Scarecrow enters the battlefield, choose a color. - this.addAbility(new AsEntersBattlefieldAbility(new ChooseColorEffect())); + this.addAbility(new AsEntersBattlefieldAbility(new ChooseColorEffect(Outcome.Detriment))); // When you control no permanents of the chosen color, sacrifice Lurebound Scarecrow. this.addAbility(new LureboundScarecrowTriggeredAbility()); diff --git a/Mage.Sets/src/mage/sets/shadowmoor/PaintersServant.java b/Mage.Sets/src/mage/sets/shadowmoor/PaintersServant.java index 10364727e8c..8ec07fbc98f 100644 --- a/Mage.Sets/src/mage/sets/shadowmoor/PaintersServant.java +++ b/Mage.Sets/src/mage/sets/shadowmoor/PaintersServant.java @@ -35,10 +35,9 @@ import mage.abilities.Ability; import mage.abilities.common.AsEntersBattlefieldAbility; import mage.abilities.common.SimpleStaticAbility; import mage.abilities.effects.ContinuousEffectImpl; -import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.ChooseColorEffect; import mage.cards.Card; import mage.cards.CardImpl; -import mage.choices.ChoiceColor; import mage.constants.CardType; import mage.constants.Duration; import mage.constants.Layer; @@ -68,7 +67,7 @@ public class PaintersServant extends CardImpl { this.toughness = new MageInt(3); // As Painter's Servant enters the battlefield, choose a color. - this.addAbility(new AsEntersBattlefieldAbility(new ChooseColorEffect())); + this.addAbility(new AsEntersBattlefieldAbility(new ChooseColorEffect(Outcome.Detriment))); // All cards that aren't on the battlefield, spells, and permanents are the chosen color in addition to their other colors. this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new PaintersServantEffect())); @@ -84,40 +83,6 @@ public class PaintersServant extends CardImpl { } } -class ChooseColorEffect extends OneShotEffect { - - public ChooseColorEffect() { - super(Outcome.Detriment); - staticText = "choose a color"; - } - - public ChooseColorEffect(final ChooseColorEffect effect) { - super(effect); - } - - @Override - public boolean apply(Game game, Ability source) { - Player player = game.getPlayer(source.getControllerId()); - Permanent permanent = game.getPermanent(source.getSourceId()); - if (player != null && permanent != null) { - ChoiceColor colorChoice = new ChoiceColor(); - if (player.choose(Outcome.Neutral, colorChoice, game)) { - game.informPlayers(new StringBuilder(permanent.getName()).append(": ").append(player.getLogName()).append(" has chosen ").append(colorChoice.getChoice()).toString()); - game.getState().setValue(source.getSourceId() + "_color", colorChoice.getColor()); - permanent.addInfo("chosen color", "Chosen color: " + colorChoice.getColor().getDescription() + "", game); - } - return true; - } - return false; - } - - @Override - public ChooseColorEffect copy() { - return new ChooseColorEffect(this); - } - -} - class PaintersServantEffect extends ContinuousEffectImpl { public PaintersServantEffect() { @@ -175,10 +140,10 @@ class PaintersServantEffect extends ContinuousEffectImpl { } return false; } - + protected static void setCardColor(Card card, String colorString, Game game) { ObjectColor color = game.getState().getCreateCardAttribute(card).getColor(); - switch (colorString) { + switch (colorString) { case "W": color.setWhite(true); break; diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/single/avr/CavernOfSoulsTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/single/avr/CavernOfSoulsTest.java index eb69c8b1c41..5062c9244ab 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/single/avr/CavernOfSoulsTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/single/avr/CavernOfSoulsTest.java @@ -33,8 +33,9 @@ public class CavernOfSoulsTest extends CardTestPlayerBase { } /** - * Tests "Cavern of Souls" with "Human" creature type chosen. - * Then tests casting Azure Drake (should fail) and Elite Vanguard (should be ok as it has "Human" subtype) + * Tests "Cavern of Souls" with "Human" creature type chosen. Then tests + * casting Azure Drake (should fail) and Elite Vanguard (should be ok as it + * has "Human" subtype) */ @Test public void testNoCastBecauseOfCreatureType() { @@ -87,6 +88,9 @@ public class CavernOfSoulsTest extends CardTestPlayerBase { @Test public void testDrakeCantBeCountered() { addCard(Zone.BATTLEFIELD, playerA, "Mountain", 3); + // As Cavern of Souls enters the battlefield, choose a creature type. + // {T}: Add {1} to your mana pool. + // {T}: Add one mana of any color to your mana pool. Spend this mana only to cast a creature spell of the chosen type, and that spell can't be countered. addCard(Zone.HAND, playerA, "Cavern of Souls"); addCard(Zone.HAND, playerA, "Azure Drake"); @@ -108,6 +112,7 @@ public class CavernOfSoulsTest extends CardTestPlayerBase { assertGraveyardCount(playerA, "Azure Drake", 0); assertPermanentCount(playerA, "Azure Drake", 1); } + /** * Tests spell can be countered if cast with colorless mana from Cavern */ @@ -136,59 +141,59 @@ public class CavernOfSoulsTest extends CardTestPlayerBase { assertGraveyardCount(playerA, "Azure Drake", 1); assertPermanentCount(playerA, "Azure Drake", 0); } - + /** - * Tests conditional mana from Cavern in pool will still work if Cavern got back to hand and is played again with other creature type + * Tests conditional mana from Cavern in pool will still work if Cavern got + * back to hand and is played again with other creature type */ @Test public void testConditionlManaWorksIfCavernIsReplayed() { addCard(Zone.HAND, playerA, "Cavern of Souls"); addCard(Zone.HAND, playerA, "Gladecover Scout"); // Elf costing {G} // addCard(Zone.HAND, playerA, "Fume Spitter"); // Horror costing {B} - + // Instant - {U}{U} - Return target permanent to its owner's hand. addCard(Zone.HAND, playerB, "Boomerang"); addCard(Zone.BATTLEFIELD, playerB, "Island", 2); playLand(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Cavern of Souls"); setChoice(playerA, "Elf"); - + // getting green mana for Elf into pool activateManaAbility(3, PhaseStep.PRECOMBAT_MAIN, playerA, "{T}: Add 1 mana of any one color to your mana pool. Spend this mana only to cast a creature spell of the chosen type, and that spell can't be countered."); - setChoice(playerA, "Green"); - + setChoice(playerA, "Green"); + // return cavern to hand castSpell(3, PhaseStep.PRECOMBAT_MAIN, playerB, "Boomerang", "Cavern of Souls"); - + // playing the cavern again choose different creature type playLand(3, PhaseStep.PRECOMBAT_MAIN, playerA, "Cavern of Souls"); setChoice(playerA, "Horror"); - // the green mana usable for Elf should be in the mana pool + // the green mana usable for Elf should be in the mana pool castSpell(3, PhaseStep.PRECOMBAT_MAIN, playerA, "Gladecover Scout"); activateManaAbility(3, PhaseStep.PRECOMBAT_MAIN, playerA, "{T}: Add 1 mana of any one color to your mana pool. Spend this mana only to cast a creature spell of the chosen type, and that spell can't be countered."); - setChoice(playerA, "Black"); + setChoice(playerA, "Black"); - // the black mana usable for Horror should be in the mana pool + // the black mana usable for Horror should be in the mana pool // castSpell(3, PhaseStep.PRECOMBAT_MAIN, playerA, "Fume Spitter"); - setStopAt(3, PhaseStep.BEGIN_COMBAT); execute(); - assertGraveyardCount(playerB, "Boomerang", 1); assertPermanentCount(playerA, "Cavern of Souls", 1); - + // Check the elf was cast assertPermanentCount(playerA, "Gladecover Scout", 1); // Check Horror on the Battlefield // assertPermanentCount(playerA, "Fume Spitter", 1); - } + } /** - * Return to the Ranks cannot be countered if mana produced by Cavern of Souls - * was used to pay X. Can be bug also for all other spells with X in their cost, not sure. + * Return to the Ranks cannot be countered if mana produced by Cavern of + * Souls was used to pay X. Can be bug also for all other spells with X in + * their cost, not sure. * */ @Test @@ -205,12 +210,11 @@ public class CavernOfSoulsTest extends CardTestPlayerBase { addCard(Zone.HAND, playerB, "Counterspell"); addCard(Zone.BATTLEFIELD, playerB, "Island", 2); - playLand(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Cavern of Souls"); setChoice(playerA, "Drake"); castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Return to the Ranks", "Silvercoat Lion"); setChoice(playerA, "X=1"); - + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerB, "Counterspell", "Return to the Ranks"); setStopAt(1, PhaseStep.BEGIN_COMBAT); @@ -223,11 +227,12 @@ public class CavernOfSoulsTest extends CardTestPlayerBase { assertPermanentCount(playerA, "Silvercoat Lion", 0); } - + /** - * Cavern of Souls can produce any colour of mana with its second ability when Contamination is in play. + * Cavern of Souls can produce any colour of mana with its second ability + * when Contamination is in play. */ - @Test + @Test public void testUseWithConversionInPlay() { addCard(Zone.BATTLEFIELD, playerA, "Plains", 3); addCard(Zone.HAND, playerA, "Cavern of Souls"); @@ -235,8 +240,6 @@ public class CavernOfSoulsTest extends CardTestPlayerBase { addCard(Zone.HAND, playerA, "Desert Drake"); addCard(Zone.BATTLEFIELD, playerB, "Contamination", 1); - - playLand(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Cavern of Souls"); setChoice(playerA, "Drake"); @@ -249,5 +252,5 @@ public class CavernOfSoulsTest extends CardTestPlayerBase { assertPermanentCount(playerA, "Desert Drake", 0); } - + } diff --git a/Mage/src/mage/abilities/effects/common/ChooseBasicLandTypeEffect.java b/Mage/src/mage/abilities/effects/common/ChooseBasicLandTypeEffect.java new file mode 100644 index 00000000000..07c1e706e9b --- /dev/null +++ b/Mage/src/mage/abilities/effects/common/ChooseBasicLandTypeEffect.java @@ -0,0 +1,68 @@ +/* + * To change this license header, choose License Headers in Project Properties. + * To change this template file, choose Tools | Templates + * and open the template in the editor. + */ +package mage.abilities.effects.common; + +import mage.MageObject; +import mage.abilities.Ability; +import mage.abilities.effects.EntersBattlefieldEffect; +import mage.abilities.effects.OneShotEffect; +import mage.choices.ChoiceImpl; +import mage.constants.Outcome; +import mage.game.Game; +import mage.game.permanent.Permanent; +import mage.players.Player; +import mage.util.CardUtil; + +/** + * + * @author LevelX2 + */ +public class ChooseBasicLandTypeEffect extends OneShotEffect { + + public static String VALUE_KEY = "BasicLandType"; + + public ChooseBasicLandTypeEffect(Outcome outcome) { + super(outcome); + this.staticText = "Choose a basic land type"; + } + + public ChooseBasicLandTypeEffect(final ChooseBasicLandTypeEffect effect) { + super(effect); + } + + @Override + public ChooseBasicLandTypeEffect copy() { + return new ChooseBasicLandTypeEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player controller = game.getPlayer(source.getControllerId()); + MageObject mageObject = (Permanent) getValue(EntersBattlefieldEffect.ENTERING_PERMANENT); + if (mageObject == null) { + mageObject = game.getObject(source.getSourceId()); + } + if (controller != null && mageObject != null) { + ChoiceImpl choices = new ChoiceImpl(true); + choices.setMessage("Choose basic land type"); + choices.isRequired(); + choices.getChoices().add("Forest"); + choices.getChoices().add("Plains"); + choices.getChoices().add("Mountain"); + choices.getChoices().add("Island"); + choices.getChoices().add("Swamp"); + if (controller.choose(Outcome.Neutral, choices, game)) { + game.informPlayers(mageObject.getName() + ": Chosen basic land type is " + choices.getChoice()); + game.getState().setValue(mageObject.getId().toString() + VALUE_KEY, choices.getChoice()); + if (mageObject instanceof Permanent) { + ((Permanent) mageObject).addInfo("chosen color", CardUtil.addToolTipMarkTags("Chosen basic land type: " + choices.getChoice()), game); + } + return true; + } + } + return false; + } +} diff --git a/Mage/src/mage/abilities/effects/common/ChooseColorEffect.java b/Mage/src/mage/abilities/effects/common/ChooseColorEffect.java index 43836dd2f74..2fe01116753 100644 --- a/Mage/src/mage/abilities/effects/common/ChooseColorEffect.java +++ b/Mage/src/mage/abilities/effects/common/ChooseColorEffect.java @@ -27,6 +27,7 @@ */ package mage.abilities.effects.common; +import mage.MageObject; import mage.abilities.Ability; import mage.abilities.effects.EntersBattlefieldEffect; import mage.abilities.effects.OneShotEffect; @@ -55,11 +56,11 @@ public class ChooseColorEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { Player controller = game.getPlayer(source.getControllerId()); - Permanent permanent = game.getPermanent(source.getSourceId()); - if (permanent == null) { - permanent = (Permanent) getValue(EntersBattlefieldEffect.ENTERING_PERMANENT); + MageObject mageObject = (Permanent) getValue(EntersBattlefieldEffect.ENTERING_PERMANENT); + if (mageObject == null) { + mageObject = game.getObject(source.getSourceId()); } - if (controller != null && permanent != null) { + if (controller != null && mageObject != null) { ChoiceColor choice = new ChoiceColor(); while (!choice.isChosen()) { controller.choose(outcome, choice, game); @@ -68,10 +69,12 @@ public class ChooseColorEffect extends OneShotEffect { } } if (!game.isSimulation()) { - game.informPlayers(permanent.getLogName() + ": " + controller.getLogName() + " has chosen " + choice.getChoice()); + game.informPlayers(mageObject.getLogName() + ": " + controller.getLogName() + " has chosen " + choice.getChoice()); + } + game.getState().setValue(mageObject.getId() + "_color", choice.getColor()); + if (mageObject instanceof Permanent) { + ((Permanent) mageObject).addInfo("chosen color", CardUtil.addToolTipMarkTags("Chosen color: " + choice.getChoice()), game); } - game.getState().setValue(source.getSourceId() + "_color", choice.getColor()); - permanent.addInfo("chosen color", CardUtil.addToolTipMarkTags("Chosen color: " + choice.getChoice()), game); return true; } return false; diff --git a/Mage/src/mage/abilities/effects/common/ChooseCreatureTypeEffect.java b/Mage/src/mage/abilities/effects/common/ChooseCreatureTypeEffect.java index 2ebd99cc9d2..06178b02843 100644 --- a/Mage/src/mage/abilities/effects/common/ChooseCreatureTypeEffect.java +++ b/Mage/src/mage/abilities/effects/common/ChooseCreatureTypeEffect.java @@ -27,7 +27,9 @@ */ package mage.abilities.effects.common; +import mage.MageObject; import mage.abilities.Ability; +import mage.abilities.effects.EntersBattlefieldEffect; import mage.abilities.effects.OneShotEffect; import mage.cards.repository.CardRepository; import mage.choices.Choice; @@ -42,7 +44,6 @@ import mage.util.CardUtil; * * @author LevelX2 */ - public class ChooseCreatureTypeEffect extends OneShotEffect { public ChooseCreatureTypeEffect(Outcome outcome) { @@ -57,8 +58,11 @@ public class ChooseCreatureTypeEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { Player controller = game.getPlayer(source.getControllerId()); - Permanent permanent = game.getPermanent(source.getSourceId()); - if (controller != null && permanent != null) { + MageObject mageObject = (Permanent) getValue(EntersBattlefieldEffect.ENTERING_PERMANENT); + if (mageObject == null) { + mageObject = game.getObject(source.getSourceId()); + } + if (controller != null && mageObject != null) { Choice typeChoice = new ChoiceImpl(true); typeChoice.setMessage("Choose creature type"); typeChoice.setChoices(CardRepository.instance.getCreatureTypes()); @@ -68,10 +72,12 @@ public class ChooseCreatureTypeEffect extends OneShotEffect { } } if (!game.isSimulation()) { - game.informPlayers(permanent.getName() + ": " + controller.getLogName() + " has chosen " + typeChoice.getChoice()); + game.informPlayers(mageObject.getName() + ": " + controller.getLogName() + " has chosen " + typeChoice.getChoice()); + } + game.getState().setValue(mageObject.getId() + "_type", typeChoice.getChoice()); + if (mageObject instanceof Permanent) { + ((Permanent) mageObject).addInfo("chosen type", CardUtil.addToolTipMarkTags("Chosen type: " + typeChoice.getChoice()), game); } - game.getState().setValue(permanent.getId() + "_type", typeChoice.getChoice()); - permanent.addInfo("chosen type", CardUtil.addToolTipMarkTags("Chosen type: " + typeChoice.getChoice()), game); } return false; } diff --git a/Mage/src/mage/abilities/effects/common/ChooseLandTypeEffect.java b/Mage/src/mage/abilities/effects/common/ChooseLandTypeEffect.java index 0480effa493..52259dbac52 100644 --- a/Mage/src/mage/abilities/effects/common/ChooseLandTypeEffect.java +++ b/Mage/src/mage/abilities/effects/common/ChooseLandTypeEffect.java @@ -5,7 +5,9 @@ */ package mage.abilities.effects.common; +import mage.MageObject; import mage.abilities.Ability; +import mage.abilities.effects.EntersBattlefieldEffect; import mage.abilities.effects.OneShotEffect; import mage.cards.repository.CardRepository; import mage.choices.Choice; @@ -34,8 +36,11 @@ public class ChooseLandTypeEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { Player controller = game.getPlayer(source.getControllerId()); - Permanent permanent = game.getPermanent(source.getSourceId()); - if (controller != null && permanent != null) { + MageObject mageObject = (Permanent) getValue(EntersBattlefieldEffect.ENTERING_PERMANENT); + if (mageObject == null) { + mageObject = game.getObject(source.getSourceId()); + } + if (controller != null && mageObject != null) { Choice typeChoice = new ChoiceImpl(true); typeChoice.setMessage("Choose land type"); typeChoice.setChoices(CardRepository.instance.getLandTypes()); @@ -45,10 +50,12 @@ public class ChooseLandTypeEffect extends OneShotEffect { } } if (!game.isSimulation()) { - game.informPlayers(permanent.getName() + ": " + controller.getLogName() + " has chosen " + typeChoice.getChoice()); + game.informPlayers(mageObject.getName() + ": " + controller.getLogName() + " has chosen " + typeChoice.getChoice()); + } + game.getState().setValue(mageObject.getId() + "_type", typeChoice.getChoice()); + if (mageObject instanceof Permanent) { + ((Permanent) mageObject).addInfo("chosen type", CardUtil.addToolTipMarkTags("Chosen type: " + typeChoice.getChoice()), game); } - game.getState().setValue(permanent.getId() + "_type", typeChoice.getChoice()); - permanent.addInfo("chosen type", CardUtil.addToolTipMarkTags("Chosen type: " + typeChoice.getChoice()), game); } return false; } diff --git a/Mage/src/mage/abilities/effects/common/ChooseNewTargetsTargetEffect.java b/Mage/src/mage/abilities/effects/common/ChooseNewTargetsTargetEffect.java index 265b66e9cdd..35ac9818cd5 100644 --- a/Mage/src/mage/abilities/effects/common/ChooseNewTargetsTargetEffect.java +++ b/Mage/src/mage/abilities/effects/common/ChooseNewTargetsTargetEffect.java @@ -1,38 +1,36 @@ /* -* 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 mage.constants.Outcome; import mage.abilities.Ability; import mage.abilities.Mode; import mage.abilities.effects.OneShotEffect; -import mage.filter.Filter; +import mage.constants.Outcome; import mage.filter.FilterPermanent; import mage.game.Game; import mage.game.stack.StackObject; @@ -46,21 +44,22 @@ public class ChooseNewTargetsTargetEffect extends OneShotEffect { private boolean forceChange; private boolean onlyOneTarget; private FilterPermanent filterNewTarget; - + public ChooseNewTargetsTargetEffect() { this(false, false); } + public ChooseNewTargetsTargetEffect(boolean forceChange, boolean onlyOneTarget) { this(forceChange, onlyOneTarget, null); } /** * - * @param forceChange forces the user to choose another target (only targets with maxtargets = 1 supported) + * @param forceChange forces the user to choose another target (only targets + * with maxtargets = 1 supported) * @param onlyOneTarget only one target can be selected for the change * @param filterNewTarget restriction to the new target */ - public ChooseNewTargetsTargetEffect(boolean forceChange, boolean onlyOneTarget, FilterPermanent filterNewTarget) { super(Outcome.Benefit); this.forceChange = forceChange; diff --git a/Mage/src/mage/abilities/effects/common/ChooseOpponentEffect.java b/Mage/src/mage/abilities/effects/common/ChooseOpponentEffect.java new file mode 100644 index 00000000000..9ac1910128e --- /dev/null +++ b/Mage/src/mage/abilities/effects/common/ChooseOpponentEffect.java @@ -0,0 +1,64 @@ +/* + * To change this license header, choose License Headers in Project Properties. + * To change this template file, choose Tools | Templates + * and open the template in the editor. + */ +package mage.abilities.effects.common; + +import mage.MageObject; +import mage.abilities.Ability; +import mage.abilities.effects.EntersBattlefieldEffect; +import mage.abilities.effects.OneShotEffect; +import mage.constants.Outcome; +import mage.game.Game; +import mage.game.permanent.Permanent; +import mage.players.Player; +import mage.target.common.TargetOpponent; +import mage.util.CardUtil; + +/** + * + * @author LevelX2 + */ +public class ChooseOpponentEffect extends OneShotEffect { + + public static String VALUE_KEY = "_opponent"; + + public ChooseOpponentEffect(Outcome outcome) { + super(outcome); + this.staticText = "choose an opponent"; + } + + public ChooseOpponentEffect(final ChooseOpponentEffect effect) { + super(effect); + } + + @Override + public ChooseOpponentEffect copy() { + return new ChooseOpponentEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player controller = game.getPlayer(source.getControllerId()); + MageObject mageObject = (Permanent) getValue(EntersBattlefieldEffect.ENTERING_PERMANENT); + if (mageObject == null) { + mageObject = game.getObject(source.getSourceId()); + } + if (controller != null && mageObject != null) { + TargetOpponent target = new TargetOpponent(true); + if (controller.choose(this.outcome, target, source.getSourceId(), game)) { + Player chosenPlayer = game.getPlayer(target.getFirstTarget()); + if (chosenPlayer != null) { + game.informPlayers(mageObject.getName() + ": " + controller.getLogName() + " has chosen " + chosenPlayer.getLogName()); + game.getState().setValue(mageObject.getId() + VALUE_KEY, target.getFirstTarget()); + if (mageObject instanceof Permanent) { + ((Permanent) mageObject).addInfo("chosen opponent", CardUtil.addToolTipMarkTags("Chosen player: " + chosenPlayer.getLogName()), game); + } + return true; + } + } + } + return false; + } +} diff --git a/Mage/src/mage/abilities/effects/common/ChoosePlayerEffect.java b/Mage/src/mage/abilities/effects/common/ChoosePlayerEffect.java index 9f4481515c5..7e5c6402c1b 100644 --- a/Mage/src/mage/abilities/effects/common/ChoosePlayerEffect.java +++ b/Mage/src/mage/abilities/effects/common/ChoosePlayerEffect.java @@ -5,7 +5,9 @@ */ package mage.abilities.effects.common; +import mage.MageObject; import mage.abilities.Ability; +import mage.abilities.effects.EntersBattlefieldEffect; import mage.abilities.effects.OneShotEffect; import mage.constants.Outcome; import mage.game.Game; @@ -36,16 +38,21 @@ public class ChoosePlayerEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { - Player player = game.getPlayer(source.getControllerId()); - Permanent permanent = game.getPermanent(source.getSourceId()); - if (player != null && permanent != null) { + Player controller = game.getPlayer(source.getControllerId()); + MageObject mageObject = (Permanent) getValue(EntersBattlefieldEffect.ENTERING_PERMANENT); + if (mageObject == null) { + mageObject = game.getObject(source.getSourceId()); + } + if (controller != null && mageObject != null) { TargetPlayer target = new TargetPlayer(1, 1, true); - if (player.choose(this.outcome, target, source.getSourceId(), game)) { + if (controller.choose(this.outcome, target, source.getSourceId(), game)) { Player chosenPlayer = game.getPlayer(target.getFirstTarget()); if (chosenPlayer != null) { - game.informPlayers(permanent.getName() + ": " + player.getLogName() + " has chosen " + chosenPlayer.getLogName()); - game.getState().setValue(permanent.getId() + "_player", target.getFirstTarget()); - permanent.addInfo("chosen player", CardUtil.addToolTipMarkTags("Chosen player: " + chosenPlayer.getLogName()), game); + game.informPlayers(mageObject.getName() + ": " + controller.getLogName() + " has chosen " + chosenPlayer.getLogName()); + game.getState().setValue(mageObject.getId() + "_player", target.getFirstTarget()); + if (mageObject instanceof Permanent) { + ((Permanent) mageObject).addInfo("chosen player", CardUtil.addToolTipMarkTags("Chosen player: " + chosenPlayer.getLogName()), game); + } return true; } } diff --git a/Mage/src/mage/abilities/effects/common/TapSourceUnlessPaysEffect.java b/Mage/src/mage/abilities/effects/common/TapSourceUnlessPaysEffect.java index 55bc3ad99ed..0d2e474b159 100644 --- a/Mage/src/mage/abilities/effects/common/TapSourceUnlessPaysEffect.java +++ b/Mage/src/mage/abilities/effects/common/TapSourceUnlessPaysEffect.java @@ -1,16 +1,16 @@ /* * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. - * + * * Redistribution and use in source and binary forms, with or without modification, are * permitted provided that the following conditions are met: - * + * * 1. Redistributions of source code must retain the above copyright notice, this list of * conditions and the following disclaimer. - * + * * 2. Redistributions in binary form must reproduce the above copyright notice, this list * of conditions and the following disclaimer in the documentation and/or other materials * provided with the distribution. - * + * * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR @@ -20,16 +20,16 @@ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * + * * The views and conclusions contained in the software and documentation are those of the * authors and should not be interpreted as representing official policies, either expressed * or implied, of BetaSteward_at_googlemail.com. */ - package mage.abilities.effects.common; import mage.abilities.Ability; import mage.abilities.costs.Cost; +import mage.abilities.effects.EntersBattlefieldEffect; import mage.abilities.effects.OneShotEffect; import mage.constants.Outcome; import mage.game.Game; @@ -59,7 +59,10 @@ public class TapSourceUnlessPaysEffect extends OneShotEffect { public boolean apply(Game game, Ability source) { Player player = game.getPlayer(source.getControllerId()); Permanent permanent = game.getPermanent(source.getSourceId()); - if (player != null && permanent != null) { + if (permanent == null) { + permanent = (Permanent) getValue(EntersBattlefieldEffect.ENTERING_PERMANENT); + } + if (player != null && permanent != null) { if (cost.canPay(source, source.getSourceId(), source.getControllerId(), game) && player.chooseUse(Outcome.Benefit, cost.getText() + "? (otherwise " + permanent.getName() + " becomes tapped)", source, game)) { cost.clearPaid(); @@ -78,5 +81,4 @@ public class TapSourceUnlessPaysEffect extends OneShotEffect { return new TapSourceUnlessPaysEffect(this); } - } diff --git a/Mage/src/mage/abilities/keyword/ModularAbility.java b/Mage/src/mage/abilities/keyword/ModularAbility.java index 19219e21b2d..3d9133f57ec 100644 --- a/Mage/src/mage/abilities/keyword/ModularAbility.java +++ b/Mage/src/mage/abilities/keyword/ModularAbility.java @@ -22,24 +22,24 @@ import mage.target.Target; import mage.target.common.TargetArtifactPermanent; import mage.util.CardUtil; - /** * * 702.41. Modular * - * 702.41a Modular represents both a static ability and a triggered ability. - * "Modular N" means "This permanent enters the battlefield with N +1/+1 - * counters on it" and "When this permanent is put into a graveyard - * from the battlefield, you may put a +1/+1 counter on target artifact - * creature for each +1/+1 counter on this permanent." - * 702.41b If a creature has multiple instances of modular, each one works separately. + * 702.41a Modular represents both a static ability and a triggered ability. + * "Modular N" means "This permanent enters the battlefield with N +1/+1 + * counters on it" and "When this permanent is put into a graveyard from the + * battlefield, you may put a +1/+1 counter on target artifact creature for each + * +1/+1 counter on this permanent." 702.41b If a creature has multiple + * instances of modular, each one works separately. + * * - * * @author Loki, LevelX2 */ - public class ModularAbility extends DiesTriggeredAbility { + private static final FilterArtifactPermanent filter = new FilterArtifactPermanent("artifact creature"); + static { filter.add(new CardTypePredicate(CardType.CREATURE)); } @@ -74,7 +74,7 @@ public class ModularAbility extends DiesTriggeredAbility { @Override public boolean checkTrigger(GameEvent event, Game game) { if (super.checkTrigger(event, game)) { - ZoneChangeEvent zEvent = (ZoneChangeEvent)event; + ZoneChangeEvent zEvent = (ZoneChangeEvent) event; if (zEvent.getTarget().getCounters().getCount(CounterType.P1P1) > 0) { return true; } @@ -94,9 +94,9 @@ public class ModularAbility extends DiesTriggeredAbility { sb.append("-Sunburst (This enters the battlefield with a +1/+1 counter on it for each color of mana spent to cast it. When it dies, you may put its +1/+1 counters on target artifact creature.)"); } else { sb.append(" ").append(amount).append(" (This enters the battlefield with ") - .append(CardUtil.numberToText(amount, "a")) - .append(" +1/+1 counter").append(amount != 1 ? "s":"") - .append(" on it. When it dies, you may put its +1/+1 counters on target artifact creature.)"); + .append(CardUtil.numberToText(amount, "a")) + .append(" +1/+1 counter").append(amount != 1 ? "s" : "") + .append(" on it. When it dies, you may put its +1/+1 counters on target artifact creature.)"); } return sb.toString(); } @@ -109,9 +109,7 @@ class ModularStaticAbility extends StaticAbility { public ModularStaticAbility(int amount) { super(Zone.BATTLEFIELD, new EntersBattlefieldEffect(new AddCountersSourceEffect(CounterType.P1P1.createInstance(amount)))); - ruleText = new StringBuilder("This enters the battlefield with ").append(CardUtil.numberToText(amount, "a")) - .append(" +1/+1 counter").append(amount != 1 ? "s":"") - .append(" on it.").toString(); + ruleText = "This enters the battlefield with " + CardUtil.numberToText(amount, "a") + " +1/+1 counter" + (amount != 1 ? "s" : "") + " on it."; this.setRuleVisible(false); } @@ -131,9 +129,10 @@ class ModularStaticAbility extends StaticAbility { } } - class ModularDistributeCounterEffect extends OneShotEffect { + private static final FilterArtifactPermanent filter = new FilterArtifactPermanent("artifact creature"); + static { filter.add(new CardTypePredicate(CardType.CREATURE)); } From 9b7f56ca2ceaab5e93c79c4854e8c12ee4e76b4e Mon Sep 17 00:00:00 2001 From: LevelX2 Date: Fri, 16 Oct 2015 00:32:55 +0200 Subject: [PATCH 157/268] * Updated enters battlefield replacement effects for new handling. --- .../sets/riseoftheeldrazi/NotOfThisWorld.java | 105 ++++++++++++++++-- .../EntersBattlefieldTappedAbility.java | 17 ++- .../EntersBattlefieldWithXCountersEffect.java | 3 + .../effects/common/TapSourceEffect.java | 60 +++++----- .../continuous/GainAbilitySourceEffect.java | 20 ++-- .../abilities/keyword/BloodthirstAbility.java | 14 ++- .../mage/abilities/keyword/FadingAbility.java | 36 +++--- .../abilities/keyword/SunburstAbility.java | 40 +++---- .../abilities/keyword/TributeAbility.java | 25 ++--- 9 files changed, 201 insertions(+), 119 deletions(-) diff --git a/Mage.Sets/src/mage/sets/riseoftheeldrazi/NotOfThisWorld.java b/Mage.Sets/src/mage/sets/riseoftheeldrazi/NotOfThisWorld.java index 97363cb0aa8..42b6e9c8f46 100644 --- a/Mage.Sets/src/mage/sets/riseoftheeldrazi/NotOfThisWorld.java +++ b/Mage.Sets/src/mage/sets/riseoftheeldrazi/NotOfThisWorld.java @@ -27,6 +27,8 @@ */ package mage.sets.riseoftheeldrazi; +import java.util.HashSet; +import java.util.Set; import java.util.UUID; import mage.abilities.Ability; import mage.abilities.common.SimpleStaticAbility; @@ -39,17 +41,17 @@ import mage.constants.Rarity; import mage.constants.TargetController; import mage.constants.Zone; import mage.filter.Filter; -import mage.filter.FilterSpell; -import mage.filter.common.FilterControlledPermanent; import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.mageobject.PowerPredicate; -import mage.filter.predicate.other.TargetsPermanentPredicate; import mage.filter.predicate.permanent.ControllerPredicate; import mage.game.Game; import mage.game.permanent.Permanent; +import mage.game.stack.Spell; +import mage.game.stack.StackAbility; import mage.game.stack.StackObject; import mage.target.Target; -import mage.target.TargetSpell; +import mage.target.TargetObject; +import mage.target.Targets; /** * @@ -57,19 +59,14 @@ import mage.target.TargetSpell; */ public class NotOfThisWorld extends CardImpl { - private final static FilterSpell filter = new FilterSpell("spell that targets a permanent you control"); - - static { - filter.add(new TargetsPermanentPredicate(new FilterControlledPermanent())); - } - public NotOfThisWorld(UUID ownerId) { super(ownerId, 8, "Not of This World", Rarity.UNCOMMON, new CardType[]{CardType.TRIBAL, CardType.INSTANT}, "{7}"); this.expansionSetCode = "ROE"; this.subtype.add("Eldrazi"); // Counter target spell or ability that targets a permanent you control. - this.getSpellAbility().addTarget(new TargetSpell(filter)); + this.getSpellAbility().addTarget( + new TargetStackObjectTargetingControlledPermanent()); this.getSpellAbility().addEffect(new CounterTargetEffect()); // Not of This World costs {7} less to cast if it targets a spell or ability that targets a creature you control with power 7 or greater. this.addAbility(new SimpleStaticAbility(Zone.STACK, new SpellCostReductionSourceEffect(7, NotOfThisWorldCondition.getInstance()))); @@ -85,6 +82,92 @@ public class NotOfThisWorld extends CardImpl { } } +class TargetStackObjectTargetingControlledPermanent extends TargetObject { + + public TargetStackObjectTargetingControlledPermanent() { + this.minNumberOfTargets = 1; + this.maxNumberOfTargets = 1; + this.zone = Zone.STACK; + this.targetName = "spell or ability that targets a permanent you control"; + } + + public TargetStackObjectTargetingControlledPermanent(final TargetStackObjectTargetingControlledPermanent target) { + super(target); + } + + @Override + public Filter getFilter() { + throw new UnsupportedOperationException("Not supported."); //To change body of generated methods, choose Tools | Templates. + } + + @Override + public boolean canTarget(UUID id, Ability source, Game game) { + StackObject stackObject = game.getStack().getStackObject(id); + if ((stackObject instanceof Spell) || (stackObject instanceof StackAbility)) { + return true; + } + return false; + } + + @Override + public boolean canChoose(UUID sourceId, UUID sourceControllerId, Game game) { + return canChoose(sourceControllerId, game); + } + + @Override + public boolean canChoose(UUID sourceControllerId, Game game) { + for (StackObject stackObject : game.getStack()) { + if ((stackObject instanceof Spell) || (stackObject instanceof StackAbility)) { + Targets objectTargets = stackObject.getStackAbility().getTargets(); + if (!objectTargets.isEmpty()) { + for (Target target : objectTargets) { + for (UUID targetId : target.getTargets()) { + Permanent targetedPermanent = game.getPermanentOrLKIBattlefield(targetId); + if (targetedPermanent != null && targetedPermanent.getControllerId().equals(sourceControllerId)) { + return true; + } + } + } + } + } + } + return false; + } + + @Override + public Set possibleTargets(UUID sourceId, UUID sourceControllerId, + Game game) { + return possibleTargets(sourceControllerId, game); + } + + @Override + public Set possibleTargets(UUID sourceControllerId, Game game) { + Set possibleTargets = new HashSet<>(); + for (StackObject stackObject : game.getStack()) { + if ((stackObject instanceof Spell) || (stackObject instanceof StackAbility)) { + Targets objectTargets = stackObject.getStackAbility().getTargets(); + if (!objectTargets.isEmpty()) { + for (Target target : objectTargets) { + for (UUID targetId : target.getTargets()) { + Permanent targetedPermanent = game.getPermanentOrLKIBattlefield(targetId); + if (targetedPermanent != null && targetedPermanent.getControllerId().equals(sourceControllerId)) { + possibleTargets.add(stackObject.getId()); + } + } + } + } + } + } + return possibleTargets; + } + + @Override + public TargetStackObjectTargetingControlledPermanent copy() { + return new TargetStackObjectTargetingControlledPermanent(this); + } + +} + class NotOfThisWorldCondition implements Condition { private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("creature you control with power 7 or greater"); diff --git a/Mage/src/mage/abilities/common/EntersBattlefieldTappedAbility.java b/Mage/src/mage/abilities/common/EntersBattlefieldTappedAbility.java index 1d8d119f17c..f62f02ab29e 100644 --- a/Mage/src/mage/abilities/common/EntersBattlefieldTappedAbility.java +++ b/Mage/src/mage/abilities/common/EntersBattlefieldTappedAbility.java @@ -1,16 +1,16 @@ /* * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. - * + * * Redistribution and use in source and binary forms, with or without modification, are * permitted provided that the following conditions are met: - * + * * 1. Redistributions of source code must retain the above copyright notice, this list of * conditions and the following disclaimer. - * + * * 2. Redistributions in binary form must reproduce the above copyright notice, this list * of conditions and the following disclaimer in the documentation and/or other materials * provided with the distribution. - * + * * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR @@ -20,18 +20,17 @@ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * + * * The views and conclusions contained in the software and documentation are those of the * authors and should not be interpreted as representing official policies, either expressed * or implied, of BetaSteward_at_googlemail.com. */ - package mage.abilities.common; -import mage.constants.Zone; import mage.abilities.StaticAbility; import mage.abilities.effects.EntersBattlefieldEffect; import mage.abilities.effects.common.TapSourceEffect; +import mage.constants.Zone; /** * @@ -40,9 +39,9 @@ import mage.abilities.effects.common.TapSourceEffect; public class EntersBattlefieldTappedAbility extends StaticAbility { private String ruleText; - + public EntersBattlefieldTappedAbility() { - super(Zone.BATTLEFIELD, new EntersBattlefieldEffect(new TapSourceEffect(true))); + super(Zone.ALL, new EntersBattlefieldEffect(new TapSourceEffect(true))); } public EntersBattlefieldTappedAbility(String ruleText) { diff --git a/Mage/src/mage/abilities/effects/common/EntersBattlefieldWithXCountersEffect.java b/Mage/src/mage/abilities/effects/common/EntersBattlefieldWithXCountersEffect.java index 999e70423dc..7451cd90dbb 100644 --- a/Mage/src/mage/abilities/effects/common/EntersBattlefieldWithXCountersEffect.java +++ b/Mage/src/mage/abilities/effects/common/EntersBattlefieldWithXCountersEffect.java @@ -59,6 +59,9 @@ public class EntersBattlefieldWithXCountersEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { Permanent permanent = game.getPermanent(source.getSourceId()); + if (permanent == null) { + permanent = (Permanent) getValue(EntersBattlefieldEffect.ENTERING_PERMANENT); + } if (permanent != null) { SpellAbility spellAbility = (SpellAbility) getValue(EntersBattlefieldEffect.SOURCE_CAST_SPELL_ABILITY); if (spellAbility != null diff --git a/Mage/src/mage/abilities/effects/common/TapSourceEffect.java b/Mage/src/mage/abilities/effects/common/TapSourceEffect.java index fcbc92c1e4c..aa655d15bfe 100644 --- a/Mage/src/mage/abilities/effects/common/TapSourceEffect.java +++ b/Mage/src/mage/abilities/effects/common/TapSourceEffect.java @@ -1,36 +1,36 @@ /* -* 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 mage.constants.Outcome; import mage.abilities.Ability; +import mage.abilities.effects.EntersBattlefieldEffect; import mage.abilities.effects.OneShotEffect; +import mage.constants.Outcome; import mage.game.Game; import mage.game.permanent.Permanent; @@ -39,6 +39,7 @@ import mage.game.permanent.Permanent; * @author BetaSteward_at_googlemail.com */ public class TapSourceEffect extends OneShotEffect { + private boolean withoutTrigger; public TapSourceEffect() { @@ -64,6 +65,9 @@ public class TapSourceEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { Permanent permanent = game.getPermanent(source.getSourceId()); + if (permanent == null) { + permanent = (Permanent) getValue(EntersBattlefieldEffect.ENTERING_PERMANENT); + } if (permanent != null) { if (withoutTrigger) { permanent.setTapped(true); diff --git a/Mage/src/mage/abilities/effects/common/continuous/GainAbilitySourceEffect.java b/Mage/src/mage/abilities/effects/common/continuous/GainAbilitySourceEffect.java index 81fc17c970c..6d37cfc4bad 100644 --- a/Mage/src/mage/abilities/effects/common/continuous/GainAbilitySourceEffect.java +++ b/Mage/src/mage/abilities/effects/common/continuous/GainAbilitySourceEffect.java @@ -1,16 +1,16 @@ /* * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. - * + * * Redistribution and use in source and binary forms, with or without modification, are * permitted provided that the following conditions are met: - * + * * 1. Redistributions of source code must retain the above copyright notice, this list of * conditions and the following disclaimer. - * + * * 2. Redistributions in binary form must reproduce the above copyright notice, this list * of conditions and the following disclaimer in the documentation and/or other materials * provided with the distribution. - * + * * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR @@ -20,7 +20,7 @@ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * + * * The views and conclusions contained in the software and documentation are those of the * authors and should not be interpreted as representing official policies, either expressed * or implied, of BetaSteward_at_googlemail.com. @@ -30,6 +30,7 @@ package mage.abilities.effects.common.continuous; import mage.MageObjectReference; import mage.abilities.Ability; import mage.abilities.effects.ContinuousEffectImpl; +import mage.abilities.effects.EntersBattlefieldEffect; import mage.cards.Card; import mage.constants.Duration; import mage.constants.Layer; @@ -88,12 +89,17 @@ public class GainAbilitySourceEffect extends ContinuousEffectImpl implements Sou public GainAbilitySourceEffect copy() { return new GainAbilitySourceEffect(this); } - + @Override public void init(Ability source, Game game) { super.init(source, game); if (affectedObjectsSet) { - affectedObjectList.add(new MageObjectReference(source.getSourceId(), game)); + Permanent permanent = (Permanent) getValue(EntersBattlefieldEffect.ENTERING_PERMANENT); + if (permanent != null) { + affectedObjectList.add(new MageObjectReference(source.getSourceId(), game.getState().getZoneChangeCounter(source.getSourceId()) + 1, game)); + } else { + affectedObjectList.add(new MageObjectReference(source.getSourceId(), game)); + } } } diff --git a/Mage/src/mage/abilities/keyword/BloodthirstAbility.java b/Mage/src/mage/abilities/keyword/BloodthirstAbility.java index f93ca9824d6..a7ae3282a18 100644 --- a/Mage/src/mage/abilities/keyword/BloodthirstAbility.java +++ b/Mage/src/mage/abilities/keyword/BloodthirstAbility.java @@ -2,6 +2,7 @@ package mage.abilities.keyword; import mage.abilities.Ability; import mage.abilities.common.EntersBattlefieldAbility; +import mage.abilities.effects.EntersBattlefieldEffect; import mage.abilities.effects.OneShotEffect; import mage.constants.Outcome; import mage.counters.CounterType; @@ -12,10 +13,11 @@ import mage.util.CardUtil; import mage.watchers.common.BloodthirstWatcher; /** - * + * * @author Loki */ public class BloodthirstAbility extends EntersBattlefieldAbility { + private int amount; public BloodthirstAbility(int amount) { @@ -48,12 +50,13 @@ public class BloodthirstAbility extends EntersBattlefieldAbility { } class BloodthirstEffect extends OneShotEffect { + private final int amount; BloodthirstEffect(int amount) { super(Outcome.BoostCreature); this.amount = amount; - staticText = new StringBuilder("this permanent comes into play with ").append(this.amount).append(" +1/+1 counters on it").toString(); + staticText = new StringBuilder("this permanent comes into play with ").append(this.amount).append(" +1/+1 counters on it").toString(); } BloodthirstEffect(final BloodthirstEffect effect) { @@ -67,9 +70,9 @@ class BloodthirstEffect extends OneShotEffect { if (player != null) { BloodthirstWatcher watcher = (BloodthirstWatcher) game.getState().getWatchers().get("DamagedOpponents", source.getControllerId()); if (watcher != null && watcher.conditionMet()) { - Permanent p = game.getPermanent(source.getSourceId()); - if (p != null) { - p.addCounters(CounterType.P1P1.createInstance(amount), game); + Permanent permanent = (Permanent) getValue(EntersBattlefieldEffect.ENTERING_PERMANENT); + if (permanent != null) { + permanent.addCounters(CounterType.P1P1.createInstance(amount), game); } } @@ -83,4 +86,3 @@ class BloodthirstEffect extends OneShotEffect { return new BloodthirstEffect(this); } } - diff --git a/Mage/src/mage/abilities/keyword/FadingAbility.java b/Mage/src/mage/abilities/keyword/FadingAbility.java index 4a66d7dcda7..a433ac3cd5c 100644 --- a/Mage/src/mage/abilities/keyword/FadingAbility.java +++ b/Mage/src/mage/abilities/keyword/FadingAbility.java @@ -3,6 +3,7 @@ package mage.abilities.keyword; import mage.abilities.Ability; import mage.abilities.common.BeginningOfUpkeepTriggeredAbility; import mage.abilities.common.EntersBattlefieldAbility; +import mage.abilities.effects.EntersBattlefieldEffect; import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.counter.AddCountersSourceEffect; import mage.cards.Card; @@ -18,25 +19,17 @@ import mage.game.permanent.Permanent; * 702.31a Fading is a keyword that represents two abilities. “Fading N” means “This permanent enters the battlefield with N fade counters on it” and “At the beginning of your upkeep, remove a fade counter from this permanent. If you can’t, sacrifice the permanent.” * */ - public class FadingAbility extends EntersBattlefieldAbility { - - + private String ruleText; - + public FadingAbility(int fadeCounter, Card card) { super(new AddCountersSourceEffect(CounterType.FADE.createInstance(fadeCounter)), "with"); Ability ability = new BeginningOfUpkeepTriggeredAbility(new FadingEffect(), TargetController.YOU, false); ability.setRuleVisible(false); addSubAbility(ability); - StringBuilder sb = new StringBuilder("Fading "); - sb.append(fadeCounter); - sb.append(" (This permanent enters the battlefield with ") - .append(fadeCounter) - .append(" fade counters on it. ") - .append(" At the beginning of your upkeep, remove a fade counter from this permanent. If you can’t, sacrifice the permanent.") - .append(")"); - ruleText = sb.toString(); + ruleText = "Fading " + fadeCounter + " (This permanent enters the battlefield with " + fadeCounter + " fade counters on it." + + " At the beginning of your upkeep, remove a fade counter from this permanent. If you can’t, sacrifice the permanent."; } public FadingAbility(final FadingAbility ability) { @@ -54,7 +47,9 @@ public class FadingAbility extends EntersBattlefieldAbility { return ruleText; } } + class FadingEffect extends OneShotEffect { + FadingEffect() { super(Outcome.Sacrifice); staticText = "remove a fade counter from this permanent. If you can’t, sacrifice the permanent"; @@ -64,18 +59,15 @@ class FadingEffect extends OneShotEffect { super(effect); } - @Override public boolean apply(Game game, Ability source) { - Permanent p = game.getPermanent(source.getSourceId()); - if (p != null) { - int amount = p.getCounters().getCount(CounterType.FADE); + Permanent permanent = (Permanent) getValue(EntersBattlefieldEffect.ENTERING_PERMANENT); + if (permanent != null) { + int amount = permanent.getCounters().getCount(CounterType.FADE); if (amount > 0) { - p.removeCounters(CounterType.FADE.createInstance(), game); - } - else - { - p.sacrifice(source.getSourceId(), game); + permanent.removeCounters(CounterType.FADE.createInstance(), game); + } else { + permanent.sacrifice(source.getSourceId(), game); } return true; } @@ -86,4 +78,4 @@ class FadingEffect extends OneShotEffect { public FadingEffect copy() { return new FadingEffect(this); } -} \ No newline at end of file +} diff --git a/Mage/src/mage/abilities/keyword/SunburstAbility.java b/Mage/src/mage/abilities/keyword/SunburstAbility.java index 12b9d7834ae..bc4a9319046 100644 --- a/Mage/src/mage/abilities/keyword/SunburstAbility.java +++ b/Mage/src/mage/abilities/keyword/SunburstAbility.java @@ -25,13 +25,13 @@ * authors and should not be interpreted as representing official policies, either expressed * or implied, of BetaSteward_at_googlemail.com. */ - package mage.abilities.keyword; import mage.abilities.Ability; import mage.abilities.common.EntersBattlefieldAbility; import mage.abilities.dynamicvalue.DynamicValue; import mage.abilities.dynamicvalue.common.SunburstCount; +import mage.abilities.effects.EntersBattlefieldEffect; import mage.abilities.effects.OneShotEffect; import mage.cards.Card; import mage.constants.CardType; @@ -46,25 +46,22 @@ import mage.players.Player; * * @author Plopman */ +public class SunburstAbility extends EntersBattlefieldAbility { - -public class SunburstAbility extends EntersBattlefieldAbility{ - - private final static String ruleCreature ="Sunburst (This enters the battlefield with a +1/+1 counter on it for each color of mana spent to cast it.)"; - private final static String ruleNonCreature ="Sunburst (This enters the battlefield with a charge counter on it for each color of mana spent to cast it.)"; + private final static String ruleCreature = "Sunburst (This enters the battlefield with a +1/+1 counter on it for each color of mana spent to cast it.)"; + private final static String ruleNonCreature = "Sunburst (This enters the battlefield with a charge counter on it for each color of mana spent to cast it.)"; private boolean isCreature; - public SunburstAbility(Card card){ - super(new SunburstEffect(),""); + public SunburstAbility(Card card) { + super(new SunburstEffect(), ""); isCreature = card.getCardType().contains(CardType.CREATURE); } - - public SunburstAbility(final SunburstAbility ability){ + + public SunburstAbility(final SunburstAbility ability) { super(ability); this.isCreature = ability.isCreature; } - - + @Override public EntersBattlefieldAbility copy() { return new SunburstAbility(this); @@ -74,15 +71,13 @@ public class SunburstAbility extends EntersBattlefieldAbility{ public String getRule() { return isCreature ? ruleCreature : ruleNonCreature; } - - + } class SunburstEffect extends OneShotEffect { private static final DynamicValue amount = new SunburstCount(); - public SunburstEffect() { super(Outcome.Benefit); staticText = "Sunburst"; @@ -94,22 +89,21 @@ class SunburstEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { - Permanent permanent = game.getPermanent(source.getSourceId()); + Permanent permanent = (Permanent) getValue(EntersBattlefieldEffect.ENTERING_PERMANENT); if (permanent != null) { Counter counter; - if(permanent.getCardType().contains(CardType.CREATURE)){ - counter = CounterType.P1P1.createInstance(amount.calculate(game, source, this)); - } - else{ - counter = CounterType.CHARGE.createInstance(amount.calculate(game, source, this)); + if (permanent.getCardType().contains(CardType.CREATURE)) { + counter = CounterType.P1P1.createInstance(amount.calculate(game, source, this)); + } else { + counter = CounterType.CHARGE.createInstance(amount.calculate(game, source, this)); } if (counter != null) { - + permanent.addCounters(counter, game); if (!game.isSimulation()) { Player player = game.getPlayer(source.getControllerId()); if (player != null) { - game.informPlayers(player.getLogName()+ " puts " + counter.getCount() + " " + counter.getName() + " counter on " + permanent.getName()); + game.informPlayers(player.getLogName() + " puts " + counter.getCount() + " " + counter.getName() + " counter on " + permanent.getName()); } } } diff --git a/Mage/src/mage/abilities/keyword/TributeAbility.java b/Mage/src/mage/abilities/keyword/TributeAbility.java index ad5ad5b6b7b..f752865498b 100644 --- a/Mage/src/mage/abilities/keyword/TributeAbility.java +++ b/Mage/src/mage/abilities/keyword/TributeAbility.java @@ -25,12 +25,12 @@ * authors and should not be interpreted as representing official policies, either expressed * or implied, of BetaSteward_at_googlemail.com. */ - package mage.abilities.keyword; import java.util.UUID; import mage.abilities.Ability; import mage.abilities.common.EntersBattlefieldAbility; +import mage.abilities.effects.EntersBattlefieldEffect; import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.counter.AddCountersSourceEffect; import mage.constants.Outcome; @@ -46,23 +46,20 @@ import mage.util.CardUtil; * * @author LevelX2 */ - - -public class TributeAbility extends EntersBattlefieldAbility{ +public class TributeAbility extends EntersBattlefieldAbility { private int tributeValue; - public TributeAbility(int tributeValue){ + public TributeAbility(int tributeValue) { super(new TributeEffect(tributeValue), false); this.tributeValue = tributeValue; } - public TributeAbility(final TributeAbility ability){ + public TributeAbility(final TributeAbility ability) { super(ability); this.tributeValue = ability.tributeValue; } - @Override public EntersBattlefieldAbility copy() { return new TributeAbility(this); @@ -81,7 +78,7 @@ public class TributeAbility extends EntersBattlefieldAbility{ class TributeEffect extends OneShotEffect { - private int tributeValue; + private final int tributeValue; public TributeEffect(int tributeValue) { super(Outcome.Detriment); @@ -101,7 +98,7 @@ class TributeEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { Player controller = game.getPlayer(source.getControllerId()); - Permanent sourcePermanent = game.getPermanent(source.getSourceId()); + Permanent sourcePermanent = (Permanent) getValue(EntersBattlefieldEffect.ENTERING_PERMANENT); if (controller != null && sourcePermanent != null) { UUID opponentId; if (game.getOpponents(controller.getId()).size() == 1) { @@ -117,16 +114,18 @@ class TributeEffect extends OneShotEffect { StringBuilder sb = new StringBuilder("Pay tribute to "); sb.append(sourcePermanent.getName()); sb.append(" (add ").append(CardUtil.numberToText(tributeValue)).append(" +1/+1 counter"); - sb.append(tributeValue > 1 ? "s":"").append(" to it)?"); + sb.append(tributeValue > 1 ? "s" : "").append(" to it)?"); if (opponent.chooseUse(outcome, sb.toString(), source, game)) { - if (!game.isSimulation()) + if (!game.isSimulation()) { game.informPlayers(opponent.getLogName() + " pays tribute to " + sourcePermanent.getLogName()); + } game.getState().setValue("tributeValue" + source.getSourceId(), "yes"); return new AddCountersSourceEffect(CounterType.P1P1.createInstance(tributeValue), true).apply(game, source); } else { - if (!game.isSimulation()) + if (!game.isSimulation()) { game.informPlayers(opponent.getLogName() + " does not pay tribute to " + sourcePermanent.getLogName()); - game.getState().setValue("tributeValue"+ source.getSourceId(), "no"); + } + game.getState().setValue("tributeValue" + source.getSourceId(), "no"); } return true; } From c94be5f4d31e101696bd1f83533fdcb8edd344f0 Mon Sep 17 00:00:00 2001 From: LevelX2 Date: Fri, 16 Oct 2015 00:39:16 +0200 Subject: [PATCH 158/268] * Updated enters battlefield replacement effects for new handling. --- Mage/src/mage/abilities/keyword/FadingAbility.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/Mage/src/mage/abilities/keyword/FadingAbility.java b/Mage/src/mage/abilities/keyword/FadingAbility.java index a433ac3cd5c..e8e45295810 100644 --- a/Mage/src/mage/abilities/keyword/FadingAbility.java +++ b/Mage/src/mage/abilities/keyword/FadingAbility.java @@ -3,7 +3,6 @@ package mage.abilities.keyword; import mage.abilities.Ability; import mage.abilities.common.BeginningOfUpkeepTriggeredAbility; import mage.abilities.common.EntersBattlefieldAbility; -import mage.abilities.effects.EntersBattlefieldEffect; import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.counter.AddCountersSourceEffect; import mage.cards.Card; @@ -61,7 +60,7 @@ class FadingEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { - Permanent permanent = (Permanent) getValue(EntersBattlefieldEffect.ENTERING_PERMANENT); + Permanent permanent = game.getPermanent(source.getSourceId()); if (permanent != null) { int amount = permanent.getCounters().getCount(CounterType.FADE); if (amount > 0) { From 57dfa70837bd0a697263a913422491910adc8ff0 Mon Sep 17 00:00:00 2001 From: AlumiuN Date: Thu, 15 Oct 2015 18:19:23 +1300 Subject: [PATCH 159/268] Updated Teferi's Response to use FilterControlledLandPermanent. --- .../sets/darksteel/SurestrikeTrident.java | 30 +++-- .../mage/sets/invasion/TeferisResponse.java | 107 ++---------------- 2 files changed, 29 insertions(+), 108 deletions(-) diff --git a/Mage.Sets/src/mage/sets/darksteel/SurestrikeTrident.java b/Mage.Sets/src/mage/sets/darksteel/SurestrikeTrident.java index 761ed72d842..4640efecad6 100644 --- a/Mage.Sets/src/mage/sets/darksteel/SurestrikeTrident.java +++ b/Mage.Sets/src/mage/sets/darksteel/SurestrikeTrident.java @@ -64,15 +64,17 @@ public class SurestrikeTrident extends CardImpl { this.subtype.add("Equipment"); // Equipped creature has first strike and "{tap}, Unattach Surestrike Trident: This creature deals damage equal to its power to target player." - this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new GainAbilityAttachedEffect(FirstStrikeAbility.getInstance(), AttachmentType.EQUIPMENT))); - + Ability ability = new SimpleStaticAbility(Zone.BATTLEFIELD, new GainAbilityAttachedEffect(FirstStrikeAbility.getInstance(), AttachmentType.EQUIPMENT)); DynamicValue xValue = new SourcePermanentPowerCount(); Effect effect = new DamageTargetEffect(xValue); effect.setText("This creature deals damage equal to its power to target player"); - Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, effect, new TapSourceCost()); - ability.addTarget(new TargetPlayer()); - ability.addCost(new SurestrikeTridentUnattachCost()); - this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new GainAbilityAttachedEffect(ability, AttachmentType.EQUIPMENT, Duration.WhileOnBattlefield))); + Ability gainedAbility = new SimpleActivatedAbility(Zone.BATTLEFIELD, effect, new TapSourceCost()); + gainedAbility.addTarget(new TargetPlayer()); + gainedAbility.addCost(new SurestrikeTridentUnattachCost(getName(), getId())); + effect = new GainAbilityAttachedEffect(gainedAbility, AttachmentType.EQUIPMENT); + effect.setText("and \"{T}, Unattach {this}: This creature deals damage equal to its power to target player.\""); + ability.addEffect(effect); + this.addAbility(ability); // Equip {4} this.addAbility(new EquipAbility(Outcome.Benefit, new GenericManaCost(4))); @@ -90,21 +92,25 @@ public class SurestrikeTrident extends CardImpl { class SurestrikeTridentUnattachCost extends CostImpl { - public SurestrikeTridentUnattachCost() { - this.text = "Unattach Surestrike Trident"; + protected UUID sourceEquipmentId; + + public SurestrikeTridentUnattachCost(String name, UUID sourceId) { + this.text = "Unattach " + name; + this.sourceEquipmentId = sourceId; } public SurestrikeTridentUnattachCost(final SurestrikeTridentUnattachCost cost) { super(cost); + this.sourceEquipmentId = cost.sourceEquipmentId; } @Override public boolean pay(Ability ability, Game game, UUID sourceId, UUID controllerId, boolean noMana) { Permanent permanent = game.getPermanent(sourceId); if (permanent != null) { - for (UUID attachmentId :permanent.getAttachments()) { + for (UUID attachmentId : permanent.getAttachments()) { Permanent attachment = game.getPermanent(attachmentId); - if (attachment != null && attachment.getName().equals("Surestrike Trident")) { + if (attachment != null && attachment.getId().equals(sourceEquipmentId)) { paid = permanent.removeAttachment(attachmentId, game); if (paid) { break; @@ -120,9 +126,9 @@ class SurestrikeTridentUnattachCost extends CostImpl { public boolean canPay(Ability ability, UUID sourceId, UUID controllerId, Game game) { Permanent permanent = game.getPermanent(sourceId); if (permanent != null) { - for (UUID attachmentId :permanent.getAttachments()) { + for (UUID attachmentId : permanent.getAttachments()) { Permanent attachment = game.getPermanent(attachmentId); - if (attachment != null && attachment.getName().equals("Surestrike Trident") ) { + if (attachment != null && attachment.getId().equals(sourceEquipmentId)) { return true; } } diff --git a/Mage.Sets/src/mage/sets/invasion/TeferisResponse.java b/Mage.Sets/src/mage/sets/invasion/TeferisResponse.java index f61b1d22bd6..57e5f15db4f 100644 --- a/Mage.Sets/src/mage/sets/invasion/TeferisResponse.java +++ b/Mage.Sets/src/mage/sets/invasion/TeferisResponse.java @@ -27,8 +27,6 @@ */ package mage.sets.invasion; -import java.util.HashSet; -import java.util.Set; import java.util.UUID; import mage.abilities.Ability; import mage.abilities.effects.OneShotEffect; @@ -37,16 +35,13 @@ import mage.cards.CardImpl; import mage.constants.CardType; import mage.constants.Outcome; import mage.constants.Rarity; -import mage.constants.Zone; -import mage.filter.Filter; +import mage.filter.FilterStackObject; +import mage.filter.common.FilterControlledLandPermanent; +import mage.filter.predicate.other.TargetsPermanentPredicate; import mage.game.Game; import mage.game.permanent.Permanent; -import mage.game.stack.Spell; -import mage.game.stack.StackAbility; import mage.game.stack.StackObject; -import mage.target.Target; -import mage.target.TargetObject; -import mage.target.Targets; +import mage.target.TargetStackObject; /** * @@ -54,13 +49,19 @@ import mage.target.Targets; */ public class TeferisResponse extends CardImpl { + private final static FilterStackObject filter = new FilterStackObject("spell or ability an opponent controls that targets a land you control"); + + static { + filter.add(new TargetsPermanentPredicate(new FilterControlledLandPermanent())); + } + public TeferisResponse(UUID ownerId) { super(ownerId, 78, "Teferi's Response", Rarity.RARE, new CardType[]{CardType.INSTANT}, "{1}{U}"); this.expansionSetCode = "INV"; // Counter target spell or ability an opponent controls that targets a land you control. If a permanent's ability is countered this way, destroy that permanent. this.getSpellAbility().addEffect(new TeferisResponseEffect()); - this.getSpellAbility().addTarget(new TargetStackObjectTargetingControlledLand()); + this.getSpellAbility().addTarget(new TargetStackObject(filter)); // Draw two cards. this.getSpellAbility().addEffect(new DrawCardSourceControllerEffect(2)); @@ -76,92 +77,6 @@ public class TeferisResponse extends CardImpl { } } -class TargetStackObjectTargetingControlledLand extends TargetObject { - - public TargetStackObjectTargetingControlledLand() { - this.minNumberOfTargets = 1; - this.maxNumberOfTargets = 1; - this.zone = Zone.STACK; - this.targetName = "spell or ability an opponent controls that targets a land you control"; - } - - public TargetStackObjectTargetingControlledLand(final TargetStackObjectTargetingControlledLand target) { - super(target); - } - - @Override - public Filter getFilter() { - throw new UnsupportedOperationException("Not supported."); //To change body of generated methods, choose Tools | Templates. - } - - @Override - public boolean canTarget(UUID id, Ability source, Game game) { - StackObject stackObject = game.getStack().getStackObject(id); - if ((stackObject instanceof Spell) || (stackObject instanceof StackAbility)) { - return true; - } - return false; - } - - @Override - public boolean canChoose(UUID sourceId, UUID sourceControllerId, Game game) { - return canChoose(sourceControllerId, game); - } - - @Override - public boolean canChoose(UUID sourceControllerId, Game game) { - for (StackObject stackObject : game.getStack()) { - if (((stackObject instanceof Spell) || (stackObject instanceof StackAbility)) && stackObject.getControllerId() != sourceControllerId) { - Targets objectTargets = stackObject.getStackAbility().getTargets(); - if(!objectTargets.isEmpty()) { - for (Target target : objectTargets) { - for (UUID targetId : target.getTargets()) { - Permanent targetedPermanent = game.getPermanentOrLKIBattlefield(targetId); - if (targetedPermanent != null && targetedPermanent.getCardType().contains(CardType.LAND) && targetedPermanent.getControllerId().equals(sourceControllerId)) { - return true; - } - } - } - } - } - } - return false; - } - - @Override - public Set possibleTargets(UUID sourceId, UUID sourceControllerId, - Game game) { - return possibleTargets(sourceControllerId, game); - } - - @Override - public Set possibleTargets(UUID sourceControllerId, Game game) { - Set possibleTargets = new HashSet<>(); - for (StackObject stackObject : game.getStack()) { - if (((stackObject instanceof Spell) || (stackObject instanceof StackAbility)) && stackObject.getControllerId() != sourceControllerId) { - Targets objectTargets = stackObject.getStackAbility().getTargets(); - if(!objectTargets.isEmpty()) { - for (Target target : objectTargets) { - for (UUID targetId : target.getTargets()) { - Permanent targetedPermanent = game.getPermanentOrLKIBattlefield(targetId); - if (targetedPermanent != null && targetedPermanent.getCardType().contains(CardType.LAND) && targetedPermanent.getControllerId().equals(sourceControllerId)) { - possibleTargets.add(stackObject.getId()); - } - } - } - } - } - } - return possibleTargets; - } - - @Override - public TargetStackObjectTargetingControlledLand copy() { - return new TargetStackObjectTargetingControlledLand(this); - } - -} - class TeferisResponseEffect extends OneShotEffect { public TeferisResponseEffect() { From 597d530a3718a34eeb3f596d865bd257b4733c07 Mon Sep 17 00:00:00 2001 From: LevelX2 Date: Fri, 16 Oct 2015 15:03:40 +0200 Subject: [PATCH 160/268] Some minor changes. --- .../mage/sets/gatecrash/MasterBiomancer.java | 90 +++++++++---------- .../test/cards/triggers/FathomMageTest.java | 20 +++-- .../mage/abilities/keyword/EvolveAbility.java | 81 +++++++++-------- 3 files changed, 103 insertions(+), 88 deletions(-) diff --git a/Mage.Sets/src/mage/sets/gatecrash/MasterBiomancer.java b/Mage.Sets/src/mage/sets/gatecrash/MasterBiomancer.java index eeb0b6346dd..34fcc5b6294 100644 --- a/Mage.Sets/src/mage/sets/gatecrash/MasterBiomancer.java +++ b/Mage.Sets/src/mage/sets/gatecrash/MasterBiomancer.java @@ -1,30 +1,30 @@ /* -* Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. -* -* Redistribution and use in source and binary forms, with or without modification, are -* permitted provided that the following conditions are met: -* -* 1. Redistributions of source code must retain the above copyright notice, this list of -* conditions and the following disclaimer. -* -* 2. Redistributions in binary form must reproduce the above copyright notice, this list -* of conditions and the following disclaimer in the documentation and/or other materials -* provided with the distribution. -* -* THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED -* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND -* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR -* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR -* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON -* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING -* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF -* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -* -* The views and conclusions contained in the software and documentation are those of the -* authors and should not be interpreted as representing official policies, either expressed -* or implied, of BetaSteward_at_googlemail.com. -*/ + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ package mage.sets.gatecrash; import java.util.UUID; @@ -42,37 +42,38 @@ import mage.constants.Rarity; import mage.constants.Zone; import mage.counters.CounterType; import mage.game.Game; +import mage.game.events.EntersTheBattlefieldEvent; import mage.game.events.GameEvent; import mage.game.events.GameEvent.EventType; import mage.game.permanent.Permanent; import mage.target.targetpointer.FixedTarget; /** -* -* @author LevelX2 -*/ + * + * @author LevelX2 + */ public class MasterBiomancer extends CardImpl { public MasterBiomancer(UUID ownerId) { - super(ownerId, 176, "Master Biomancer", Rarity.MYTHIC, new CardType[]{CardType.CREATURE}, "{2}{G}{U}"); - this.expansionSetCode = "GTC"; - this.subtype.add("Elf"); - this.subtype.add("Wizard"); + super(ownerId, 176, "Master Biomancer", Rarity.MYTHIC, new CardType[]{CardType.CREATURE}, "{2}{G}{U}"); + this.expansionSetCode = "GTC"; + this.subtype.add("Elf"); + this.subtype.add("Wizard"); - this.power = new MageInt(2); - this.toughness = new MageInt(4); + this.power = new MageInt(2); + this.toughness = new MageInt(4); - // Each other creature you control enters the battlefield with a number of additional +1/+1 counters on it equal to Master Biomancer's power and as a Mutant in addition to its other types. - this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new MasterBiomancerEntersBattlefieldEffect())); + // Each other creature you control enters the battlefield with a number of additional +1/+1 counters on it equal to Master Biomancer's power and as a Mutant in addition to its other types. + this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new MasterBiomancerEntersBattlefieldEffect())); } public MasterBiomancer(final MasterBiomancer card) { - super(card); + super(card); } @Override public MasterBiomancer copy() { - return new MasterBiomancer(this); + return new MasterBiomancer(this); } } @@ -86,16 +87,16 @@ class MasterBiomancerEntersBattlefieldEffect extends ReplacementEffectImpl { public MasterBiomancerEntersBattlefieldEffect(MasterBiomancerEntersBattlefieldEffect effect) { super(effect); } - + @Override public boolean checksEventType(GameEvent event, Game game) { return event.getType() == EventType.ENTERS_THE_BATTLEFIELD; } - + @Override public boolean applies(GameEvent event, Ability source, Game game) { - Permanent creature = game.getPermanent(event.getTargetId()); - return creature != null && creature.getControllerId().equals(source.getControllerId()) + Permanent creature = ((EntersTheBattlefieldEvent) event).getTarget(); + return creature != null && creature.getControllerId().equals(source.getControllerId()) && creature.getCardType().contains(CardType.CREATURE) && !event.getTargetId().equals(source.getSourceId()); } @@ -103,7 +104,7 @@ class MasterBiomancerEntersBattlefieldEffect extends ReplacementEffectImpl { @Override public boolean replaceEvent(GameEvent event, Ability source, Game game) { Permanent sourceCreature = game.getPermanent(source.getSourceId()); - Permanent creature = game.getPermanent(event.getTargetId()); + Permanent creature = ((EntersTheBattlefieldEvent) event).getTarget(); if (sourceCreature != null && creature != null) { int power = sourceCreature.getPower().getValue(); if (power > 0) { @@ -116,7 +117,6 @@ class MasterBiomancerEntersBattlefieldEffect extends ReplacementEffectImpl { return false; } - @Override public MasterBiomancerEntersBattlefieldEffect copy() { return new MasterBiomancerEntersBattlefieldEffect(this); diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/triggers/FathomMageTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/triggers/FathomMageTest.java index 5d8f468f12c..a57ef6b9837 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/triggers/FathomMageTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/triggers/FathomMageTest.java @@ -2,6 +2,8 @@ package org.mage.test.cards.triggers; import mage.constants.PhaseStep; import mage.constants.Zone; +import mage.game.permanent.Permanent; +import org.junit.Assert; import org.junit.Test; import org.mage.test.serverside.base.CardTestPlayerBase; @@ -13,14 +15,16 @@ public class FathomMageTest extends CardTestPlayerBase { /** * Fathom Mage - Creature — Human Wizard 1/1, 2UG * - * Evolve (Whenever a creature enters the battlefield under your control, if that creature has greater power or toughness than this creature, put a +1/+1 counter on this creature.) - * Whenever a +1/+1 counter is placed on Fathom Mage, you may draw a card. + * Evolve (Whenever a creature enters the battlefield under your control, if + * that creature has greater power or toughness than this creature, put a + * +1/+1 counter on this creature.) Whenever a +1/+1 counter is placed on + * Fathom Mage, you may draw a card. + * * - */ @Test public void testDrawCardsAddedCounters() { - // card draw triggered ability will trigger once for each of those counters from Blessings of Nature. + // card draw triggered ability will trigger once for each of those counters from Blessings of Nature. addCard(Zone.HAND, playerA, "Blessings of Nature"); addCard(Zone.BATTLEFIELD, playerA, "Fathom Mage", 1); @@ -38,9 +42,11 @@ public class FathomMageTest extends CardTestPlayerBase { @Test public void testDrawCardsEntersTheBattlefield() { - // card draw triggered ability will trigger once for each of those counters from Master Biomancer. + // card draw triggered ability will trigger once for each of those counters from Master Biomancer. addCard(Zone.HAND, playerA, "Fathom Mage"); + // Each other creature you control enters the battlefield with a number of additional +1/+1 counters on it equal to + // Master Biomancer's power and as a Mutant in addition to its other types. addCard(Zone.BATTLEFIELD, playerA, "Master Biomancer", 1); addCard(Zone.BATTLEFIELD, playerA, "Forest", 4); addCard(Zone.BATTLEFIELD, playerA, "Island", 4); @@ -52,6 +58,10 @@ public class FathomMageTest extends CardTestPlayerBase { assertPermanentCount(playerA, "Fathom Mage", 1); assertPowerToughness(playerA, "Fathom Mage", 3, 3); + + Permanent fathomMage = getPermanent("Fathom Mage", playerA); + Assert.assertEquals("Fathom Mage has to be a Mutant", fathomMage.getSubtype().contains("Mutant"), true); + assertHandCount(playerA, 2); } } diff --git a/Mage/src/mage/abilities/keyword/EvolveAbility.java b/Mage/src/mage/abilities/keyword/EvolveAbility.java index 16c1b316e01..00712d973c8 100644 --- a/Mage/src/mage/abilities/keyword/EvolveAbility.java +++ b/Mage/src/mage/abilities/keyword/EvolveAbility.java @@ -25,7 +25,6 @@ * authors and should not be interpreted as representing official policies, either expressed * or implied, of BetaSteward_at_googlemail.com. */ - package mage.abilities.keyword; import mage.abilities.Ability; @@ -44,46 +43,53 @@ import mage.target.targetpointer.FixedTarget; * FAQ 2013/01/11 * * 702.98. Evolve - * - * 702.98a Evolve is a triggered ability. "Evolve" means "Whenever a creature enters - * the battlefield under your control, if that creature's power is greater than this - * creature's power and/or that creature's toughness is greater than this creature's - * toughness, put a +1/+1 counter on this creature." * - * 702.98b If a creature has multiple instances of evolve, each triggers separately - * + * 702.98a Evolve is a triggered ability. "Evolve" means "Whenever a creature + * enters the battlefield under your control, if that creature's power is + * greater than this creature's power and/or that creature's toughness is + * greater than this creature's toughness, put a +1/+1 counter on this + * creature." + * + * 702.98b If a creature has multiple instances of evolve, each triggers + * separately + * * Rulings - * - * When comparing the stats of the two creatures, you always compare power to power and toughness to toughness. - * Whenever a creature enters the battlefield under your control, check its power and toughness against - * the power and toughness of the creature with evolve. If neither stat of the new creature is greater, - * evolve won't trigger at all. For example, if you control a 2/3 creature with evolve and a 2/2 creature - * enters the battlefield under your control, you won't have the opportunity to cast a spell like Giant Growth - * to make the 2/2 creature large enough to cause evolve to trigger. - * If evolve triggers, the stat comparison will happen again when the ability tries to resolve. If - * neither stat of the new creature is greater, the ability will do nothing. If the creature that - * entered the battlefield leaves the battlefield before evolve tries to resolve, use its last known - * power and toughness to compare the stats. - * If a creature enters the battlefield with +1/+1 counters on it, consider those counters when determining - * if evolve will trigger. For example, a 1/1 creature that enters the battlefield with two +1/+1 counters - * on it will cause the evolve ability of a 2/2 creature to trigger. - * If multiple creatures enter the battlefield at the same time, evolve may trigger multiple times, although the stat - * comparison will take place each time one of those abilities tries to resolve. For example, if you control a 2/2 - * creature with evolve and two 3/3 creatures enter the battlefield, evolve will trigger twice. The first ability - * will resolve and put a +1/+1 counter on the creature with evolve. When the second ability tries to resolve, - * neither the power nor the toughness of the new creature is greater than that of the creature with evolve, - * so that ability does nothing. - * When comparing the stats as the evolve ability resolves, it's possible that the stat that's greater changes - * from power to toughness or vice versa. If this happens, the ability will still resolve and you'll put a +1/+1 - * counter on the creature with evolve. For example, if you control a 2/2 creature with evolve and a 1/3 creature - * enters the battlefield under your control, it toughness is greater so evolve will trigger. In response, the 1/3 - * creature gets +2/-2. When the evolve trigger tries to resolve, its power is greater. You'll put a +1/+1 - * counter on the creature with evolve. - * + * + * When comparing the stats of the two creatures, you always compare power to + * power and toughness to toughness. Whenever a creature enters the battlefield + * under your control, check its power and toughness against the power and + * toughness of the creature with evolve. If neither stat of the new creature is + * greater, evolve won't trigger at all. For example, if you control a 2/3 + * creature with evolve and a 2/2 creature enters the battlefield under your + * control, you won't have the opportunity to cast a spell like Giant Growth to + * make the 2/2 creature large enough to cause evolve to trigger. If evolve + * triggers, the stat comparison will happen again when the ability tries to + * resolve. If neither stat of the new creature is greater, the ability will do + * nothing. If the creature that entered the battlefield leaves the battlefield + * before evolve tries to resolve, use its last known power and toughness to + * compare the stats. If a creature enters the battlefield with +1/+1 counters + * on it, consider those counters when determining if evolve will trigger. For + * example, a 1/1 creature that enters the battlefield with two +1/+1 counters + * on it will cause the evolve ability of a 2/2 creature to trigger. If multiple + * creatures enter the battlefield at the same time, evolve may trigger multiple + * times, although the stat comparison will take place each time one of those + * abilities tries to resolve. For example, if you control a 2/2 creature with + * evolve and two 3/3 creatures enter the battlefield, evolve will trigger + * twice. The first ability will resolve and put a +1/+1 counter on the creature + * with evolve. When the second ability tries to resolve, neither the power nor + * the toughness of the new creature is greater than that of the creature with + * evolve, so that ability does nothing. When comparing the stats as the evolve + * ability resolves, it's possible that the stat that's greater changes from + * power to toughness or vice versa. If this happens, the ability will still + * resolve and you'll put a +1/+1 counter on the creature with evolve. For + * example, if you control a 2/2 creature with evolve and a 1/3 creature enters + * the battlefield under your control, it toughness is greater so evolve will + * trigger. In response, the 1/3 creature gets +2/-2. When the evolve trigger + * tries to resolve, its power is greater. You'll put a +1/+1 counter on the + * creature with evolve. + * * @author LevelX2 */ - - public class EvolveAbility extends TriggeredAbilityImpl { public EvolveAbility() { @@ -169,4 +175,3 @@ class EvolveEffect extends OneShotEffect { return false; } } - From 790b06c99338a1fe289d720b2564f408c2b4779e Mon Sep 17 00:00:00 2001 From: Jeff Date: Fri, 16 Oct 2015 14:18:05 -0500 Subject: [PATCH 161/268] - Set "Outcome.Detrimental" on Black Vise. --- Mage.Sets/src/mage/sets/limitedalpha/BlackVise.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Mage.Sets/src/mage/sets/limitedalpha/BlackVise.java b/Mage.Sets/src/mage/sets/limitedalpha/BlackVise.java index 57732f49119..82e9d7e9b09 100644 --- a/Mage.Sets/src/mage/sets/limitedalpha/BlackVise.java +++ b/Mage.Sets/src/mage/sets/limitedalpha/BlackVise.java @@ -103,7 +103,7 @@ class BlackViseTriggeredAbility extends TriggeredAbilityImpl { class BlackViseEffect extends OneShotEffect { public BlackViseEffect() { - super(Outcome.Benefit); + super(Outcome.Detriment); this.staticText = "{this} deals X damage to that player, where X is the number of cards in his or her hand minus 4"; } From fad50a4ecf43dd737f95f8d107ee780508b6a870 Mon Sep 17 00:00:00 2001 From: LoneFox Date: Sat, 17 Oct 2015 11:39:45 +0300 Subject: [PATCH 162/268] Update the list of ability words (CompRules 207.2c) --- Mage/src/mage/constants/AbilityWord.java | 24 +++++++++++++++++++++--- 1 file changed, 21 insertions(+), 3 deletions(-) diff --git a/Mage/src/mage/constants/AbilityWord.java b/Mage/src/mage/constants/AbilityWord.java index 29088e89d1f..c09e01877b9 100644 --- a/Mage/src/mage/constants/AbilityWord.java +++ b/Mage/src/mage/constants/AbilityWord.java @@ -33,19 +33,37 @@ package mage.constants; */ public enum AbilityWord { - RALLY("Rally"), + BATTALION("Battalion"), BLOODRUSH("Bloodrush"), - CONVERGE("Converge"), + CHANNEL("Channel"), + CHROMA("Chroma"), CONSTELLATION("Constellation"), + CONVERGE("Converge"), + DOMAIN("Domain"), + FATEFUL_HOUR("Fateful hour"), FEROCIOUS("Ferocious"), FORMIDABLE("Formidable"), GRANDEUR("Grandeur"), HELLBENT("Hellbent"), HEROIC("Heroic"), + IMPRINT("Imprint"), + INSPIRED("Inspided"), + JOIN_FORCES("Join forces"), + KINSHIP("Kinship"), LANDFALL("Landfall"), + LIEUTENANT("Lieutenant"), METALCRAFT("Metalcraft"), + MORBID("Morbid"), PARLEY("Parley"), - RAID("Raid"); + RADIANCE("Radiance"), + RAID("Raid"), + RALLY("Rally"), + SPELL_MASTERY("Spell mastery"), + STRIVE("Strive"), + SWEEP("Sweep"), + TEMPTING_OFFER("Tempting offer"), + THRESHOLD("Threshold"), + WILL_OF_THE_COUNCIL("Will of the council"); private final String text; From 8b42cf9bfa61a68ba30e70a91c19a2f150fe7ab0 Mon Sep 17 00:00:00 2001 From: LoneFox Date: Sat, 17 Oct 2015 12:18:49 +0300 Subject: [PATCH 163/268] Implement the Possessed creatures from Torment --- .../src/mage/sets/torment/PossessedAven.java | 107 ++++++++++++++++++ .../mage/sets/torment/PossessedBarbarian.java | 107 ++++++++++++++++++ .../mage/sets/torment/PossessedCentaur.java | 106 +++++++++++++++++ .../src/mage/sets/torment/PossessedNomad.java | 107 ++++++++++++++++++ 4 files changed, 427 insertions(+) create mode 100644 Mage.Sets/src/mage/sets/torment/PossessedAven.java create mode 100644 Mage.Sets/src/mage/sets/torment/PossessedBarbarian.java create mode 100644 Mage.Sets/src/mage/sets/torment/PossessedCentaur.java create mode 100644 Mage.Sets/src/mage/sets/torment/PossessedNomad.java diff --git a/Mage.Sets/src/mage/sets/torment/PossessedAven.java b/Mage.Sets/src/mage/sets/torment/PossessedAven.java new file mode 100644 index 00000000000..e51fc4f6625 --- /dev/null +++ b/Mage.Sets/src/mage/sets/torment/PossessedAven.java @@ -0,0 +1,107 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.sets.torment; + +import java.util.UUID; +import mage.MageInt; +import mage.ObjectColor; +import mage.abilities.Ability; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.condition.common.CardsInControllerGraveCondition; +import mage.abilities.costs.common.TapSourceCost; +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.decorator.ConditionalContinuousEffect; +import mage.abilities.effects.Effect; +import mage.abilities.effects.common.DestroyTargetEffect; +import mage.abilities.effects.common.continuous.BecomesColorSourceEffect; +import mage.abilities.effects.common.continuous.BoostSourceEffect; +import mage.abilities.effects.common.continuous.GainAbilitySourceEffect; +import mage.abilities.keyword.FlyingAbility; +import mage.cards.CardImpl; +import mage.constants.AbilityWord; +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.mageobject.ColorPredicate; +import mage.target.common.TargetCreaturePermanent; + +/** + * + * @author LoneFox + */ +public class PossessedAven extends CardImpl { + + private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("blue creature"); + + static { + filter.add(new ColorPredicate(ObjectColor.BLUE)); + } + + public PossessedAven(UUID ownerId) { + super(ownerId, 45, "Possessed Aven", Rarity.RARE, new CardType[]{CardType.CREATURE}, "{2}{U}{U}"); + this.expansionSetCode = "TOR"; + this.subtype.add("Bird"); + this.subtype.add("Soldier"); + this.subtype.add("Horror"); + this.power = new MageInt(3); + this.toughness = new MageInt(3); + + // Flying + this.addAbility(FlyingAbility.getInstance()); + // Threshold - As long as seven or more cards are in your graveyard, Possessed Aven gets +1/+1, is black, and has "{2}{B}, {tap}: Destroy target blue creature." + Ability ability = new SimpleStaticAbility(Zone.BATTLEFIELD, new ConditionalContinuousEffect( + new BoostSourceEffect(1, 1, Duration.WhileOnBattlefield), new CardsInControllerGraveCondition(7), + "As long as seven or more cards are in your graveyard, {this} gets +1/+1")); + + Effect effect = new ConditionalContinuousEffect(new BecomesColorSourceEffect(ObjectColor.BLACK, Duration.WhileOnBattlefield), + new CardsInControllerGraveCondition(7), ", is black"); + ability.addEffect(effect); + + Ability gainedAbility = new SimpleActivatedAbility(Zone.BATTLEFIELD, new DestroyTargetEffect(), new ManaCostsImpl("{2}{B}")); + gainedAbility.addCost(new TapSourceCost()); + gainedAbility.addTarget(new TargetCreaturePermanent(filter)); + effect = new ConditionalContinuousEffect(new GainAbilitySourceEffect(gainedAbility), + new CardsInControllerGraveCondition(7), ", and has \"{2}{B}, {T}: Destroy target blue creature.\""); + ability.addEffect(effect); + + ability.setAbilityWord(AbilityWord.THRESHOLD); + this.addAbility(ability); + } + + public PossessedAven(final PossessedAven card) { + super(card); + } + + @Override + public PossessedAven copy() { + return new PossessedAven(this); + } +} diff --git a/Mage.Sets/src/mage/sets/torment/PossessedBarbarian.java b/Mage.Sets/src/mage/sets/torment/PossessedBarbarian.java new file mode 100644 index 00000000000..311f0475080 --- /dev/null +++ b/Mage.Sets/src/mage/sets/torment/PossessedBarbarian.java @@ -0,0 +1,107 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.sets.torment; + +import java.util.UUID; +import mage.MageInt; +import mage.ObjectColor; +import mage.abilities.Ability; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.condition.common.CardsInControllerGraveCondition; +import mage.abilities.costs.common.TapSourceCost; +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.decorator.ConditionalContinuousEffect; +import mage.abilities.effects.Effect; +import mage.abilities.effects.common.DestroyTargetEffect; +import mage.abilities.effects.common.continuous.BecomesColorSourceEffect; +import mage.abilities.effects.common.continuous.BoostSourceEffect; +import mage.abilities.effects.common.continuous.GainAbilitySourceEffect; +import mage.abilities.keyword.FirstStrikeAbility; +import mage.cards.CardImpl; +import mage.constants.AbilityWord; +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.mageobject.ColorPredicate; +import mage.target.common.TargetCreaturePermanent; + +/** + * + * @author LoneFox + */ +public class PossessedBarbarian extends CardImpl { + + private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("red creature"); + + static { + filter.add(new ColorPredicate(ObjectColor.RED)); + } + + public PossessedBarbarian(UUID ownerId) { + super(ownerId, 111, "Possessed Barbarian", Rarity.RARE, new CardType[]{CardType.CREATURE}, "{2}{R}{R}"); + this.expansionSetCode = "TOR"; + this.subtype.add("Human"); + this.subtype.add("Barbarian"); + this.subtype.add("Horror"); + this.power = new MageInt(3); + this.toughness = new MageInt(3); + + // First strike + this.addAbility(FirstStrikeAbility.getInstance()); + // Threshold - As long as seven or more cards are in your graveyard, Possessed Barbarian gets +1/+1, is black, and has "{2}{B}, {tap}: Destroy target red creature." + Ability ability = new SimpleStaticAbility(Zone.BATTLEFIELD, new ConditionalContinuousEffect( + new BoostSourceEffect(1, 1, Duration.WhileOnBattlefield), new CardsInControllerGraveCondition(7), + "As long as seven or more cards are in your graveyard, {this} gets +1/+1")); + + Effect effect = new ConditionalContinuousEffect(new BecomesColorSourceEffect(ObjectColor.BLACK, Duration.WhileOnBattlefield), + new CardsInControllerGraveCondition(7), ", is black"); + ability.addEffect(effect); + + Ability gainedAbility = new SimpleActivatedAbility(Zone.BATTLEFIELD, new DestroyTargetEffect(), new ManaCostsImpl("{2}{B}")); + gainedAbility.addCost(new TapSourceCost()); + gainedAbility.addTarget(new TargetCreaturePermanent(filter)); + effect = new ConditionalContinuousEffect(new GainAbilitySourceEffect(gainedAbility), + new CardsInControllerGraveCondition(7), ", and has \"{2}{B}, {T}: Destroy target red creature.\""); + ability.addEffect(effect); + + ability.setAbilityWord(AbilityWord.THRESHOLD); + this.addAbility(ability); + } + + public PossessedBarbarian(final PossessedBarbarian card) { + super(card); + } + + @Override + public PossessedBarbarian copy() { + return new PossessedBarbarian(this); + } +} diff --git a/Mage.Sets/src/mage/sets/torment/PossessedCentaur.java b/Mage.Sets/src/mage/sets/torment/PossessedCentaur.java new file mode 100644 index 00000000000..8117de8c695 --- /dev/null +++ b/Mage.Sets/src/mage/sets/torment/PossessedCentaur.java @@ -0,0 +1,106 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.sets.torment; + +import java.util.UUID; +import mage.MageInt; +import mage.ObjectColor; +import mage.abilities.Ability; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.condition.common.CardsInControllerGraveCondition; +import mage.abilities.costs.common.TapSourceCost; +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.decorator.ConditionalContinuousEffect; +import mage.abilities.effects.Effect; +import mage.abilities.effects.common.DestroyTargetEffect; +import mage.abilities.effects.common.continuous.BecomesColorSourceEffect; +import mage.abilities.effects.common.continuous.BoostSourceEffect; +import mage.abilities.effects.common.continuous.GainAbilitySourceEffect; +import mage.abilities.keyword.TrampleAbility; +import mage.cards.CardImpl; +import mage.constants.AbilityWord; +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.mageobject.ColorPredicate; +import mage.target.common.TargetCreaturePermanent; + +/** + * + * @author LoneFox + */ +public class PossessedCentaur extends CardImpl { + + private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("green creature"); + + static { + filter.add(new ColorPredicate(ObjectColor.GREEN)); + } + + public PossessedCentaur(UUID ownerId) { + super(ownerId, 137, "Possessed Centaur", Rarity.RARE, new CardType[]{CardType.CREATURE}, "{2}{G}{G}"); + this.expansionSetCode = "TOR"; + this.subtype.add("Centaur"); + this.subtype.add("Horror"); + this.power = new MageInt(3); + this.toughness = new MageInt(3); + + // Trample + this.addAbility(TrampleAbility.getInstance()); + // Threshold - As long as seven or more cards are in your graveyard, Possessed Centaur gets +1/+1, is black, and has "{2}{B}, {tap}: Destroy target green creature." + Ability ability = new SimpleStaticAbility(Zone.BATTLEFIELD, new ConditionalContinuousEffect( + new BoostSourceEffect(1, 1, Duration.WhileOnBattlefield), new CardsInControllerGraveCondition(7), + "As long as seven or more cards are in your graveyard, {this} gets +1/+1")); + + Effect effect = new ConditionalContinuousEffect(new BecomesColorSourceEffect(ObjectColor.BLACK, Duration.WhileOnBattlefield), + new CardsInControllerGraveCondition(7), ", is black"); + ability.addEffect(effect); + + Ability gainedAbility = new SimpleActivatedAbility(Zone.BATTLEFIELD, new DestroyTargetEffect(), new ManaCostsImpl("{2}{B}")); + gainedAbility.addCost(new TapSourceCost()); + gainedAbility.addTarget(new TargetCreaturePermanent(filter)); + effect = new ConditionalContinuousEffect(new GainAbilitySourceEffect(gainedAbility), + new CardsInControllerGraveCondition(7), ", and has \"{2}{B}, {T}: Destroy target green creature.\""); + ability.addEffect(effect); + + ability.setAbilityWord(AbilityWord.THRESHOLD); + this.addAbility(ability); + } + + public PossessedCentaur(final PossessedCentaur card) { + super(card); + } + + @Override + public PossessedCentaur copy() { + return new PossessedCentaur(this); + } +} diff --git a/Mage.Sets/src/mage/sets/torment/PossessedNomad.java b/Mage.Sets/src/mage/sets/torment/PossessedNomad.java new file mode 100644 index 00000000000..2f8f67b3e07 --- /dev/null +++ b/Mage.Sets/src/mage/sets/torment/PossessedNomad.java @@ -0,0 +1,107 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.sets.torment; + +import java.util.UUID; +import mage.MageInt; +import mage.ObjectColor; +import mage.abilities.Ability; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.condition.common.CardsInControllerGraveCondition; +import mage.abilities.costs.common.TapSourceCost; +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.decorator.ConditionalContinuousEffect; +import mage.abilities.effects.Effect; +import mage.abilities.effects.common.DestroyTargetEffect; +import mage.abilities.effects.common.continuous.BecomesColorSourceEffect; +import mage.abilities.effects.common.continuous.BoostSourceEffect; +import mage.abilities.effects.common.continuous.GainAbilitySourceEffect; +import mage.abilities.keyword.VigilanceAbility; +import mage.cards.CardImpl; +import mage.constants.AbilityWord; +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.mageobject.ColorPredicate; +import mage.target.common.TargetCreaturePermanent; + +/** + * + * @author LoneFox + */ +public class PossessedNomad extends CardImpl { + + private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("white creature"); + + static { + filter.add(new ColorPredicate(ObjectColor.WHITE)); + } + + public PossessedNomad(UUID ownerId) { + super(ownerId, 13, "Possessed Nomad", Rarity.RARE, new CardType[]{CardType.CREATURE}, "{2}{W}{W}"); + this.expansionSetCode = "TOR"; + this.subtype.add("Human"); + this.subtype.add("Nomad"); + this.subtype.add("Horror"); + this.power = new MageInt(3); + this.toughness = new MageInt(3); + + // Vigilance + this.addAbility(VigilanceAbility.getInstance()); + // Threshold - As long as seven or more cards are in your graveyard, Possessed Nomad gets +1/+1, is black, and has "{2}{B}, {tap}: Destroy target white creature." + Ability ability = new SimpleStaticAbility(Zone.BATTLEFIELD, new ConditionalContinuousEffect( + new BoostSourceEffect(1, 1, Duration.WhileOnBattlefield), new CardsInControllerGraveCondition(7), + "As long as seven or more cards are in your graveyard, {this} gets +1/+1")); + + Effect effect = new ConditionalContinuousEffect(new BecomesColorSourceEffect(ObjectColor.BLACK, Duration.WhileOnBattlefield), + new CardsInControllerGraveCondition(7), ", is black"); + ability.addEffect(effect); + + Ability gainedAbility = new SimpleActivatedAbility(Zone.BATTLEFIELD, new DestroyTargetEffect(), new ManaCostsImpl("{2}{B}")); + gainedAbility.addCost(new TapSourceCost()); + gainedAbility.addTarget(new TargetCreaturePermanent(filter)); + effect = new ConditionalContinuousEffect(new GainAbilitySourceEffect(gainedAbility), + new CardsInControllerGraveCondition(7), ", and has \"{2}{B}, {T}: Destroy target white creature.\""); + ability.addEffect(effect); + + ability.setAbilityWord(AbilityWord.THRESHOLD); + this.addAbility(ability); + } + + public PossessedNomad(final PossessedNomad card) { + super(card); + } + + @Override + public PossessedNomad copy() { + return new PossessedNomad(this); + } +} From a847e5619dbf86794b8a65c08a0515088cea3739 Mon Sep 17 00:00:00 2001 From: LoneFox Date: Sat, 17 Oct 2015 15:14:38 +0300 Subject: [PATCH 164/268] Fix a few broken tooltip texts and kill an unnecessary custom Cost class from Skirksdag High Priest --- .../mage/sets/dissension/FlaringFlameKin.java | 30 +++++++------- .../sets/innistrad/SkirsdagHighPriest.java | 41 ++++--------------- .../src/mage/sets/magic2012/ThranGolem.java | 36 ++++++++-------- .../src/mage/sets/magic2012/Trollhide.java | 20 +++++++-- .../condition/common/MorbidCondition.java | 5 +++ 5 files changed, 59 insertions(+), 73 deletions(-) diff --git a/Mage.Sets/src/mage/sets/dissension/FlaringFlameKin.java b/Mage.Sets/src/mage/sets/dissension/FlaringFlameKin.java index c8b77cfc298..1cfe02e7dc6 100644 --- a/Mage.Sets/src/mage/sets/dissension/FlaringFlameKin.java +++ b/Mage.Sets/src/mage/sets/dissension/FlaringFlameKin.java @@ -29,9 +29,9 @@ package mage.sets.dissension; import java.util.UUID; import mage.MageInt; +import mage.abilities.Ability; import mage.abilities.common.SimpleActivatedAbility; import mage.abilities.common.SimpleStaticAbility; -import mage.abilities.condition.Condition; import mage.abilities.condition.common.EnchantedCondition; import mage.abilities.costs.mana.ManaCostsImpl; import mage.abilities.decorator.ConditionalContinuousEffect; @@ -50,10 +50,6 @@ import mage.constants.Zone; */ public class FlaringFlameKin extends CardImpl { - private static final String rule1 = "As long as {this} is enchanted, it gets +2/+2"; - private static final String rule2 = "As long as {this} is enchanted, it has trample"; - private static final String rule3 = "As long as {this} is enchanted, it has \"{R}: {this} gets +1/+0 until end of turn.\""; - public FlaringFlameKin(UUID ownerId) { super(ownerId, 62, "Flaring Flame-Kin", Rarity.UNCOMMON, new CardType[]{CardType.CREATURE}, "{2}{R}"); this.expansionSetCode = "DIS"; @@ -63,17 +59,19 @@ public class FlaringFlameKin extends CardImpl { this.power = new MageInt(2); this.toughness = new MageInt(2); - SimpleActivatedAbility grantedAbility = new SimpleActivatedAbility(Zone.BATTLEFIELD, - new BoostSourceEffect(1, 0, Duration.EndOfTurn), - new ManaCostsImpl("{R}")); - - Condition enchanted = new EnchantedCondition(); - ConditionalContinuousEffect effect1 = new ConditionalContinuousEffect(new BoostSourceEffect(2, 2, Duration.WhileOnBattlefield), enchanted, rule1); - this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, effect1)); - ConditionalContinuousEffect effect2 = new ConditionalContinuousEffect(new GainAbilitySourceEffect(TrampleAbility.getInstance()), enchanted, rule2); - this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, effect2)); - ConditionalContinuousEffect effect3 = new ConditionalContinuousEffect(new GainAbilitySourceEffect(grantedAbility), enchanted, rule3); - this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, effect3)); + // As long as Flaring Flame-Kin is enchanted, it gets +2/+2, has trample, and has "{R}: Flaring Flame-Kin gets +1/+0 until end of turn." + EnchantedCondition enchanted = new EnchantedCondition(); + Ability ability = new SimpleStaticAbility(Zone.BATTLEFIELD, new ConditionalContinuousEffect( + new BoostSourceEffect(2, 2, Duration.WhileOnBattlefield), enchanted, + "As long as {this} is enchanted, it gets +2/+2")); + ability.addEffect(new ConditionalContinuousEffect( + new GainAbilitySourceEffect(TrampleAbility.getInstance()), enchanted, + ", has trample")); + Ability grantedAbility = new SimpleActivatedAbility(Zone.BATTLEFIELD, + new BoostSourceEffect(1, 0, Duration.EndOfTurn), new ManaCostsImpl("{R}")); + ability.addEffect(new ConditionalContinuousEffect(new GainAbilitySourceEffect(grantedAbility), + enchanted, ", and has \"{R}: {this} gets +1/+0 until end of turn.\"")); + this.addAbility(ability); } public FlaringFlameKin(final FlaringFlameKin card) { diff --git a/Mage.Sets/src/mage/sets/innistrad/SkirsdagHighPriest.java b/Mage.Sets/src/mage/sets/innistrad/SkirsdagHighPriest.java index 16fef1058fe..3f50f943347 100644 --- a/Mage.Sets/src/mage/sets/innistrad/SkirsdagHighPriest.java +++ b/Mage.Sets/src/mage/sets/innistrad/SkirsdagHighPriest.java @@ -30,20 +30,19 @@ package mage.sets.innistrad; import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; -import mage.abilities.common.SimpleActivatedAbility; -import mage.abilities.costs.CostImpl; +import mage.abilities.condition.common.MorbidCondition; import mage.abilities.costs.common.TapSourceCost; import mage.abilities.costs.common.TapTargetCost; +import mage.abilities.decorator.ConditionalActivatedAbility; import mage.abilities.effects.common.CreateTokenEffect; -import mage.abilities.keyword.FlyingAbility; import mage.cards.CardImpl; +import mage.constants.AbilityWord; import mage.constants.CardType; import mage.constants.Rarity; import mage.constants.Zone; import mage.filter.common.FilterControlledCreaturePermanent; import mage.filter.predicate.Predicates; import mage.filter.predicate.permanent.TappedPredicate; -import mage.game.Game; import mage.game.permanent.token.DemonToken; import mage.target.common.TargetControlledCreaturePermanent; @@ -69,9 +68,10 @@ public class SkirsdagHighPriest extends CardImpl { this.toughness = new MageInt(2); // Morbid - {tap}, Tap two untapped creatures you control: Put a 5/5 black Demon creature token with flying onto the battlefield. Activate this ability only if a creature died this turn. - Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new CreateTokenEffect(new DemonToken()), new TapSourceCost()); - ability.addCost(new TapTargetCost(new TargetControlledCreaturePermanent(2,2,filter, false))); - ability.addCost(new SkirsdagHighPriestCost()); + Ability ability = new ConditionalActivatedAbility(Zone.BATTLEFIELD, new CreateTokenEffect(new DemonToken()), + new TapSourceCost(), MorbidCondition.getInstance()); + ability.addCost(new TapTargetCost(new TargetControlledCreaturePermanent(2, 2, filter, false))); + ability.setAbilityWord(AbilityWord.MORBID); this.addAbility(ability); } @@ -84,30 +84,3 @@ public class SkirsdagHighPriest extends CardImpl { return new SkirsdagHighPriest(this); } } - -class SkirsdagHighPriestCost extends CostImpl { - - public SkirsdagHighPriestCost() { - this.text = "Activate this ability only if a creature died this turn"; - } - - public SkirsdagHighPriestCost(final SkirsdagHighPriestCost cost) { - super(cost); - } - - @Override - public SkirsdagHighPriestCost copy() { - return new SkirsdagHighPriestCost(this); - } - - @Override - public boolean canPay(Ability ability, UUID sourceId, UUID controllerId, Game game) { - return game.getState().getWatchers().get("Morbid").conditionMet(); - } - - @Override - public boolean pay(Ability ability, Game game, UUID sourceId, UUID controllerId, boolean noMana) { - this.paid = true; - return paid; - } -} diff --git a/Mage.Sets/src/mage/sets/magic2012/ThranGolem.java b/Mage.Sets/src/mage/sets/magic2012/ThranGolem.java index eb4d72649fe..b8e679ff356 100644 --- a/Mage.Sets/src/mage/sets/magic2012/ThranGolem.java +++ b/Mage.Sets/src/mage/sets/magic2012/ThranGolem.java @@ -28,13 +28,9 @@ package mage.sets.magic2012; import java.util.UUID; -import mage.constants.CardType; -import mage.constants.Duration; -import mage.constants.Rarity; -import mage.constants.Zone; import mage.MageInt; +import mage.abilities.Ability; import mage.abilities.common.SimpleStaticAbility; -import mage.abilities.condition.Condition; import mage.abilities.condition.common.EnchantedCondition; import mage.abilities.decorator.ConditionalContinuousEffect; import mage.abilities.effects.common.continuous.BoostSourceEffect; @@ -43,6 +39,10 @@ import mage.abilities.keyword.FirstStrikeAbility; import mage.abilities.keyword.FlyingAbility; import mage.abilities.keyword.TrampleAbility; import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.Rarity; +import mage.constants.Zone; /** * @@ -50,11 +50,6 @@ import mage.cards.CardImpl; */ public class ThranGolem extends CardImpl { - private static final String rule1 = "As long as {this} is enchanted, it gets +2/+2 "; - private static final String rule2 = "As long as {this} is enchanted, it has flying"; - private static final String rule3 = "As long as {this} is enchanted, it has first strike"; - private static final String rule4 = "As long as {this} is enchanted, it has flying trample"; - public ThranGolem(UUID ownerId) { super(ownerId, 220, "Thran Golem", Rarity.UNCOMMON, new CardType[]{CardType.ARTIFACT, CardType.CREATURE}, "{5}"); this.expansionSetCode = "M12"; @@ -63,15 +58,18 @@ public class ThranGolem extends CardImpl { this.power = new MageInt(3); this.toughness = new MageInt(3); - Condition enchanted = new EnchantedCondition(); - ConditionalContinuousEffect effect1 = new ConditionalContinuousEffect(new BoostSourceEffect(2, 2, Duration.WhileOnBattlefield), enchanted, rule1); - this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, effect1)); - ConditionalContinuousEffect effect2 = new ConditionalContinuousEffect(new GainAbilitySourceEffect(FlyingAbility.getInstance()), enchanted, rule2); - this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, effect2)); - ConditionalContinuousEffect effect3 = new ConditionalContinuousEffect(new GainAbilitySourceEffect(FirstStrikeAbility.getInstance()), enchanted, rule3); - this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, effect3)); - ConditionalContinuousEffect effect4 = new ConditionalContinuousEffect(new GainAbilitySourceEffect(TrampleAbility.getInstance()), enchanted, rule4); - this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, effect4)); + // As long as Thran Golem is enchanted, it gets +2/+2 and has flying, first strike, and trample. + EnchantedCondition enchanted = new EnchantedCondition(); + Ability ability = new SimpleStaticAbility(Zone.BATTLEFIELD, new ConditionalContinuousEffect( + new BoostSourceEffect(2, 2, Duration.WhileOnBattlefield), enchanted, + "As long as {this} is enchanted, it gets +2/+2")); + ability.addEffect(new ConditionalContinuousEffect(new GainAbilitySourceEffect(FlyingAbility.getInstance()), + enchanted, "and has flying")); + ability.addEffect(new ConditionalContinuousEffect(new GainAbilitySourceEffect(FirstStrikeAbility.getInstance()), + enchanted, ", first strike")); + ability.addEffect(new ConditionalContinuousEffect(new GainAbilitySourceEffect(TrampleAbility.getInstance()), + enchanted, ", and trample.")); + this.addAbility(ability); } public ThranGolem(final ThranGolem card) { diff --git a/Mage.Sets/src/mage/sets/magic2012/Trollhide.java b/Mage.Sets/src/mage/sets/magic2012/Trollhide.java index 47337163b65..a62c43d19e5 100644 --- a/Mage.Sets/src/mage/sets/magic2012/Trollhide.java +++ b/Mage.Sets/src/mage/sets/magic2012/Trollhide.java @@ -29,18 +29,23 @@ package mage.sets.magic2012; import java.util.UUID; - -import mage.constants.*; import mage.abilities.Ability; import mage.abilities.common.SimpleActivatedAbility; import mage.abilities.common.SimpleStaticAbility; import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.effects.Effect; import mage.abilities.effects.common.AttachEffect; import mage.abilities.effects.common.RegenerateSourceEffect; import mage.abilities.effects.common.continuous.BoostEnchantedEffect; import mage.abilities.effects.common.continuous.GainAbilityAttachedEffect; import mage.abilities.keyword.EnchantAbility; 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.Zone; import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; @@ -55,13 +60,20 @@ public class Trollhide extends CardImpl { this.expansionSetCode = "M12"; this.subtype.add("Aura"); + // Enchant creature TargetPermanent auraTarget = new TargetCreaturePermanent(); this.getSpellAbility().addTarget(auraTarget); this.getSpellAbility().addEffect(new AttachEffect(Outcome.BoostCreature)); Ability ability = new EnchantAbility(auraTarget.getTargetName()); this.addAbility(ability); - this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new BoostEnchantedEffect(2, 2, Duration.WhileOnBattlefield))); - this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new GainAbilityAttachedEffect(new SimpleActivatedAbility(Zone.BATTLEFIELD, new RegenerateSourceEffect(), new ManaCostsImpl("{1}{G}")), AttachmentType.AURA))); + + // Enchanted creature gets +2/+2 and has "{1}{G}: Regenerate this creature." + ability = new SimpleStaticAbility(Zone.BATTLEFIELD, new BoostEnchantedEffect(2, 2, Duration.WhileOnBattlefield)); + Effect effect = new GainAbilityAttachedEffect(new SimpleActivatedAbility(Zone.BATTLEFIELD, + new RegenerateSourceEffect(), new ManaCostsImpl("{1}{G}")), AttachmentType.AURA); + effect.setText("and has \"{1}{G}: Regenerate this creature.\""); + ability.addEffect(effect); + this.addAbility(ability); } public Trollhide (final Trollhide card) { diff --git a/Mage/src/mage/abilities/condition/common/MorbidCondition.java b/Mage/src/mage/abilities/condition/common/MorbidCondition.java index 04de2a9aec9..22a4bc7a74c 100644 --- a/Mage/src/mage/abilities/condition/common/MorbidCondition.java +++ b/Mage/src/mage/abilities/condition/common/MorbidCondition.java @@ -49,4 +49,9 @@ public class MorbidCondition implements Condition { return watcher.conditionMet(); } + @Override + public String toString() { + return "if a creature died this turn"; + } + } From 693bc1501de3453d7e620611438a6e56a3f2f855 Mon Sep 17 00:00:00 2001 From: LoneFox Date: Sat, 17 Oct 2015 15:21:33 +0300 Subject: [PATCH 165/268] Fix typo --- Mage/src/mage/constants/AbilityWord.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Mage/src/mage/constants/AbilityWord.java b/Mage/src/mage/constants/AbilityWord.java index c09e01877b9..f9c33524530 100644 --- a/Mage/src/mage/constants/AbilityWord.java +++ b/Mage/src/mage/constants/AbilityWord.java @@ -47,7 +47,7 @@ public enum AbilityWord { HELLBENT("Hellbent"), HEROIC("Heroic"), IMPRINT("Imprint"), - INSPIRED("Inspided"), + INSPIRED("Inspired"), JOIN_FORCES("Join forces"), KINSHIP("Kinship"), LANDFALL("Landfall"), From 3891a5d6e2fa39f8ece258e592f11e94739477d9 Mon Sep 17 00:00:00 2001 From: LoneFox Date: Sat, 17 Oct 2015 16:30:58 +0300 Subject: [PATCH 166/268] Implement cards: Cabal Torturer, Centaur Chieftain, Pardic Arsonist, and Seton's Scout --- .../src/mage/sets/torment/CabalTorturer.java | 84 +++++++++++++++++ .../mage/sets/torment/CentaurChieftain.java | 90 +++++++++++++++++++ .../src/mage/sets/torment/PardicArsonist.java | 79 ++++++++++++++++ .../src/mage/sets/torment/SetonsScout.java | 79 ++++++++++++++++ 4 files changed, 332 insertions(+) create mode 100644 Mage.Sets/src/mage/sets/torment/CabalTorturer.java create mode 100644 Mage.Sets/src/mage/sets/torment/CentaurChieftain.java create mode 100644 Mage.Sets/src/mage/sets/torment/PardicArsonist.java create mode 100644 Mage.Sets/src/mage/sets/torment/SetonsScout.java diff --git a/Mage.Sets/src/mage/sets/torment/CabalTorturer.java b/Mage.Sets/src/mage/sets/torment/CabalTorturer.java new file mode 100644 index 00000000000..9c68435e04f --- /dev/null +++ b/Mage.Sets/src/mage/sets/torment/CabalTorturer.java @@ -0,0 +1,84 @@ +/* + * 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.torment; + +import java.util.UUID; +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.condition.common.CardsInControllerGraveCondition; +import mage.abilities.costs.common.TapSourceCost; +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.decorator.ConditionalActivatedAbility; +import mage.abilities.decorator.ConditionalContinuousEffect; +import mage.abilities.effects.common.continuous.BoostTargetEffect; +import mage.cards.CardImpl; +import mage.constants.AbilityWord; +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 CabalTorturer extends CardImpl { + + public CabalTorturer(UUID ownerId) { + super(ownerId, 53, "Cabal Torturer", Rarity.COMMON, new CardType[]{CardType.CREATURE}, "{1}{B}{B}"); + this.expansionSetCode = "TOR"; + this.subtype.add("Human"); + this.subtype.add("Minion"); + this.power = new MageInt(1); + this.toughness = new MageInt(1); + + // {B}, {tap}: Target creature gets -1/-1 until end of turn. + Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new BoostTargetEffect(-1, -1, Duration.EndOfTurn), new ManaCostsImpl("{B}")); + ability.addCost(new TapSourceCost()); + ability.addTarget(new TargetCreaturePermanent()); + this.addAbility(ability); + // Threshold - {3}{B}{B}, {tap}: Target creature gets -2/-2 until end of turn. Activate this ability only if seven or more cards are in your graveyard. + ability = new ConditionalActivatedAbility(Zone.BATTLEFIELD, new BoostTargetEffect(-2, -2, Duration.EndOfTurn), + new ManaCostsImpl("{3}{B}{B}"), new CardsInControllerGraveCondition(7)); + ability.addCost(new TapSourceCost()); + ability.addTarget(new TargetCreaturePermanent()); + ability.setAbilityWord(AbilityWord.THRESHOLD); + this.addAbility(ability); + } + + public CabalTorturer(final CabalTorturer card) { + super(card); + } + + @Override + public CabalTorturer copy() { + return new CabalTorturer(this); + } +} diff --git a/Mage.Sets/src/mage/sets/torment/CentaurChieftain.java b/Mage.Sets/src/mage/sets/torment/CentaurChieftain.java new file mode 100644 index 00000000000..a548a2bb0c9 --- /dev/null +++ b/Mage.Sets/src/mage/sets/torment/CentaurChieftain.java @@ -0,0 +1,90 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.sets.torment; + +import java.util.UUID; +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.condition.common.CardsInControllerGraveCondition; +import mage.abilities.decorator.ConditionalContinuousEffect; +import mage.abilities.effects.Effect; +import mage.abilities.effects.common.continuous.BoostControlledEffect; +import mage.abilities.effects.common.continuous.GainAbilityControlledEffect; +import mage.abilities.effects.common.continuous.GainAbilitySourceEffect; +import mage.abilities.keyword.HasteAbility; +import mage.abilities.keyword.TrampleAbility; +import mage.cards.CardImpl; +import mage.constants.AbilityWord; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.Rarity; +import mage.constants.Zone; +import mage.filter.common.FilterControlledCreaturePermanent; + +/** + * + * @author LoneFox + */ +public class CentaurChieftain extends CardImpl { + + public CentaurChieftain(UUID ownerId) { + super(ownerId, 122, "Centaur Chieftain", Rarity.UNCOMMON, new CardType[]{CardType.CREATURE}, "{3}{G}"); + this.expansionSetCode = "TOR"; + this.subtype.add("Centaur"); + this.power = new MageInt(3); + this.toughness = new MageInt(3); + + // Haste + this.addAbility(HasteAbility.getInstance()); + // Threshold - As long as seven or more cards are in your graveyard, Centaur Chieftain has "When Centaur Chieftain enters the battlefield, creatures you control get +1/+1 and gain trample until end of turn." + Effect effect = new BoostControlledEffect(1, 1, Duration.EndOfTurn); + effect.setText("creatures you control get +1/+1"); + Ability gainedAbility = new EntersBattlefieldTriggeredAbility(effect); + effect = new GainAbilityControlledEffect(TrampleAbility.getInstance(), Duration.EndOfTurn, + new FilterControlledCreaturePermanent()); + effect.setText("and gain trample until end of turn"); + gainedAbility.addEffect(effect); + + Ability ability = new SimpleStaticAbility(Zone.BATTLEFIELD, new ConditionalContinuousEffect( + new GainAbilitySourceEffect(gainedAbility), new CardsInControllerGraveCondition(7), + "As long as seven or more cards are in your graveyard, {this} has \"When {this} enters the battlefield, creatures you control get +1/+1 and gain trample until end of turn.\"")); + ability.setAbilityWord(AbilityWord.THRESHOLD); + this.addAbility(ability); + } + + public CentaurChieftain(final CentaurChieftain card) { + super(card); + } + + @Override + public CentaurChieftain copy() { + return new CentaurChieftain(this); + } +} diff --git a/Mage.Sets/src/mage/sets/torment/PardicArsonist.java b/Mage.Sets/src/mage/sets/torment/PardicArsonist.java new file mode 100644 index 00000000000..0a7b965bfab --- /dev/null +++ b/Mage.Sets/src/mage/sets/torment/PardicArsonist.java @@ -0,0 +1,79 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.sets.torment; + +import java.util.UUID; +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.condition.common.CardsInControllerGraveCondition; +import mage.abilities.decorator.ConditionalContinuousEffect; +import mage.abilities.effects.common.DamageTargetEffect; +import mage.abilities.effects.common.continuous.GainAbilitySourceEffect; +import mage.cards.CardImpl; +import mage.constants.AbilityWord; +import mage.constants.CardType; +import mage.constants.Rarity; +import mage.constants.Zone; +import mage.target.common.TargetCreatureOrPlayer; + +/** + * + * @author LoneFox + */ +public class PardicArsonist extends CardImpl { + + public PardicArsonist(UUID ownerId) { + super(ownerId, 105, "Pardic Arsonist", Rarity.UNCOMMON, new CardType[]{CardType.CREATURE}, "{2}{R}{R}"); + this.expansionSetCode = "TOR"; + this.subtype.add("Human"); + this.subtype.add("Barbarian"); + this.power = new MageInt(3); + this.toughness = new MageInt(3); + + // Threshold - As long as seven or more cards are in your graveyard, Pardic Arsonist has "When Pardic Arsonist enters the battlefield, it deals 3 damage to target creature or player." + Ability gainedAbility = new EntersBattlefieldTriggeredAbility(new DamageTargetEffect(3)); + gainedAbility.addTarget(new TargetCreatureOrPlayer()); + + Ability ability = new SimpleStaticAbility(Zone.BATTLEFIELD, new ConditionalContinuousEffect( + new GainAbilitySourceEffect(gainedAbility), new CardsInControllerGraveCondition(7), + "As long as seven or more cards are in your graveyard, {this} has \"When {this} enters the battlefield, it deals 3 damage to target creature or player.\"")); + ability.setAbilityWord(AbilityWord.THRESHOLD); + this.addAbility(ability); + } + + public PardicArsonist(final PardicArsonist card) { + super(card); + } + + @Override + public PardicArsonist copy() { + return new PardicArsonist(this); + } +} diff --git a/Mage.Sets/src/mage/sets/torment/SetonsScout.java b/Mage.Sets/src/mage/sets/torment/SetonsScout.java new file mode 100644 index 00000000000..cced148dca5 --- /dev/null +++ b/Mage.Sets/src/mage/sets/torment/SetonsScout.java @@ -0,0 +1,79 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.sets.torment; + +import java.util.UUID; +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.condition.common.CardsInControllerGraveCondition; +import mage.abilities.decorator.ConditionalContinuousEffect; +import mage.abilities.effects.common.continuous.BoostSourceEffect; +import mage.abilities.keyword.ReachAbility; +import mage.cards.CardImpl; +import mage.constants.AbilityWord; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.Rarity; +import mage.constants.Zone; + +/** + * + * @author LoneFox + */ +public class SetonsScout extends CardImpl { + + public SetonsScout(UUID ownerId) { + super(ownerId, 138, "Seton's Scout", Rarity.UNCOMMON, new CardType[]{CardType.CREATURE}, "{1}{G}"); + this.expansionSetCode = "TOR"; + this.subtype.add("Centaur"); + this.subtype.add("Druid"); + this.subtype.add("Scout"); + this.subtype.add("Archer"); + this.power = new MageInt(2); + this.toughness = new MageInt(1); + + // Reach + this.addAbility(ReachAbility.getInstance()); + // Threshold - Seton's Scout gets +2/+2 as long as seven or more cards are in your graveyard. + Ability ability = new SimpleStaticAbility(Zone.BATTLEFIELD, new ConditionalContinuousEffect( + new BoostSourceEffect(2, 2, Duration.WhileOnBattlefield), new CardsInControllerGraveCondition(7), + "As long as seven or more cards are in your graveyard, {this} gets +2/+2")); + ability.setAbilityWord(AbilityWord.THRESHOLD); + this.addAbility(ability); + } + + public SetonsScout(final SetonsScout card) { + super(card); + } + + @Override + public SetonsScout copy() { + return new SetonsScout(this); + } +} From 59ef2a2889159d9b7007a57d8bcb213d64201dea Mon Sep 17 00:00:00 2001 From: LevelX2 Date: Sat, 17 Oct 2015 16:30:28 +0200 Subject: [PATCH 167/268] * Reworked ENTERS_THE_BATTLEFIELD event for replacement effects. Some rework to card movement. --- .../sets/alarareborn/ArsenalThresher.java | 3 +- .../src/mage/sets/apocalypse/Anavolver.java | 4 +- .../src/mage/sets/apocalypse/Cetavolver.java | 4 +- .../src/mage/sets/apocalypse/Degavolver.java | 4 +- .../src/mage/sets/apocalypse/Necravolver.java | 4 +- .../src/mage/sets/apocalypse/Rakavolver.java | 4 +- .../avacynrestored/TamiyoTheMoonSage.java | 12 +- .../avacynrestored/TibaltTheFiendBlooded.java | 21 ++-- .../GideonAllyOfZendikar.java | 6 +- .../KioraMasterOfTheDepths.java | 6 +- .../battleforzendikar/ObNixilisReignited.java | 6 +- .../sets/battleforzendikar/OranRiefHydra.java | 19 ++-- .../sets/battleforzendikar/PrismArray.java | 2 +- .../sets/battleforzendikar/SkyriderElf.java | 2 +- .../battleforzendikar/TajuruStalwart.java | 2 +- .../battleforzendikar/UlamogsDespoiler.java | 2 +- .../battleforzendikar/WoodlandWanderer.java | 2 +- .../sets/betrayersofkamigawa/OrbOfDreams.java | 20 ++-- .../bornofthegods/KioraTheCrashingWave.java | 23 ++-- .../mage/sets/bornofthegods/Ornitharch.java | 1 - .../OtherworldlyJourney.java | 28 +++-- .../ShimatsuTheBloodcloaked.java | 31 +++--- .../sets/commander/ChorusOfTheConclave.java | 57 +++++----- .../mage/sets/commander/TheMimeoplasm.java | 3 +- .../sets/commander2013/NayaSoulbeast.java | 3 +- .../mage/sets/commander2013/OpalPalace.java | 22 ++-- .../mage/sets/commander2014/BitterFeud.java | 3 +- .../commander2014/DarettiScrapSavant.java | 7 +- .../commander2014/FreyaliseLlanowarsFury.java | 13 +-- .../commander2014/MasterworkOfIngenuity.java | 13 +-- .../commander2014/NahiriTheLithomancer.java | 20 ++-- .../commander2014/NecromanticSelection.java | 7 +- .../ObNixilisOfTheBlackOath.java | 14 +-- .../commander2014/TeferiTemporalArchmage.java | 7 +- .../mage/sets/conflux/ApocalypseHydra.java | 7 +- .../sets/conflux/NicolBolasPlaneswalker.java | 21 ++-- .../mage/sets/conspiracy/AcademyElite.java | 2 +- .../src/mage/sets/conspiracy/DackFayden.java | 35 +++--- .../sets/conspiracy/ExtractFromDarkness.java | 12 +- .../conspiracy/MuzzioVisionaryArchitect.java | 20 ++-- .../darkascension/SorinLordOfInnistrad.java | 23 ++-- .../src/mage/sets/darksteel/AEtherVial.java | 24 ++-- .../src/mage/sets/dissension/ProteanHulk.java | 32 +++--- .../src/mage/sets/dragonsmaze/BeckCall.java | 12 +- .../sets/dragonsmaze/ProgenitorMimic.java | 13 +-- .../src/mage/sets/dragonsmaze/RalZarek.java | 24 ++-- .../dragonsoftarkir/NarsetTranscendent.java | 6 +- .../sets/dragonsoftarkir/SarkhanUnbroken.java | 8 +- .../mage/sets/eventide/CankerAbomination.java | 3 +- .../mage/sets/fatereforged/CitadelSiege.java | 2 +- .../sets/fatereforged/FrontierMastodon.java | 2 +- .../mage/sets/fatereforged/FrontierSiege.java | 2 +- .../sets/fatereforged/MonasterySiege.java | 2 +- .../mage/sets/fatereforged/OutpostSiege.java | 2 +- .../mage/sets/fatereforged/PalaceSiege.java | 2 +- .../fatereforged/UginTheSpiritDragon.java | 11 +- .../src/mage/sets/fifthdawn/Acquire.java | 10 +- .../src/mage/sets/fifthedition/Kismet.java | 11 +- .../mage/sets/fifthedition/PrimalClay.java | 6 +- .../src/mage/sets/futuresight/CloudKey.java | 3 +- .../mage/sets/futuresight/KavuPrimarch.java | 2 +- .../sets/futuresight/RavagingRiftwurm.java | 2 +- .../sets/gameday/ScaleguardSentinels.java | 2 +- .../mage/sets/gatecrash/BlindObedience.java | 20 ++-- .../src/mage/sets/gatecrash/DomriRade.java | 7 +- .../src/mage/sets/gatecrash/FathomMage.java | 7 +- .../gatecrash/GideonChampionOfJustice.java | 13 ++- .../mage/sets/gatecrash/MasterBiomancer.java | 89 ++++++++------- .../mage/sets/gatecrash/ZameckGuildmage.java | 63 +++-------- .../mage/sets/innistrad/DearlyDeparted.java | 81 +++----------- .../mage/sets/innistrad/EssenceOfTheWild.java | 85 ++------------- .../src/mage/sets/innistrad/EvilTwin.java | 13 +-- .../mage/sets/innistrad/GarrukRelentless.java | 8 +- .../mage/sets/innistrad/LilianaOfTheVeil.java | 32 +++--- .../src/mage/sets/invasion/AlloyGolem.java | 2 +- .../src/mage/sets/invasion/ArdentSoldier.java | 2 +- .../mage/sets/invasion/BenalishLancer.java | 2 +- .../src/mage/sets/invasion/Duskwalker.java | 2 +- .../mage/sets/invasion/FaerieSquadron.java | 2 +- .../src/mage/sets/invasion/KavuAggressor.java | 2 +- .../src/mage/sets/invasion/KavuTitan.java | 2 +- .../src/mage/sets/invasion/PouncingKavu.java | 2 +- .../mage/sets/invasion/PrisonBarricade.java | 2 +- .../mage/sets/invasion/UrborgSkeleton.java | 2 +- .../mage/sets/invasion/VodalianSerpent.java | 2 +- .../mage/sets/jacevsvraska/BodyDouble.java | 16 +-- .../journeyintonyx/AjaniMentorOfHeroes.java | 18 ++- .../journeyintonyx/BloodcrazedHoplite.java | 2 +- .../mage/sets/judgment/BalthorTheDefiled.java | 22 ++-- .../khansoftarkir/CleverImpersonator.java | 9 +- .../SarkhanTheDragonspeaker.java | 14 +-- .../khansoftarkir/SorinSolemnVisitor.java | 16 +-- .../sets/khansoftarkir/WarNameAspirant.java | 1 - .../mage/sets/limitedalpha/AnimateDead.java | 52 +++++---- .../mage/sets/limitedalpha/CopyArtifact.java | 89 ++------------- .../mage/sets/magic2010/AjaniGoldmane.java | 40 ++++--- .../mage/sets/magic2010/ChandraNalaar.java | 24 ++-- .../sets/magic2010/GarrukWildspeaker.java | 60 +++++----- .../src/mage/sets/magic2010/JaceBeleren.java | 23 ++-- .../src/mage/sets/magic2010/LilianaVess.java | 6 +- .../src/mage/sets/magic2011/InfernoTitan.java | 16 +-- .../src/mage/sets/magic2011/SunTitan.java | 16 +-- .../sets/magic2012/ChandraTheFirebrand.java | 23 ++-- .../sets/magic2012/GarrukPrimalHunter.java | 22 ++-- .../mage/sets/magic2012/JaceMemoryAdept.java | 16 +-- .../mage/sets/magic2012/PhantasmalImage.java | 103 ++++++------------ .../src/mage/sets/magic2012/SuturedGhoul.java | 3 +- .../sets/magic2013/AjaniCallerOfThePride.java | 8 +- .../magic2013/LilianaOfTheDarkRealms.java | 29 +++-- .../sets/magic2014/ChandraPyromaster.java | 6 +- .../sets/magic2014/GarrukCallerOfBeasts.java | 15 ++- .../sets/magic2014/ImposingSovereign.java | 10 +- .../mage/sets/magic2014/SavageSummoning.java | 2 +- .../mage/sets/magic2015/AjaniSteadfast.java | 22 ++-- .../sets/magic2015/GarrukApexPredator.java | 6 +- .../src/mage/sets/magic2015/GenesisHydra.java | 8 +- .../mage/sets/magic2015/HushwingGryff.java | 2 +- .../magic2015/JaceTheLivingGuildpact.java | 19 ++-- .../sets/magic2015/MercurialPretender.java | 63 ++--------- .../mage/sets/magic2015/NissaWorldwaker.java | 21 ++-- .../magicorigins/ChandraRoaringFlame.java | 36 +++--- .../sets/magicorigins/GideonBattleForged.java | 6 +- .../sets/magicorigins/HallowedMoonlight.java | 4 +- .../magicorigins/JaceTelepathUnbound.java | 6 +- .../LilianaDefiantNecromancer.java | 6 +- .../sets/magicorigins/NissaSageAnimist.java | 6 +- .../src/mage/sets/mirrodin/ProteusStaff.java | 22 ++-- .../TezzeretAgentOfBolas.java | 23 ++-- .../mage/sets/modernmasters/Epochrasite.java | 2 +- .../modernmasters2015/WorldheartPhoenix.java | 2 +- .../sets/morningtide/BramblewoodParagon.java | 24 ++-- .../sets/morningtide/OonasBlackguard.java | 4 +- .../sets/morningtide/RecrossThePaths.java | 16 +-- .../mage/sets/morningtide/SageOfFables.java | 13 +-- .../src/mage/sets/nemesis/ParallaxWave.java | 19 +--- .../src/mage/sets/newphyrexia/DueRespect.java | 15 ++- .../mage/sets/newphyrexia/KarnLiberated.java | 6 +- .../mage/sets/newphyrexia/OmenMachine.java | 15 ++- .../src/mage/sets/newphyrexia/TorporOrb.java | 12 +- .../sets/newphyrexia/UrabraskTheHidden.java | 20 ++-- .../mage/sets/planarchaos/FrozenAEther.java | 15 +-- .../sets/planarchaos/VoidstoneGargoyle.java | 3 +- .../sets/planechase2012/PrimalPlasma.java | 6 +- .../planechase2012/SakashimasStudent.java | 39 ++----- .../mage/sets/planeshift/ArcticMerfolk.java | 3 +- .../src/mage/sets/planeshift/DralnusPet.java | 4 +- .../mage/sets/planeshift/PhyrexianScuta.java | 3 +- .../mage/sets/ravnica/CopyEnchantment.java | 27 ++--- .../mage/sets/ravnica/LoxodonGatekeeper.java | 24 ++-- .../returntoravnica/CorpsejackMenace.java | 46 ++++---- .../JaceArchitectOfThought.java | 6 +- .../returntoravnica/TabletOfTheGuilds.java | 3 +- .../sets/returntoravnica/VraskaTheUnseen.java | 6 +- .../sets/riseoftheeldrazi/GideonJura.java | 26 ++--- .../sets/riseoftheeldrazi/SarkhanTheMad.java | 6 +- .../sets/riseoftheeldrazi/WallOfOmens.java | 18 +-- .../SakashimaTheImpostor.java | 98 +++++------------ .../sets/scarsofmirrodin/ElspethTirel.java | 28 +++-- .../sets/scarsofmirrodin/KothOfTheHammer.java | 18 +-- .../scarsofmirrodin/VenserTheSojourner.java | 6 +- .../sets/shadowmoor/FlourishingDefenses.java | 6 +- .../mage/sets/shadowmoor/GlamerSpinners.java | 5 +- .../sets/shardsofalara/AjaniVengeant.java | 69 ++++++------ .../shardsofalara/ElspethKnightErrant.java | 26 ++--- .../mage/sets/shardsofalara/SarkhanVol.java | 80 +++++++------- .../sets/shardsofalara/TezzeretTheSeeker.java | 6 +- .../sets/speedvscunning/AquamorphEntity.java | 14 +-- .../src/mage/sets/tempest/Dracoplasm.java | 32 +++--- Mage.Sets/src/mage/sets/tempest/RootMaze.java | 9 +- .../src/mage/sets/tenthedition/Clone.java | 21 ++-- .../sets/tenthedition/SculptingSteel.java | 19 +--- .../sets/theros/AshiokNightmareWeaver.java | 6 +- .../mage/sets/theros/ElspethSunsChampion.java | 10 +- .../mage/sets/theros/XenagosTheReveler.java | 21 ++-- .../mage/sets/timespiral/Hypergenesis.java | 9 +- .../src/mage/sets/timespiral/Vesuva.java | 23 ++-- .../mage/sets/urzasdestiny/AcademyRector.java | 2 +- .../sets/vintagemasters/DacksDuplicate.java | 14 +-- .../mage/sets/weatherlight/CallOfTheWild.java | 30 +++-- .../sets/worldwake/JaceTheMindSculptor.java | 23 ++-- .../sets/worldwake/JwariShapeshifter.java | 19 +--- .../src/mage/sets/zendikar/AetherFigment.java | 27 +++-- .../src/mage/sets/zendikar/ChandraAblaze.java | 6 +- .../src/mage/sets/zendikar/NissaRevane.java | 19 ++-- .../src/mage/sets/zendikar/SorinMarkov.java | 14 +-- .../abilities/enters/MasterBiomancerTest.java | 34 +++--- .../cards/abilities/keywords/SuspendTest.java | 2 + .../cards/copy/KikiJikiMirrorBreakerTest.java | 2 +- .../org/mage/test/cards/copy/VesuvaTest.java | 1 - .../cards/replacement/PillarOfFlameTest.java | 21 +++- .../test/cards/replacement/TorporOrbTest.java | 20 ++-- .../test/cards/triggers/FathomMageTest.java | 18 +-- .../java/org/mage/test/player/TestPlayer.java | 15 +++ .../base/impl/CardTestPlayerAPIImpl.java | 6 +- Mage/src/mage/abilities/AbilityImpl.java | 4 + .../common/DiesTriggeredAbility.java | 2 +- .../common/EntersBattlefieldAbility.java | 31 +++--- ...lkerEntersWithLoyalityCountersAbility.java | 30 +++++ .../common/CastFromHandCondition.java | 9 +- .../abilities/costs/AlternativeCost2Impl.java | 2 - .../abilities/effects/ContinuousEffects.java | 2 +- .../effects/EntersBattlefieldEffect.java | 24 ++-- .../common/AddManaInAnyCombinationEffect.java | 17 ++- .../effects/common/AmplifyEffect.java | 28 ++--- .../common/ChooseBasicLandTypeEffect.java | 3 +- .../effects/common/ChooseColorEffect.java | 3 +- .../common/ChooseCreatureTypeEffect.java | 3 +- .../effects/common/ChooseLandTypeEffect.java | 3 +- .../effects/common/ChooseOpponentEffect.java | 3 +- .../effects/common/ChoosePlayerEffect.java | 3 +- .../abilities/effects/common/CopyEffect.java | 28 +++-- .../effects/common/CopyPermanentEffect.java | 7 +- .../effects/common/DevourEffect.java | 43 ++++---- .../common/DiscardOntoBattlefieldEffect.java | 4 +- .../EntersBattlefieldWithXCountersEffect.java | 7 +- ...ExileAndReturnTransformedSourceEffect.java | 2 +- .../LookLibraryAndPickControllerEffect.java | 26 +---- .../effects/common/NameACardEffect.java | 3 +- .../PutPermanentOnBattlefieldEffect.java | 17 ++- ...ttlefieldUnderYourControlTargetEffect.java | 3 +- .../effects/common/TapSourceEffect.java | 3 +- .../common/TapSourceUnlessPaysEffect.java | 6 +- .../continuous/GainAbilitySourceEffect.java | 3 +- .../counter/AddCountersSourceEffect.java | 6 +- .../abilities/keyword/AmplifyAbility.java | 6 +- .../abilities/keyword/AuraSwapAbility.java | 4 +- .../abilities/keyword/BloodthirstAbility.java | 6 +- .../mage/abilities/keyword/DashAbility.java | 26 +++-- .../mage/abilities/keyword/DevourAbility.java | 52 ++++----- .../mage/abilities/keyword/EvolveAbility.java | 81 +++++++------- .../mage/abilities/keyword/GraftAbility.java | 78 ++++++------- .../abilities/keyword/HideawayAbility.java | 13 +-- .../mage/abilities/keyword/KickerAbility.java | 2 +- .../abilities/keyword/ModularAbility.java | 2 +- .../abilities/keyword/SunburstAbility.java | 3 +- .../abilities/keyword/TributeAbility.java | 5 +- .../abilities/keyword/UnleashAbility.java | 66 +++++------ Mage/src/mage/cards/CardImpl.java | 7 +- Mage/src/mage/game/Game.java | 4 + Mage/src/mage/game/GameImpl.java | 20 +++- .../mage/game/permanent/PermanentImpl.java | 3 + Mage/src/mage/game/permanent/token/Token.java | 51 +++++---- Mage/src/mage/game/stack/Spell.java | 9 +- Mage/src/mage/players/Player.java | 12 ++ Mage/src/mage/players/PlayerImpl.java | 97 ++++++++++------- .../util/functions/AddSubtypeApplier.java | 40 +++++++ .../mage/util/functions/CardTypeApplier.java | 28 ++++- 247 files changed, 1842 insertions(+), 2287 deletions(-) create mode 100644 Mage/src/mage/abilities/common/PlanswalkerEntersWithLoyalityCountersAbility.java create mode 100644 Mage/src/mage/util/functions/AddSubtypeApplier.java diff --git a/Mage.Sets/src/mage/sets/alarareborn/ArsenalThresher.java b/Mage.Sets/src/mage/sets/alarareborn/ArsenalThresher.java index f4203cb0d58..af33a411bba 100644 --- a/Mage.Sets/src/mage/sets/alarareborn/ArsenalThresher.java +++ b/Mage.Sets/src/mage/sets/alarareborn/ArsenalThresher.java @@ -31,7 +31,6 @@ import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.AsEntersBattlefieldAbility; -import mage.abilities.effects.EntersBattlefieldEffect; import mage.abilities.effects.OneShotEffect; import mage.cards.CardImpl; import mage.cards.Cards; @@ -97,7 +96,7 @@ class ArsenalThresherEffect extends OneShotEffect { if (controller == null) { return false; } - Permanent arsenalThresher = (Permanent) getValue(EntersBattlefieldEffect.ENTERING_PERMANENT); + Permanent arsenalThresher = game.getPermanentEntering(source.getSourceId()); FilterArtifactCard filter = new FilterArtifactCard(); filter.add(new AnotherCardPredicate()); if (controller.chooseUse(Outcome.Benefit, "Do you want to reveal other artifacts in your hand?", source, game)) { diff --git a/Mage.Sets/src/mage/sets/apocalypse/Anavolver.java b/Mage.Sets/src/mage/sets/apocalypse/Anavolver.java index 0452fbb018e..a746e9877c9 100644 --- a/Mage.Sets/src/mage/sets/apocalypse/Anavolver.java +++ b/Mage.Sets/src/mage/sets/apocalypse/Anavolver.java @@ -68,14 +68,14 @@ public class Anavolver extends CardImpl { // If Anavolver was kicked with its {1}{U} kicker, it enters the battlefield with two +1/+1 counters on it and with flying. EntersBattlefieldAbility ability1 = new EntersBattlefieldAbility( new AddCountersSourceEffect(CounterType.P1P1.createInstance(2),false), - new KickedCostCondition("{1}{U}"), true, "If {this} was kicked with its {1}{U} kicker, it enters the battlefield with two +1/+1 counters on it and with flying.", + new KickedCostCondition("{1}{U}"), "If {this} was kicked with its {1}{U} kicker, it enters the battlefield with two +1/+1 counters on it and with flying.", "{this} enters the battlefield with two +1/+1 counters on it and with flying"); ((EntersBattlefieldEffect)ability1.getEffects().get(0)).addEffect(new GainAbilitySourceEffect(FlyingAbility.getInstance(), Duration.WhileOnBattlefield)); this.addAbility(ability1); // If Anavolver was kicked with its {B} kicker, it enters the battlefield with a +1/+1 counter on it and with "Pay 3 life: Regenerate Anavolver." EntersBattlefieldAbility ability2 = new EntersBattlefieldAbility( - new AddCountersSourceEffect(CounterType.P1P1.createInstance(1),false), new KickedCostCondition("{B}"), true, + new AddCountersSourceEffect(CounterType.P1P1.createInstance(1),false), new KickedCostCondition("{B}"), "If {this} was kicked with its {B} kicker, it enters the battlefield with a +1/+1 counter on it and with \"Pay 3 life: Regenerate Anavolver.\"", "{this} enters the battlefield with a +1/+1 counter on it and with \"Pay 3 life: Regenerate Anavolver.\""); ((EntersBattlefieldEffect)ability2.getEffects().get(0)).addEffect(new GainAbilitySourceEffect(new SimpleActivatedAbility(Zone.BATTLEFIELD, new RegenerateSourceEffect(), new PayLifeCost(3)), Duration.WhileOnBattlefield)); diff --git a/Mage.Sets/src/mage/sets/apocalypse/Cetavolver.java b/Mage.Sets/src/mage/sets/apocalypse/Cetavolver.java index 8a040de3b0d..16029793e73 100644 --- a/Mage.Sets/src/mage/sets/apocalypse/Cetavolver.java +++ b/Mage.Sets/src/mage/sets/apocalypse/Cetavolver.java @@ -65,14 +65,14 @@ public class Cetavolver extends CardImpl { // If Cetavolver was kicked with its {1}{R} kicker, it enters the battlefield with two +1/+1 counters on it and with first strike. EntersBattlefieldAbility ability1 = new EntersBattlefieldAbility( new AddCountersSourceEffect(CounterType.P1P1.createInstance(2),false), - new KickedCostCondition("{1}{R}"), true, "If Cetavolver was kicked with its {1}{R} kicker, it enters the battlefield with two +1/+1 counters on it and with first strike.", + new KickedCostCondition("{1}{R}"), "If Cetavolver was kicked with its {1}{R} kicker, it enters the battlefield with two +1/+1 counters on it and with first strike.", "{this} enters the battlefield with two +1/+1 counters on it and with first strike"); ((EntersBattlefieldEffect)ability1.getEffects().get(0)).addEffect(new GainAbilitySourceEffect(FirstStrikeAbility.getInstance(), Duration.WhileOnBattlefield)); this.addAbility(ability1); // If Cetavolver was kicked with its {G} kicker, it enters the battlefield with a +1/+1 counter on it and with trample. EntersBattlefieldAbility ability2 = new EntersBattlefieldAbility( - new AddCountersSourceEffect(CounterType.P1P1.createInstance(1),false), new KickedCostCondition("{G}"), true, + new AddCountersSourceEffect(CounterType.P1P1.createInstance(1),false), new KickedCostCondition("{G}"), "If Cetavolver was kicked with its {G} kicker, it enters the battlefield with a +1/+1 counter on it and with trample.", "{this} enters the battlefield with a +1/+1 counter on it and with trample"); ((EntersBattlefieldEffect)ability2.getEffects().get(0)).addEffect(new GainAbilitySourceEffect(TrampleAbility.getInstance(), Duration.WhileOnBattlefield)); diff --git a/Mage.Sets/src/mage/sets/apocalypse/Degavolver.java b/Mage.Sets/src/mage/sets/apocalypse/Degavolver.java index 87577042db5..c0b557454ac 100644 --- a/Mage.Sets/src/mage/sets/apocalypse/Degavolver.java +++ b/Mage.Sets/src/mage/sets/apocalypse/Degavolver.java @@ -69,14 +69,14 @@ public class Degavolver extends CardImpl { // If Degavolver was kicked with its {1}{B} kicker, it enters the battlefield with two +1/+1 counters on it and with "Pay 3 life: Regenerate Degavolver." EntersBattlefieldAbility ability1 = new EntersBattlefieldAbility( new AddCountersSourceEffect(CounterType.P1P1.createInstance(2),false), - new KickedCostCondition("{1}{B}"), true, "If Degavolver was kicked with its {1}{B} kicker, it enters the battlefield with two +1/+1 counters on it and with \"Pay 3 life: Regenerate Degavolver.\"", + new KickedCostCondition("{1}{B}"), "If Degavolver was kicked with its {1}{B} kicker, it enters the battlefield with two +1/+1 counters on it and with \"Pay 3 life: Regenerate Degavolver.\"", "{this} enters the battlefield with two +1/+1 counters on it and with \"Pay 3 life: Regenerate Degavolver.\""); ((EntersBattlefieldEffect)ability1.getEffects().get(0)).addEffect(new GainAbilitySourceEffect(new SimpleActivatedAbility(Zone.BATTLEFIELD, new RegenerateSourceEffect(), new PayLifeCost(3)), Duration.WhileOnBattlefield)); this.addAbility(ability1); // If Degavolver was kicked with its {R} kicker, it enters the battlefield with a +1/+1 counter on it and with first strike. EntersBattlefieldAbility ability2 = new EntersBattlefieldAbility( - new AddCountersSourceEffect(CounterType.P1P1.createInstance(1),false), new KickedCostCondition("{R}"), true, + new AddCountersSourceEffect(CounterType.P1P1.createInstance(1),false), new KickedCostCondition("{R}"), "If Degavolver was kicked with its {R} kicker, it enters the battlefield with a +1/+1 counter on it and with first strike.", "{this} enters the battlefield with a +1/+1 counter on it and with first strike"); ((EntersBattlefieldEffect)ability2.getEffects().get(0)).addEffect(new GainAbilitySourceEffect(FirstStrikeAbility.getInstance(), Duration.WhileOnBattlefield)); diff --git a/Mage.Sets/src/mage/sets/apocalypse/Necravolver.java b/Mage.Sets/src/mage/sets/apocalypse/Necravolver.java index 03427cbaf88..1a37ec37553 100644 --- a/Mage.Sets/src/mage/sets/apocalypse/Necravolver.java +++ b/Mage.Sets/src/mage/sets/apocalypse/Necravolver.java @@ -64,12 +64,12 @@ public class Necravolver extends CardImpl { this.addAbility(kickerAbility); // If Necravolver was kicked with its {1}{G} kicker, it enters the battlefield with two +1/+1 counters on it and with trample. Ability ability = new EntersBattlefieldAbility(new AddCountersSourceEffect(CounterType.P1P1.createInstance(2)), - new KickedCostCondition("{1}{G}"), true, "If {this} was kicked with its {1}{G} kicker, it enters the battlefield with two +1/+1 counters on it and with trample.", ""); + new KickedCostCondition("{1}{G}"), "If {this} was kicked with its {1}{G} kicker, it enters the battlefield with two +1/+1 counters on it and with trample.", ""); ability.addEffect(new GainAbilitySourceEffect(TrampleAbility.getInstance(), Duration.WhileOnBattlefield)); this.addAbility(ability); // If Necravolver was kicked with its {W} kicker, it enters the battlefield with a +1/+1 counter on it and with "Whenever Necravolver deals damage, you gain that much life." ability = new EntersBattlefieldAbility(new AddCountersSourceEffect(CounterType.P1P1.createInstance(1)), - new KickedCostCondition("{W}"), true, "If {this} was kicked with its {W} kicker, it enters the battlefield with a +1/+1 counter on it and with \"Whenever {this} deals damage, you gain that much life.\"", ""); + new KickedCostCondition("{W}"), "If {this} was kicked with its {W} kicker, it enters the battlefield with a +1/+1 counter on it and with \"Whenever {this} deals damage, you gain that much life.\"", ""); ability.addEffect(new GainAbilitySourceEffect(new DealsDamageGainLifeSourceTriggeredAbility(), Duration.WhileOnBattlefield)); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/sets/apocalypse/Rakavolver.java b/Mage.Sets/src/mage/sets/apocalypse/Rakavolver.java index 62444bed93b..e020d9fd2ff 100644 --- a/Mage.Sets/src/mage/sets/apocalypse/Rakavolver.java +++ b/Mage.Sets/src/mage/sets/apocalypse/Rakavolver.java @@ -64,12 +64,12 @@ public class Rakavolver extends CardImpl { this.addAbility(kickerAbility); // If Rakavolver was kicked with its {1}{W} kicker, it enters the battlefield with two +1/+1 counters on it and with "Whenever Rakavolver deals damage, you gain that much life." Ability ability = new EntersBattlefieldAbility(new AddCountersSourceEffect(CounterType.P1P1.createInstance(2)), - new KickedCostCondition("{1}{W}"), true, "If {this} was kicked with its {1}{W} kicker, it enters the battlefield with two +1/+1 counters on it and with \"Whenever {this} deals damage, you gain that much life.\"", ""); + new KickedCostCondition("{1}{W}"), "If {this} was kicked with its {1}{W} kicker, it enters the battlefield with two +1/+1 counters on it and with \"Whenever {this} deals damage, you gain that much life.\"", ""); ability.addEffect(new GainAbilitySourceEffect(new DealsDamageGainLifeSourceTriggeredAbility(), Duration.WhileOnBattlefield)); this.addAbility(ability); // If Rakavolver was kicked with its {U} kicker, it enters the battlefield with a +1/+1 counter on it and with flying. ability = new EntersBattlefieldAbility(new AddCountersSourceEffect(CounterType.P1P1.createInstance(1)), - new KickedCostCondition("{U}"), true, "If {this} was kicked with its {U} kicker, it enters the battlefield with a +1/+1 counter on it and with flying.", ""); + new KickedCostCondition("{U}"), "If {this} was kicked with its {U} kicker, it enters the battlefield with a +1/+1 counter on it and with flying.", ""); ability.addEffect(new GainAbilitySourceEffect(FlyingAbility.getInstance(), Duration.WhileOnBattlefield)); this.addAbility(ability); diff --git a/Mage.Sets/src/mage/sets/avacynrestored/TamiyoTheMoonSage.java b/Mage.Sets/src/mage/sets/avacynrestored/TamiyoTheMoonSage.java index 9e716508d32..19905589e8d 100644 --- a/Mage.Sets/src/mage/sets/avacynrestored/TamiyoTheMoonSage.java +++ b/Mage.Sets/src/mage/sets/avacynrestored/TamiyoTheMoonSage.java @@ -30,19 +30,18 @@ package mage.sets.avacynrestored; import java.util.UUID; import mage.abilities.Ability; import mage.abilities.LoyaltyAbility; -import mage.abilities.common.EntersBattlefieldAbility; +import mage.abilities.common.PlanswalkerEntersWithLoyalityCountersAbility; import mage.abilities.common.PutCardIntoGraveFromAnywhereAllTriggeredAbility; import mage.abilities.common.SimpleStaticAbility; import mage.abilities.dynamicvalue.DynamicValue; import mage.abilities.effects.Effect; +import mage.abilities.effects.common.DontUntapInControllersNextUntapStepTargetEffect; import mage.abilities.effects.common.DrawCardSourceControllerEffect; import mage.abilities.effects.common.GetEmblemEffect; import mage.abilities.effects.common.ReturnToHandTargetEffect; -import mage.abilities.effects.common.DontUntapInControllersNextUntapStepTargetEffect; import mage.abilities.effects.common.TapTargetEffect; import mage.abilities.effects.common.continuous.MaximumHandSizeControllerEffect; import mage.abilities.effects.common.continuous.MaximumHandSizeControllerEffect.HandSizeModification; -import mage.abilities.effects.common.counter.AddCountersSourceEffect; import mage.cards.CardImpl; import mage.constants.CardType; import mage.constants.Duration; @@ -50,7 +49,6 @@ import mage.constants.Rarity; import mage.constants.SetTargetPointer; import mage.constants.TargetController; import mage.constants.Zone; -import mage.counters.CounterType; import mage.filter.FilterCard; import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.permanent.TappedPredicate; @@ -71,8 +69,7 @@ public class TamiyoTheMoonSage extends CardImpl { this.expansionSetCode = "AVR"; this.subtype.add("Tamiyo"); - - this.addAbility(new EntersBattlefieldAbility(new AddCountersSourceEffect(CounterType.LOYALTY.createInstance(4)), false)); + this.addAbility(new PlanswalkerEntersWithLoyalityCountersAbility(4)); // +1: Tap target permanent. It doesn't untap during its controller's next untap step. LoyaltyAbility ability = new LoyaltyAbility(new TapTargetEffect(), 1); @@ -130,7 +127,8 @@ class TappedCreaturesControlledByTargetCount implements DynamicValue { } /** - * Emblem with "You have no maximum hand size" and "Whenever a card is put into your graveyard from anywhere, you may return it to your hand." + * Emblem with "You have no maximum hand size" and "Whenever a card is put into + * your graveyard from anywhere, you may return it to your hand." */ class TamiyoTheMoonSageEmblem extends Emblem { diff --git a/Mage.Sets/src/mage/sets/avacynrestored/TibaltTheFiendBlooded.java b/Mage.Sets/src/mage/sets/avacynrestored/TibaltTheFiendBlooded.java index b899d7e651a..b17f824dd78 100644 --- a/Mage.Sets/src/mage/sets/avacynrestored/TibaltTheFiendBlooded.java +++ b/Mage.Sets/src/mage/sets/avacynrestored/TibaltTheFiendBlooded.java @@ -29,29 +29,27 @@ package mage.sets.avacynrestored; import java.util.List; import java.util.UUID; -import mage.constants.CardType; -import mage.constants.Duration; -import mage.constants.Layer; -import mage.constants.Outcome; -import mage.constants.Rarity; -import mage.constants.SubLayer; import mage.abilities.Ability; import mage.abilities.LoyaltyAbility; -import mage.abilities.common.EntersBattlefieldAbility; +import mage.abilities.common.PlanswalkerEntersWithLoyalityCountersAbility; import mage.abilities.dynamicvalue.DynamicValue; import mage.abilities.effects.ContinuousEffect; import mage.abilities.effects.ContinuousEffectImpl; import mage.abilities.effects.Effect; import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.DamageTargetEffect; -import mage.abilities.effects.common.discard.DiscardControllerEffect; import mage.abilities.effects.common.DrawCardSourceControllerEffect; import mage.abilities.effects.common.continuous.GainAbilityTargetEffect; -import mage.abilities.effects.common.counter.AddCountersSourceEffect; +import mage.abilities.effects.common.discard.DiscardControllerEffect; import mage.abilities.keyword.HasteAbility; import mage.cards.Card; import mage.cards.CardImpl; -import mage.counters.CounterType; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.Layer; +import mage.constants.Outcome; +import mage.constants.Rarity; +import mage.constants.SubLayer; import mage.filter.common.FilterCreaturePermanent; import mage.game.Game; import mage.game.permanent.Permanent; @@ -70,8 +68,7 @@ public class TibaltTheFiendBlooded extends CardImpl { this.expansionSetCode = "AVR"; this.subtype.add("Tibalt"); - - this.addAbility(new EntersBattlefieldAbility(new AddCountersSourceEffect(CounterType.LOYALTY.createInstance(2)), false)); + this.addAbility(new PlanswalkerEntersWithLoyalityCountersAbility(2)); // +1: Draw a card, then discard a card at random. LoyaltyAbility ability = new LoyaltyAbility(new DrawCardSourceControllerEffect(1), 1); diff --git a/Mage.Sets/src/mage/sets/battleforzendikar/GideonAllyOfZendikar.java b/Mage.Sets/src/mage/sets/battleforzendikar/GideonAllyOfZendikar.java index 9da9eacd178..07c4d334a5e 100644 --- a/Mage.Sets/src/mage/sets/battleforzendikar/GideonAllyOfZendikar.java +++ b/Mage.Sets/src/mage/sets/battleforzendikar/GideonAllyOfZendikar.java @@ -31,7 +31,7 @@ import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.LoyaltyAbility; -import mage.abilities.common.EntersBattlefieldAbility; +import mage.abilities.common.PlanswalkerEntersWithLoyalityCountersAbility; import mage.abilities.common.SimpleStaticAbility; import mage.abilities.effects.Effect; import mage.abilities.effects.common.CreateTokenEffect; @@ -39,14 +39,12 @@ import mage.abilities.effects.common.GetEmblemEffect; import mage.abilities.effects.common.PreventAllDamageToSourceEffect; import mage.abilities.effects.common.continuous.BecomesCreatureSourceEffect; import mage.abilities.effects.common.continuous.BoostControlledEffect; -import mage.abilities.effects.common.counter.AddCountersSourceEffect; import mage.abilities.keyword.IndestructibleAbility; import mage.cards.CardImpl; import mage.constants.CardType; import mage.constants.Duration; import mage.constants.Rarity; import mage.constants.Zone; -import mage.counters.CounterType; import mage.game.command.Emblem; import mage.game.permanent.token.Token; @@ -61,7 +59,7 @@ public class GideonAllyOfZendikar extends CardImpl { this.expansionSetCode = "BFZ"; this.subtype.add("Gideon"); - this.addAbility(new EntersBattlefieldAbility(new AddCountersSourceEffect(CounterType.LOYALTY.createInstance(4)), false)); + this.addAbility(new PlanswalkerEntersWithLoyalityCountersAbility(4)); // +1: Until end of turn, Gideon, Ally of Zendikar becomes a 5/5 Human Soldier Ally creature with indestructible that's still a planeswalker. Prevent all damage that would be dealt to him this turn. LoyaltyAbility ability = new LoyaltyAbility(new BecomesCreatureSourceEffect(new GideonAllyOfZendikarToken(), "planeswalker", Duration.EndOfTurn), 1); diff --git a/Mage.Sets/src/mage/sets/battleforzendikar/KioraMasterOfTheDepths.java b/Mage.Sets/src/mage/sets/battleforzendikar/KioraMasterOfTheDepths.java index 557c17be929..ead4e657e67 100644 --- a/Mage.Sets/src/mage/sets/battleforzendikar/KioraMasterOfTheDepths.java +++ b/Mage.Sets/src/mage/sets/battleforzendikar/KioraMasterOfTheDepths.java @@ -32,13 +32,12 @@ import mage.MageInt; import mage.MageObject; import mage.abilities.Ability; import mage.abilities.LoyaltyAbility; -import mage.abilities.common.EntersBattlefieldAbility; import mage.abilities.common.EntersBattlefieldControlledTriggeredAbility; +import mage.abilities.common.PlanswalkerEntersWithLoyalityCountersAbility; import mage.abilities.effects.Effect; import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.CreateTokenEffect; import mage.abilities.effects.common.GetEmblemEffect; -import mage.abilities.effects.common.counter.AddCountersSourceEffect; import mage.cards.Card; import mage.cards.CardImpl; import mage.cards.Cards; @@ -48,7 +47,6 @@ import mage.constants.Outcome; import mage.constants.Rarity; import mage.constants.SetTargetPointer; import mage.constants.Zone; -import mage.counters.CounterType; import mage.filter.common.FilterCreatureCard; import mage.filter.common.FilterCreaturePermanent; import mage.filter.common.FilterLandCard; @@ -73,7 +71,7 @@ public class KioraMasterOfTheDepths extends CardImpl { this.expansionSetCode = "BFZ"; this.subtype.add("Kiora"); - this.addAbility(new EntersBattlefieldAbility(new AddCountersSourceEffect(CounterType.LOYALTY.createInstance(4)), false)); + this.addAbility(new PlanswalkerEntersWithLoyalityCountersAbility(4)); // +1: Untap up to one target creature and up to one target land. LoyaltyAbility ability1 = new LoyaltyAbility(new KioraUntapEffect(), 1); diff --git a/Mage.Sets/src/mage/sets/battleforzendikar/ObNixilisReignited.java b/Mage.Sets/src/mage/sets/battleforzendikar/ObNixilisReignited.java index 419aaba047a..242438d7fdd 100644 --- a/Mage.Sets/src/mage/sets/battleforzendikar/ObNixilisReignited.java +++ b/Mage.Sets/src/mage/sets/battleforzendikar/ObNixilisReignited.java @@ -30,18 +30,16 @@ package mage.sets.battleforzendikar; import java.util.UUID; import mage.abilities.LoyaltyAbility; import mage.abilities.TriggeredAbilityImpl; -import mage.abilities.common.EntersBattlefieldAbility; +import mage.abilities.common.PlanswalkerEntersWithLoyalityCountersAbility; import mage.abilities.effects.Effect; import mage.abilities.effects.common.DestroyTargetEffect; import mage.abilities.effects.common.DrawCardSourceControllerEffect; import mage.abilities.effects.common.GetEmblemTargetPlayerEffect; import mage.abilities.effects.common.LoseLifeSourceControllerEffect; -import mage.abilities.effects.common.counter.AddCountersSourceEffect; import mage.cards.CardImpl; import mage.constants.CardType; import mage.constants.Rarity; import mage.constants.Zone; -import mage.counters.CounterType; import mage.game.Game; import mage.game.command.Emblem; import mage.game.events.GameEvent; @@ -60,7 +58,7 @@ public class ObNixilisReignited extends CardImpl { this.expansionSetCode = "BFZ"; this.subtype.add("Nixilis"); - this.addAbility(new EntersBattlefieldAbility(new AddCountersSourceEffect(CounterType.LOYALTY.createInstance(5)), false)); + this.addAbility(new PlanswalkerEntersWithLoyalityCountersAbility(5)); // +1: You draw a card and you lose 1 life. Effect effect = new DrawCardSourceControllerEffect(1); diff --git a/Mage.Sets/src/mage/sets/battleforzendikar/OranRiefHydra.java b/Mage.Sets/src/mage/sets/battleforzendikar/OranRiefHydra.java index b3f7679d293..a997e01fd4b 100644 --- a/Mage.Sets/src/mage/sets/battleforzendikar/OranRiefHydra.java +++ b/Mage.Sets/src/mage/sets/battleforzendikar/OranRiefHydra.java @@ -60,8 +60,8 @@ public class OranRiefHydra extends CardImpl { // Trample this.addAbility(TrampleAbility.getInstance()); - - // Landfall - Whenever a land enters the battlefield under your control, put a +1/+1 counter on Oran-Rief Hydra. + + // Landfall - Whenever a land enters the battlefield under your control, put a +1/+1 counter on Oran-Rief Hydra. // If that land is a Forest, put two +1/+1 counters on Oran-Rief Hydra instead. this.addAbility(new OranRiefHydraTriggeredAbility()); } @@ -77,9 +77,9 @@ public class OranRiefHydra extends CardImpl { } class OranRiefHydraTriggeredAbility extends TriggeredAbilityImpl { - - private static final String text = "Landfall - Whenever a land enters the battlefield under your control, put a +1/+1 counter on Oran-Rief Hydra. " - + "If that land is a Forest, put two +1/+1 counters on Oran-Rief Hydra instead."; + + private static final String text = "Landfall - Whenever a land enters the battlefield under your control, put a +1/+1 counter on {this}. " + + "If that land is a Forest, put two +1/+1 counters on {this} instead."; public OranRiefHydraTriggeredAbility() { super(Zone.BATTLEFIELD, new OranRiefHydraEffect()); @@ -106,12 +106,13 @@ class OranRiefHydraTriggeredAbility extends TriggeredAbilityImpl { && permanent.getCardType().contains(CardType.LAND) && permanent.getControllerId().equals(getControllerId())) { Permanent sourcePermanent = game.getPermanent(getSourceId()); - if (sourcePermanent != null) + if (sourcePermanent != null) { for (Effect effect : getEffects()) { - if (effect instanceof OranRiefHydraEffect) { - effect.setTargetPointer(new FixedTarget(permanent, game)); + if (effect instanceof OranRiefHydraEffect) { + effect.setTargetPointer(new FixedTarget(permanent, game)); + } + return true; } - return true; } } return false; diff --git a/Mage.Sets/src/mage/sets/battleforzendikar/PrismArray.java b/Mage.Sets/src/mage/sets/battleforzendikar/PrismArray.java index f1594a72cf4..c86c1acfc31 100644 --- a/Mage.Sets/src/mage/sets/battleforzendikar/PrismArray.java +++ b/Mage.Sets/src/mage/sets/battleforzendikar/PrismArray.java @@ -57,7 +57,7 @@ public class PrismArray extends CardImpl { // Converge - Prism Array enters the battlefield with a crystal counter on it for each color of mana spent to cast it. this.addAbility(new EntersBattlefieldAbility( new AddCountersSourceEffect(CounterType.CRYSTAL.createInstance(), ColorsOfManaSpentToCastCount.getInstance(), true), - null, true, "Converge — {this} enters the battlefield with a +1/+1 counter on it for each color of mana spent to cast it.", null)); + null, "Converge — {this} enters the battlefield with a +1/+1 counter on it for each color of mana spent to cast it.", null)); // Remove a crystal counter from Prism Array: Tap target creature. Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, diff --git a/Mage.Sets/src/mage/sets/battleforzendikar/SkyriderElf.java b/Mage.Sets/src/mage/sets/battleforzendikar/SkyriderElf.java index e08242cc827..d02eccfbc59 100644 --- a/Mage.Sets/src/mage/sets/battleforzendikar/SkyriderElf.java +++ b/Mage.Sets/src/mage/sets/battleforzendikar/SkyriderElf.java @@ -59,7 +59,7 @@ public class SkyriderElf extends CardImpl { // Converge-Skyrider Elf enters the battlefield with a +1/+1 counter on it for each color of mana spent to cast it. this.addAbility(new EntersBattlefieldAbility( new AddCountersSourceEffect(CounterType.P1P1.createInstance(), ColorsOfManaSpentToCastCount.getInstance(), true), - null, true, "Converge — {this} enters the battlefield with a +1/+1 counter on it for each color of mana spent to cast it.", null)); + null, "Converge — {this} enters the battlefield with a +1/+1 counter on it for each color of mana spent to cast it.", null)); } diff --git a/Mage.Sets/src/mage/sets/battleforzendikar/TajuruStalwart.java b/Mage.Sets/src/mage/sets/battleforzendikar/TajuruStalwart.java index 15981c7815d..73947b4132e 100644 --- a/Mage.Sets/src/mage/sets/battleforzendikar/TajuruStalwart.java +++ b/Mage.Sets/src/mage/sets/battleforzendikar/TajuruStalwart.java @@ -55,7 +55,7 @@ public class TajuruStalwart extends CardImpl { // Converge - Tajuru Stalwart enters the battlefield with a +1/+1 counter on it for each color of mana spent to cast it. this.addAbility(new EntersBattlefieldAbility( new AddCountersSourceEffect(CounterType.P1P1.createInstance(), ColorsOfManaSpentToCastCount.getInstance(), true), - null, true, "Converge - {this} enters the battlefield with a +1/+1 counter on it for each color of mana spent to cast it.", null)); + null, "Converge - {this} enters the battlefield with a +1/+1 counter on it for each color of mana spent to cast it.", null)); } diff --git a/Mage.Sets/src/mage/sets/battleforzendikar/UlamogsDespoiler.java b/Mage.Sets/src/mage/sets/battleforzendikar/UlamogsDespoiler.java index c879bbeb29e..bcf90209c59 100644 --- a/Mage.Sets/src/mage/sets/battleforzendikar/UlamogsDespoiler.java +++ b/Mage.Sets/src/mage/sets/battleforzendikar/UlamogsDespoiler.java @@ -64,7 +64,7 @@ public class UlamogsDespoiler extends CardImpl { this.toughness = new MageInt(5); // As Ulamog's Despoiler enters the battlefield, you may put two cards your opponents own from exile into their owners' graveyards. If you do, Ulamog's Despoiler enters the battlefield with four +1/+1 counters on it. - this.addAbility(new EntersBattlefieldAbility(new UlamogsDespoilerEffect(), null, true, + this.addAbility(new EntersBattlefieldAbility(new UlamogsDespoilerEffect(), null, "As {this} enters the battlefield, you may put two cards your opponents own from exile into their owners' graveyards. If you do, {this} enters the battlefield with four +1/+1 counters on it", null)); } diff --git a/Mage.Sets/src/mage/sets/battleforzendikar/WoodlandWanderer.java b/Mage.Sets/src/mage/sets/battleforzendikar/WoodlandWanderer.java index 5fa4a7be4c8..0ddd17b5cbf 100644 --- a/Mage.Sets/src/mage/sets/battleforzendikar/WoodlandWanderer.java +++ b/Mage.Sets/src/mage/sets/battleforzendikar/WoodlandWanderer.java @@ -59,7 +59,7 @@ public class WoodlandWanderer extends CardImpl { // Converge - Woodland Wanderer enters the battlefield with a +1/+1 counter on it for each color of mana spent to cast it. this.addAbility(new EntersBattlefieldAbility( new AddCountersSourceEffect(CounterType.P1P1.createInstance(), ColorsOfManaSpentToCastCount.getInstance(), true), - null, true, "Converge — {this} enters the battlefield with a +1/+1 counter on it for each color of mana spent to cast it.", null)); + null, "Converge — {this} enters the battlefield with a +1/+1 counter on it for each color of mana spent to cast it.", null)); } public WoodlandWanderer(final WoodlandWanderer card) { diff --git a/Mage.Sets/src/mage/sets/betrayersofkamigawa/OrbOfDreams.java b/Mage.Sets/src/mage/sets/betrayersofkamigawa/OrbOfDreams.java index b896f12a2c3..00f69ecb32e 100644 --- a/Mage.Sets/src/mage/sets/betrayersofkamigawa/OrbOfDreams.java +++ b/Mage.Sets/src/mage/sets/betrayersofkamigawa/OrbOfDreams.java @@ -28,12 +28,15 @@ package mage.sets.betrayersofkamigawa; import java.util.UUID; - -import mage.constants.*; import mage.abilities.Ability; import mage.abilities.common.SimpleStaticAbility; import mage.abilities.effects.ReplacementEffectImpl; import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.Outcome; +import mage.constants.Rarity; +import mage.constants.Zone; import mage.game.Game; import mage.game.events.GameEvent; import mage.game.permanent.Permanent; @@ -47,7 +50,7 @@ public class OrbOfDreams extends CardImpl { public OrbOfDreams(UUID ownerId) { super(ownerId, 156, "Orb of Dreams", Rarity.RARE, new CardType[]{CardType.ARTIFACT}, "{3}"); this.expansionSetCode = "BOK"; - + // Permanents enter the battlefield tapped. this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new OrbOfDreamsEffect())); } @@ -60,7 +63,7 @@ public class OrbOfDreams extends CardImpl { public OrbOfDreams copy() { return new OrbOfDreams(this); } - + private class OrbOfDreamsEffect extends ReplacementEffectImpl { OrbOfDreamsEffect() { @@ -79,23 +82,22 @@ public class OrbOfDreams extends CardImpl { @Override public boolean replaceEvent(GameEvent event, Ability source, Game game) { - Permanent permanent = game.getPermanent(event.getTargetId()); + Permanent permanent = game.getPermanentEntering(event.getTargetId()); if (permanent != null) { permanent.setTapped(true); } return false; } - + @Override public boolean checksEventType(GameEvent event, Game game) { return event.getType() == GameEvent.EventType.ENTERS_THE_BATTLEFIELD; } - + @Override public boolean applies(GameEvent event, Ability source, Game game) { return true; } - } + } } - diff --git a/Mage.Sets/src/mage/sets/bornofthegods/KioraTheCrashingWave.java b/Mage.Sets/src/mage/sets/bornofthegods/KioraTheCrashingWave.java index e7d04f82ebb..ccfb16f61e7 100644 --- a/Mage.Sets/src/mage/sets/bornofthegods/KioraTheCrashingWave.java +++ b/Mage.Sets/src/mage/sets/bornofthegods/KioraTheCrashingWave.java @@ -32,20 +32,18 @@ import mage.MageInt; import mage.abilities.Ability; import mage.abilities.LoyaltyAbility; import mage.abilities.common.BeginningOfEndStepTriggeredAbility; -import mage.abilities.common.EntersBattlefieldAbility; +import mage.abilities.common.PlanswalkerEntersWithLoyalityCountersAbility; import mage.abilities.effects.PreventionEffectImpl; import mage.abilities.effects.common.CreateTokenEffect; import mage.abilities.effects.common.DrawCardSourceControllerEffect; import mage.abilities.effects.common.GetEmblemEffect; import mage.abilities.effects.common.continuous.PlayAdditionalLandsControllerEffect; -import mage.abilities.effects.common.counter.AddCountersSourceEffect; import mage.cards.CardImpl; import mage.constants.CardType; import mage.constants.Duration; import mage.constants.Rarity; import mage.constants.TargetController; import mage.constants.Zone; -import mage.counters.CounterType; import mage.filter.FilterPermanent; import mage.filter.predicate.permanent.ControllerPredicate; import mage.game.Game; @@ -64,6 +62,7 @@ import mage.util.CardUtil; public class KioraTheCrashingWave extends CardImpl { private static final FilterPermanent filter = new FilterPermanent("permanent an opponent control"); + static { filter.add(new ControllerPredicate(TargetController.OPPONENT)); } @@ -73,8 +72,7 @@ public class KioraTheCrashingWave extends CardImpl { this.expansionSetCode = "BNG"; this.subtype.add("Kiora"); - - this.addAbility(new EntersBattlefieldAbility(new AddCountersSourceEffect(CounterType.LOYALTY.createInstance(2)), false)); + this.addAbility(new PlanswalkerEntersWithLoyalityCountersAbility(2)); // +1: Until your next turn, prevent all damage that would be dealt to and dealt by target permanent an opponent controls. LoyaltyAbility ability = new LoyaltyAbility(new KioraPreventionEffect(), 1); @@ -89,7 +87,6 @@ public class KioraTheCrashingWave extends CardImpl { // -5: You get an emblem with "At the beginning of your end step, put a 9/9 blue Kraken creature token onto the battlefield." this.addAbility(new LoyaltyAbility(new GetEmblemEffect(new KioraEmblem()), -5)); - } public KioraTheCrashingWave(final KioraTheCrashingWave card) { @@ -126,10 +123,10 @@ class KioraPreventionEffect extends PreventionEffectImpl { @Override public void init(Ability source, Game game) { super.init(source, game); - for(UUID targetId :this.getTargetPointer().getTargets(game, source)) { + for (UUID targetId : this.getTargetPointer().getTargets(game, source)) { Permanent permanent = game.getPermanent(targetId); if (permanent != null) { - permanent.addInfo(new StringBuilder("kioraPrevention").append(getId()).toString(),CardUtil.addToolTipMarkTags("All damage that would be dealt to and dealt by this permanent is prevented."), game); + permanent.addInfo(new StringBuilder("kioraPrevention").append(getId()).toString(), CardUtil.addToolTipMarkTags("All damage that would be dealt to and dealt by this permanent is prevented."), game); } } } @@ -138,7 +135,7 @@ class KioraPreventionEffect extends PreventionEffectImpl { public boolean applies(GameEvent event, Ability source, Game game) { if (super.applies(event, source, game) && event instanceof DamageEvent) { Permanent targetPermanent = game.getPermanent(this.getTargetPointer().getFirst(game, source)); - if (targetPermanent != null + if (targetPermanent != null && (event.getSourceId().equals(targetPermanent.getId()) || event.getTargetId().equals(targetPermanent.getId()))) { return true; } @@ -149,10 +146,10 @@ class KioraPreventionEffect extends PreventionEffectImpl { @Override public boolean isInactive(Ability source, Game game) { if (super.isInactive(source, game)) { - for(UUID targetId :this.getTargetPointer().getTargets(game, source)) { + for (UUID targetId : this.getTargetPointer().getTargets(game, source)) { Permanent permanent = game.getPermanent(targetId); if (permanent != null) { - permanent.addInfo(new StringBuilder("kioraPrevention").append(getId()).toString(),"", game); + permanent.addInfo(new StringBuilder("kioraPrevention").append(getId()).toString(), "", game); } } return true; @@ -162,9 +159,11 @@ class KioraPreventionEffect extends PreventionEffectImpl { } /** - * Emblem: "At the beginning of your end step, put a 9/9 blue Kraken creature token onto the battlefield." + * Emblem: "At the beginning of your end step, put a 9/9 blue Kraken creature + * token onto the battlefield." */ class KioraEmblem extends Emblem { + public KioraEmblem() { this.setName("EMBLEM: Kiora, the Crashing Wave"); Ability ability = new BeginningOfEndStepTriggeredAbility(Zone.COMMAND, new CreateTokenEffect(new KioraKrakenToken()), TargetController.YOU, null, false); diff --git a/Mage.Sets/src/mage/sets/bornofthegods/Ornitharch.java b/Mage.Sets/src/mage/sets/bornofthegods/Ornitharch.java index 971027d4b3f..930ff9345d3 100644 --- a/Mage.Sets/src/mage/sets/bornofthegods/Ornitharch.java +++ b/Mage.Sets/src/mage/sets/bornofthegods/Ornitharch.java @@ -29,7 +29,6 @@ package mage.sets.bornofthegods; import java.util.UUID; import mage.MageInt; -import mage.ObjectColor; import mage.abilities.TriggeredAbility; import mage.abilities.common.EntersBattlefieldTriggeredAbility; import mage.abilities.condition.common.TributeNotPaidCondition; diff --git a/Mage.Sets/src/mage/sets/championsofkamigawa/OtherworldlyJourney.java b/Mage.Sets/src/mage/sets/championsofkamigawa/OtherworldlyJourney.java index 00a11497edb..1444229d62b 100644 --- a/Mage.Sets/src/mage/sets/championsofkamigawa/OtherworldlyJourney.java +++ b/Mage.Sets/src/mage/sets/championsofkamigawa/OtherworldlyJourney.java @@ -25,14 +25,10 @@ * 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.MageObjectReference; - -import mage.constants.CardType; -import mage.constants.Rarity; import mage.abilities.Ability; import mage.abilities.DelayedTriggeredAbility; import mage.abilities.common.delayed.AtTheBeginOfNextEndStepDelayedTriggeredAbility; @@ -40,8 +36,10 @@ import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.ReplacementEffectImpl; import mage.cards.Card; import mage.cards.CardImpl; +import mage.constants.CardType; import mage.constants.Duration; import mage.constants.Outcome; +import mage.constants.Rarity; import mage.constants.Zone; import mage.counters.CounterType; import mage.game.ExileZone; @@ -61,7 +59,7 @@ public class OtherworldlyJourney extends CardImpl { super(ownerId, 37, "Otherworldly Journey", Rarity.UNCOMMON, new CardType[]{CardType.INSTANT}, "{1}{W}"); this.expansionSetCode = "CHK"; this.subtype.add("Arcane"); - + // Exile target creature. At the beginning of the next end step, return that card to the battlefield under its owner's control with a +1/+1 counter on it. this.getSpellAbility().addEffect(new OtherworldlyJourneyEffect()); this.getSpellAbility().addTarget(new TargetCreaturePermanent()); @@ -82,7 +80,7 @@ class OtherworldlyJourneyEffect extends OneShotEffect { private static final String effectText = "Exile target creature. At the beginning of the next end step, return that card to the battlefield under its owner's control with a +1/+1 counter on it"; - OtherworldlyJourneyEffect ( ) { + OtherworldlyJourneyEffect() { super(Outcome.Benefit); staticText = effectText; } @@ -102,12 +100,12 @@ class OtherworldlyJourneyEffect extends OneShotEffect { Card card = game.getCard(permanent.getId()); if (card != null) { //create delayed triggered ability - DelayedTriggeredAbility delayedAbility = - new AtTheBeginOfNextEndStepDelayedTriggeredAbility(new OtherworldlyJourneyReturnFromExileEffect(new MageObjectReference(card, game))); + DelayedTriggeredAbility delayedAbility + = new AtTheBeginOfNextEndStepDelayedTriggeredAbility(new OtherworldlyJourneyReturnFromExileEffect(new MageObjectReference(card, game))); delayedAbility.setSourceId(source.getSourceId()); delayedAbility.setControllerId(source.getControllerId()); delayedAbility.setSourceObject(source.getSourceObject(game), game); - game.addDelayedTriggeredAbility(delayedAbility); + game.addDelayedTriggeredAbility(delayedAbility); } } return true; @@ -126,6 +124,7 @@ class OtherworldlyJourneyEffect extends OneShotEffect { class OtherworldlyJourneyReturnFromExileEffect extends OneShotEffect { MageObjectReference objectToReturn; + public OtherworldlyJourneyReturnFromExileEffect(MageObjectReference objectToReturn) { super(Outcome.PutCardInPlay); this.objectToReturn = objectToReturn; @@ -148,19 +147,18 @@ class OtherworldlyJourneyReturnFromExileEffect extends OneShotEffect { if (card != null && objectToReturn.refersTo(card, game)) { Player owner = game.getPlayer(card.getOwnerId()); if (owner != null) { - game.addEffect(new OtherworldlyJourneyEntersBattlefieldEffect(objectToReturn), source); - owner.putOntoBattlefieldWithInfo(card, game, Zone.EXILED, source.getSourceId()); + game.addEffect(new OtherworldlyJourneyEntersBattlefieldEffect(objectToReturn), source); + owner.moveCards(card, Zone.BATTLEFIELD, source, game, false, false, true, null); } } return true; } } - class OtherworldlyJourneyEntersBattlefieldEffect extends ReplacementEffectImpl { - + MageObjectReference objectToReturn; - + public OtherworldlyJourneyEntersBattlefieldEffect(MageObjectReference objectToReturn) { super(Duration.Custom, Outcome.BoostCreature); this.objectToReturn = objectToReturn; @@ -187,7 +185,7 @@ class OtherworldlyJourneyEntersBattlefieldEffect extends ReplacementEffectImpl { @Override public boolean replaceEvent(GameEvent event, Ability source, Game game) { - Permanent permanent = game.getPermanent(event.getTargetId()); + Permanent permanent = game.getPermanentEntering(event.getTargetId()); if (permanent != null) { permanent.addCounters(CounterType.P1P1.createInstance(), game); discard(); // use only once diff --git a/Mage.Sets/src/mage/sets/championsofkamigawa/ShimatsuTheBloodcloaked.java b/Mage.Sets/src/mage/sets/championsofkamigawa/ShimatsuTheBloodcloaked.java index 49f139f2639..f25c4609992 100644 --- a/Mage.Sets/src/mage/sets/championsofkamigawa/ShimatsuTheBloodcloaked.java +++ b/Mage.Sets/src/mage/sets/championsofkamigawa/ShimatsuTheBloodcloaked.java @@ -28,13 +28,16 @@ package mage.sets.championsofkamigawa; import java.util.UUID; - -import mage.constants.*; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.SimpleStaticAbility; import mage.abilities.effects.ReplacementEffectImpl; import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.Outcome; +import mage.constants.Rarity; +import mage.constants.Zone; import mage.counters.CounterType; import mage.filter.common.FilterControlledPermanent; import mage.game.Game; @@ -61,7 +64,7 @@ public class ShimatsuTheBloodcloaked extends CardImpl { this.toughness = new MageInt(0); // As Shimatsu the Bloodcloaked enters the battlefield, sacrifice any number of permanents. Shimatsu enters the battlefield with that many +1/+1 counters on it. - this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new ShimatsuTheBloodcloakedEffect())); + this.addAbility(new SimpleStaticAbility(Zone.ALL, new ShimatsuTheBloodcloakedEffect())); } public ShimatsuTheBloodcloaked(final ShimatsuTheBloodcloaked card) { @@ -75,16 +78,16 @@ public class ShimatsuTheBloodcloaked extends CardImpl { } class ShimatsuTheBloodcloakedEffect extends ReplacementEffectImpl { - + public ShimatsuTheBloodcloakedEffect() { - super(Duration.WhileOnBattlefield, Outcome.BoostCreature); + super(Duration.EndOfGame, Outcome.BoostCreature); this.staticText = "As {this} enters the battlefield, sacrifice any number of permanents. {this} enters the battlefield with that many +1/+1 counters on it"; } - + public ShimatsuTheBloodcloakedEffect(final ShimatsuTheBloodcloakedEffect effect) { super(effect); } - + @Override public ShimatsuTheBloodcloakedEffect copy() { return new ShimatsuTheBloodcloakedEffect(this); @@ -94,15 +97,15 @@ class ShimatsuTheBloodcloakedEffect extends ReplacementEffectImpl { public boolean checksEventType(GameEvent event, Game game) { return event.getType() == GameEvent.EventType.ENTERS_THE_BATTLEFIELD; } - + @Override public boolean applies(GameEvent event, Ability source, Game game) { - return event.getTargetId().equals(source.getSourceId()); + return event.getTargetId().equals(source.getSourceId()); } - + @Override public boolean replaceEvent(GameEvent event, Ability source, Game game) { - Permanent creature = game.getPermanent(event.getTargetId()); + Permanent creature = game.getPermanentEntering(event.getTargetId()); Player controller = game.getPlayer(source.getControllerId()); if (creature != null && controller != null) { Target target = new TargetControlledPermanent(0, Integer.MAX_VALUE, new FilterControlledPermanent(), true); @@ -112,8 +115,8 @@ class ShimatsuTheBloodcloakedEffect extends ReplacementEffectImpl { controller.chooseTarget(Outcome.Detriment, target, source, game); if (target.getTargets().size() > 0) { int sacrificedCreatures = target.getTargets().size(); - game.informPlayers(new StringBuilder(controller.getLogName()).append(" sacrifices ").append(sacrificedCreatures).append(" creatures for ").append(creature.getName()).toString()); - for (UUID targetId: target.getTargets()) { + game.informPlayers(controller.getLogName() + " sacrifices " + sacrificedCreatures + " creatures for " + creature.getLogName()); + for (UUID targetId : target.getTargets()) { Permanent targetCreature = game.getPermanent(targetId); if (targetCreature == null || !targetCreature.sacrifice(source.getSourceId(), game)) { return false; @@ -124,5 +127,5 @@ class ShimatsuTheBloodcloakedEffect extends ReplacementEffectImpl { } return false; } - + } diff --git a/Mage.Sets/src/mage/sets/commander/ChorusOfTheConclave.java b/Mage.Sets/src/mage/sets/commander/ChorusOfTheConclave.java index 70fc31b6951..466966ec6dd 100644 --- a/Mage.Sets/src/mage/sets/commander/ChorusOfTheConclave.java +++ b/Mage.Sets/src/mage/sets/commander/ChorusOfTheConclave.java @@ -101,33 +101,6 @@ class ChorusOfTheConclaveReplacementEffect extends ReplacementEffectImpl { return new ChorusOfTheConclaveReplacementEffect(this); } - @Override - public boolean apply(Game game, Ability source) { - return true; - } - - @Override - public boolean replaceEvent(GameEvent event, Ability source, Game game) { - int xCost = 0; - Player you = game.getPlayer(source.getControllerId()); - if (you != null) { - if (you.chooseUse(Outcome.Benefit, "Do you wish to pay the additonal cost to add +1/+1 counters to the creature you cast?", source, game)) { - xCost += playerPaysXGenericMana(you, source, game); - // save the x value to be available for ETB replacement effect - Object object = game.getState().getValue("spellX" + source.getSourceId()); - Map spellX; - if (object != null && object instanceof Map) { - spellX = (Map) object; - } else { - spellX = new HashMap<>(); - } - spellX.put(event.getSourceId().toString() + game.getState().getZoneChangeCounter(event.getSourceId()), xCost); - game.getState().setValue("spellX" + source.getSourceId(), spellX); - } - } - return false; - } - @Override public boolean checksEventType(GameEvent event, Game game) { return event.getType() == GameEvent.EventType.CAST_SPELL; @@ -144,6 +117,28 @@ class ChorusOfTheConclaveReplacementEffect extends ReplacementEffectImpl { return false; } + @Override + public boolean replaceEvent(GameEvent event, Ability source, Game game) { + int xCost = 0; + Player controller = game.getPlayer(source.getControllerId()); + if (controller != null) { + if (controller.chooseUse(Outcome.Benefit, "Do you wish to pay the additonal cost to add +1/+1 counters to the creature you cast?", source, game)) { + xCost += playerPaysXGenericMana(controller, source, game); + // save the x value to be available for ETB replacement effect + Object object = game.getState().getValue("spellX" + source.getSourceId()); + Map spellX; + if (object != null && object instanceof Map) { + spellX = (Map) object; + } else { + spellX = new HashMap<>(); + } + spellX.put(event.getSourceId().toString() + game.getState().getZoneChangeCounter(event.getSourceId()), xCost); + game.getState().setValue("spellX" + source.getSourceId(), spellX); + } + } + return false; + } + protected static int playerPaysXGenericMana(Player player, Ability source, Game game) { int xValue = 0; boolean payed = false; @@ -191,16 +186,18 @@ class ChorusOfTheConclaveReplacementEffect2 extends ReplacementEffectImpl { @Override public boolean applies(GameEvent event, Ability source, Game game) { Map spellX = (Map) game.getState().getValue("spellX" + source.getSourceId()); - return spellX != null && event.getSourceId() != null && spellX.containsKey(event.getSourceId().toString() + (game.getState().getZoneChangeCounter(event.getSourceId()) - 2)); + return spellX != null + && event.getSourceId() != null + && spellX.containsKey(event.getSourceId().toString() + (game.getState().getZoneChangeCounter(event.getSourceId()) - 1)); } @Override public boolean replaceEvent(GameEvent event, Ability source, Game game) { - Permanent creature = game.getPermanent(event.getSourceId()); + Permanent creature = game.getPermanentEntering(event.getSourceId()); Map spellX = (Map) game.getState().getValue("spellX" + source.getSourceId()); MageObject sourceObject = source.getSourceObject(game); if (sourceObject != null && creature != null && spellX != null) { - String key = event.getSourceId().toString() + (game.getState().getZoneChangeCounter(event.getSourceId()) - 2); + String key = event.getSourceId().toString() + (game.getState().getZoneChangeCounter(event.getSourceId()) - 1); int xValue = spellX.get(key); if (xValue > 0) { creature.addCounters(CounterType.P1P1.createInstance(xValue), game); diff --git a/Mage.Sets/src/mage/sets/commander/TheMimeoplasm.java b/Mage.Sets/src/mage/sets/commander/TheMimeoplasm.java index 238bb1bc6c3..7ff4058deb2 100644 --- a/Mage.Sets/src/mage/sets/commander/TheMimeoplasm.java +++ b/Mage.Sets/src/mage/sets/commander/TheMimeoplasm.java @@ -32,7 +32,6 @@ import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.AsEntersBattlefieldAbility; import mage.abilities.dynamicvalue.common.CardsInAllGraveyardsCount; -import mage.abilities.effects.EntersBattlefieldEffect; import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.CopyEffect; import mage.cards.Card; @@ -98,7 +97,7 @@ class TheMimeoplasmEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { Player controller = game.getPlayer(source.getControllerId()); - Permanent permanent = (Permanent) getValue(EntersBattlefieldEffect.ENTERING_PERMANENT); + Permanent permanent = game.getPermanentEntering(source.getSourceId()); if (controller != null && permanent != null) { if (new CardsInAllGraveyardsCount(new FilterCreatureCard()).calculate(game, source, this) >= 2) { if (controller.chooseUse(Outcome.Benefit, "Do you want to exile two creature cards from graveyards?", source, game)) { diff --git a/Mage.Sets/src/mage/sets/commander2013/NayaSoulbeast.java b/Mage.Sets/src/mage/sets/commander2013/NayaSoulbeast.java index b375229ce70..4143523f77c 100644 --- a/Mage.Sets/src/mage/sets/commander2013/NayaSoulbeast.java +++ b/Mage.Sets/src/mage/sets/commander2013/NayaSoulbeast.java @@ -66,8 +66,9 @@ public class NayaSoulbeast extends CardImpl { // Trample this.addAbility(TrampleAbility.getInstance()); - // When you cast Naya Soulbeast, each player reveals the top card of his or her library. Naya Soulbeast enters the battlefield with X +1/+1 counters on it, where X is the total converted mana cost of all cards revealed this way. + // When you cast Naya Soulbeast, each player reveals the top card of his or her library. Ability ability = new CastSourceTriggeredAbility(new NayaSoulbeastCastEffect(), false); + // Naya Soulbeast enters the battlefield with X +1/+1 counters on it, where X is the total converted mana cost of all cards revealed this way. ability.addEffect(new NayaSoulbeastReplacementEffect()); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/sets/commander2013/OpalPalace.java b/Mage.Sets/src/mage/sets/commander2013/OpalPalace.java index 4601e1a29d5..0086d731e92 100644 --- a/Mage.Sets/src/mage/sets/commander2013/OpalPalace.java +++ b/Mage.Sets/src/mage/sets/commander2013/OpalPalace.java @@ -74,7 +74,7 @@ public class OpalPalace extends CardImpl { ability = new SimpleStaticAbility(Zone.ALL, new OpalPalaceEntersBattlefieldEffect()); ability.setRuleVisible(false); this.addAbility(ability); - + } public OpalPalace(final OpalPalace card) { @@ -91,10 +91,10 @@ class OpalPalaceWatcher extends Watcher { public List commanderId = new ArrayList<>(); private final String originalId; - + public OpalPalaceWatcher(String originalId) { super("ManaPaidFromOpalPalaceWatcher", WatcherScope.CARD); - this.originalId = originalId; + this.originalId = originalId; } public OpalPalaceWatcher(final OpalPalaceWatcher watcher) { @@ -116,16 +116,16 @@ class OpalPalaceWatcher extends Watcher { if (spell != null) { Card card = spell.getCard(); if (card != null) { - for (UUID playerId :game.getPlayerList()) { + for (UUID playerId : game.getPlayerList()) { Player player = game.getPlayer(playerId); if (player != null) { if (player.getCommanderId() != null && player.getCommanderId().equals(card.getId())) { commanderId.add(card.getId()); break; } - } + } } - } + } } } } @@ -153,19 +153,19 @@ class OpalPalaceEntersBattlefieldEffect extends ReplacementEffectImpl { public boolean checksEventType(GameEvent event, Game game) { return event.getType() == EventType.ENTERS_THE_BATTLEFIELD; } - + @Override public boolean applies(GameEvent event, Ability source, Game game) { OpalPalaceWatcher watcher = (OpalPalaceWatcher) game.getState().getWatchers().get("ManaPaidFromOpalPalaceWatcher", source.getSourceId()); - return watcher != null && - watcher.commanderId.contains(event.getTargetId()); + return watcher != null + && watcher.commanderId.contains(event.getTargetId()); } @Override public boolean replaceEvent(GameEvent event, Ability source, Game game) { - Permanent permanent = game.getPermanent(event.getTargetId()); + Permanent permanent = game.getPermanentEntering(event.getTargetId()); if (permanent != null) { - Integer castCount = (Integer)game.getState().getValue(permanent.getId() + "_castCount"); + Integer castCount = (Integer) game.getState().getValue(permanent.getId() + "_castCount"); if (castCount != null && castCount > 0) { permanent.addCounters(CounterType.P1P1.createInstance(castCount), game); } diff --git a/Mage.Sets/src/mage/sets/commander2014/BitterFeud.java b/Mage.Sets/src/mage/sets/commander2014/BitterFeud.java index 22d87b793ea..0ce63beead1 100644 --- a/Mage.Sets/src/mage/sets/commander2014/BitterFeud.java +++ b/Mage.Sets/src/mage/sets/commander2014/BitterFeud.java @@ -32,7 +32,6 @@ import mage.MageObject; import mage.abilities.Ability; import mage.abilities.common.AsEntersBattlefieldAbility; import mage.abilities.common.SimpleStaticAbility; -import mage.abilities.effects.EntersBattlefieldEffect; import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.ReplacementEffectImpl; import mage.cards.Card; @@ -92,7 +91,7 @@ class BitterFeudEntersBattlefieldEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { Player controller = game.getPlayer(source.getControllerId()); - Permanent permanent = (Permanent) getValue(EntersBattlefieldEffect.ENTERING_PERMANENT); + Permanent permanent = game.getPermanentEntering(source.getSourceId()); if (controller != null && permanent != null) { TargetPlayer target = new TargetPlayer(2, 2, true); controller.chooseTarget(outcome, target, source, game); diff --git a/Mage.Sets/src/mage/sets/commander2014/DarettiScrapSavant.java b/Mage.Sets/src/mage/sets/commander2014/DarettiScrapSavant.java index 48b846573c7..a4d4ceab35c 100644 --- a/Mage.Sets/src/mage/sets/commander2014/DarettiScrapSavant.java +++ b/Mage.Sets/src/mage/sets/commander2014/DarettiScrapSavant.java @@ -33,13 +33,12 @@ import mage.abilities.DelayedTriggeredAbility; import mage.abilities.LoyaltyAbility; import mage.abilities.TriggeredAbilityImpl; import mage.abilities.common.CanBeYourCommanderAbility; -import mage.abilities.common.EntersBattlefieldAbility; +import mage.abilities.common.PlanswalkerEntersWithLoyalityCountersAbility; import mage.abilities.common.delayed.AtTheBeginOfNextEndStepDelayedTriggeredAbility; import mage.abilities.effects.Effect; import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.GetEmblemEffect; import mage.abilities.effects.common.ReturnFromGraveyardToBattlefieldTargetEffect; -import mage.abilities.effects.common.counter.AddCountersSourceEffect; import mage.cards.Card; import mage.cards.CardImpl; import mage.constants.CardType; @@ -47,7 +46,6 @@ import mage.constants.Outcome; import mage.constants.Rarity; import mage.constants.TargetController; import mage.constants.Zone; -import mage.counters.CounterType; import mage.filter.FilterCard; import mage.filter.common.FilterArtifactCard; import mage.filter.common.FilterControlledArtifactPermanent; @@ -75,7 +73,7 @@ public class DarettiScrapSavant extends CardImpl { this.expansionSetCode = "C14"; this.subtype.add("Daretti"); - this.addAbility(new EntersBattlefieldAbility(new AddCountersSourceEffect(CounterType.LOYALTY.createInstance(3)), false)); + this.addAbility(new PlanswalkerEntersWithLoyalityCountersAbility(3)); // +2: Discard up to two cards, then draw that many cards. this.addAbility(new LoyaltyAbility(new DarettiDiscardDrawEffect(), 2)); @@ -179,7 +177,6 @@ class DarettiSacrificeEffect extends OneShotEffect { class DarettiScrapSavantEmblem extends Emblem { // You get an emblem with "Whenever an artifact is put into your graveyard from the battlefield, return that card to the battlefield at the beginning of the next end step." - public DarettiScrapSavantEmblem() { this.setName("Emblem - Daretti"); this.getAbilities().add(new DarettiScrapSavantTriggeredAbility()); diff --git a/Mage.Sets/src/mage/sets/commander2014/FreyaliseLlanowarsFury.java b/Mage.Sets/src/mage/sets/commander2014/FreyaliseLlanowarsFury.java index adf5daa6ca5..e8d82a0618a 100644 --- a/Mage.Sets/src/mage/sets/commander2014/FreyaliseLlanowarsFury.java +++ b/Mage.Sets/src/mage/sets/commander2014/FreyaliseLlanowarsFury.java @@ -32,19 +32,17 @@ import mage.MageInt; import mage.ObjectColor; import mage.abilities.LoyaltyAbility; import mage.abilities.common.CanBeYourCommanderAbility; -import mage.abilities.common.EntersBattlefieldAbility; +import mage.abilities.common.PlanswalkerEntersWithLoyalityCountersAbility; import mage.abilities.dynamicvalue.common.PermanentsOnBattlefieldCount; import mage.abilities.effects.common.CreateTokenEffect; import mage.abilities.effects.common.DestroyTargetEffect; import mage.abilities.effects.common.DrawCardSourceControllerEffect; -import mage.abilities.effects.common.counter.AddCountersSourceEffect; import mage.abilities.mana.GreenManaAbility; import mage.cards.CardImpl; import mage.constants.CardType; import mage.constants.Rarity; -import mage.counters.CounterType; -import mage.filter.common.FilterControlledCreaturePermanent; import mage.filter.common.FilterArtifactOrEnchantmentPermanent; +import mage.filter.common.FilterControlledCreaturePermanent; import mage.filter.predicate.mageobject.ColorPredicate; import mage.game.permanent.token.Token; import mage.target.TargetPermanent; @@ -56,6 +54,7 @@ import mage.target.TargetPermanent; public class FreyaliseLlanowarsFury extends CardImpl { private static final FilterControlledCreaturePermanent filterGreen = new FilterControlledCreaturePermanent("green creature you control"); + static { filterGreen.add(new ColorPredicate(ObjectColor.GREEN)); } @@ -65,8 +64,8 @@ public class FreyaliseLlanowarsFury extends CardImpl { this.expansionSetCode = "C14"; this.subtype.add("Freyalise"); - this.addAbility(new EntersBattlefieldAbility(new AddCountersSourceEffect(CounterType.LOYALTY.createInstance(3)), false)); - + this.addAbility(new PlanswalkerEntersWithLoyalityCountersAbility(3)); + // +2: Put a 1/1 green Elf Druid creature token onto the battlefield with "{T}: Add {G} to your mana pool." this.addAbility(new LoyaltyAbility(new CreateTokenEffect(new FreyaliseLlanowarsFuryToken()), 2)); // -2: Destroy target artifact or enchantment. @@ -106,4 +105,4 @@ class FreyaliseLlanowarsFuryToken extends Token { // {T}: Add {G} to your mana pool. this.addAbility(new GreenManaAbility()); } -} \ No newline at end of file +} diff --git a/Mage.Sets/src/mage/sets/commander2014/MasterworkOfIngenuity.java b/Mage.Sets/src/mage/sets/commander2014/MasterworkOfIngenuity.java index 7485d6c1534..1ec61bbb10e 100644 --- a/Mage.Sets/src/mage/sets/commander2014/MasterworkOfIngenuity.java +++ b/Mage.Sets/src/mage/sets/commander2014/MasterworkOfIngenuity.java @@ -28,14 +28,11 @@ package mage.sets.commander2014; import java.util.UUID; -import mage.abilities.Ability; -import mage.abilities.common.SimpleStaticAbility; -import mage.abilities.effects.EntersBattlefieldEffect; +import mage.abilities.common.EntersBattlefieldAbility; import mage.abilities.effects.common.CopyPermanentEffect; import mage.cards.CardImpl; import mage.constants.CardType; import mage.constants.Rarity; -import mage.constants.Zone; import mage.filter.FilterPermanent; import mage.filter.predicate.mageobject.CardTypePredicate; import mage.filter.predicate.mageobject.SubtypePredicate; @@ -45,6 +42,7 @@ import mage.filter.predicate.mageobject.SubtypePredicate; * @author LevelX2 */ public class MasterworkOfIngenuity extends CardImpl { + private static final FilterPermanent filter = new FilterPermanent("artifact"); static { @@ -58,12 +56,7 @@ public class MasterworkOfIngenuity extends CardImpl { this.subtype.add("Equipment"); // You may have Masterwork of Ingenuity enter the battlefield as a copy of any Equipment on the battlefield. - Ability ability = new SimpleStaticAbility(Zone.BATTLEFIELD, new EntersBattlefieldEffect( - new CopyPermanentEffect(filter), - "You may have {this} enter the battlefield as a copy of any Equipment on the battlefield", - true)); - this.addAbility(ability); - + this.addAbility(new EntersBattlefieldAbility(new CopyPermanentEffect(filter), true)); } public MasterworkOfIngenuity(final MasterworkOfIngenuity card) { diff --git a/Mage.Sets/src/mage/sets/commander2014/NahiriTheLithomancer.java b/Mage.Sets/src/mage/sets/commander2014/NahiriTheLithomancer.java index c9f5dad4248..890dd2eab04 100644 --- a/Mage.Sets/src/mage/sets/commander2014/NahiriTheLithomancer.java +++ b/Mage.Sets/src/mage/sets/commander2014/NahiriTheLithomancer.java @@ -27,15 +27,11 @@ */ package mage.sets.commander2014; -import java.io.Serializable; -import java.util.HashMap; -import java.util.Map; import java.util.UUID; -import mage.MageInt; import mage.abilities.Ability; import mage.abilities.LoyaltyAbility; import mage.abilities.common.CanBeYourCommanderAbility; -import mage.abilities.common.EntersBattlefieldAbility; +import mage.abilities.common.PlanswalkerEntersWithLoyalityCountersAbility; import mage.abilities.common.SimpleStaticAbility; import mage.abilities.costs.mana.GenericManaCost; import mage.abilities.effects.Effect; @@ -43,7 +39,6 @@ import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.CreateTokenEffect; import mage.abilities.effects.common.continuous.BoostEquippedEffect; import mage.abilities.effects.common.continuous.GainAbilityAttachedEffect; -import mage.abilities.effects.common.counter.AddCountersSourceEffect; import mage.abilities.keyword.DoubleStrikeAbility; import mage.abilities.keyword.EquipAbility; import mage.abilities.keyword.IndestructibleAbility; @@ -55,7 +50,6 @@ import mage.constants.Duration; import mage.constants.Outcome; import mage.constants.Rarity; import mage.constants.Zone; -import mage.counters.CounterType; import mage.filter.FilterCard; import mage.filter.common.FilterControlledPermanent; import mage.filter.predicate.mageobject.SubtypePredicate; @@ -80,8 +74,7 @@ public class NahiriTheLithomancer extends CardImpl { this.expansionSetCode = "C14"; this.subtype.add("Nahiri"); - - this.addAbility(new EntersBattlefieldAbility(new AddCountersSourceEffect(CounterType.LOYALTY.createInstance(3)), false)); + this.addAbility(new PlanswalkerEntersWithLoyalityCountersAbility(3)); // +2: Put a 1/1 white Kor Soldier creature token onto the battlefield. You may attach an Equipment you control to it. this.addAbility(new LoyaltyAbility(new NahiriTheLithomancerFirstAbilityEffect(), 2)); @@ -111,6 +104,7 @@ public class NahiriTheLithomancer extends CardImpl { class NahiriTheLithomancerFirstAbilityEffect extends OneShotEffect { private static final FilterControlledPermanent filter = new FilterControlledPermanent("an Equipment you control"); + static { filter.add(new SubtypePredicate("Equipment")); } @@ -139,8 +133,8 @@ class NahiriTheLithomancerFirstAbilityEffect extends OneShotEffect { if (tokenPermanent != null) { //TODO: Make sure the Equipment can legally enchant the token, preferably on targetting. Target target = new TargetControlledPermanent(0, 1, filter, true); - if (target.canChoose(source.getSourceId(), controller.getId(), game) && - controller.chooseUse(outcome, "Attach an Equipment you control to the created Token?", source, game)) { + if (target.canChoose(source.getSourceId(), controller.getId(), game) + && controller.chooseUse(outcome, "Attach an Equipment you control to the created Token?", source, game)) { if (target.choose(Outcome.Neutral, source.getControllerId(), source.getSourceId(), game)) { Permanent equipmentPermanent = game.getPermanent(target.getFirstTarget()); if (equipmentPermanent != null) { @@ -164,6 +158,7 @@ class NahiriTheLithomancerFirstAbilityEffect extends OneShotEffect { class NahiriTheLithomancerSecondAbilityEffect extends OneShotEffect { private static final FilterCard filter = new FilterCard("an Equipment"); + static { filter.add(new SubtypePredicate("Equipment")); } @@ -193,8 +188,7 @@ class NahiriTheLithomancerSecondAbilityEffect extends OneShotEffect { if (card != null) { controller.putOntoBattlefieldWithInfo(card, game, Zone.HAND, source.getSourceId()); } - } - else { + } else { Target target = new TargetCardInYourGraveyard(0, 1, filter); target.choose(Outcome.PutCardInPlay, source.getControllerId(), source.getSourceId(), game); Card card = controller.getGraveyard().get(target.getFirstTarget(), game); diff --git a/Mage.Sets/src/mage/sets/commander2014/NecromanticSelection.java b/Mage.Sets/src/mage/sets/commander2014/NecromanticSelection.java index b595331cf91..240f34a2f5f 100644 --- a/Mage.Sets/src/mage/sets/commander2014/NecromanticSelection.java +++ b/Mage.Sets/src/mage/sets/commander2014/NecromanticSelection.java @@ -71,7 +71,6 @@ public class NecromanticSelection extends CardImpl { super(ownerId, 26, "Necromantic Selection", Rarity.RARE, new CardType[]{CardType.SORCERY}, "{4}{B}{B}{B}"); this.expansionSetCode = "C14"; - // Destroy all creatures, then return a creature card put into a graveyard this way to the battlefield under your control. It's a black Zombie in addition to its other colors and types. Exile Necromantic Selection. this.getSpellAbility().addEffect(new NecromanticSelectionEffect()); this.getSpellAbility().addEffect(ExileSpellEffect.getInstance()); @@ -110,7 +109,7 @@ class NecromanticSelectionEffect extends OneShotEffect { MageObject sourceObject = game.getObject(source.getSourceId()); if (sourceObject != null && controller != null) { Cards cards = new CardsImpl(); - for(Permanent permanent: game.getBattlefield().getActivePermanents(new FilterCreaturePermanent(), controller.getId(), source.getSourceId(), game)) { + for (Permanent permanent : game.getBattlefield().getActivePermanents(new FilterCreaturePermanent(), controller.getId(), source.getSourceId(), game)) { permanent.destroy(source.getSourceId(), game, false); if (game.getState().getZone(permanent.getId()).equals(Zone.GRAVEYARD)) { cards.add(permanent); @@ -118,7 +117,7 @@ class NecromanticSelectionEffect extends OneShotEffect { } FilterCard filter = new FilterCreatureCard("creature card put into a graveyard with " + sourceObject.getLogName()); ArrayList> cardIdPredicates = new ArrayList<>(); - for(UUID cardId: cards) { + for (UUID cardId : cards) { cardIdPredicates.add(new CardIdPredicate(cardId)); } filter.add(Predicates.or(cardIdPredicates)); @@ -126,7 +125,7 @@ class NecromanticSelectionEffect extends OneShotEffect { if (controller.chooseTarget(outcome, target, source, game)) { Card card = game.getCard(target.getFirstTarget()); if (card != null) { - controller.putOntoBattlefieldWithInfo(card, game, Zone.GRAVEYARD, source.getSourceId()); + controller.moveCards(card, Zone.BATTLEFIELD, source, game); ContinuousEffect effect = new NecromanticSelectionContinuousEffect(); effect.setTargetPointer(new FixedTarget(card.getId())); game.addEffect(effect, source); diff --git a/Mage.Sets/src/mage/sets/commander2014/ObNixilisOfTheBlackOath.java b/Mage.Sets/src/mage/sets/commander2014/ObNixilisOfTheBlackOath.java index 2593433d2ea..2a1e6544c52 100644 --- a/Mage.Sets/src/mage/sets/commander2014/ObNixilisOfTheBlackOath.java +++ b/Mage.Sets/src/mage/sets/commander2014/ObNixilisOfTheBlackOath.java @@ -31,7 +31,7 @@ import java.util.UUID; import mage.abilities.Ability; import mage.abilities.LoyaltyAbility; import mage.abilities.common.CanBeYourCommanderAbility; -import mage.abilities.common.EntersBattlefieldAbility; +import mage.abilities.common.PlanswalkerEntersWithLoyalityCountersAbility; import mage.abilities.common.SimpleActivatedAbility; import mage.abilities.costs.common.SacrificeTargetCost; import mage.abilities.costs.mana.ManaCostsImpl; @@ -44,14 +44,11 @@ import mage.abilities.effects.common.DrawCardSourceControllerEffect; import mage.abilities.effects.common.GainLifeEffect; import mage.abilities.effects.common.GetEmblemEffect; import mage.abilities.effects.common.LoseLifeSourceControllerEffect; -import mage.abilities.effects.common.counter.AddCountersSourceEffect; -import mage.abilities.keyword.FlyingAbility; import mage.cards.CardImpl; import mage.constants.CardType; import mage.constants.Outcome; import mage.constants.Rarity; import mage.constants.Zone; -import mage.counters.CounterType; import mage.game.Game; import mage.game.command.Emblem; import mage.game.permanent.token.DemonToken; @@ -69,8 +66,7 @@ public class ObNixilisOfTheBlackOath extends CardImpl { this.expansionSetCode = "C14"; this.subtype.add("Nixilis"); - - this.addAbility(new EntersBattlefieldAbility(new AddCountersSourceEffect(CounterType.LOYALTY.createInstance(3)), false)); + this.addAbility(new PlanswalkerEntersWithLoyalityCountersAbility(3)); // +2: Each opponent loses 1 life. You gain life equal to the life lost this way. this.addAbility(new LoyaltyAbility(new ObNixilisOfTheBlackOathEffect1(), 2)); @@ -113,7 +109,7 @@ class ObNixilisOfTheBlackOathEffect1 extends OneShotEffect { Player controller = game.getPlayer(source.getControllerId()); if (controller != null) { int loseLife = 0; - for (UUID opponentId: game.getOpponents(source.getControllerId())) { + for (UUID opponentId : game.getOpponents(source.getControllerId())) { Player opponent = game.getPlayer(opponentId); if (opponent != null) { loseLife += opponent.loseLife(1, game); @@ -134,13 +130,15 @@ class ObNixilisOfTheBlackOathEffect1 extends OneShotEffect { } class ObNixilisOfTheBlackOathEmblem extends Emblem { + // You get an emblem with "{1}{B}, Sacrifice a creature: You gain X life and draw X cards, where X is the sacrificed creature's power." + public ObNixilisOfTheBlackOathEmblem() { this.setName("EMBLEM: Ob Nixilis of the Black Oath"); DynamicValue xValue = new SacrificeCostCreaturesPower(); Effect effect = new GainLifeEffect(xValue); effect.setText("You gain X life"); - Ability ability = new SimpleActivatedAbility(Zone.COMMAND, effect, new ManaCostsImpl("{1}{B}")); + Ability ability = new SimpleActivatedAbility(Zone.COMMAND, effect, new ManaCostsImpl("{1}{B}")); ability.addCost(new SacrificeTargetCost(new TargetControlledCreaturePermanent())); effect = new DrawCardSourceControllerEffect(xValue); effect.setText("and draw X cards, where X is the sacrificed creature's power"); diff --git a/Mage.Sets/src/mage/sets/commander2014/TeferiTemporalArchmage.java b/Mage.Sets/src/mage/sets/commander2014/TeferiTemporalArchmage.java index 4990384fa41..bf6477bc1ea 100644 --- a/Mage.Sets/src/mage/sets/commander2014/TeferiTemporalArchmage.java +++ b/Mage.Sets/src/mage/sets/commander2014/TeferiTemporalArchmage.java @@ -31,14 +31,13 @@ import java.util.UUID; import mage.abilities.Ability; import mage.abilities.LoyaltyAbility; import mage.abilities.common.CanBeYourCommanderAbility; -import mage.abilities.common.EntersBattlefieldAbility; +import mage.abilities.common.PlanswalkerEntersWithLoyalityCountersAbility; import mage.abilities.common.SimpleStaticAbility; import mage.abilities.dynamicvalue.common.StaticValue; import mage.abilities.effects.AsThoughEffectImpl; import mage.abilities.effects.common.GetEmblemEffect; import mage.abilities.effects.common.LookLibraryAndPickControllerEffect; import mage.abilities.effects.common.UntapTargetEffect; -import mage.abilities.effects.common.counter.AddCountersSourceEffect; import mage.cards.CardImpl; import mage.constants.AsThoughEffectType; import mage.constants.CardType; @@ -46,7 +45,6 @@ import mage.constants.Duration; import mage.constants.Outcome; import mage.constants.Rarity; import mage.constants.Zone; -import mage.counters.CounterType; import mage.filter.FilterCard; import mage.filter.FilterPermanent; import mage.game.Game; @@ -64,7 +62,7 @@ public class TeferiTemporalArchmage extends CardImpl { this.expansionSetCode = "C14"; this.subtype.add("Teferi"); - this.addAbility(new EntersBattlefieldAbility(new AddCountersSourceEffect(CounterType.LOYALTY.createInstance(5)), false)); + this.addAbility(new PlanswalkerEntersWithLoyalityCountersAbility(5)); // +1: Look at the top two cards of your library. Put one of them into your hand and the other on the bottom of your library. this.addAbility(new LoyaltyAbility(new LookLibraryAndPickControllerEffect( @@ -96,7 +94,6 @@ public class TeferiTemporalArchmage extends CardImpl { class TeferiTemporalArchmageEmblem extends Emblem { // "You may activate loyalty abilities of planeswalkers you control on any player's turn any time you could cast an instant." - public TeferiTemporalArchmageEmblem() { this.setName("EMBLEM: Teferi, Temporal Archmage"); this.getAbilities().add(new SimpleStaticAbility(Zone.COMMAND, new TeferiTemporalArchmageAsThoughEffect())); diff --git a/Mage.Sets/src/mage/sets/conflux/ApocalypseHydra.java b/Mage.Sets/src/mage/sets/conflux/ApocalypseHydra.java index a195c86159a..5c3a39ffaad 100644 --- a/Mage.Sets/src/mage/sets/conflux/ApocalypseHydra.java +++ b/Mage.Sets/src/mage/sets/conflux/ApocalypseHydra.java @@ -63,7 +63,8 @@ public class ApocalypseHydra extends CardImpl { this.toughness = new MageInt(0); // Apocalypse Hydra enters the battlefield with X +1/+1 counters on it. If X is 5 or more, it enters the battlefield with an additional X +1/+1 counters on it. - this.addAbility(new EntersBattlefieldAbility(new ApocalypseHydraEffect(), true)); + this.addAbility(new EntersBattlefieldAbility(new ApocalypseHydraEffect())); + // {1}{R}, Remove a +1/+1 counter from Apocalypse Hydra: Apocalypse Hydra deals 1 damage to target creature or player. Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new DamageTargetEffect(1), new ManaCostsImpl("{1}{R}")); ability.addCost(new RemoveCountersSourceCost(CounterType.P1P1.createInstance())); @@ -94,12 +95,12 @@ class ApocalypseHydraEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { - Permanent permanent = game.getPermanent(source.getSourceId()); + Permanent permanent = game.getPermanentEntering(source.getSourceId()); if (permanent != null) { SpellAbility spellAbility = (SpellAbility) getValue(EntersBattlefieldEffect.SOURCE_CAST_SPELL_ABILITY); if (spellAbility != null && spellAbility.getSourceId().equals(source.getSourceId()) - && permanent.getZoneChangeCounter(game) - 1 == spellAbility.getSourceObjectZoneChangeCounter()) { + && permanent.getZoneChangeCounter(game) == spellAbility.getSourceObjectZoneChangeCounter()) { int amount = spellAbility.getManaCostsToPay().getX(); if (amount > 0) { if (amount < 5) { diff --git a/Mage.Sets/src/mage/sets/conflux/NicolBolasPlaneswalker.java b/Mage.Sets/src/mage/sets/conflux/NicolBolasPlaneswalker.java index 892139f72c1..07e9f18043d 100644 --- a/Mage.Sets/src/mage/sets/conflux/NicolBolasPlaneswalker.java +++ b/Mage.Sets/src/mage/sets/conflux/NicolBolasPlaneswalker.java @@ -28,19 +28,17 @@ package mage.sets.conflux; import java.util.UUID; +import mage.abilities.LoyaltyAbility; +import mage.abilities.common.PlanswalkerEntersWithLoyalityCountersAbility; +import mage.abilities.effects.common.DamageTargetEffect; +import mage.abilities.effects.common.DestroyTargetEffect; +import mage.abilities.effects.common.SacrificeEffect; +import mage.abilities.effects.common.continuous.GainControlTargetEffect; +import mage.abilities.effects.common.discard.DiscardTargetEffect; +import mage.cards.CardImpl; import mage.constants.CardType; import mage.constants.Duration; import mage.constants.Rarity; -import mage.abilities.LoyaltyAbility; -import mage.abilities.common.EntersBattlefieldAbility; -import mage.abilities.effects.common.DamageTargetEffect; -import mage.abilities.effects.common.DestroyTargetEffect; -import mage.abilities.effects.common.discard.DiscardTargetEffect; -import mage.abilities.effects.common.SacrificeEffect; -import mage.abilities.effects.common.continuous.GainControlTargetEffect; -import mage.abilities.effects.common.counter.AddCountersSourceEffect; -import mage.cards.CardImpl; -import mage.counters.CounterType; import mage.filter.FilterPermanent; import mage.filter.predicate.Predicates; import mage.filter.predicate.mageobject.CardTypePredicate; @@ -65,8 +63,7 @@ public class NicolBolasPlaneswalker extends CardImpl { this.expansionSetCode = "CON"; this.subtype.add("Bolas"); - - this.addAbility(new EntersBattlefieldAbility(new AddCountersSourceEffect(CounterType.LOYALTY.createInstance(5)), false)); + this.addAbility(new PlanswalkerEntersWithLoyalityCountersAbility(5)); // +3: Destroy target noncreature permanent. LoyaltyAbility ability = new LoyaltyAbility(new DestroyTargetEffect(), 3); diff --git a/Mage.Sets/src/mage/sets/conspiracy/AcademyElite.java b/Mage.Sets/src/mage/sets/conspiracy/AcademyElite.java index 97809e24314..3ca79dcdde7 100644 --- a/Mage.Sets/src/mage/sets/conspiracy/AcademyElite.java +++ b/Mage.Sets/src/mage/sets/conspiracy/AcademyElite.java @@ -103,7 +103,7 @@ class AcademyEliteEffect1 extends OneShotEffect { SpellAbility spellAbility = (SpellAbility) getValue(EntersBattlefieldEffect.SOURCE_CAST_SPELL_ABILITY); if (spellAbility != null && spellAbility.getSourceId().equals(source.getSourceId()) - && permanent.getZoneChangeCounter(game) - 1 == spellAbility.getSourceObjectZoneChangeCounter()) { + && permanent.getZoneChangeCounter(game) == spellAbility.getSourceObjectZoneChangeCounter()) { CardsInAllGraveyardsCount instantsAndSorceries = new CardsInAllGraveyardsCount(new FilterInstantOrSorceryCard("instant or sorcery cards")); int instantsAndSorceriesCount = instantsAndSorceries.calculate(game, source, this); if (instantsAndSorceriesCount > 0) { diff --git a/Mage.Sets/src/mage/sets/conspiracy/DackFayden.java b/Mage.Sets/src/mage/sets/conspiracy/DackFayden.java index e9d62fe6ab5..05b0faad94c 100644 --- a/Mage.Sets/src/mage/sets/conspiracy/DackFayden.java +++ b/Mage.Sets/src/mage/sets/conspiracy/DackFayden.java @@ -34,13 +34,12 @@ import mage.abilities.Ability; import mage.abilities.LoyaltyAbility; import mage.abilities.SpellAbility; import mage.abilities.TriggeredAbilityImpl; -import mage.abilities.common.EntersBattlefieldAbility; +import mage.abilities.common.PlanswalkerEntersWithLoyalityCountersAbility; import mage.abilities.effects.ContinuousEffectImpl; import mage.abilities.effects.Effect; import mage.abilities.effects.common.DrawCardTargetEffect; import mage.abilities.effects.common.GetEmblemEffect; import mage.abilities.effects.common.continuous.GainControlTargetEffect; -import mage.abilities.effects.common.counter.AddCountersSourceEffect; import mage.abilities.effects.common.discard.DiscardTargetEffect; import mage.cards.CardImpl; import mage.constants.CardType; @@ -50,7 +49,6 @@ import mage.constants.Outcome; import mage.constants.Rarity; import mage.constants.SubLayer; import mage.constants.Zone; -import mage.counters.CounterType; import mage.game.Game; import mage.game.command.Emblem; import mage.game.events.GameEvent; @@ -73,8 +71,7 @@ public class DackFayden extends CardImpl { this.expansionSetCode = "CNS"; this.subtype.add("Dack"); - - this.addAbility(new EntersBattlefieldAbility(new AddCountersSourceEffect(CounterType.LOYALTY.createInstance(3)), false)); + this.addAbility(new PlanswalkerEntersWithLoyalityCountersAbility(3)); // +1: Target player draws two cards, then discards two cards. LoyaltyAbility ability = new LoyaltyAbility(new DrawCardTargetEffect(2), 1); @@ -83,14 +80,14 @@ public class DackFayden extends CardImpl { ability.addEffect(effect); ability.addTarget(new TargetPlayer()); this.addAbility(ability); - + // -2: Gain control of target artifact. effect = new GainControlTargetEffect(Duration.EndOfGame, true); effect.setText("Gain control of target artifact"); ability = new LoyaltyAbility(effect, -2); ability.addTarget(new TargetArtifactPermanent()); this.addAbility(ability); - + // -6: You get an emblem with "Whenever you cast a spell that targets one or more permanents, gain control of those permanents." effect = new GetEmblemEffect(new DackFaydenEmblem()); effect.setText("You get an emblem with \"Whenever you cast a spell that targets one or more permanents, gain control of those permanents.\""); @@ -109,7 +106,7 @@ public class DackFayden extends CardImpl { } class DackFaydenEmblem extends Emblem { - + DackFaydenEmblem() { this.setName("EMBLEM: Dack Fayden"); this.getAbilities().add(new DackFaydenEmblemTriggeredAbility()); @@ -117,15 +114,15 @@ class DackFaydenEmblem extends Emblem { } class DackFaydenEmblemTriggeredAbility extends TriggeredAbilityImpl { - + DackFaydenEmblemTriggeredAbility() { super(Zone.COMMAND, new DackFaydenEmblemEffect(), false); } - + DackFaydenEmblemTriggeredAbility(final DackFaydenEmblemTriggeredAbility ability) { super(ability); } - + @Override public DackFaydenEmblemTriggeredAbility copy() { return new DackFaydenEmblemTriggeredAbility(this); @@ -135,7 +132,7 @@ class DackFaydenEmblemTriggeredAbility extends TriggeredAbilityImpl { public boolean checkEventType(GameEvent event, Game game) { return event.getType() == EventType.SPELL_CAST; } - + @Override public boolean checkTrigger(GameEvent event, Game game) { boolean returnValue = false; @@ -175,7 +172,7 @@ class DackFaydenEmblemTriggeredAbility extends TriggeredAbilityImpl { } return returnValue; } - + @Override public String getRule() { return "Whenever you cast a spell that targets one or more permanents, gain control of those permanents."; @@ -183,24 +180,24 @@ class DackFaydenEmblemTriggeredAbility extends TriggeredAbilityImpl { } class DackFaydenEmblemEffect extends ContinuousEffectImpl { - + protected List permanents; - + DackFaydenEmblemEffect() { super(Duration.EndOfGame, Layer.ControlChangingEffects_2, SubLayer.NA, Outcome.GainControl); this.staticText = "gain control of those permanents"; } - + DackFaydenEmblemEffect(final DackFaydenEmblemEffect effect) { super(effect); this.permanents = effect.permanents; } - + @Override public DackFaydenEmblemEffect copy() { return new DackFaydenEmblemEffect(this); } - + @Override public boolean apply(Game game, Ability source) { for (UUID permanentId : this.permanents) { @@ -211,7 +208,7 @@ class DackFaydenEmblemEffect extends ContinuousEffectImpl { } return true; } - + public void setPermanents(List targettedPermanents) { this.permanents = new ArrayList<>(targettedPermanents); } diff --git a/Mage.Sets/src/mage/sets/conspiracy/ExtractFromDarkness.java b/Mage.Sets/src/mage/sets/conspiracy/ExtractFromDarkness.java index 9b30e45ef2c..4fe08b08edc 100644 --- a/Mage.Sets/src/mage/sets/conspiracy/ExtractFromDarkness.java +++ b/Mage.Sets/src/mage/sets/conspiracy/ExtractFromDarkness.java @@ -30,7 +30,6 @@ package mage.sets.conspiracy; import java.util.UUID; import mage.abilities.Ability; import mage.abilities.effects.OneShotEffect; -import mage.cards.Card; import mage.cards.CardImpl; import mage.constants.CardType; import mage.constants.Outcome; @@ -114,17 +113,16 @@ class ExtractFromDarknessReturnFromGraveyardToBattlefieldEffect extends OneShotE @Override public boolean apply(Game game, Ability source) { - Player player = game.getPlayer(source.getControllerId()); - if (player != null) { + Player controller = game.getPlayer(source.getControllerId()); + if (controller != null) { Target target = new TargetCardInGraveyard(new FilterCreatureCard()); target.setNotTarget(true); if (target.canChoose(source.getSourceId(), source.getControllerId(), game) - && player.chooseTarget(outcome, target, source, game)) { - Card card = game.getCard(target.getFirstTarget()); - player.putOntoBattlefieldWithInfo(card, game, Zone.GRAVEYARD, source.getSourceId()); + && controller.chooseTarget(outcome, target, source, game)) { + return controller.moveCards(game.getCard(target.getFirstTarget()), Zone.BATTLEFIELD, source, game); } return true; } return false; } -} \ No newline at end of file +} diff --git a/Mage.Sets/src/mage/sets/conspiracy/MuzzioVisionaryArchitect.java b/Mage.Sets/src/mage/sets/conspiracy/MuzzioVisionaryArchitect.java index 71a562bab0f..437601df097 100644 --- a/Mage.Sets/src/mage/sets/conspiracy/MuzzioVisionaryArchitect.java +++ b/Mage.Sets/src/mage/sets/conspiracy/MuzzioVisionaryArchitect.java @@ -99,14 +99,14 @@ class MuzzioVisionaryArchitectEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { - Player player = game.getPlayer(source.getControllerId()); + Player controller = game.getPlayer(source.getControllerId()); Permanent sourcePermanent = game.getPermanentOrLKIBattlefield(source.getSourceId()); - if (player == null || sourcePermanent == null) { + if (controller == null || sourcePermanent == null) { return false; } int highCMC = 0; - List controlledArtifacts = game.getBattlefield().getAllActivePermanents(new FilterArtifactPermanent(), player.getId(), game); + List controlledArtifacts = game.getBattlefield().getAllActivePermanents(new FilterArtifactPermanent(), controller.getId(), game); for (Permanent permanent : controlledArtifacts) { if (permanent.getSpellAbility() != null) { int cmc = permanent.getSpellAbility().getManaCosts().convertedManaCost(); @@ -119,26 +119,26 @@ class MuzzioVisionaryArchitectEffect extends OneShotEffect { Cards cards = new CardsImpl(); for (int i = 0; i < highCMC; i++) { - Card card = player.getLibrary().removeFromTop(game); + Card card = controller.getLibrary().removeFromTop(game); if (card != null) { cards.add(card); } } - player.lookAtCards(sourcePermanent.getName(), cards, game); + controller.lookAtCards(sourcePermanent.getIdName(), cards, game); if (!cards.isEmpty()) { TargetCard target = new TargetCard(Zone.LIBRARY, new FilterArtifactCard("artifact card to put onto the battlefield")); - if (target.canChoose(source.getSourceId(), player.getId(), game) && player.choose(Outcome.Benefit, cards, target, game)) { + if (target.canChoose(source.getSourceId(), controller.getId(), game) && controller.choose(Outcome.Benefit, cards, target, game)) { Card card = cards.get(target.getFirstTarget(), game); if (card != null) { - player.revealCards(sourcePermanent.getName(), new CardsImpl(card), game); + controller.revealCards(sourcePermanent.getIdName(), new CardsImpl(card), game); cards.remove(card); - player.putOntoBattlefieldWithInfo(card, game, Zone.LIBRARY, source.getSourceId()); + controller.moveCards(card, Zone.BATTLEFIELD, source, game); } } } - player.putCardsOnBottomOfLibrary(cards, game, source, true); + controller.putCardsOnBottomOfLibrary(cards, game, source, true); return true; } -} \ No newline at end of file +} diff --git a/Mage.Sets/src/mage/sets/darkascension/SorinLordOfInnistrad.java b/Mage.Sets/src/mage/sets/darkascension/SorinLordOfInnistrad.java index d351fa80033..f5a89e1c6dc 100644 --- a/Mage.Sets/src/mage/sets/darkascension/SorinLordOfInnistrad.java +++ b/Mage.Sets/src/mage/sets/darkascension/SorinLordOfInnistrad.java @@ -27,25 +27,24 @@ */ package mage.sets.darkascension; -import mage.constants.CardType; -import mage.constants.Duration; -import mage.constants.Rarity; -import mage.constants.Zone; +import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.LoyaltyAbility; -import mage.abilities.common.EntersBattlefieldAbility; +import mage.abilities.common.PlanswalkerEntersWithLoyalityCountersAbility; import mage.abilities.common.SimpleStaticAbility; import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.CreateTokenEffect; import mage.abilities.effects.common.GetEmblemEffect; import mage.abilities.effects.common.continuous.BoostControlledEffect; -import mage.abilities.effects.common.counter.AddCountersSourceEffect; import mage.abilities.keyword.LifelinkAbility; import mage.cards.Card; import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.Duration; import mage.constants.Outcome; -import mage.counters.CounterType; +import mage.constants.Rarity; +import mage.constants.Zone; import mage.filter.FilterPermanent; import mage.filter.predicate.Predicates; import mage.filter.predicate.mageobject.CardTypePredicate; @@ -56,8 +55,6 @@ import mage.game.permanent.token.Token; import mage.players.Player; import mage.target.TargetPermanent; -import java.util.UUID; - /** * * @author BetaSteward @@ -77,8 +74,7 @@ public class SorinLordOfInnistrad extends CardImpl { this.expansionSetCode = "DKA"; this.subtype.add("Sorin"); - - this.addAbility(new EntersBattlefieldAbility(new AddCountersSourceEffect(CounterType.LOYALTY.createInstance(3)), false)); + this.addAbility(new PlanswalkerEntersWithLoyalityCountersAbility(3)); // +1: Put a 1/1 black Vampire creature token with lifelink onto the battlefield. this.addAbility(new LoyaltyAbility(new CreateTokenEffect(new VampireToken()), 1)); @@ -103,6 +99,7 @@ public class SorinLordOfInnistrad extends CardImpl { } class VampireToken extends Token { + VampireToken() { super("Vampire", "a 1/1 black Vampire creature token with lifelink"); cardType.add(CardType.CREATURE); @@ -142,7 +139,7 @@ class SorinLordOfInnistradEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { - for (UUID targetId: source.getTargets().get(0).getTargets()) { + for (UUID targetId : source.getTargets().get(0).getTargets()) { Permanent perm = game.getPermanent(targetId); if (perm != null) { perm.destroy(source.getSourceId(), game, false); @@ -150,7 +147,7 @@ class SorinLordOfInnistradEffect extends OneShotEffect { } Player player = game.getPlayer(source.getControllerId()); if (player != null) { - for (UUID targetId: source.getTargets().get(0).getTargets()) { + for (UUID targetId : source.getTargets().get(0).getTargets()) { if (game.getState().getZone(targetId) == Zone.GRAVEYARD) { Card card = game.getCard(targetId); if (card != null) { diff --git a/Mage.Sets/src/mage/sets/darksteel/AEtherVial.java b/Mage.Sets/src/mage/sets/darksteel/AEtherVial.java index baa5d24d1c4..8c1332a991b 100644 --- a/Mage.Sets/src/mage/sets/darksteel/AEtherVial.java +++ b/Mage.Sets/src/mage/sets/darksteel/AEtherVial.java @@ -28,11 +28,6 @@ package mage.sets.darksteel; import java.util.UUID; -import mage.constants.CardType; -import mage.constants.Outcome; -import mage.constants.Rarity; -import mage.constants.TargetController; -import mage.constants.Zone; import mage.abilities.Ability; import mage.abilities.common.BeginningOfUpkeepTriggeredAbility; import mage.abilities.common.SimpleActivatedAbility; @@ -41,6 +36,11 @@ import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.counter.AddCountersSourceEffect; import mage.cards.Card; import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.Outcome; +import mage.constants.Rarity; +import mage.constants.TargetController; +import mage.constants.Zone; import mage.counters.CounterType; import mage.filter.Filter; import mage.filter.common.FilterCreatureCard; @@ -107,18 +107,20 @@ class AEtherVialEffect extends OneShotEffect { filter.add(new ConvertedManaCostPredicate(Filter.ComparisonType.Equal, count)); String choiceText = "Put a " + filter.getMessage() + " from your hand onto the battlefield?"; - Player player = game.getPlayer(source.getControllerId()); - if (player == null || player.getHand().count(filter, game) == 0 - || !player.chooseUse(this.outcome, choiceText, source, game)) { + Player controller = game.getPlayer(source.getControllerId()); + if (controller == null) { return false; } + if (controller.getHand().count(filter, game) == 0 + || !controller.chooseUse(this.outcome, choiceText, source, game)) { + return true; + } TargetCardInHand target = new TargetCardInHand(filter); - if (player.choose(this.outcome, target, source.getSourceId(), game)) { + if (controller.choose(this.outcome, target, source.getSourceId(), game)) { Card card = game.getCard(target.getFirstTarget()); if (card != null) { - player.putOntoBattlefieldWithInfo(card, game, Zone.HAND, source.getSourceId()); - return true; + return controller.moveCards(card, Zone.BATTLEFIELD, source, game); } } return false; diff --git a/Mage.Sets/src/mage/sets/dissension/ProteanHulk.java b/Mage.Sets/src/mage/sets/dissension/ProteanHulk.java index 4a7804b3443..064145d1981 100644 --- a/Mage.Sets/src/mage/sets/dissension/ProteanHulk.java +++ b/Mage.Sets/src/mage/sets/dissension/ProteanHulk.java @@ -78,47 +78,42 @@ public class ProteanHulk extends CardImpl { } class ProteanHulkEffect extends OneShotEffect { - + ProteanHulkEffect() { super(Outcome.PutCreatureInPlay); this.staticText = "search your library for any number of creature cards with total converted mana cost 6 or less and put them onto the battlefield. Then shuffle your library"; } - + ProteanHulkEffect(final ProteanHulkEffect effect) { super(effect); } - + @Override public ProteanHulkEffect copy() { return new ProteanHulkEffect(this); } - + @Override public boolean apply(Game game, Ability source) { - Player player = game.getPlayer(source.getControllerId()); - if (player != null) { + Player controller = game.getPlayer(source.getControllerId()); + if (controller != null) { Cards cardsPicked = this.ProteanHulkSearch(game, source); - for (UUID cardId : cardsPicked) { - Card card = game.getCard(cardId); - if (card != null) { - player.putOntoBattlefieldWithInfo(card, game, Zone.PICK, source.getSourceId()); - } - } - player.shuffleLibrary(game); + controller.moveCards(cardsPicked.getCards(game), Zone.BATTLEFIELD, source, game); + controller.shuffleLibrary(game); return true; } return false; } - + Cards ProteanHulkSearch(Game game, Ability source) { - Cards cardsPicked = new CardsImpl(Zone.PICK); + Cards cardsPicked = new CardsImpl(Zone.LIBRARY); Player player = game.getPlayer(source.getControllerId()); if (player != null) { GameEvent event = GameEvent.getEvent(GameEvent.EventType.SEARCH_LIBRARY, source.getControllerId(), source.getControllerId(), source.getControllerId(), Integer.MAX_VALUE); if (!game.replaceEvent(event)) { int manaCostLeftToFetch = 6; int librarySearchLimit = event.getAmount(); - + FilterCard filter = new FilterCreatureCard("number of creature cards with total converted mana cost 6 or less (6 CMC left)"); filter.add(new ConvertedManaCostPredicate(ComparisonType.LessThan, manaCostLeftToFetch + 1)); TargetCardInLibrary target = new TargetCardInLibrary(0, 1, filter); @@ -131,15 +126,14 @@ class ProteanHulkEffect extends OneShotEffect { break; } cardsPicked.add(card); - game.setZone(card.getId(), Zone.PICK); game.getState().getLookedAt(source.getControllerId()).add("Protean Hulk", cardsPicked); - + librarySearchLimit--; if (librarySearchLimit == 0) { break; } manaCostLeftToFetch -= card.getManaCost().convertedManaCost(); - filter = new FilterCreatureCard("number of creature cards with total converted mana cost 6 or less ("+ manaCostLeftToFetch +" CMC left)"); + filter = new FilterCreatureCard("number of creature cards with total converted mana cost 6 or less (" + manaCostLeftToFetch + " CMC left)"); filter.add(new ConvertedManaCostPredicate(ComparisonType.LessThan, manaCostLeftToFetch + 1)); target = new TargetCardInLibrary(0, 1, filter); target.setCardLimit(librarySearchLimit); diff --git a/Mage.Sets/src/mage/sets/dragonsmaze/BeckCall.java b/Mage.Sets/src/mage/sets/dragonsmaze/BeckCall.java index 45ce77a9176..d79ba674371 100644 --- a/Mage.Sets/src/mage/sets/dragonsmaze/BeckCall.java +++ b/Mage.Sets/src/mage/sets/dragonsmaze/BeckCall.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.dragonsmaze; import java.util.UUID; @@ -39,13 +38,11 @@ import mage.constants.Duration; import mage.constants.Rarity; import mage.filter.common.FilterCreaturePermanent; import mage.game.Game; -import mage.game.events.GameEvent.EventType; import mage.game.events.GameEvent; +import mage.game.events.GameEvent.EventType; import mage.game.permanent.Permanent; import mage.game.permanent.token.BirdToken; - - public class BeckCall extends SplitCard { public BeckCall(UUID ownerId) { @@ -58,7 +55,7 @@ public class BeckCall extends SplitCard { // Call // Put four 1/1 white Bird creature tokens with flying onto the battlefield. - getRightHalfCard().getSpellAbility().addEffect(new CreateTokenEffect(new BirdToken(),4)); + getRightHalfCard().getSpellAbility().addEffect(new CreateTokenEffect(new BirdToken(), 4)); } @@ -94,10 +91,7 @@ class BeckTriggeredAbility extends DelayedTriggeredAbility { public boolean checkTrigger(GameEvent event, Game game) { UUID targetId = event.getTargetId(); Permanent permanent = game.getPermanent(targetId); - if (filter.match(permanent, getSourceId(), getControllerId(), game)) { - return true; - } - return false; + return filter.match(permanent, getSourceId(), getControllerId(), game); } @Override diff --git a/Mage.Sets/src/mage/sets/dragonsmaze/ProgenitorMimic.java b/Mage.Sets/src/mage/sets/dragonsmaze/ProgenitorMimic.java index 0553d75993b..9df44c4d7df 100644 --- a/Mage.Sets/src/mage/sets/dragonsmaze/ProgenitorMimic.java +++ b/Mage.Sets/src/mage/sets/dragonsmaze/ProgenitorMimic.java @@ -30,18 +30,16 @@ package mage.sets.dragonsmaze; import java.util.UUID; import mage.MageInt; import mage.abilities.common.BeginningOfUpkeepTriggeredAbility; -import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.common.EntersBattlefieldAbility; import mage.abilities.condition.common.SourceMatchesFilterCondition; import mage.abilities.decorator.ConditionalTriggeredAbility; import mage.abilities.effects.Effect; -import mage.abilities.effects.EntersBattlefieldEffect; import mage.abilities.effects.PutTokenOntoBattlefieldCopySourceEffect; import mage.abilities.effects.common.CopyPermanentEffect; import mage.cards.CardImpl; import mage.constants.CardType; import mage.constants.Rarity; import mage.constants.TargetController; -import mage.constants.Zone; import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.Predicates; import mage.filter.predicate.permanent.TokenPredicate; @@ -72,17 +70,16 @@ public class ProgenitorMimic extends CardImpl { // put a token onto the battlefield that's a copy of this creature." Effect effect = new PutTokenOntoBattlefieldCopySourceEffect(); effect.setText("put a token onto the battlefield that's a copy of this creature"); + AbilityApplier applier = new AbilityApplier( new ConditionalTriggeredAbility( new BeginningOfUpkeepTriggeredAbility(effect, TargetController.YOU, false), new SourceMatchesFilterCondition(filter), "At the beginning of your upkeep, if this creature isn't a token, put a token onto the battlefield that's a copy of this creature.") ); - this.addAbility(new SimpleStaticAbility( - Zone.BATTLEFIELD, - new EntersBattlefieldEffect(new CopyPermanentEffect(applier), - "You may have {this} enter the battlefield as a copy of any creature on the battlefield except it gains \"At the beginning of your upkeep, if this creature isn't a token, put a token onto the battlefield that's a copy of this creature.\"", - true))); + effect = new CopyPermanentEffect(); + effect.setText("as a copy of any creature on the battlefield except it gains \"At the beginning of your upkeep, if this creature isn't a token, put a token onto the battlefield that's a copy of this creature.\""); + this.addAbility(new EntersBattlefieldAbility(new CopyPermanentEffect(applier), true)); } public ProgenitorMimic(final ProgenitorMimic card) { diff --git a/Mage.Sets/src/mage/sets/dragonsmaze/RalZarek.java b/Mage.Sets/src/mage/sets/dragonsmaze/RalZarek.java index 829bc093bde..121946e99aa 100644 --- a/Mage.Sets/src/mage/sets/dragonsmaze/RalZarek.java +++ b/Mage.Sets/src/mage/sets/dragonsmaze/RalZarek.java @@ -28,17 +28,15 @@ package mage.sets.dragonsmaze; import java.util.UUID; +import mage.abilities.Ability; +import mage.abilities.LoyaltyAbility; +import mage.abilities.common.PlanswalkerEntersWithLoyalityCountersAbility; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.DamageTargetEffect; +import mage.cards.CardImpl; import mage.constants.CardType; import mage.constants.Outcome; import mage.constants.Rarity; -import mage.abilities.Ability; -import mage.abilities.LoyaltyAbility; -import mage.abilities.common.EntersBattlefieldAbility; -import mage.abilities.effects.OneShotEffect; -import mage.abilities.effects.common.DamageTargetEffect; -import mage.abilities.effects.common.counter.AddCountersSourceEffect; -import mage.cards.CardImpl; -import mage.counters.CounterType; import mage.filter.FilterPermanent; import mage.game.Game; import mage.game.permanent.Permanent; @@ -58,8 +56,7 @@ public class RalZarek extends CardImpl { this.expansionSetCode = "DGM"; this.subtype.add("Ral"); - - this.addAbility(new EntersBattlefieldAbility(new AddCountersSourceEffect(CounterType.LOYALTY.createInstance(4)), false)); + this.addAbility(new PlanswalkerEntersWithLoyalityCountersAbility(4)); // +1: Tap target permanent, then untap another target permanent. LoyaltyAbility ability1 = new LoyaltyAbility(new RalZarekTapUntapEffect(), 1); @@ -86,7 +83,6 @@ public class RalZarek extends CardImpl { } } - class RalZarekTapUntapEffect extends OneShotEffect { public RalZarekTapUntapEffect() { @@ -112,10 +108,10 @@ class RalZarekTapUntapEffect extends OneShotEffect { i++; Permanent permanent = game.getPermanent(targetId); if (permanent != null) { - if (i==1) { + if (i == 1) { permanent.tap(game); } - if (i==2) { + if (i == 2) { permanent.untap(game); } } @@ -146,7 +142,7 @@ class RalZarekExtraTurnsEffect extends OneShotEffect { public boolean apply(Game game, Ability source) { Player controller = game.getPlayer(source.getControllerId()); if (controller != null) { - for (int i=0; i<5; i++) { + for (int i = 0; i < 5; i++) { if (controller.flipCoin(game)) { game.getState().getTurnMods().add(new TurnMod(source.getControllerId(), false)); } diff --git a/Mage.Sets/src/mage/sets/dragonsoftarkir/NarsetTranscendent.java b/Mage.Sets/src/mage/sets/dragonsoftarkir/NarsetTranscendent.java index 639d3f36c38..3873609cb39 100644 --- a/Mage.Sets/src/mage/sets/dragonsoftarkir/NarsetTranscendent.java +++ b/Mage.Sets/src/mage/sets/dragonsoftarkir/NarsetTranscendent.java @@ -32,7 +32,7 @@ import mage.MageObject; import mage.abilities.Ability; import mage.abilities.DelayedTriggeredAbility; import mage.abilities.LoyaltyAbility; -import mage.abilities.common.EntersBattlefieldAbility; +import mage.abilities.common.PlanswalkerEntersWithLoyalityCountersAbility; import mage.abilities.common.SimpleStaticAbility; import mage.abilities.effects.ContinuousEffectImpl; import mage.abilities.effects.ContinuousRuleModifyingEffectImpl; @@ -40,7 +40,6 @@ import mage.abilities.effects.Effect; import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.CreateDelayedTriggeredAbilityEffect; import mage.abilities.effects.common.GetEmblemEffect; -import mage.abilities.effects.common.counter.AddCountersSourceEffect; import mage.abilities.keyword.ReboundAbility; import mage.cards.Card; import mage.cards.CardImpl; @@ -52,7 +51,6 @@ import mage.constants.Outcome; import mage.constants.Rarity; import mage.constants.SubLayer; import mage.constants.Zone; -import mage.counters.CounterType; import mage.game.Game; import mage.game.command.Emblem; import mage.game.events.GameEvent; @@ -71,7 +69,7 @@ public class NarsetTranscendent extends CardImpl { this.expansionSetCode = "DTK"; this.subtype.add("Narset"); - this.addAbility(new EntersBattlefieldAbility(new AddCountersSourceEffect(CounterType.LOYALTY.createInstance(6)), false)); + this.addAbility(new PlanswalkerEntersWithLoyalityCountersAbility(6)); // +1: Look at the top card of your library. If it's a noncreature, nonland card, you may reveal it and put it into your hand. this.addAbility(new LoyaltyAbility(new NarsetTranscendentEffect1(), 1)); diff --git a/Mage.Sets/src/mage/sets/dragonsoftarkir/SarkhanUnbroken.java b/Mage.Sets/src/mage/sets/dragonsoftarkir/SarkhanUnbroken.java index 095e054558d..ccd28a1c476 100644 --- a/Mage.Sets/src/mage/sets/dragonsoftarkir/SarkhanUnbroken.java +++ b/Mage.Sets/src/mage/sets/dragonsoftarkir/SarkhanUnbroken.java @@ -33,10 +33,9 @@ import java.util.UUID; import mage.Mana; import mage.abilities.Ability; import mage.abilities.LoyaltyAbility; -import mage.abilities.common.EntersBattlefieldAbility; +import mage.abilities.common.PlanswalkerEntersWithLoyalityCountersAbility; import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.CreateTokenEffect; -import mage.abilities.effects.common.counter.AddCountersSourceEffect; import mage.abilities.effects.common.search.SearchLibraryPutInPlayEffect; import mage.cards.CardImpl; import mage.choices.Choice; @@ -44,7 +43,6 @@ import mage.choices.ChoiceImpl; import mage.constants.CardType; import mage.constants.Outcome; import mage.constants.Rarity; -import mage.counters.CounterType; import mage.filter.FilterCard; import mage.filter.predicate.mageobject.SubtypePredicate; import mage.game.Game; @@ -69,7 +67,7 @@ public class SarkhanUnbroken extends CardImpl { this.expansionSetCode = "DTK"; this.subtype.add("Sarkhan"); - this.addAbility(new EntersBattlefieldAbility(new AddCountersSourceEffect(CounterType.LOYALTY.createInstance(4)), false)); + this.addAbility(new PlanswalkerEntersWithLoyalityCountersAbility(4)); // +1: Draw a card, then add one mana of any color to your mana pool. this.addAbility(new LoyaltyAbility(new SarkhanUnbrokenAbility1(), 1)); @@ -127,7 +125,7 @@ class SarkhanUnbrokenAbility1 extends OneShotEffect { Mana mana = new Mana(); controller.choose(Outcome.Benefit, manaChoice, game); - + if (manaChoice.getChoice() == null) { return false; } diff --git a/Mage.Sets/src/mage/sets/eventide/CankerAbomination.java b/Mage.Sets/src/mage/sets/eventide/CankerAbomination.java index 812f571064a..3af4a21d774 100644 --- a/Mage.Sets/src/mage/sets/eventide/CankerAbomination.java +++ b/Mage.Sets/src/mage/sets/eventide/CankerAbomination.java @@ -31,7 +31,6 @@ import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.AsEntersBattlefieldAbility; -import mage.abilities.effects.EntersBattlefieldEffect; import mage.abilities.effects.OneShotEffect; import mage.cards.CardImpl; import mage.constants.CardType; @@ -95,7 +94,7 @@ class CankerAbominationEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { Player controller = game.getPlayer(source.getControllerId()); - Permanent cankerAbomination = (Permanent) getValue(EntersBattlefieldEffect.ENTERING_PERMANENT); + Permanent cankerAbomination = game.getPermanentEntering(source.getSourceId()); if (controller != null && cankerAbomination != null) { Target target = new TargetOpponent(); target.setNotTarget(true); diff --git a/Mage.Sets/src/mage/sets/fatereforged/CitadelSiege.java b/Mage.Sets/src/mage/sets/fatereforged/CitadelSiege.java index 8914495c7f5..01b26cd052d 100644 --- a/Mage.Sets/src/mage/sets/fatereforged/CitadelSiege.java +++ b/Mage.Sets/src/mage/sets/fatereforged/CitadelSiege.java @@ -61,7 +61,7 @@ public class CitadelSiege extends CardImpl { this.expansionSetCode = "FRF"; // As Citadel Siege enters the battlefield, choose Khans or Dragons. - this.addAbility(new EntersBattlefieldAbility(new ChooseModeEffect("Khans or Dragons?","Khans", "Dragons"),null, true, + this.addAbility(new EntersBattlefieldAbility(new ChooseModeEffect("Khans or Dragons?","Khans", "Dragons"),null, "As {this} enters the battlefield, choose Khans or Dragons.","")); // * Khans - At the beginning of combat on your turn, put two +1/+1 counters on target creature you control. diff --git a/Mage.Sets/src/mage/sets/fatereforged/FrontierMastodon.java b/Mage.Sets/src/mage/sets/fatereforged/FrontierMastodon.java index 9de1b018b1e..008f8a3c2c4 100644 --- a/Mage.Sets/src/mage/sets/fatereforged/FrontierMastodon.java +++ b/Mage.Sets/src/mage/sets/fatereforged/FrontierMastodon.java @@ -53,7 +53,7 @@ public class FrontierMastodon extends CardImpl { // Ferocious - Frontier Mastodon enters the battlefield with a +1/+1 counter on it if you control a creature with power 4 or greater. this.addAbility(new EntersBattlefieldAbility( new AddCountersSourceEffect(CounterType.P1P1.createInstance(1)), - FerociousCondition.getInstance(), true, + FerociousCondition.getInstance(), "Ferocious — {this} enters the battlefield with a +1/+1 counter on it if you control a creature with power 4 or greater.","" )); } diff --git a/Mage.Sets/src/mage/sets/fatereforged/FrontierSiege.java b/Mage.Sets/src/mage/sets/fatereforged/FrontierSiege.java index f02ca1e3c0b..1a98c5c215c 100644 --- a/Mage.Sets/src/mage/sets/fatereforged/FrontierSiege.java +++ b/Mage.Sets/src/mage/sets/fatereforged/FrontierSiege.java @@ -76,7 +76,7 @@ public class FrontierSiege extends CardImpl { this.expansionSetCode = "FRF"; // As Frontier Siege enters the battlefield, choose Khans or Dragons. - this.addAbility(new EntersBattlefieldAbility(new ChooseModeEffect("Khans or Dragons?", "Khans", "Dragons"), null, true, + this.addAbility(new EntersBattlefieldAbility(new ChooseModeEffect("Khans or Dragons?", "Khans", "Dragons"), null, "As {this} enters the battlefield, choose Khans or Dragons.", "")); // * Khans - At the beginning of each of your main phases, add {G}{G} to your mana pool. diff --git a/Mage.Sets/src/mage/sets/fatereforged/MonasterySiege.java b/Mage.Sets/src/mage/sets/fatereforged/MonasterySiege.java index 799cfbb802d..9753a5cf199 100644 --- a/Mage.Sets/src/mage/sets/fatereforged/MonasterySiege.java +++ b/Mage.Sets/src/mage/sets/fatereforged/MonasterySiege.java @@ -62,7 +62,7 @@ public class MonasterySiege extends CardImpl { this.expansionSetCode = "FRF"; // As Monastery Siege enters the battlefield, choose Khans or Dragons. - this.addAbility(new EntersBattlefieldAbility(new ChooseModeEffect("Khans or Dragons?", "Khans", "Dragons"), null, true, + this.addAbility(new EntersBattlefieldAbility(new ChooseModeEffect("Khans or Dragons?", "Khans", "Dragons"), null, "As {this} enters the battlefield, choose Khans or Dragons.", "")); // * Khans - At the beginning of your draw step, draw an additional card, then discard a card. diff --git a/Mage.Sets/src/mage/sets/fatereforged/OutpostSiege.java b/Mage.Sets/src/mage/sets/fatereforged/OutpostSiege.java index a2598cdb69a..4ee0f6accad 100644 --- a/Mage.Sets/src/mage/sets/fatereforged/OutpostSiege.java +++ b/Mage.Sets/src/mage/sets/fatereforged/OutpostSiege.java @@ -69,7 +69,7 @@ public class OutpostSiege extends CardImpl { this.expansionSetCode = "FRF"; // As Outpost Siege enters the battlefield, choose Khans or Dragons. - this.addAbility(new EntersBattlefieldAbility(new ChooseModeEffect("Khans or Dragons?", "Khans", "Dragons"), null, true, + this.addAbility(new EntersBattlefieldAbility(new ChooseModeEffect("Khans or Dragons?", "Khans", "Dragons"), null, "As {this} enters the battlefield, choose Khans or Dragons.", "")); // * Khans - At the beginning of your upkeep, exile the top card of your library. Until end of turn, you may play that card. diff --git a/Mage.Sets/src/mage/sets/fatereforged/PalaceSiege.java b/Mage.Sets/src/mage/sets/fatereforged/PalaceSiege.java index 3b153f3e251..d23bb16257a 100644 --- a/Mage.Sets/src/mage/sets/fatereforged/PalaceSiege.java +++ b/Mage.Sets/src/mage/sets/fatereforged/PalaceSiege.java @@ -59,7 +59,7 @@ public class PalaceSiege extends CardImpl { this.expansionSetCode = "FRF"; // As Palace Siege enters the battlefield, choose Khans or Dragons. - this.addAbility(new EntersBattlefieldAbility(new ChooseModeEffect("Khans or Dragons?","Khans", "Dragons"),null, true, + this.addAbility(new EntersBattlefieldAbility(new ChooseModeEffect("Khans or Dragons?","Khans", "Dragons"),null, "As {this} enters the battlefield, choose Khans or Dragons.","")); // * Khans - At the beginning of your upkeep, return target creature card from your graveyard to your hand. diff --git a/Mage.Sets/src/mage/sets/fatereforged/UginTheSpiritDragon.java b/Mage.Sets/src/mage/sets/fatereforged/UginTheSpiritDragon.java index 90ffdb0ca48..2ebf0e1caa3 100644 --- a/Mage.Sets/src/mage/sets/fatereforged/UginTheSpiritDragon.java +++ b/Mage.Sets/src/mage/sets/fatereforged/UginTheSpiritDragon.java @@ -30,19 +30,17 @@ package mage.sets.fatereforged; import java.util.UUID; import mage.abilities.Ability; import mage.abilities.LoyaltyAbility; -import mage.abilities.common.EntersBattlefieldAbility; +import mage.abilities.common.PlanswalkerEntersWithLoyalityCountersAbility; import mage.abilities.costs.Cost; import mage.abilities.costs.common.PayVariableLoyaltyCost; import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.DamageTargetEffect; -import mage.abilities.effects.common.counter.AddCountersSourceEffect; import mage.cards.Card; import mage.cards.CardImpl; import mage.constants.CardType; import mage.constants.Outcome; import mage.constants.Rarity; import mage.constants.Zone; -import mage.counters.CounterType; import mage.filter.Filter.ComparisonType; import mage.filter.FilterPermanent; import mage.filter.common.FilterPermanentCard; @@ -59,7 +57,6 @@ import mage.target.common.TargetCreatureOrPlayer; * * @author LevelX2 */ - public class UginTheSpiritDragon extends CardImpl { public UginTheSpiritDragon(UUID ownerId) { @@ -67,7 +64,7 @@ public class UginTheSpiritDragon extends CardImpl { this.expansionSetCode = "FRF"; this.subtype.add("Ugin"); - this.addAbility(new EntersBattlefieldAbility(new AddCountersSourceEffect(CounterType.LOYALTY.createInstance(7)), false)); + this.addAbility(new PlanswalkerEntersWithLoyalityCountersAbility(7)); // +2: Ugin, the Spirit Dragon deals 3 damage to target creature or player. LoyaltyAbility ability = new LoyaltyAbility(new DamageTargetEffect(3), 2); @@ -126,7 +123,7 @@ class UginTheSpiritDragonEffect2 extends OneShotEffect { FilterPermanent filter = new FilterPermanent("permanent with converted mana cost X or less that's one or more colors"); filter.add(new ConvertedManaCostPredicate(ComparisonType.LessThan, cmc + 1)); filter.add(Predicates.not(new ColorlessPredicate())); - for(Permanent permanent: game.getBattlefield().getActivePermanents(filter, source.getControllerId(), source.getSourceId(), game)) { + for (Permanent permanent : game.getBattlefield().getActivePermanents(filter, source.getControllerId(), source.getSourceId(), game)) { controller.moveCardToExileWithInfo(permanent, null, "", source.getSourceId(), game, Zone.BATTLEFIELD, true); } return true; @@ -157,7 +154,7 @@ class UginTheSpiritDragonEffect3 extends OneShotEffect { controller.drawCards(7, game); TargetCardInHand target = new TargetCardInHand(0, 7, new FilterPermanentCard("permanent cards")); if (controller.choose(Outcome.PutCardInPlay, target, source.getSourceId(), game)) { - for (UUID targetId: target.getTargets()) { + for (UUID targetId : target.getTargets()) { Card card = game.getCard(targetId); if (card != null) { controller.putOntoBattlefieldWithInfo(card, game, Zone.HAND, source.getControllerId()); diff --git a/Mage.Sets/src/mage/sets/fifthdawn/Acquire.java b/Mage.Sets/src/mage/sets/fifthdawn/Acquire.java index 2ed36891b4a..bae08d67839 100644 --- a/Mage.Sets/src/mage/sets/fifthdawn/Acquire.java +++ b/Mage.Sets/src/mage/sets/fifthdawn/Acquire.java @@ -1,5 +1,6 @@ package mage.sets.fifthdawn; +import java.util.UUID; import mage.abilities.Ability; import mage.abilities.effects.OneShotEffect; import mage.cards.Card; @@ -15,17 +16,15 @@ import mage.players.Player; import mage.target.common.TargetCardInLibrary; import mage.target.common.TargetOpponent; -import java.util.UUID; - /** * @author andyfries */ -public class Acquire extends CardImpl{ +public class Acquire extends CardImpl { + public Acquire(UUID ownerId) { super(ownerId, 21, "Acquire", Rarity.RARE, new CardType[]{CardType.SORCERY}, "{3}{U}{U}"); this.expansionSetCode = "5DN"; - // Search target opponent's library for an artifact card and put that card onto the battlefield under your control. // Then that player shuffles his or her library. this.getSpellAbility().addEffect(new AcquireEffect()); @@ -68,7 +67,7 @@ class AcquireEffect extends OneShotEffect { controller.searchLibrary(target, game, opponent.getId()); Card targetCard = game.getCard(target.getFirstTarget()); if (targetCard != null) { - controller.putOntoBattlefieldWithInfo(targetCard, game, Zone.LIBRARY, source.getSourceId()); + controller.moveCards(targetCard, Zone.BATTLEFIELD, source, game); } opponent.shuffleLibrary(game); return true; @@ -81,4 +80,3 @@ class AcquireEffect extends OneShotEffect { return new AcquireEffect(this); } } - diff --git a/Mage.Sets/src/mage/sets/fifthedition/Kismet.java b/Mage.Sets/src/mage/sets/fifthedition/Kismet.java index 9e327b22775..673526b4b61 100644 --- a/Mage.Sets/src/mage/sets/fifthedition/Kismet.java +++ b/Mage.Sets/src/mage/sets/fifthedition/Kismet.java @@ -79,26 +79,25 @@ class KismetEffect extends ReplacementEffectImpl { @Override public boolean replaceEvent(GameEvent event, Ability source, Game game) { - Permanent target = game.getPermanent(event.getTargetId()); + Permanent target = game.getPermanentEntering(event.getTargetId()); if (target != null) { target.setTapped(true); } return false; } - @Override public boolean checksEventType(GameEvent event, Game game) { return event.getType() == EventType.ENTERS_THE_BATTLEFIELD; } - + @Override public boolean applies(GameEvent event, Ability source, Game game) { if (game.getOpponents(source.getControllerId()).contains(event.getPlayerId())) { Permanent permanent = game.getPermanent(event.getTargetId()); - if (permanent != null && (permanent.getCardType().contains(CardType.ARTIFACT) || - permanent.getCardType().contains(CardType.CREATURE) || - permanent.getCardType().contains(CardType.LAND))) { + if (permanent != null && (permanent.getCardType().contains(CardType.ARTIFACT) + || permanent.getCardType().contains(CardType.CREATURE) + || permanent.getCardType().contains(CardType.LAND))) { return true; } } diff --git a/Mage.Sets/src/mage/sets/fifthedition/PrimalClay.java b/Mage.Sets/src/mage/sets/fifthedition/PrimalClay.java index 561def505a0..998dd517b31 100644 --- a/Mage.Sets/src/mage/sets/fifthedition/PrimalClay.java +++ b/Mage.Sets/src/mage/sets/fifthedition/PrimalClay.java @@ -65,7 +65,7 @@ public class PrimalClay extends CardImpl { this.toughness = new MageInt(0); // As Primal Clay enters the battlefield, it becomes your choice of a 3/3 artifact creature, a 2/2 artifact creature with flying, or a 1/6 Wall artifact creature with defender in addition to its other types. - this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new PrimalPlasmaReplacementEffect())); + this.addAbility(new SimpleStaticAbility(Zone.ALL, new PrimalPlasmaReplacementEffect())); } public PrimalClay(final PrimalClay card) { @@ -101,7 +101,7 @@ class PrimalPlasmaReplacementEffect extends ReplacementEffectImpl { @Override public boolean applies(GameEvent event, Ability source, Game game) { if (event.getTargetId().equals(source.getSourceId())) { - Permanent sourcePermanent = game.getPermanent(source.getSourceId()); + Permanent sourcePermanent = game.getPermanentEntering(event.getTargetId()); if (sourcePermanent != null && !sourcePermanent.isFaceDown(game)) { return true; } @@ -116,7 +116,7 @@ class PrimalPlasmaReplacementEffect extends ReplacementEffectImpl { @Override public boolean replaceEvent(GameEvent event, Ability source, Game game) { - Permanent permanent = game.getPermanent(source.getSourceId()); + Permanent permanent = game.getPermanentEntering(event.getTargetId()); if (permanent != null) { Choice choice = new ChoiceImpl(true); choice.setMessage("Choose what " + permanent.getIdName() + " becomes to"); diff --git a/Mage.Sets/src/mage/sets/futuresight/CloudKey.java b/Mage.Sets/src/mage/sets/futuresight/CloudKey.java index 33e946d9393..b357c8b83f1 100644 --- a/Mage.Sets/src/mage/sets/futuresight/CloudKey.java +++ b/Mage.Sets/src/mage/sets/futuresight/CloudKey.java @@ -11,7 +11,6 @@ import mage.abilities.Ability; import mage.abilities.SpellAbility; import mage.abilities.common.AsEntersBattlefieldAbility; import mage.abilities.common.SimpleStaticAbility; -import mage.abilities.effects.EntersBattlefieldEffect; import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.cost.CostModificationEffectImpl; import mage.cards.Card; @@ -75,7 +74,7 @@ class CloudKeyChooseTypeEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { Player controller = game.getPlayer(source.getControllerId()); - MageObject mageObject = (Permanent) getValue(EntersBattlefieldEffect.ENTERING_PERMANENT); + MageObject mageObject = game.getPermanentEntering(source.getSourceId()); if (mageObject == null) { mageObject = game.getObject(source.getSourceId()); } diff --git a/Mage.Sets/src/mage/sets/futuresight/KavuPrimarch.java b/Mage.Sets/src/mage/sets/futuresight/KavuPrimarch.java index deca054ff68..c9055368a95 100644 --- a/Mage.Sets/src/mage/sets/futuresight/KavuPrimarch.java +++ b/Mage.Sets/src/mage/sets/futuresight/KavuPrimarch.java @@ -61,7 +61,7 @@ public class KavuPrimarch extends CardImpl { // If Kavu Primarch was kicked, it enters the battlefield with four +1/+1 counters on it. - this.addAbility(new EntersBattlefieldAbility(new AddCountersSourceEffect(CounterType.P1P1.createInstance(4)),KickedCondition.getInstance(), true, + this.addAbility(new EntersBattlefieldAbility(new AddCountersSourceEffect(CounterType.P1P1.createInstance(4)),KickedCondition.getInstance(), "If Kavu Primarch was kicked, it enters the battlefield with four +1/+1 counters on it.", "")); } diff --git a/Mage.Sets/src/mage/sets/futuresight/RavagingRiftwurm.java b/Mage.Sets/src/mage/sets/futuresight/RavagingRiftwurm.java index 30c9a66fcf0..a1f6e59f044 100644 --- a/Mage.Sets/src/mage/sets/futuresight/RavagingRiftwurm.java +++ b/Mage.Sets/src/mage/sets/futuresight/RavagingRiftwurm.java @@ -64,7 +64,7 @@ public class RavagingRiftwurm extends CardImpl { this.addAbility(new VanishingSacrificeAbility()); // If Ravaging Riftwurm was kicked, it enters the battlefield with three additional time counters on it. this.addAbility(new EntersBattlefieldAbility(new AddCountersSourceEffect(CounterType.TIME.createInstance(3)), - KickedCondition.getInstance(), true, "If {this} was kicked, it enters the battlefield with three additional time counters on it.", "")); + KickedCondition.getInstance(), "If {this} was kicked, it enters the battlefield with three additional time counters on it.", "")); } public RavagingRiftwurm(final RavagingRiftwurm card) { diff --git a/Mage.Sets/src/mage/sets/gameday/ScaleguardSentinels.java b/Mage.Sets/src/mage/sets/gameday/ScaleguardSentinels.java index 5167e1c6d68..27985e968f3 100644 --- a/Mage.Sets/src/mage/sets/gameday/ScaleguardSentinels.java +++ b/Mage.Sets/src/mage/sets/gameday/ScaleguardSentinels.java @@ -73,7 +73,7 @@ public class ScaleguardSentinels extends CardImpl { // Scaleguard Sentinels enters the battlefield with a +1/+1 counter on it if you revealed a Dragon card or controlled a Dragon as you cast Scaleguard Sentinels. this.addAbility(new EntersBattlefieldAbility(new AddCountersSourceEffect(CounterType.P1P1.createInstance(), true), - ScaleguardSentinelsCondition.getInstance(), true, + ScaleguardSentinelsCondition.getInstance(), "{this} enters the battlefield with a +1/+1 counter on it if you revealed a Dragon card or controlled a Dragon as you cast {this}", ""), new DragonOnTheBattlefieldWhileSpellWasCastWatcher()); diff --git a/Mage.Sets/src/mage/sets/gatecrash/BlindObedience.java b/Mage.Sets/src/mage/sets/gatecrash/BlindObedience.java index 3bc36d45269..537b7304668 100644 --- a/Mage.Sets/src/mage/sets/gatecrash/BlindObedience.java +++ b/Mage.Sets/src/mage/sets/gatecrash/BlindObedience.java @@ -28,16 +28,16 @@ package mage.sets.gatecrash; 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.common.SimpleStaticAbility; import mage.abilities.effects.ReplacementEffectImpl; import mage.abilities.keyword.ExtortAbility; import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.Outcome; +import mage.constants.Rarity; +import mage.constants.Zone; import mage.game.Game; import mage.game.events.GameEvent; import mage.game.permanent.Permanent; @@ -52,7 +52,6 @@ public class BlindObedience extends CardImpl { super(ownerId, 6, "Blind Obedience", Rarity.RARE, new CardType[]{CardType.ENCHANTMENT}, "{1}{W}"); this.expansionSetCode = "GTC"; - // Extort (Whenever you cast a spell, you may pay {WB}. If you do, each opponent loses 1 life and you gain that much life.) this.addAbility(new ExtortAbility()); @@ -72,6 +71,7 @@ public class BlindObedience extends CardImpl { } class BlindObedienceTapEffect extends ReplacementEffectImpl { + BlindObedienceTapEffect() { super(Duration.WhileOnBattlefield, Outcome.Tap); staticText = "Artifacts and creatures your opponents control enter the battlefield tapped"; @@ -83,22 +83,22 @@ class BlindObedienceTapEffect extends ReplacementEffectImpl { @Override public boolean replaceEvent(GameEvent event, Ability source, Game game) { - Permanent target = game.getPermanent(event.getTargetId()); + Permanent target = game.getPermanentEntering(event.getTargetId()); if (target != null) { target.setTapped(true); } return false; } - + @Override public boolean checksEventType(GameEvent event, Game game) { return event.getType() == GameEvent.EventType.ENTERS_THE_BATTLEFIELD; } - + @Override public boolean applies(GameEvent event, Ability source, Game game) { if (game.getOpponents(source.getControllerId()).contains(event.getPlayerId())) { - Permanent permanent = game.getPermanent(event.getTargetId()); + Permanent permanent = game.getPermanentEntering(event.getTargetId()); if (permanent != null && (permanent.getCardType().contains(CardType.CREATURE) || permanent.getCardType().contains(CardType.ARTIFACT))) { return true; } diff --git a/Mage.Sets/src/mage/sets/gatecrash/DomriRade.java b/Mage.Sets/src/mage/sets/gatecrash/DomriRade.java index 0d92cdf0bac..cf84a981cc3 100644 --- a/Mage.Sets/src/mage/sets/gatecrash/DomriRade.java +++ b/Mage.Sets/src/mage/sets/gatecrash/DomriRade.java @@ -31,13 +31,12 @@ import java.util.UUID; import mage.MageObject; import mage.abilities.Ability; import mage.abilities.LoyaltyAbility; -import mage.abilities.common.EntersBattlefieldAbility; +import mage.abilities.common.PlanswalkerEntersWithLoyalityCountersAbility; import mage.abilities.common.SimpleStaticAbility; import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.FightTargetsEffect; import mage.abilities.effects.common.GetEmblemEffect; import mage.abilities.effects.common.continuous.GainAbilityControlledEffect; -import mage.abilities.effects.common.counter.AddCountersSourceEffect; import mage.abilities.keyword.DoubleStrikeAbility; import mage.abilities.keyword.HasteAbility; import mage.abilities.keyword.HexproofAbility; @@ -50,7 +49,6 @@ import mage.constants.Duration; import mage.constants.Outcome; import mage.constants.Rarity; import mage.constants.Zone; -import mage.counters.CounterType; import mage.filter.FilterPermanent; import mage.filter.common.FilterControlledCreaturePermanent; import mage.game.Game; @@ -70,7 +68,7 @@ public class DomriRade extends CardImpl { this.expansionSetCode = "GTC"; this.subtype.add("Domri"); - this.addAbility(new EntersBattlefieldAbility(new AddCountersSourceEffect(CounterType.LOYALTY.createInstance(3)), false)); + this.addAbility(new PlanswalkerEntersWithLoyalityCountersAbility(3)); // +1: Look at the top card of your library. If it's a creature card, you may reveal it and put it into your hand. this.addAbility(new LoyaltyAbility(new DomriRadeEffect1(), 1)); @@ -138,7 +136,6 @@ class DomriRadeEffect1 extends OneShotEffect { class DomriRadeEmblem extends Emblem { // "Creatures you control have double strike, trample, hexproof and haste." - public DomriRadeEmblem() { this.setName("EMBLEM: Domri Rade"); FilterPermanent filter = new FilterControlledCreaturePermanent("Creatures"); diff --git a/Mage.Sets/src/mage/sets/gatecrash/FathomMage.java b/Mage.Sets/src/mage/sets/gatecrash/FathomMage.java index 67f67d0d830..5f125a6fec3 100644 --- a/Mage.Sets/src/mage/sets/gatecrash/FathomMage.java +++ b/Mage.Sets/src/mage/sets/gatecrash/FathomMage.java @@ -1,5 +1,5 @@ /* -/* + /* * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, are @@ -60,7 +60,7 @@ public class FathomMage extends CardImpl { // Evolve (Whenever a creature enters the battlefield under your control, if that creature // has greater power or toughness than this creature, put a +1/+1 counter on this creature.) this.addAbility(new EvolveAbility()); - + //Whenever a +1/+1 counter is placed on Fathom Mage, you may draw a card. this.addAbility(new FathomMageTriggeredAbility()); } @@ -75,11 +75,10 @@ public class FathomMage extends CardImpl { } } - class FathomMageTriggeredAbility extends TriggeredAbilityImpl { public FathomMageTriggeredAbility() { - super(Zone.BATTLEFIELD, new DrawCardSourceControllerEffect(1), true); + super(Zone.ALL, new DrawCardSourceControllerEffect(1), true); } public FathomMageTriggeredAbility(FathomMageTriggeredAbility ability) { diff --git a/Mage.Sets/src/mage/sets/gatecrash/GideonChampionOfJustice.java b/Mage.Sets/src/mage/sets/gatecrash/GideonChampionOfJustice.java index 60ce90daeed..9467a3ccfcc 100644 --- a/Mage.Sets/src/mage/sets/gatecrash/GideonChampionOfJustice.java +++ b/Mage.Sets/src/mage/sets/gatecrash/GideonChampionOfJustice.java @@ -27,10 +27,11 @@ */ package mage.sets.gatecrash; +import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.LoyaltyAbility; -import mage.abilities.common.EntersBattlefieldAbility; +import mage.abilities.common.PlanswalkerEntersWithLoyalityCountersAbility; import mage.abilities.common.SimpleStaticAbility; import mage.abilities.dynamicvalue.common.CountersCount; import mage.abilities.dynamicvalue.common.PermanentsTargetOpponentControlsCount; @@ -41,7 +42,11 @@ import mage.abilities.effects.common.continuous.SetPowerToughnessSourceEffect; import mage.abilities.effects.common.counter.AddCountersSourceEffect; import mage.abilities.keyword.IndestructibleAbility; import mage.cards.CardImpl; -import mage.constants.*; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.Outcome; +import mage.constants.Rarity; +import mage.constants.Zone; import mage.counters.CounterType; import mage.filter.common.FilterCreaturePermanent; import mage.game.Game; @@ -49,8 +54,6 @@ import mage.game.permanent.Permanent; import mage.game.permanent.token.Token; import mage.target.common.TargetOpponent; -import java.util.UUID; - /** * * @author LevelX2 @@ -62,7 +65,7 @@ public class GideonChampionOfJustice extends CardImpl { this.expansionSetCode = "GTC"; this.subtype.add("Gideon"); - this.addAbility(new EntersBattlefieldAbility(new AddCountersSourceEffect(CounterType.LOYALTY.createInstance(4)), false)); + this.addAbility(new PlanswalkerEntersWithLoyalityCountersAbility(4)); // +1: Put a loyalty counter on Gideon, Champion of Justice for each creature target opponent controls. LoyaltyAbility ability1 = new LoyaltyAbility( diff --git a/Mage.Sets/src/mage/sets/gatecrash/MasterBiomancer.java b/Mage.Sets/src/mage/sets/gatecrash/MasterBiomancer.java index eeb0b6346dd..0052145c333 100644 --- a/Mage.Sets/src/mage/sets/gatecrash/MasterBiomancer.java +++ b/Mage.Sets/src/mage/sets/gatecrash/MasterBiomancer.java @@ -1,30 +1,30 @@ /* -* Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. -* -* Redistribution and use in source and binary forms, with or without modification, are -* permitted provided that the following conditions are met: -* -* 1. Redistributions of source code must retain the above copyright notice, this list of -* conditions and the following disclaimer. -* -* 2. Redistributions in binary form must reproduce the above copyright notice, this list -* of conditions and the following disclaimer in the documentation and/or other materials -* provided with the distribution. -* -* THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED -* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND -* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR -* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR -* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON -* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING -* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF -* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -* -* The views and conclusions contained in the software and documentation are those of the -* authors and should not be interpreted as representing official policies, either expressed -* or implied, of BetaSteward_at_googlemail.com. -*/ + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ package mage.sets.gatecrash; import java.util.UUID; @@ -48,31 +48,31 @@ import mage.game.permanent.Permanent; import mage.target.targetpointer.FixedTarget; /** -* -* @author LevelX2 -*/ + * + * @author LevelX2 + */ public class MasterBiomancer extends CardImpl { public MasterBiomancer(UUID ownerId) { - super(ownerId, 176, "Master Biomancer", Rarity.MYTHIC, new CardType[]{CardType.CREATURE}, "{2}{G}{U}"); - this.expansionSetCode = "GTC"; - this.subtype.add("Elf"); - this.subtype.add("Wizard"); + super(ownerId, 176, "Master Biomancer", Rarity.MYTHIC, new CardType[]{CardType.CREATURE}, "{2}{G}{U}"); + this.expansionSetCode = "GTC"; + this.subtype.add("Elf"); + this.subtype.add("Wizard"); - this.power = new MageInt(2); - this.toughness = new MageInt(4); + this.power = new MageInt(2); + this.toughness = new MageInt(4); - // Each other creature you control enters the battlefield with a number of additional +1/+1 counters on it equal to Master Biomancer's power and as a Mutant in addition to its other types. - this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new MasterBiomancerEntersBattlefieldEffect())); + // Each other creature you control enters the battlefield with a number of additional +1/+1 counters on it equal to Master Biomancer's power and as a Mutant in addition to its other types. + this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new MasterBiomancerEntersBattlefieldEffect())); } public MasterBiomancer(final MasterBiomancer card) { - super(card); + super(card); } @Override public MasterBiomancer copy() { - return new MasterBiomancer(this); + return new MasterBiomancer(this); } } @@ -86,16 +86,16 @@ class MasterBiomancerEntersBattlefieldEffect extends ReplacementEffectImpl { public MasterBiomancerEntersBattlefieldEffect(MasterBiomancerEntersBattlefieldEffect effect) { super(effect); } - + @Override public boolean checksEventType(GameEvent event, Game game) { return event.getType() == EventType.ENTERS_THE_BATTLEFIELD; } - + @Override public boolean applies(GameEvent event, Ability source, Game game) { - Permanent creature = game.getPermanent(event.getTargetId()); - return creature != null && creature.getControllerId().equals(source.getControllerId()) + Permanent creature = game.getPermanentEntering(event.getTargetId()); + return creature != null && creature.getControllerId().equals(source.getControllerId()) && creature.getCardType().contains(CardType.CREATURE) && !event.getTargetId().equals(source.getSourceId()); } @@ -103,7 +103,7 @@ class MasterBiomancerEntersBattlefieldEffect extends ReplacementEffectImpl { @Override public boolean replaceEvent(GameEvent event, Ability source, Game game) { Permanent sourceCreature = game.getPermanent(source.getSourceId()); - Permanent creature = game.getPermanent(event.getTargetId()); + Permanent creature = game.getPermanentEntering(event.getTargetId()); if (sourceCreature != null && creature != null) { int power = sourceCreature.getPower().getValue(); if (power > 0) { @@ -116,7 +116,6 @@ class MasterBiomancerEntersBattlefieldEffect extends ReplacementEffectImpl { return false; } - @Override public MasterBiomancerEntersBattlefieldEffect copy() { return new MasterBiomancerEntersBattlefieldEffect(this); diff --git a/Mage.Sets/src/mage/sets/gatecrash/ZameckGuildmage.java b/Mage.Sets/src/mage/sets/gatecrash/ZameckGuildmage.java index 48c906b6fec..cf831b2939c 100644 --- a/Mage.Sets/src/mage/sets/gatecrash/ZameckGuildmage.java +++ b/Mage.Sets/src/mage/sets/gatecrash/ZameckGuildmage.java @@ -28,29 +28,24 @@ package mage.sets.gatecrash; 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.Mode; import mage.abilities.common.SimpleActivatedAbility; import mage.abilities.costs.common.RemoveCounterCost; import mage.abilities.costs.mana.ManaCostsImpl; -import mage.abilities.effects.Effect; -import mage.abilities.effects.Effects; import mage.abilities.effects.ReplacementEffectImpl; import mage.abilities.effects.common.DrawCardSourceControllerEffect; -import mage.abilities.effects.common.counter.AddCountersTargetEffect; import mage.cards.CardImpl; +import mage.constants.CardType; import mage.constants.Duration; +import mage.constants.Outcome; +import mage.constants.Rarity; +import mage.constants.Zone; import mage.counters.CounterType; import mage.game.Game; import mage.game.events.GameEvent; import mage.game.permanent.Permanent; import mage.target.common.TargetControlledCreaturePermanent; -import mage.target.targetpointer.FixedTarget; /** * @@ -58,8 +53,6 @@ import mage.target.targetpointer.FixedTarget; */ public class ZameckGuildmage extends CardImpl { - private static final String ruleText = "This turn, each creature you control enters the battlefield with an additional +1/+1 counter on it"; - public ZameckGuildmage(UUID ownerId) { super(ownerId, 209, "Zameck Guildmage", Rarity.UNCOMMON, new CardType[]{CardType.CREATURE}, "{G}{U}"); this.expansionSetCode = "GTC"; @@ -69,9 +62,8 @@ public class ZameckGuildmage extends CardImpl { this.power = new MageInt(2); this.toughness = new MageInt(2); - // {G}{U}: This turn, each creature you control enters the battlefield with an additional +1/+1 counter on it. - this.addAbility(new SimpleActivatedAbility(Zone.BATTLEFIELD, new EntersBattlefieldEffect(new AddCountersTargetEffect(CounterType.P1P1.createInstance(1)), ruleText), new ManaCostsImpl("{G}{U}"))); + this.addAbility(new SimpleActivatedAbility(Zone.ALL, new ZameckGuildmageEntersBattlefieldEffect(), new ManaCostsImpl("{G}{U}"))); // {G}{U}, Remove a +1/+1 counter from a creature you control: Draw a card. Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new DrawCardSourceControllerEffect(1), new ManaCostsImpl("{G}{U}")); @@ -89,25 +81,15 @@ public class ZameckGuildmage extends CardImpl { } } -class EntersBattlefieldEffect extends ReplacementEffectImpl { +class ZameckGuildmageEntersBattlefieldEffect extends ReplacementEffectImpl { - protected Effects baseEffects = new Effects(); - protected String text; - - public EntersBattlefieldEffect(Effect baseEffect, String text) { - super(Duration.EndOfTurn, baseEffect.getOutcome()); - this.baseEffects.add(baseEffect); - this.text = text; + public ZameckGuildmageEntersBattlefieldEffect() { + super(Duration.EndOfTurn, Outcome.BoostCreature); + this.staticText = "This turn, each creature you control enters the battlefield with an additional +1/+1 counter on it"; } - public EntersBattlefieldEffect(EntersBattlefieldEffect effect) { + public ZameckGuildmageEntersBattlefieldEffect(ZameckGuildmageEntersBattlefieldEffect effect) { super(effect); - this.baseEffects = effect.baseEffects.copy(); - this.text = effect.text; - } - - public void addEffect(Effect effect) { - baseEffects.add(effect); } @Override @@ -117,11 +99,8 @@ class EntersBattlefieldEffect extends ReplacementEffectImpl { @Override public boolean applies(GameEvent event, Ability source, Game game) { - Permanent permanent = game.getPermanent(event.getTargetId()); - if (permanent != null && permanent.getControllerId().equals(source.getControllerId()) && permanent.getCardType().contains(CardType.CREATURE)) { - return true; - } - return false; + Permanent permanent = game.getPermanentEntering(event.getTargetId()); + return permanent != null && permanent.getControllerId().equals(source.getControllerId()) && permanent.getCardType().contains(CardType.CREATURE); } @Override @@ -131,23 +110,15 @@ class EntersBattlefieldEffect extends ReplacementEffectImpl { @Override public boolean replaceEvent(GameEvent event, Ability source, Game game) { - for (Effect effect: baseEffects) { - Permanent target = game.getPermanent(event.getTargetId()); - if (target != null) { - effect.setTargetPointer(new FixedTarget(target.getId())); - effect.apply(game, source); - } + Permanent target = game.getPermanentEntering(event.getTargetId()); + if (target != null) { + target.addCounters(CounterType.P1P1.createInstance(), game); } return false; } @Override - public String getText(Mode mode) { - return (text == null || text.isEmpty()) ? baseEffects.getText(mode) : text; - } - - @Override - public EntersBattlefieldEffect copy() { - return new EntersBattlefieldEffect(this); + public ZameckGuildmageEntersBattlefieldEffect copy() { + return new ZameckGuildmageEntersBattlefieldEffect(this); } } diff --git a/Mage.Sets/src/mage/sets/innistrad/DearlyDeparted.java b/Mage.Sets/src/mage/sets/innistrad/DearlyDeparted.java index 4a1345a52c9..71d69e1ebc2 100644 --- a/Mage.Sets/src/mage/sets/innistrad/DearlyDeparted.java +++ b/Mage.Sets/src/mage/sets/innistrad/DearlyDeparted.java @@ -27,39 +27,29 @@ */ package mage.sets.innistrad; - -import mage.constants.CardType; -import mage.constants.Rarity; +import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; -import mage.abilities.Mode; import mage.abilities.common.SimpleStaticAbility; -import mage.abilities.effects.ContinuousEffect; -import mage.abilities.effects.Effect; -import mage.abilities.effects.Effects; import mage.abilities.effects.ReplacementEffectImpl; -import mage.abilities.effects.common.counter.AddCountersTargetEffect; import mage.abilities.keyword.FlyingAbility; import mage.cards.CardImpl; +import mage.constants.CardType; import mage.constants.Duration; +import mage.constants.Outcome; +import mage.constants.Rarity; import mage.constants.Zone; import mage.counters.CounterType; import mage.game.Game; import mage.game.events.GameEvent; -import mage.game.permanent.Permanent; -import mage.game.stack.Spell; -import mage.target.targetpointer.FixedTarget; - -import java.util.UUID; import mage.game.events.GameEvent.EventType; +import mage.game.permanent.Permanent; /** * @author nantuko */ public class DearlyDeparted extends CardImpl { - private static final String ruleText = "As long as {this} is in your graveyard, each Human creature you control enters the battlefield with an additional +1/+1 counter on it"; - public DearlyDeparted(UUID ownerId) { super(ownerId, 9, "Dearly Departed", Rarity.RARE, new CardType[]{CardType.CREATURE}, "{4}{W}{W}"); this.expansionSetCode = "ISD"; @@ -71,8 +61,7 @@ public class DearlyDeparted extends CardImpl { this.addAbility(FlyingAbility.getInstance()); // As long as Dearly Departed is in your graveyard, each Human creature you control enters the battlefield with an additional +1/+1 counter on it. - this.addAbility(new SimpleStaticAbility(Zone.GRAVEYARD, - new EntersBattlefieldEffect(new AddCountersTargetEffect(CounterType.P1P1.createInstance(1)), ruleText))); + this.addAbility(new SimpleStaticAbility(Zone.GRAVEYARD, new DearlyDepartedEntersBattlefieldEffect())); } public DearlyDeparted(final DearlyDeparted card) { @@ -85,43 +74,26 @@ public class DearlyDeparted extends CardImpl { } } -class EntersBattlefieldEffect extends ReplacementEffectImpl { +class DearlyDepartedEntersBattlefieldEffect extends ReplacementEffectImpl { - protected Effects baseEffects = new Effects(); - protected String text; - - public static final String SOURCE_CAST_SPELL_ABILITY = "sourceCastSpellAbility"; - - public EntersBattlefieldEffect(Effect baseEffect) { - this(baseEffect, ""); + public DearlyDepartedEntersBattlefieldEffect() { + super(Duration.OneUse, Outcome.BoostCreature); + staticText = "As long as {this} is in your graveyard, each Human creature you control enters the battlefield with an additional +1/+1 counter on it"; } - public EntersBattlefieldEffect(Effect baseEffect, String text) { - super(Duration.OneUse, baseEffect.getOutcome()); - this.baseEffects.add(baseEffect); - this.text = text; - } - - public EntersBattlefieldEffect(EntersBattlefieldEffect effect) { + public DearlyDepartedEntersBattlefieldEffect(DearlyDepartedEntersBattlefieldEffect effect) { super(effect); - this.baseEffects = effect.baseEffects.copy(); - this.text = effect.text; } - public void addEffect(Effect effect) { - baseEffects.add(effect); - } - @Override public boolean checksEventType(GameEvent event, Game game) { return event.getType() == EventType.ENTERS_THE_BATTLEFIELD; } - + @Override public boolean applies(GameEvent event, Ability source, Game game) { - Permanent permanent = game.getPermanent(event.getTargetId()); + Permanent permanent = game.getPermanentEntering(event.getTargetId()); if (permanent != null && permanent.getControllerId().equals(source.getControllerId()) && permanent.hasSubtype("Human")) { - setValue("target", permanent); return true; } return false; @@ -129,33 +101,16 @@ class EntersBattlefieldEffect extends ReplacementEffectImpl { @Override public boolean replaceEvent(GameEvent event, Ability source, Game game) { - Spell spell = game.getStack().getSpell(event.getSourceId()); - for (Effect effect: baseEffects) { - Object target = getValue("target"); - if (target != null && target instanceof Permanent) { - effect.setTargetPointer(new FixedTarget(((Permanent)target).getId())); - if (effect instanceof ContinuousEffect) { - game.addEffect((ContinuousEffect) effect, source); - } - else { - if (spell != null) { - effect.setValue(SOURCE_CAST_SPELL_ABILITY, spell.getSpellAbility()); - } - effect.apply(game, source); - } - } + Permanent target = game.getPermanentEntering(event.getTargetId()); + if (target != null) { + target.addCounters(CounterType.P1P1.createInstance(), game); } return false; } @Override - public String getText(Mode mode) { - return (text == null || text.isEmpty()) ? baseEffects.getText(mode) : text; - } - - @Override - public EntersBattlefieldEffect copy() { - return new EntersBattlefieldEffect(this); + public DearlyDepartedEntersBattlefieldEffect copy() { + return new DearlyDepartedEntersBattlefieldEffect(this); } } diff --git a/Mage.Sets/src/mage/sets/innistrad/EssenceOfTheWild.java b/Mage.Sets/src/mage/sets/innistrad/EssenceOfTheWild.java index 657f77a94c3..1e5aebd4ea2 100644 --- a/Mage.Sets/src/mage/sets/innistrad/EssenceOfTheWild.java +++ b/Mage.Sets/src/mage/sets/innistrad/EssenceOfTheWild.java @@ -28,19 +28,17 @@ package mage.sets.innistrad; import java.util.UUID; -import mage.constants.CardType; -import mage.constants.Duration; -import mage.constants.Layer; -import mage.constants.Outcome; -import mage.constants.Rarity; -import mage.constants.SubLayer; -import mage.constants.Zone; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.SimpleStaticAbility; -import mage.abilities.effects.ContinuousEffectImpl; import mage.abilities.effects.ReplacementEffectImpl; +import mage.abilities.effects.common.CopyEffect; import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.Outcome; +import mage.constants.Rarity; +import mage.constants.Zone; import mage.game.Game; import mage.game.events.GameEvent; import mage.game.events.GameEvent.EventType; @@ -89,21 +87,18 @@ class EssenceOfTheWildEffect extends ReplacementEffectImpl { public boolean checksEventType(GameEvent event, Game game) { return event.getType() == EventType.ENTERS_THE_BATTLEFIELD; } - + @Override public boolean applies(GameEvent event, Ability source, Game game) { - Permanent perm = game.getPermanent(event.getTargetId()); + Permanent perm = game.getPermanentEntering(event.getTargetId()); return perm != null && perm.getCardType().contains(CardType.CREATURE) && perm.getControllerId().equals(source.getControllerId()); } - + @Override public boolean replaceEvent(GameEvent event, Ability source, Game game) { - Permanent perm = game.getPermanent(source.getSourceId()); - if (perm != null) { - perm = perm.copy(); - perm.reset(game); - perm.assignNewId(); - game.addEffect(new EssenceOfTheWildCopyEffect(perm, event.getTargetId()), source); + Permanent sourceObject = game.getPermanent(source.getSourceId()); + if (sourceObject != null) { + game.addEffect(new CopyEffect(Duration.Custom, sourceObject, event.getTargetId()), source); } return false; } @@ -114,59 +109,3 @@ class EssenceOfTheWildEffect extends ReplacementEffectImpl { } } - -class EssenceOfTheWildCopyEffect extends ContinuousEffectImpl { - - private final Permanent essence; - private final UUID targetId; - - public EssenceOfTheWildCopyEffect(Permanent essence, UUID targetId) { - super(Duration.EndOfGame, Layer.CopyEffects_1, SubLayer.NA, Outcome.BecomeCreature); - this.essence = essence; - this.targetId = targetId; - } - - public EssenceOfTheWildCopyEffect(final EssenceOfTheWildCopyEffect effect) { - super(effect); - this.essence = effect.essence.copy(); - this.targetId = effect.targetId; - } - - @Override - public boolean apply(Game game, Ability source) { - Permanent permanent = game.getPermanent(targetId); - if (permanent != null) { - permanent.setName(essence.getName()); - permanent.getColor(game).setColor(essence.getColor(game)); - permanent.getManaCost().clear(); - permanent.getManaCost().add(essence.getManaCost()); - permanent.getCardType().clear(); - for (CardType type: essence.getCardType()) { - permanent.getCardType().add(type); - } - permanent.getSubtype().clear(); - for (String type: essence.getSubtype()) { - permanent.getSubtype().add(type); - } - permanent.getSupertype().clear(); - for (String type: essence.getSupertype()) { - permanent.getSupertype().add(type); - } - permanent.getAbilities().clear(); - for (Ability ability: essence.getAbilities()) { - permanent.addAbility(ability, game); - } - permanent.getPower().setValue(essence.getPower().getValue()); - permanent.getToughness().setValue(essence.getToughness().getValue()); - - return true; - } - return false; - } - - @Override - public EssenceOfTheWildCopyEffect copy() { - return new EssenceOfTheWildCopyEffect(this); - } - -} diff --git a/Mage.Sets/src/mage/sets/innistrad/EvilTwin.java b/Mage.Sets/src/mage/sets/innistrad/EvilTwin.java index 3cf16f8fbe3..62ec36b5d7e 100644 --- a/Mage.Sets/src/mage/sets/innistrad/EvilTwin.java +++ b/Mage.Sets/src/mage/sets/innistrad/EvilTwin.java @@ -31,11 +31,11 @@ import java.util.UUID; import mage.MageInt; import mage.MageObject; import mage.abilities.Ability; +import mage.abilities.common.EntersBattlefieldAbility; import mage.abilities.common.SimpleActivatedAbility; -import mage.abilities.common.SimpleStaticAbility; import mage.abilities.costs.common.TapSourceCost; import mage.abilities.costs.mana.ManaCostsImpl; -import mage.abilities.effects.EntersBattlefieldEffect; +import mage.abilities.effects.Effect; import mage.abilities.effects.common.CopyPermanentEffect; import mage.abilities.effects.common.DestroyTargetEffect; import mage.cards.CardImpl; @@ -65,11 +65,10 @@ public class EvilTwin extends CardImpl { this.toughness = new MageInt(0); // You may have Evil Twin enter the battlefield as a copy of any creature on the battlefield except it gains "{U}{B}, {T}: Destroy target creature with the same name as this creature." - this.addAbility(new SimpleStaticAbility( - Zone.BATTLEFIELD, - new EntersBattlefieldEffect(new CopyPermanentEffect(new EvilTwinApplyToPermanent()), - "You may have {this} enter the battlefield as a copy of any creature on the battlefield except it gains \"{U}{B}, {T}: Destroy target creature with the same name as this creature\"", - true))); + Effect effect = new CopyPermanentEffect(new FilterCreaturePermanent(), new EvilTwinApplyToPermanent()); + effect.setText("a copy of any creature on the battlefield except it gains \"{U}{B}, {T}: Destroy target creature with the same name as this creature.\""); + this.addAbility(new EntersBattlefieldAbility(effect, true)); + } public EvilTwin(final EvilTwin card) { diff --git a/Mage.Sets/src/mage/sets/innistrad/GarrukRelentless.java b/Mage.Sets/src/mage/sets/innistrad/GarrukRelentless.java index 3d3e258a14b..1f43014bc50 100644 --- a/Mage.Sets/src/mage/sets/innistrad/GarrukRelentless.java +++ b/Mage.Sets/src/mage/sets/innistrad/GarrukRelentless.java @@ -31,11 +31,10 @@ import java.util.UUID; import mage.abilities.Ability; import mage.abilities.LoyaltyAbility; import mage.abilities.TriggeredAbilityImpl; -import mage.abilities.common.EntersBattlefieldAbility; +import mage.abilities.common.PlanswalkerEntersWithLoyalityCountersAbility; import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.CreateTokenEffect; import mage.abilities.effects.common.TransformSourceEffect; -import mage.abilities.effects.common.counter.AddCountersSourceEffect; import mage.abilities.keyword.TransformAbility; import mage.cards.CardImpl; import mage.constants.CardType; @@ -60,11 +59,10 @@ public class GarrukRelentless extends CardImpl { this.expansionSetCode = "ISD"; this.subtype.add("Garruk"); - this.canTransform = true; this.secondSideCard = new GarrukTheVeilCursed(ownerId); - this.addAbility(new EntersBattlefieldAbility(new AddCountersSourceEffect(CounterType.LOYALTY.createInstance(3)), false)); + this.addAbility(new PlanswalkerEntersWithLoyalityCountersAbility(3)); // When Garruk Relentless has two or fewer loyalty counters on him, transform him. this.addAbility(new TransformAbility()); @@ -160,4 +158,4 @@ class GarrukRelentlessDamageEffect extends OneShotEffect { return new GarrukRelentlessDamageEffect(this); } -} \ No newline at end of file +} diff --git a/Mage.Sets/src/mage/sets/innistrad/LilianaOfTheVeil.java b/Mage.Sets/src/mage/sets/innistrad/LilianaOfTheVeil.java index d20fc714ff0..0fea92be5d7 100644 --- a/Mage.Sets/src/mage/sets/innistrad/LilianaOfTheVeil.java +++ b/Mage.Sets/src/mage/sets/innistrad/LilianaOfTheVeil.java @@ -27,18 +27,19 @@ */ package mage.sets.innistrad; +import java.util.ArrayList; +import java.util.List; +import java.util.UUID; +import mage.abilities.Ability; +import mage.abilities.LoyaltyAbility; +import mage.abilities.common.PlanswalkerEntersWithLoyalityCountersAbility; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.SacrificeEffect; +import mage.abilities.effects.common.discard.DiscardEachPlayerEffect; +import mage.cards.CardImpl; import mage.constants.CardType; import mage.constants.Outcome; import mage.constants.Rarity; -import mage.abilities.Ability; -import mage.abilities.LoyaltyAbility; -import mage.abilities.common.EntersBattlefieldAbility; -import mage.abilities.effects.OneShotEffect; -import mage.abilities.effects.common.discard.DiscardEachPlayerEffect; -import mage.abilities.effects.common.SacrificeEffect; -import mage.abilities.effects.common.counter.AddCountersSourceEffect; -import mage.cards.CardImpl; -import mage.counters.CounterType; import mage.filter.FilterPermanent; import mage.filter.common.FilterCreaturePermanent; import mage.game.Game; @@ -47,10 +48,6 @@ import mage.players.Player; import mage.target.TargetPermanent; import mage.target.TargetPlayer; -import java.util.ArrayList; -import java.util.List; -import java.util.UUID; - /** * * @author North @@ -62,17 +59,16 @@ public class LilianaOfTheVeil extends CardImpl { this.expansionSetCode = "ISD"; this.subtype.add("Liliana"); - - this.addAbility(new EntersBattlefieldAbility(new AddCountersSourceEffect(CounterType.LOYALTY.createInstance(3)), false)); + this.addAbility(new PlanswalkerEntersWithLoyalityCountersAbility(3)); // +1: Each player discards a card. this.addAbility(new LoyaltyAbility(new DiscardEachPlayerEffect(), 1)); - + // -2: Target player sacrifices a creature. LoyaltyAbility ability = new LoyaltyAbility(new SacrificeEffect(new FilterCreaturePermanent(), 1, "Target player"), -2); ability.addTarget(new TargetPlayer()); this.addAbility(ability); - + // -6: Separate all permanents target player controls into two piles. That player sacrifices all permanents in the pile of his or her choice. ability = new LoyaltyAbility(new LilianaOfTheVeilEffect(), -6); ability.addTarget(new TargetPlayer()); @@ -124,7 +120,7 @@ class LilianaOfTheVeilEffect extends OneShotEffect { } } List pile2 = new ArrayList<>(); - for (Permanent p: game.getBattlefield().getAllActivePermanents(targetPlayer.getId())) { + for (Permanent p : game.getBattlefield().getAllActivePermanents(targetPlayer.getId())) { if (!pile1.contains(p)) { pile2.add(p); } diff --git a/Mage.Sets/src/mage/sets/invasion/AlloyGolem.java b/Mage.Sets/src/mage/sets/invasion/AlloyGolem.java index 92799396ef5..db8e522dc02 100644 --- a/Mage.Sets/src/mage/sets/invasion/AlloyGolem.java +++ b/Mage.Sets/src/mage/sets/invasion/AlloyGolem.java @@ -53,7 +53,7 @@ public class AlloyGolem extends CardImpl { // As Alloy Golem enters the battlefield, choose a color. // Alloy Golem is the chosen color. this.addAbility(new EntersBattlefieldAbility(new BecomesColorSourceEffect(Duration.WhileOnBattlefield), - null, true, "As {this} enters the battlefield, choose a color.\n{this} is the chosen color.", "")); + null, "As {this} enters the battlefield, choose a color.\n{this} is the chosen color.", "")); } public AlloyGolem(final AlloyGolem card) { diff --git a/Mage.Sets/src/mage/sets/invasion/ArdentSoldier.java b/Mage.Sets/src/mage/sets/invasion/ArdentSoldier.java index 8fb23c7cc30..eee53175131 100644 --- a/Mage.Sets/src/mage/sets/invasion/ArdentSoldier.java +++ b/Mage.Sets/src/mage/sets/invasion/ArdentSoldier.java @@ -60,7 +60,7 @@ public class ArdentSoldier extends CardImpl { this.addAbility(VigilanceAbility.getInstance()); // If Ardent Soldier was kicked, it enters the battlefield with a +1/+1 counter on it. this.addAbility(new EntersBattlefieldAbility(new AddCountersSourceEffect(CounterType.P1P1.createInstance(1)), - KickedCondition.getInstance(), true, "If {this} was kicked, it enters the battlefield with a +1/+1 counter on it.", "")); + KickedCondition.getInstance(), "If {this} was kicked, it enters the battlefield with a +1/+1 counter on it.", "")); } public ArdentSoldier(final ArdentSoldier card) { diff --git a/Mage.Sets/src/mage/sets/invasion/BenalishLancer.java b/Mage.Sets/src/mage/sets/invasion/BenalishLancer.java index 7fc7d46ab01..cb7bb39c3d8 100644 --- a/Mage.Sets/src/mage/sets/invasion/BenalishLancer.java +++ b/Mage.Sets/src/mage/sets/invasion/BenalishLancer.java @@ -61,7 +61,7 @@ public class BenalishLancer extends CardImpl { // If Benalish Lancer was kicked, it enters the battlefield with two +1/+1 counters on it and with first strike. Ability ability = new EntersBattlefieldAbility(new AddCountersSourceEffect(CounterType.P1P1.createInstance(2)), - KickedCondition.getInstance(), true, + KickedCondition.getInstance(), "If {this} was kicked, it enters the battlefield with two +1/+1 counters on it and with first strike.", ""); ability.addEffect(new GainAbilitySourceEffect(FirstStrikeAbility.getInstance(), Duration.WhileOnBattlefield)); this.addAbility(ability); diff --git a/Mage.Sets/src/mage/sets/invasion/Duskwalker.java b/Mage.Sets/src/mage/sets/invasion/Duskwalker.java index fecf398f9ba..23923ab9284 100644 --- a/Mage.Sets/src/mage/sets/invasion/Duskwalker.java +++ b/Mage.Sets/src/mage/sets/invasion/Duskwalker.java @@ -61,7 +61,7 @@ public class Duskwalker extends CardImpl { // If Duskwalker was kicked, it enters the battlefield with two +1/+1 counters on it and with fear. Ability ability = new EntersBattlefieldAbility(new AddCountersSourceEffect(CounterType.P1P1.createInstance(2)), - KickedCondition.getInstance(), true, + KickedCondition.getInstance(), "If {this} was kicked, it enters the battlefield with two +1/+1 counters on it and with fear.", ""); ability.addEffect(new GainAbilitySourceEffect(FearAbility.getInstance(), Duration.WhileOnBattlefield)); this.addAbility(ability); diff --git a/Mage.Sets/src/mage/sets/invasion/FaerieSquadron.java b/Mage.Sets/src/mage/sets/invasion/FaerieSquadron.java index d463f15af2e..4d36fabfd90 100644 --- a/Mage.Sets/src/mage/sets/invasion/FaerieSquadron.java +++ b/Mage.Sets/src/mage/sets/invasion/FaerieSquadron.java @@ -61,7 +61,7 @@ public class FaerieSquadron extends CardImpl { this.addAbility(new KickerAbility("{3}{U}")); // If Faerie Squadron was kicked, it enters the battlefield with two +1/+1 counters on it and with flying. Ability ability = new EntersBattlefieldAbility(new AddCountersSourceEffect(CounterType.P1P1.createInstance(2)), - KickedCondition.getInstance(), true, "If {this} was kicked, it enters the battlefield with two +1/+1 counters on it and with flying.", ""); + KickedCondition.getInstance(), "If {this} was kicked, it enters the battlefield with two +1/+1 counters on it and with flying.", ""); ability.addEffect(new GainAbilitySourceEffect(FlyingAbility.getInstance(), Duration.WhileOnBattlefield)); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/sets/invasion/KavuAggressor.java b/Mage.Sets/src/mage/sets/invasion/KavuAggressor.java index b0ce21efa99..9b0aaa5aac9 100644 --- a/Mage.Sets/src/mage/sets/invasion/KavuAggressor.java +++ b/Mage.Sets/src/mage/sets/invasion/KavuAggressor.java @@ -59,7 +59,7 @@ public class KavuAggressor extends CardImpl { this.addAbility(new CantBlockAbility()); // If Kavu Aggressor was kicked, it enters the battlefield with a +1/+1 counter on it. this.addAbility(new EntersBattlefieldAbility(new AddCountersSourceEffect(CounterType.P1P1.createInstance(1)), - KickedCondition.getInstance(), true, "If {this} was kicked, it enters the battlefield with a +1/+1 counter on it.", "")); + KickedCondition.getInstance(), "If {this} was kicked, it enters the battlefield with a +1/+1 counter on it.", "")); } public KavuAggressor(final KavuAggressor card) { diff --git a/Mage.Sets/src/mage/sets/invasion/KavuTitan.java b/Mage.Sets/src/mage/sets/invasion/KavuTitan.java index 84a39593671..ed1da4b825d 100644 --- a/Mage.Sets/src/mage/sets/invasion/KavuTitan.java +++ b/Mage.Sets/src/mage/sets/invasion/KavuTitan.java @@ -60,7 +60,7 @@ public class KavuTitan extends CardImpl { this.addAbility(new KickerAbility("{2}{G}")); // If Kavu Titan was kicked, it enters the battlefield with three +1/+1 counters on it and with trample. Ability ability = new EntersBattlefieldAbility(new AddCountersSourceEffect(CounterType.P1P1.createInstance(3)), - KickedCondition.getInstance(), true, + KickedCondition.getInstance(), "If Kavu Titan was kicked, it enters the battlefield with three +1/+1 counters on it and with trample.", ""); ability.addEffect(new GainAbilitySourceEffect(TrampleAbility.getInstance(), Duration.WhileOnBattlefield)); this.addAbility(ability); diff --git a/Mage.Sets/src/mage/sets/invasion/PouncingKavu.java b/Mage.Sets/src/mage/sets/invasion/PouncingKavu.java index 966430d562d..3793017ef35 100644 --- a/Mage.Sets/src/mage/sets/invasion/PouncingKavu.java +++ b/Mage.Sets/src/mage/sets/invasion/PouncingKavu.java @@ -64,7 +64,7 @@ public class PouncingKavu extends CardImpl { this.addAbility(FirstStrikeAbility.getInstance()); // If Pouncing Kavu was kicked, it enters the battlefield with two +1/+1 counters on it and with haste. Ability ability = new EntersBattlefieldAbility(new AddCountersSourceEffect(CounterType.P1P1.createInstance(2)), - KickedCondition.getInstance(), true, "If {this} was kicked, it enters the battlefield with two +1/+1 counters on it and with haste.", ""); + KickedCondition.getInstance(), "If {this} was kicked, it enters the battlefield with two +1/+1 counters on it and with haste.", ""); ability.addEffect(new GainAbilitySourceEffect(HasteAbility.getInstance(), Duration.WhileOnBattlefield)); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/sets/invasion/PrisonBarricade.java b/Mage.Sets/src/mage/sets/invasion/PrisonBarricade.java index e28139b407a..a50a302bef4 100644 --- a/Mage.Sets/src/mage/sets/invasion/PrisonBarricade.java +++ b/Mage.Sets/src/mage/sets/invasion/PrisonBarricade.java @@ -64,7 +64,7 @@ public class PrisonBarricade extends CardImpl { this.addAbility(new KickerAbility("{1}{W}")); // If Prison Barricade was kicked, it enters the battlefield with a +1/+1 counter on it and with "Prison Barricade can attack as though it didn't have defender." Ability ability = new EntersBattlefieldAbility(new AddCountersSourceEffect(CounterType.P1P1.createInstance(1)), - KickedCondition.getInstance(), true, "If {this} was kicked, it enters the battlefield with a +1/+1 counter on it and with \"{this} can attack as though it didn't have defender.\"", ""); + KickedCondition.getInstance(), "If {this} was kicked, it enters the battlefield with a +1/+1 counter on it and with \"{this} can attack as though it didn't have defender.\"", ""); ability.addEffect(new CanAttackAsThoughItDidntHaveDefenderSourceEffect(Duration.WhileOnBattlefield)); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/sets/invasion/UrborgSkeleton.java b/Mage.Sets/src/mage/sets/invasion/UrborgSkeleton.java index 6a5a08663fd..a729cf2c00c 100644 --- a/Mage.Sets/src/mage/sets/invasion/UrborgSkeleton.java +++ b/Mage.Sets/src/mage/sets/invasion/UrborgSkeleton.java @@ -68,7 +68,7 @@ public class UrborgSkeleton extends CardImpl { // If Urborg Skeleton was kicked, it enters the battlefield with a +1/+1 counter on it. Ability ability = new EntersBattlefieldAbility( new AddCountersSourceEffect(CounterType.P1P1.createInstance(1)), - KickedCondition.getInstance(),false, staticText,""); + KickedCondition.getInstance(), staticText,""); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/sets/invasion/VodalianSerpent.java b/Mage.Sets/src/mage/sets/invasion/VodalianSerpent.java index 02703289141..44d4bd6a633 100644 --- a/Mage.Sets/src/mage/sets/invasion/VodalianSerpent.java +++ b/Mage.Sets/src/mage/sets/invasion/VodalianSerpent.java @@ -62,7 +62,7 @@ public class VodalianSerpent extends CardImpl { this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new CantAttackUnlessDefenderControllsPermanent(new FilterLandPermanent("Island", "an Island")))); // If Vodalian Serpent was kicked, it enters the battlefield with four +1/+1 counters on it. this.addAbility(new EntersBattlefieldAbility(new AddCountersSourceEffect(CounterType.P1P1.createInstance(4)), - KickedCondition.getInstance(), true, "If {this} was kicked, it enters the battlefield with four +1/+1 counters on it.", "")); + KickedCondition.getInstance(), "If {this} was kicked, it enters the battlefield with four +1/+1 counters on it.", "")); } public VodalianSerpent(final VodalianSerpent card) { diff --git a/Mage.Sets/src/mage/sets/jacevsvraska/BodyDouble.java b/Mage.Sets/src/mage/sets/jacevsvraska/BodyDouble.java index ef7d31f7976..de36fde3e17 100644 --- a/Mage.Sets/src/mage/sets/jacevsvraska/BodyDouble.java +++ b/Mage.Sets/src/mage/sets/jacevsvraska/BodyDouble.java @@ -30,8 +30,7 @@ package mage.sets.jacevsvraska; import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; -import mage.abilities.common.SimpleStaticAbility; -import mage.abilities.effects.EntersBattlefieldEffect; +import mage.abilities.common.EntersBattlefieldAbility; import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.CopyEffect; import mage.cards.Card; @@ -40,10 +39,8 @@ import mage.constants.CardType; import mage.constants.Duration; import mage.constants.Outcome; import mage.constants.Rarity; -import mage.constants.Zone; import mage.filter.common.FilterCreatureCard; import mage.game.Game; -import mage.game.permanent.Permanent; import mage.players.Player; import mage.target.Target; import mage.target.common.TargetCardInGraveyard; @@ -63,11 +60,7 @@ public class BodyDouble extends CardImpl { this.toughness = new MageInt(0); // You may have Body Double enter the battlefield as a copy of any creature card in a graveyard. - Ability ability = new SimpleStaticAbility(Zone.BATTLEFIELD, new EntersBattlefieldEffect( - new BodyDoubleCopyEffect(), - "You may have {this} enter the battlefield as a copy of any creature card in a graveyard", - true)); - this.addAbility(ability); + this.addAbility(new EntersBattlefieldAbility(new BodyDoubleCopyEffect(), true)); } @@ -85,7 +78,7 @@ class BodyDoubleCopyEffect extends OneShotEffect { public BodyDoubleCopyEffect() { super(Outcome.Copy); - this.staticText = "You may have {this} enter the battlefield as a copy of any creature card in a graveyard"; + this.staticText = "as a copy of any creature card in a graveyard"; } public BodyDoubleCopyEffect(final BodyDoubleCopyEffect effect) { @@ -95,8 +88,7 @@ class BodyDoubleCopyEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { Player player = game.getPlayer(source.getControllerId()); - Permanent sourcePermanent = game.getPermanent(source.getSourceId()); - if (player != null && sourcePermanent != null) { + if (player != null) { Target target = new TargetCardInGraveyard(new FilterCreatureCard("creature card in a graveyard")); target.setNotTarget(true); if (target.canChoose(source.getControllerId(), game)) { diff --git a/Mage.Sets/src/mage/sets/journeyintonyx/AjaniMentorOfHeroes.java b/Mage.Sets/src/mage/sets/journeyintonyx/AjaniMentorOfHeroes.java index 82266793698..2fce108dbb9 100644 --- a/Mage.Sets/src/mage/sets/journeyintonyx/AjaniMentorOfHeroes.java +++ b/Mage.Sets/src/mage/sets/journeyintonyx/AjaniMentorOfHeroes.java @@ -30,11 +30,10 @@ package mage.sets.journeyintonyx; import java.util.UUID; import mage.abilities.Ability; import mage.abilities.LoyaltyAbility; -import mage.abilities.common.EntersBattlefieldAbility; +import mage.abilities.common.PlanswalkerEntersWithLoyalityCountersAbility; import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.GainLifeEffect; import mage.abilities.effects.common.LookLibraryAndPickControllerEffect; -import mage.abilities.effects.common.counter.AddCountersSourceEffect; import mage.cards.CardImpl; import mage.constants.CardType; import mage.constants.Outcome; @@ -62,7 +61,7 @@ public class AjaniMentorOfHeroes extends CardImpl { private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("creatures you control"); private static final FilterCard filterCard = new FilterCard("an Aura, creature, or planeswalker card"); - + static { filter.add(new ControllerPredicate(TargetController.YOU)); filterCard.add(Predicates.or( @@ -70,23 +69,22 @@ public class AjaniMentorOfHeroes extends CardImpl { new CardTypePredicate(CardType.CREATURE), new CardTypePredicate(CardType.PLANESWALKER))); } - + public AjaniMentorOfHeroes(UUID ownerId) { super(ownerId, 145, "Ajani, Mentor of Heroes", Rarity.MYTHIC, new CardType[]{CardType.PLANESWALKER}, "{3}{G}{W}"); this.expansionSetCode = "JOU"; this.subtype.add("Ajani"); - - this.addAbility(new EntersBattlefieldAbility(new AddCountersSourceEffect(CounterType.LOYALTY.createInstance(4)), false)); + this.addAbility(new PlanswalkerEntersWithLoyalityCountersAbility(4)); // +1: Distribute three +1/+1 counters among one, two, or three target creatures you control Ability ability = new LoyaltyAbility(new AjaniMentorOfHeroesAddCountersEffect(), 1); ability.addTarget(new TargetCreaturePermanentAmount(3, filter)); this.addAbility(ability); - + // +1: Look at the top four cards of your library. You may reveal an Aura, creature, or planeswalker card from among them and put that card into your hand. Put the rest on the bottom of your library in any order. - this.addAbility(new LoyaltyAbility(new LookLibraryAndPickControllerEffect(4,1, filterCard,true, false, Zone.HAND, true), 1)); - + this.addAbility(new LoyaltyAbility(new LookLibraryAndPickControllerEffect(4, 1, filterCard, true, false, Zone.HAND, true), 1)); + // -8: You gain 100 life. this.addAbility(new LoyaltyAbility(new GainLifeEffect(100), -8)); } @@ -122,7 +120,7 @@ class AjaniMentorOfHeroesAddCountersEffect extends OneShotEffect { Player controller = game.getPlayer(source.getControllerId()); if (controller != null && source.getTargets().size() > 0) { Target multiTarget = source.getTargets().get(0); - for (UUID target: multiTarget.getTargets()) { + for (UUID target : multiTarget.getTargets()) { Permanent permanent = game.getPermanent(target); if (permanent != null) { permanent.addCounters(CounterType.P1P1.createInstance(multiTarget.getTargetAmount(target)), game); diff --git a/Mage.Sets/src/mage/sets/journeyintonyx/BloodcrazedHoplite.java b/Mage.Sets/src/mage/sets/journeyintonyx/BloodcrazedHoplite.java index c5b745b5894..31e52d06b4a 100644 --- a/Mage.Sets/src/mage/sets/journeyintonyx/BloodcrazedHoplite.java +++ b/Mage.Sets/src/mage/sets/journeyintonyx/BloodcrazedHoplite.java @@ -89,7 +89,7 @@ public class BloodcrazedHoplite extends CardImpl { class BloodcrazedHopliteTriggeredAbility extends TriggeredAbilityImpl { public BloodcrazedHopliteTriggeredAbility() { - super(Zone.BATTLEFIELD, new RemoveCounterTargetEffect(CounterType.P1P1.createInstance()), true); + super(Zone.ALL, new RemoveCounterTargetEffect(CounterType.P1P1.createInstance()), true); } public BloodcrazedHopliteTriggeredAbility(BloodcrazedHopliteTriggeredAbility ability) { diff --git a/Mage.Sets/src/mage/sets/judgment/BalthorTheDefiled.java b/Mage.Sets/src/mage/sets/judgment/BalthorTheDefiled.java index f832cbe3df9..c95149465dd 100644 --- a/Mage.Sets/src/mage/sets/judgment/BalthorTheDefiled.java +++ b/Mage.Sets/src/mage/sets/judgment/BalthorTheDefiled.java @@ -37,8 +37,9 @@ import mage.abilities.costs.common.ExileSourceCost; import mage.abilities.costs.mana.ManaCostsImpl; import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.continuous.BoostAllEffect; -import mage.cards.Card; import mage.cards.CardImpl; +import mage.cards.Cards; +import mage.cards.CardsImpl; import mage.constants.CardType; import mage.constants.Duration; import mage.constants.Outcome; @@ -51,7 +52,6 @@ import mage.filter.predicate.mageobject.ColorPredicate; import mage.game.Game; import mage.players.Player; - /** * * @author LevelX2 @@ -75,7 +75,7 @@ public class BalthorTheDefiled extends CardImpl { Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new BalthorTheDefiledEffect(), new ManaCostsImpl("{B}{B}{B}")); ability.addCost(new ExileSourceCost()); this.addAbility(ability); - + } public BalthorTheDefiled(final BalthorTheDefiled card) { @@ -98,32 +98,32 @@ class BalthorTheDefiledEffect extends OneShotEffect { new ColorPredicate(ObjectColor.RED))); } - public BalthorTheDefiledEffect() { + public BalthorTheDefiledEffect() { super(Outcome.Detriment); this.staticText = "Each player returns all black and all red creature cards from his or her graveyard to the battlefield"; } - public BalthorTheDefiledEffect(final BalthorTheDefiledEffect effect) { + public BalthorTheDefiledEffect(final BalthorTheDefiledEffect effect) { super(effect); } @Override - public BalthorTheDefiledEffect copy() { - return new BalthorTheDefiledEffect(this); + public BalthorTheDefiledEffect copy() { + return new BalthorTheDefiledEffect(this); } @Override public boolean apply(Game game, Ability source) { Player controller = game.getPlayer(source.getControllerId()); if (controller != null) { - for (UUID playerId: controller.getInRange()) { + Cards cardsToReturn = new CardsImpl(); + for (UUID playerId : game.getState().getPlayersInRange(source.getControllerId(), game)) { Player player = game.getPlayer(playerId); if (player != null) { - for (Card card: player.getGraveyard().getCards(filter, source.getSourceId(), source.getControllerId(), game)) { - player.putOntoBattlefieldWithInfo(card, game, Zone.GRAVEYARD, source.getSourceId()); - } + cardsToReturn.addAll(player.getGraveyard().getCards(filter, source.getSourceId(), source.getControllerId(), game)); } } + controller.moveCards(cardsToReturn.getCards(game), Zone.BATTLEFIELD, source, game, false, false, true, null); return true; } return false; diff --git a/Mage.Sets/src/mage/sets/khansoftarkir/CleverImpersonator.java b/Mage.Sets/src/mage/sets/khansoftarkir/CleverImpersonator.java index 87503dfe207..2a058c4e4bf 100644 --- a/Mage.Sets/src/mage/sets/khansoftarkir/CleverImpersonator.java +++ b/Mage.Sets/src/mage/sets/khansoftarkir/CleverImpersonator.java @@ -29,13 +29,11 @@ package mage.sets.khansoftarkir; import java.util.UUID; import mage.MageInt; -import mage.abilities.common.SimpleStaticAbility; -import mage.abilities.effects.EntersBattlefieldEffect; +import mage.abilities.common.EntersBattlefieldAbility; import mage.abilities.effects.common.CopyPermanentEffect; import mage.cards.CardImpl; import mage.constants.CardType; import mage.constants.Rarity; -import mage.constants.Zone; import mage.filter.common.FilterNonlandPermanent; /** @@ -53,10 +51,7 @@ public class CleverImpersonator extends CardImpl { this.toughness = new MageInt(0); // You may have Clever Impersonator enter the battlefield as a copy of any nonland permanent on the battlefield. - this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, - new EntersBattlefieldEffect(new CopyPermanentEffect(new FilterNonlandPermanent()), - "You may have {this} enter the battlefield as a copy of any nonland permanent on the battlefield", - true))); + this.addAbility(new EntersBattlefieldAbility(new CopyPermanentEffect(new FilterNonlandPermanent()), true)); } public CleverImpersonator(final CleverImpersonator card) { diff --git a/Mage.Sets/src/mage/sets/khansoftarkir/SarkhanTheDragonspeaker.java b/Mage.Sets/src/mage/sets/khansoftarkir/SarkhanTheDragonspeaker.java index cb84a4e3e85..c6d95ccf67b 100644 --- a/Mage.Sets/src/mage/sets/khansoftarkir/SarkhanTheDragonspeaker.java +++ b/Mage.Sets/src/mage/sets/khansoftarkir/SarkhanTheDragonspeaker.java @@ -34,13 +34,12 @@ import mage.abilities.Ability; import mage.abilities.LoyaltyAbility; import mage.abilities.common.BeginningOfDrawTriggeredAbility; import mage.abilities.common.BeginningOfEndStepTriggeredAbility; -import mage.abilities.common.EntersBattlefieldAbility; +import mage.abilities.common.PlanswalkerEntersWithLoyalityCountersAbility; import mage.abilities.effects.ContinuousEffectImpl; import mage.abilities.effects.Effect; import mage.abilities.effects.common.DamageTargetEffect; import mage.abilities.effects.common.DrawCardSourceControllerEffect; import mage.abilities.effects.common.GetEmblemEffect; -import mage.abilities.effects.common.counter.AddCountersSourceEffect; import mage.abilities.effects.common.discard.DiscardHandControllerEffect; import mage.abilities.keyword.FlyingAbility; import mage.abilities.keyword.HasteAbility; @@ -54,7 +53,6 @@ import mage.constants.Rarity; import mage.constants.SubLayer; import mage.constants.TargetController; import mage.constants.Zone; -import mage.counters.CounterType; import mage.game.Game; import mage.game.command.Emblem; import mage.game.permanent.Permanent; @@ -71,16 +69,16 @@ public class SarkhanTheDragonspeaker extends CardImpl { this.expansionSetCode = "KTK"; this.subtype.add("Sarkhan"); - this.addAbility(new EntersBattlefieldAbility(new AddCountersSourceEffect(CounterType.LOYALTY.createInstance(4)), false)); + this.addAbility(new PlanswalkerEntersWithLoyalityCountersAbility(4)); // +1: Until end of turn, Sarkhan, the Dragonspeaker becomes a legendary 4/4 red Dragon creature with flying, indestructible, and haste. this.addAbility(new LoyaltyAbility(new SarkhanTheDragonspeakerEffect(), 1)); - + // -3: Sarkhan, the Dragonspeaker deals 4 damage to target creature. LoyaltyAbility ability = new LoyaltyAbility(new DamageTargetEffect(4), -3); ability.addTarget(new TargetCreaturePermanent()); this.addAbility(ability); - + // -6: You get an emblem with "At the beginning of your draw step, draw two additional cards" and "At the beginning of your end step, discard your hand." Effect effect = new GetEmblemEffect(new SarkhanTheDragonspeakerEmblem()); effect.setText("You get an emblem with \"At the beginning of your draw step, draw two additional cards\" and \"At the beginning of your end step, discard your hand.\""); @@ -98,7 +96,7 @@ public class SarkhanTheDragonspeaker extends CardImpl { } class SarkhanTheDragonspeakerEffect extends ContinuousEffectImpl { - + SarkhanTheDragonspeakerEffect() { super(Duration.EndOfTurn, Outcome.BecomeCreature); staticText = "Until end of turn, {this} becomes a legendary 4/4 red Dragon creature with flying, indestructible, and haste."; @@ -112,7 +110,7 @@ class SarkhanTheDragonspeakerEffect extends ContinuousEffectImpl { public SarkhanTheDragonspeakerEffect copy() { return new SarkhanTheDragonspeakerEffect(this); } - + @Override public void init(Ability source, Game game) { super.init(source, game); diff --git a/Mage.Sets/src/mage/sets/khansoftarkir/SorinSolemnVisitor.java b/Mage.Sets/src/mage/sets/khansoftarkir/SorinSolemnVisitor.java index 835039e8420..c12ea7c75ef 100644 --- a/Mage.Sets/src/mage/sets/khansoftarkir/SorinSolemnVisitor.java +++ b/Mage.Sets/src/mage/sets/khansoftarkir/SorinSolemnVisitor.java @@ -32,14 +32,13 @@ import mage.MageInt; import mage.abilities.Ability; import mage.abilities.LoyaltyAbility; import mage.abilities.common.BeginningOfUpkeepTriggeredAbility; -import mage.abilities.common.EntersBattlefieldAbility; +import mage.abilities.common.PlanswalkerEntersWithLoyalityCountersAbility; import mage.abilities.effects.Effect; import mage.abilities.effects.common.CreateTokenEffect; import mage.abilities.effects.common.GetEmblemEffect; import mage.abilities.effects.common.SacrificeEffect; import mage.abilities.effects.common.continuous.BoostControlledEffect; import mage.abilities.effects.common.continuous.GainAbilityControlledEffect; -import mage.abilities.effects.common.counter.AddCountersSourceEffect; import mage.abilities.keyword.FlyingAbility; import mage.abilities.keyword.LifelinkAbility; import mage.cards.CardImpl; @@ -48,12 +47,10 @@ import mage.constants.Duration; import mage.constants.Rarity; import mage.constants.TargetController; import mage.constants.Zone; -import mage.counters.CounterType; import mage.filter.common.FilterCreaturePermanent; import mage.game.command.Emblem; import mage.game.permanent.token.Token; - /** * * @author LevelX2 @@ -65,8 +62,7 @@ public class SorinSolemnVisitor extends CardImpl { this.expansionSetCode = "KTK"; this.subtype.add("Sorin"); - - this.addAbility(new EntersBattlefieldAbility(new AddCountersSourceEffect(CounterType.LOYALTY.createInstance(4)), false)); + this.addAbility(new PlanswalkerEntersWithLoyalityCountersAbility(4)); // +1: Until your next turn, creatures you control get +1/+0 and gain lifelink. Effect effect = new BoostControlledEffect(1, 0, Duration.UntilYourNextTurn, new FilterCreaturePermanent()); @@ -94,18 +90,22 @@ public class SorinSolemnVisitor extends CardImpl { return new SorinSolemnVisitor(this); } } + /** - * Emblem: "At the beginning of each opponent's upkeep, that player sacrifices a creature." + * Emblem: "At the beginning of each opponent's upkeep, that player sacrifices a + * creature." */ class SorinEmblem extends Emblem { + public SorinEmblem() { this.setName("EMBLEM: Sorin, Solemn Visitor"); - Ability ability = new BeginningOfUpkeepTriggeredAbility(Zone.COMMAND, new SacrificeEffect(new FilterCreaturePermanent(),1 ,"that player"), TargetController.OPPONENT, false, true); + Ability ability = new BeginningOfUpkeepTriggeredAbility(Zone.COMMAND, new SacrificeEffect(new FilterCreaturePermanent(), 1, "that player"), TargetController.OPPONENT, false, true); this.getAbilities().add(ability); } } class SorinSolemnVisitorVampireToken extends Token { + SorinSolemnVisitorVampireToken() { super("Vampire", "a 2/2 black Vampire creature token with flying"); setOriginalExpansionSetCode("KTK"); diff --git a/Mage.Sets/src/mage/sets/khansoftarkir/WarNameAspirant.java b/Mage.Sets/src/mage/sets/khansoftarkir/WarNameAspirant.java index d319410e590..cc33f764fd9 100644 --- a/Mage.Sets/src/mage/sets/khansoftarkir/WarNameAspirant.java +++ b/Mage.Sets/src/mage/sets/khansoftarkir/WarNameAspirant.java @@ -68,7 +68,6 @@ public class WarNameAspirant extends CardImpl { // Raid - War-Name Aspirant enters the battlefield with a +1/+1 counter on it if you attacked with a creature this turn. this.addAbility(new EntersBattlefieldAbility(new AddCountersSourceEffect(CounterType.P1P1.createInstance(1), false), RaidCondition.getInstance(), - true, "Raid - {this} enters the battlefield with a +1/+1 counter on it if you attacked with a creature this turn", "{this} enters the battlefield with a +1/+1 counter"), new PlayerAttackedWatcher()); diff --git a/Mage.Sets/src/mage/sets/limitedalpha/AnimateDead.java b/Mage.Sets/src/mage/sets/limitedalpha/AnimateDead.java index 3ab1fcca736..2852b95626f 100644 --- a/Mage.Sets/src/mage/sets/limitedalpha/AnimateDead.java +++ b/Mage.Sets/src/mage/sets/limitedalpha/AnimateDead.java @@ -70,15 +70,14 @@ public class AnimateDead extends CardImpl { this.expansionSetCode = "LEA"; this.subtype.add("Aura"); - // Enchant creature card in a graveyard TargetCardInGraveyard auraTarget = new TargetCardInGraveyard(new FilterCreatureCard("creature card in a graveyard")); this.getSpellAbility().addTarget(auraTarget); this.getSpellAbility().addEffect(new AnimateDeadAttachEffect(Outcome.PutCreatureInPlay)); Ability enchantAbility = new EnchantAbility(auraTarget.getTargetName()); - this.addAbility(enchantAbility); - // When Animate Dead enters the battlefield, if it's on the battlefield, it loses "enchant creature card in a graveyard" - // and gains "enchant creature put onto the battlefield with Animate Dead." Return enchanted creature card to the battlefield + this.addAbility(enchantAbility); + // When Animate Dead enters the battlefield, if it's on the battlefield, it loses "enchant creature card in a graveyard" + // and gains "enchant creature put onto the battlefield with Animate Dead." Return enchanted creature card to the battlefield // under your control and attach Animate Dead to it. When Animate Dead leaves the battlefield, that creature's controller sacrifices it. Ability ability = new ConditionalTriggeredAbility( new EntersBattlefieldTriggeredAbility(new AnimateDeadReAttachEffect(), false), @@ -86,11 +85,11 @@ public class AnimateDead extends CardImpl { "When {this} enters the battlefield, if it's on the battlefield, it loses \"enchant creature card in a graveyard\" and gains \"enchant creature put onto the battlefield with {this}.\" Return enchanted creature card to the battlefield under your control and attach {this} to it."); ability.addEffect(new AnimateDeadChangeAbilityEffect()); this.addAbility(ability); - this.addAbility(new LeavesBattlefieldTriggeredAbility(new AnimateDeadLeavesBattlefieldTriggeredEffect(), false)); - + this.addAbility(new LeavesBattlefieldTriggeredAbility(new AnimateDeadLeavesBattlefieldTriggeredEffect(), false)); + // Enchanted creature gets -1/-0. this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new BoostEnchantedEffect(-1, 0, Duration.WhileOnBattlefield))); - + } public AnimateDead(final AnimateDead card) { @@ -104,36 +103,36 @@ public class AnimateDead extends CardImpl { } class AnimateDeadReAttachEffect extends OneShotEffect { - + public AnimateDeadReAttachEffect() { super(Outcome.Benefit); this.staticText = "Return enchanted creature card to the battlefield under your control and attach {this} to it"; } - + public AnimateDeadReAttachEffect(final AnimateDeadReAttachEffect effect) { super(effect); } - + @Override public AnimateDeadReAttachEffect copy() { return new AnimateDeadReAttachEffect(this); } - + @Override public boolean apply(Game game, Ability source) { Player controller = game.getPlayer(source.getControllerId()); Permanent enchantment = game.getPermanent(source.getSourceId()); - + if (controller != null && enchantment != null) { Card cardInGraveyard = game.getCard(enchantment.getAttachedTo()); if (cardInGraveyard == null) { return true; } - + // put card into play - controller.putOntoBattlefieldWithInfo(cardInGraveyard, game, Zone.GRAVEYARD, source.getSourceId()); + controller.moveCards(cardInGraveyard, Zone.BATTLEFIELD, source, game); Permanent enchantedCreature = game.getPermanent(cardInGraveyard.getId()); - + FilterCreaturePermanent filter = new FilterCreaturePermanent("enchant creature put onto the battlefield with Animate Dead"); filter.add(new PermanentIdPredicate(cardInGraveyard.getId())); Target target = new TargetCreaturePermanent(filter); @@ -146,27 +145,27 @@ class AnimateDeadReAttachEffect extends OneShotEffect { } return true; } - + return false; } } - + class AnimateDeadLeavesBattlefieldTriggeredEffect extends OneShotEffect { - + public AnimateDeadLeavesBattlefieldTriggeredEffect() { super(Outcome.Benefit); this.staticText = "enchanted creature's controller sacrifices it"; } - + public AnimateDeadLeavesBattlefieldTriggeredEffect(final AnimateDeadLeavesBattlefieldTriggeredEffect effect) { super(effect); } - + @Override public AnimateDeadLeavesBattlefieldTriggeredEffect copy() { return new AnimateDeadLeavesBattlefieldTriggeredEffect(this); } - + @Override public boolean apply(Game game, Ability source) { Player controller = game.getPlayer(source.getControllerId()); @@ -223,17 +222,16 @@ class AnimateDeadAttachEffect extends OneShotEffect { class AnimateDeadChangeAbilityEffect extends ContinuousEffectImpl implements SourceEffect { private final static Ability newAbility = new EnchantAbility("creature put onto the battlefield with Animate Dead"); - + static { newAbility.setRuleAtTheTop(true); } - + public AnimateDeadChangeAbilityEffect() { super(Duration.WhileOnBattlefield, Layer.AbilityAddingRemovingEffects_6, SubLayer.NA, Outcome.AddAbility); staticText = "it loses \"enchant creature card in a graveyard\" and gains \"enchant creature put onto the battlefield with Animate Dead\""; } - public AnimateDeadChangeAbilityEffect(final AnimateDeadChangeAbilityEffect effect) { super(effect); } @@ -242,7 +240,7 @@ class AnimateDeadChangeAbilityEffect extends ContinuousEffectImpl implements Sou public AnimateDeadChangeAbilityEffect copy() { return new AnimateDeadChangeAbilityEffect(this); } - + @Override public void init(Ability source, Game game) { super.init(source, game); @@ -254,7 +252,7 @@ class AnimateDeadChangeAbilityEffect extends ContinuousEffectImpl implements Sou Permanent permanent = affectedObjectList.get(0).getPermanent(game); if (permanent != null) { Ability abilityToRemove = null; - for (Ability ability: permanent.getAbilities()) { + for (Ability ability : permanent.getAbilities()) { if (ability instanceof EnchantAbility) { abilityToRemove = ability; } @@ -264,7 +262,7 @@ class AnimateDeadChangeAbilityEffect extends ContinuousEffectImpl implements Sou } permanent.addAbility(newAbility, source.getSourceId(), game); return true; - } + } return false; } } diff --git a/Mage.Sets/src/mage/sets/limitedalpha/CopyArtifact.java b/Mage.Sets/src/mage/sets/limitedalpha/CopyArtifact.java index b1a99b0e249..d783513396a 100644 --- a/Mage.Sets/src/mage/sets/limitedalpha/CopyArtifact.java +++ b/Mage.Sets/src/mage/sets/limitedalpha/CopyArtifact.java @@ -28,24 +28,14 @@ package mage.sets.limitedalpha; import java.util.UUID; -import mage.MageObject; -import mage.abilities.Ability; -import mage.abilities.common.SimpleStaticAbility; -import mage.abilities.effects.EntersBattlefieldEffect; -import mage.abilities.effects.OneShotEffect; +import mage.abilities.common.EntersBattlefieldAbility; +import mage.abilities.effects.Effect; +import mage.abilities.effects.common.CopyPermanentEffect; import mage.cards.CardImpl; 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; -import mage.game.Game; -import mage.game.permanent.Permanent; -import mage.players.Player; -import mage.target.Target; -import mage.target.TargetPermanent; -import mage.util.functions.ApplyToPermanent; +import mage.filter.common.FilterArtifactPermanent; +import mage.util.functions.CardTypeApplier; /** * @@ -59,11 +49,9 @@ public class CopyArtifact extends CardImpl { this.expansionSetCode = "LEA"; // You may have Copy Artifact enter the battlefield as a copy of any artifact on the battlefield, except it's an enchantment in addition to its other types. - Ability ability = new SimpleStaticAbility(Zone.BATTLEFIELD, new EntersBattlefieldEffect( - new CopyArtifactEffect(), - "You may have {this} enter the battlefield as a copy of any artifact on the battlefield, except it's an enchantment in addition to its other types", - true)); - this.addAbility(ability); + Effect effect = new CopyPermanentEffect(new FilterArtifactPermanent(), new CardTypeApplier(CardType.ENCHANTMENT)); + effect.setText("as a copy of any artifact on the battlefield, except it's an enchantment in addition to its other types"); + this.addAbility(new EntersBattlefieldAbility(effect, true)); } public CopyArtifact(final CopyArtifact card) { @@ -75,64 +63,3 @@ public class CopyArtifact extends CardImpl { return new CopyArtifact(this); } } - -class CopyArtifactEffect extends OneShotEffect { - - ApplyToPermanent applier = new ApplyToPermanent() { - @Override - public Boolean apply(Game game, Permanent permanent) { - if (!permanent.getCardType().contains(CardType.ENCHANTMENT)) { - permanent.getCardType().add(CardType.ENCHANTMENT); - } - return true; - } - - @Override - public Boolean apply(Game game, MageObject mageObject) { - if (!mageObject.getCardType().contains(CardType.ENCHANTMENT)) { - mageObject.getCardType().add(CardType.ENCHANTMENT); - } - return true; - } - - }; - - private static final FilterPermanent filter = new FilterPermanent("artifact"); - - static { - filter.add(new CardTypePredicate(CardType.ARTIFACT)); - } - - public CopyArtifactEffect() { - super(Outcome.Copy); - } - - public CopyArtifactEffect(final CopyArtifactEffect effect) { - super(effect); - } - - @Override - public boolean apply(Game game, Ability source) { - Player player = game.getPlayer(source.getControllerId()); - MageObject sourceObject = game.getObject(source.getSourceId()); - if (player != null && sourceObject != null) { - Target target = new TargetPermanent(filter); - target.setNotTarget(true); - if (target.canChoose(source.getControllerId(), game)) { - player.choose(Outcome.Copy, target, source.getSourceId(), game); - Permanent copyFromPermanent = game.getPermanent(target.getFirstTarget()); - if (copyFromPermanent != null) { - game.copyPermanent(copyFromPermanent, sourceObject.getId(), source, applier); - return true; - } - } - } - return false; - } - - @Override - public CopyArtifactEffect copy() { - return new CopyArtifactEffect(this); - } - -} diff --git a/Mage.Sets/src/mage/sets/magic2010/AjaniGoldmane.java b/Mage.Sets/src/mage/sets/magic2010/AjaniGoldmane.java index f53660bf0f0..f123146b6a8 100644 --- a/Mage.Sets/src/mage/sets/magic2010/AjaniGoldmane.java +++ b/Mage.Sets/src/mage/sets/magic2010/AjaniGoldmane.java @@ -1,16 +1,16 @@ /* * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. - * + * * Redistribution and use in source and binary forms, with or without modification, are * permitted provided that the following conditions are met: - * + * * 1. Redistributions of source code must retain the above copyright notice, this list of * conditions and the following disclaimer. - * + * * 2. Redistributions in binary form must reproduce the above copyright notice, this list * of conditions and the following disclaimer in the documentation and/or other materials * provided with the distribution. - * + * * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR @@ -20,15 +20,26 @@ * 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.magic2010; import java.util.UUID; +import mage.abilities.Ability; +import mage.abilities.LoyaltyAbility; +import mage.abilities.common.PlanswalkerEntersWithLoyalityCountersAbility; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.effects.ContinuousEffectImpl; +import mage.abilities.effects.Effects; +import mage.abilities.effects.common.CreateTokenEffect; +import mage.abilities.effects.common.GainLifeEffect; +import mage.abilities.effects.common.continuous.GainAbilityControlledEffect; +import mage.abilities.effects.common.counter.AddCountersAllEffect; +import mage.abilities.keyword.VigilanceAbility; +import mage.cards.CardImpl; import mage.constants.CardType; import mage.constants.Duration; import mage.constants.Layer; @@ -36,19 +47,6 @@ import mage.constants.Outcome; import mage.constants.Rarity; import mage.constants.SubLayer; import mage.constants.Zone; -import mage.abilities.Ability; -import mage.abilities.LoyaltyAbility; -import mage.abilities.common.EntersBattlefieldAbility; -import mage.abilities.common.SimpleStaticAbility; -import mage.abilities.effects.ContinuousEffectImpl; -import mage.abilities.effects.Effects; -import mage.abilities.effects.common.continuous.GainAbilityControlledEffect; -import mage.abilities.effects.common.counter.AddCountersSourceEffect; -import mage.abilities.effects.common.CreateTokenEffect; -import mage.abilities.effects.common.GainLifeEffect; -import mage.abilities.effects.common.counter.AddCountersAllEffect; -import mage.abilities.keyword.VigilanceAbility; -import mage.cards.CardImpl; import mage.counters.CounterType; import mage.filter.common.FilterControlledCreaturePermanent; import mage.filter.common.FilterCreaturePermanent; @@ -68,7 +66,7 @@ public class AjaniGoldmane extends CardImpl { this.expansionSetCode = "M10"; this.subtype.add("Ajani"); - this.addAbility(new EntersBattlefieldAbility(new AddCountersSourceEffect(CounterType.LOYALTY.createInstance(4)), false)); + this.addAbility(new PlanswalkerEntersWithLoyalityCountersAbility(4)); // +1: You gain 2 life. this.addAbility(new LoyaltyAbility(new GainLifeEffect(2), 1)); @@ -136,4 +134,4 @@ class AvatarTokenEffect extends ContinuousEffectImpl { return false; } -} \ No newline at end of file +} diff --git a/Mage.Sets/src/mage/sets/magic2010/ChandraNalaar.java b/Mage.Sets/src/mage/sets/magic2010/ChandraNalaar.java index e795ef55dc2..b1ced672549 100644 --- a/Mage.Sets/src/mage/sets/magic2010/ChandraNalaar.java +++ b/Mage.Sets/src/mage/sets/magic2010/ChandraNalaar.java @@ -1,16 +1,16 @@ /* * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. - * + * * Redistribution and use in source and binary forms, with or without modification, are * permitted provided that the following conditions are met: - * + * * 1. Redistributions of source code must retain the above copyright notice, this list of * conditions and the following disclaimer. - * + * * 2. Redistributions in binary form must reproduce the above copyright notice, this list * of conditions and the following disclaimer in the documentation and/or other materials * provided with the distribution. - * + * * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR @@ -20,17 +20,17 @@ * 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.magic2010; +import java.util.UUID; import mage.abilities.Ability; import mage.abilities.LoyaltyAbility; -import mage.abilities.common.EntersBattlefieldAbility; +import mage.abilities.common.PlanswalkerEntersWithLoyalityCountersAbility; import mage.abilities.costs.Cost; import mage.abilities.costs.common.PayVariableLoyaltyCost; import mage.abilities.dynamicvalue.DynamicValue; @@ -38,18 +38,14 @@ import mage.abilities.effects.Effect; import mage.abilities.effects.Effects; import mage.abilities.effects.common.DamageAllControlledTargetEffect; import mage.abilities.effects.common.DamageTargetEffect; -import mage.abilities.effects.common.counter.AddCountersSourceEffect; import mage.cards.CardImpl; import mage.constants.CardType; import mage.constants.Rarity; -import mage.counters.CounterType; import mage.filter.common.FilterCreaturePermanent; import mage.game.Game; import mage.target.TargetPlayer; import mage.target.common.TargetCreaturePermanent; -import java.util.UUID; - /** * * @author BetaSteward_at_googlemail.com, nantuko @@ -61,8 +57,7 @@ public class ChandraNalaar extends CardImpl { this.expansionSetCode = "M10"; this.subtype.add("Chandra"); - this.addAbility(new EntersBattlefieldAbility(new AddCountersSourceEffect(CounterType.LOYALTY.createInstance(6)), false)); - + this.addAbility(new PlanswalkerEntersWithLoyalityCountersAbility(6)); LoyaltyAbility ability1 = new LoyaltyAbility(new DamageTargetEffect(1), 1); ability1.addTarget(new TargetPlayer()); @@ -98,7 +93,7 @@ class ChandraNalaarXValue implements DynamicValue { public int calculate(Game game, Ability sourceAbility, Effect effect) { for (Cost cost : sourceAbility.getCosts()) { if (cost instanceof PayVariableLoyaltyCost) { - return ((PayVariableLoyaltyCost)cost).getAmount(); + return ((PayVariableLoyaltyCost) cost).getAmount(); } } return 0; @@ -123,4 +118,3 @@ class ChandraNalaarXValue implements DynamicValue { return defaultValue; } } - diff --git a/Mage.Sets/src/mage/sets/magic2010/GarrukWildspeaker.java b/Mage.Sets/src/mage/sets/magic2010/GarrukWildspeaker.java index 7c35ee12a38..9a3ddef6c26 100644 --- a/Mage.Sets/src/mage/sets/magic2010/GarrukWildspeaker.java +++ b/Mage.Sets/src/mage/sets/magic2010/GarrukWildspeaker.java @@ -1,49 +1,46 @@ /* -* 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.sets.magic2010; import java.util.UUID; import mage.abilities.LoyaltyAbility; -import mage.abilities.common.EntersBattlefieldAbility; +import mage.abilities.common.PlanswalkerEntersWithLoyalityCountersAbility; import mage.abilities.effects.Effect; import mage.abilities.effects.Effects; import mage.abilities.effects.common.CreateTokenEffect; import mage.abilities.effects.common.UntapTargetEffect; import mage.abilities.effects.common.continuous.BoostControlledEffect; import mage.abilities.effects.common.continuous.GainAbilityControlledEffect; -import mage.abilities.effects.common.counter.AddCountersSourceEffect; import mage.abilities.keyword.TrampleAbility; import mage.cards.CardImpl; import mage.constants.CardType; import mage.constants.Duration; import mage.constants.Rarity; -import mage.counters.CounterType; import mage.filter.common.FilterCreaturePermanent; import mage.game.permanent.token.BeastToken; import mage.target.common.TargetLandPermanent; @@ -61,8 +58,7 @@ public class GarrukWildspeaker extends CardImpl { this.expansionSetCode = "M10"; this.subtype.add("Garruk"); - - this.addAbility(new EntersBattlefieldAbility(new AddCountersSourceEffect(CounterType.LOYALTY.createInstance(3)), false)); + this.addAbility(new PlanswalkerEntersWithLoyalityCountersAbility(3)); // +1: Untap two target lands. LoyaltyAbility ability1 = new LoyaltyAbility(new UntapTargetEffect(), 1); diff --git a/Mage.Sets/src/mage/sets/magic2010/JaceBeleren.java b/Mage.Sets/src/mage/sets/magic2010/JaceBeleren.java index fcd4938b0e1..b5566671786 100644 --- a/Mage.Sets/src/mage/sets/magic2010/JaceBeleren.java +++ b/Mage.Sets/src/mage/sets/magic2010/JaceBeleren.java @@ -1,16 +1,16 @@ /* * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. - * + * * Redistribution and use in source and binary forms, with or without modification, are * permitted provided that the following conditions are met: - * + * * 1. Redistributions of source code must retain the above copyright notice, this list of * conditions and the following disclaimer. - * + * * 2. Redistributions in binary form must reproduce the above copyright notice, this list * of conditions and the following disclaimer in the documentation and/or other materials * provided with the distribution. - * + * * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR @@ -20,25 +20,22 @@ * 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.magic2010; import java.util.UUID; -import mage.constants.CardType; -import mage.constants.Rarity; import mage.abilities.LoyaltyAbility; -import mage.abilities.common.EntersBattlefieldAbility; +import mage.abilities.common.PlanswalkerEntersWithLoyalityCountersAbility; import mage.abilities.effects.common.DrawCardAllEffect; import mage.abilities.effects.common.DrawCardTargetEffect; import mage.abilities.effects.common.PutLibraryIntoGraveTargetEffect; -import mage.abilities.effects.common.counter.AddCountersSourceEffect; import mage.cards.CardImpl; -import mage.counters.CounterType; +import mage.constants.CardType; +import mage.constants.Rarity; import mage.target.TargetPlayer; /** @@ -52,9 +49,9 @@ public class JaceBeleren extends CardImpl { this.expansionSetCode = "M10"; this.subtype.add("Jace"); - this.addAbility(new EntersBattlefieldAbility(new AddCountersSourceEffect(CounterType.LOYALTY.createInstance(3)), false)); + this.addAbility(new PlanswalkerEntersWithLoyalityCountersAbility(3)); - // +2: Each player draws a card. + // +2: Each player draws a card. this.addAbility(new LoyaltyAbility(new DrawCardAllEffect(1), 2)); // -1: Target player draws a card. diff --git a/Mage.Sets/src/mage/sets/magic2010/LilianaVess.java b/Mage.Sets/src/mage/sets/magic2010/LilianaVess.java index 5f955caa787..7ab2a913ae9 100644 --- a/Mage.Sets/src/mage/sets/magic2010/LilianaVess.java +++ b/Mage.Sets/src/mage/sets/magic2010/LilianaVess.java @@ -32,9 +32,8 @@ import java.util.Set; import java.util.UUID; import mage.abilities.Ability; import mage.abilities.LoyaltyAbility; -import mage.abilities.common.EntersBattlefieldAbility; +import mage.abilities.common.PlanswalkerEntersWithLoyalityCountersAbility; import mage.abilities.effects.OneShotEffect; -import mage.abilities.effects.common.counter.AddCountersSourceEffect; import mage.abilities.effects.common.discard.DiscardTargetEffect; import mage.abilities.effects.common.search.SearchLibraryPutOnLibraryEffect; import mage.cards.Card; @@ -43,7 +42,6 @@ import mage.constants.CardType; import mage.constants.Outcome; import mage.constants.Rarity; import mage.constants.Zone; -import mage.counters.CounterType; import mage.game.Game; import mage.players.Player; import mage.target.TargetPlayer; @@ -60,7 +58,7 @@ public class LilianaVess extends CardImpl { this.expansionSetCode = "M10"; this.subtype.add("Liliana"); - this.addAbility(new EntersBattlefieldAbility(new AddCountersSourceEffect(CounterType.LOYALTY.createInstance(5)), false)); + this.addAbility(new PlanswalkerEntersWithLoyalityCountersAbility(5)); // +1: Target player discards a card. LoyaltyAbility ability1 = new LoyaltyAbility(new DiscardTargetEffect(1), 1); ability1.addTarget(new TargetPlayer()); diff --git a/Mage.Sets/src/mage/sets/magic2011/InfernoTitan.java b/Mage.Sets/src/mage/sets/magic2011/InfernoTitan.java index 484242f65d6..8e61bb1817f 100644 --- a/Mage.Sets/src/mage/sets/magic2011/InfernoTitan.java +++ b/Mage.Sets/src/mage/sets/magic2011/InfernoTitan.java @@ -1,16 +1,16 @@ /* * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. - * + * * Redistribution and use in source and binary forms, with or without modification, are * permitted provided that the following conditions are met: - * + * * 1. Redistributions of source code must retain the above copyright notice, this list of * conditions and the following disclaimer. - * + * * 2. Redistributions in binary form must reproduce the above copyright notice, this list * of conditions and the following disclaimer in the documentation and/or other materials * provided with the distribution. - * + * * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR @@ -20,12 +20,11 @@ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * + * * The views and conclusions contained in the software and documentation are those of the * authors and should not be interpreted as representing official policies, either expressed * or implied, of BetaSteward_at_googlemail.com. */ - package mage.sets.magic2011; import java.util.UUID; @@ -100,10 +99,7 @@ class InfernoTitanAbility extends TriggeredAbilityImpl { if (event.getType() == EventType.ATTACKER_DECLARED && event.getSourceId().equals(this.getSourceId())) { return true; } - if (event.getType() == EventType.ENTERS_THE_BATTLEFIELD && event.getTargetId().equals(this.getSourceId()) ) { - return true; - } - return false; + return event.getType() == EventType.ENTERS_THE_BATTLEFIELD && event.getTargetId().equals(this.getSourceId()); } @Override diff --git a/Mage.Sets/src/mage/sets/magic2011/SunTitan.java b/Mage.Sets/src/mage/sets/magic2011/SunTitan.java index 03f7d21a769..0b5c5660dc7 100644 --- a/Mage.Sets/src/mage/sets/magic2011/SunTitan.java +++ b/Mage.Sets/src/mage/sets/magic2011/SunTitan.java @@ -1,16 +1,16 @@ /* * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. - * + * * Redistribution and use in source and binary forms, with or without modification, are * permitted provided that the following conditions are met: - * + * * 1. Redistributions of source code must retain the above copyright notice, this list of * conditions and the following disclaimer. - * + * * 2. Redistributions in binary form must reproduce the above copyright notice, this list * of conditions and the following disclaimer in the documentation and/or other materials * provided with the distribution. - * + * * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR @@ -20,12 +20,11 @@ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * + * * The views and conclusions contained in the software and documentation are those of the * authors and should not be interpreted as representing official policies, either expressed * or implied, of BetaSteward_at_googlemail.com. */ - package mage.sets.magic2011; import java.util.UUID; @@ -117,10 +116,7 @@ class SunTitanAbility extends TriggeredAbilityImpl { if (event.getType() == EventType.ATTACKER_DECLARED && event.getSourceId().equals(this.getSourceId())) { return true; } - if (event.getType() == EventType.ENTERS_THE_BATTLEFIELD && event.getTargetId().equals(this.getSourceId()) ) { - return true; - } - return false; + return event.getType() == EventType.ENTERS_THE_BATTLEFIELD && event.getTargetId().equals(this.getSourceId()); } @Override diff --git a/Mage.Sets/src/mage/sets/magic2012/ChandraTheFirebrand.java b/Mage.Sets/src/mage/sets/magic2012/ChandraTheFirebrand.java index 3677a7b9cc7..1fd2d3f98a1 100644 --- a/Mage.Sets/src/mage/sets/magic2012/ChandraTheFirebrand.java +++ b/Mage.Sets/src/mage/sets/magic2012/ChandraTheFirebrand.java @@ -25,23 +25,20 @@ * authors and should not be interpreted as representing official policies, either expressed * or implied, of BetaSteward_at_googlemail.com. */ - package mage.sets.magic2012; import java.util.UUID; import mage.abilities.DelayedTriggeredAbility; import mage.abilities.LoyaltyAbility; -import mage.abilities.common.EntersBattlefieldAbility; +import mage.abilities.common.PlanswalkerEntersWithLoyalityCountersAbility; import mage.abilities.effects.Effect; import mage.abilities.effects.common.CopyTargetSpellEffect; import mage.abilities.effects.common.CreateDelayedTriggeredAbilityEffect; import mage.abilities.effects.common.DamageTargetEffect; -import mage.abilities.effects.common.counter.AddCountersSourceEffect; import mage.cards.CardImpl; import mage.constants.CardType; import mage.constants.Duration; import mage.constants.Rarity; -import mage.counters.CounterType; import mage.game.Game; import mage.game.events.GameEvent; import mage.game.events.GameEvent.EventType; @@ -55,22 +52,21 @@ import mage.target.targetpointer.FixedTarget; */ public class ChandraTheFirebrand extends CardImpl { - public ChandraTheFirebrand (UUID ownerId) { + public ChandraTheFirebrand(UUID ownerId) { super(ownerId, 124, "Chandra, the Firebrand", Rarity.MYTHIC, new CardType[]{CardType.PLANESWALKER}, "{3}{R}"); this.expansionSetCode = "M12"; this.subtype.add("Chandra"); - this.addAbility(new EntersBattlefieldAbility(new AddCountersSourceEffect(CounterType.LOYALTY.createInstance(3)), false)); + this.addAbility(new PlanswalkerEntersWithLoyalityCountersAbility(3)); // +1: Chandra, the Firebrand deals 1 damage to target creature or player. - LoyaltyAbility ability1 = new LoyaltyAbility(new DamageTargetEffect(1), 1); ability1.addTarget(new TargetCreatureOrPlayer()); this.addAbility(ability1); // -2: When you cast your next instant or sorcery spell this turn, copy that spell. You may choose new targets for the copy. - Effect effect = new CreateDelayedTriggeredAbilityEffect(new ChandraTheFirebrandAbility()); - effect .setText("When you cast your next instant or sorcery spell this turn, copy that spell. You may choose new targets for the copy"); + Effect effect = new CreateDelayedTriggeredAbilityEffect(new ChandraTheFirebrandAbility()); + effect.setText("When you cast your next instant or sorcery spell this turn, copy that spell. You may choose new targets for the copy"); this.addAbility(new LoyaltyAbility(effect, -2)); // -6: Chandra, the Firebrand deals 6 damage to each of up to six target creatures and/or players @@ -79,7 +75,7 @@ public class ChandraTheFirebrand extends CardImpl { this.addAbility(ability2); } - public ChandraTheFirebrand (final ChandraTheFirebrand card) { + public ChandraTheFirebrand(final ChandraTheFirebrand card) { super(card); } @@ -91,6 +87,7 @@ public class ChandraTheFirebrand extends CardImpl { } class ChandraTheFirebrandAbility extends DelayedTriggeredAbility { + ChandraTheFirebrandAbility() { super(new CopyTargetSpellEffect(), Duration.EndOfTurn); } @@ -111,11 +108,11 @@ class ChandraTheFirebrandAbility extends DelayedTriggeredAbility { @Override public boolean checkTrigger(GameEvent event, Game game) { - if (event.getPlayerId().equals(this.getControllerId())) { + if (event.getPlayerId().equals(this.getControllerId())) { Spell spell = game.getStack().getSpell(event.getTargetId()); if (spell != null && (spell.getCardType().contains(CardType.INSTANT) || spell.getCardType().contains(CardType.SORCERY))) { for (Effect effect : this.getEffects()) { - effect.setTargetPointer(new FixedTarget(event.getTargetId())); + effect.setTargetPointer(new FixedTarget(event.getTargetId())); } return true; } @@ -127,4 +124,4 @@ class ChandraTheFirebrandAbility extends DelayedTriggeredAbility { public String getRule() { return "When you cast your next instant or sorcery spell this turn, copy that spell. You may choose new targets for the copy."; } -} \ No newline at end of file +} diff --git a/Mage.Sets/src/mage/sets/magic2012/GarrukPrimalHunter.java b/Mage.Sets/src/mage/sets/magic2012/GarrukPrimalHunter.java index 17c8316eca0..935f24def0f 100644 --- a/Mage.Sets/src/mage/sets/magic2012/GarrukPrimalHunter.java +++ b/Mage.Sets/src/mage/sets/magic2012/GarrukPrimalHunter.java @@ -25,23 +25,19 @@ * authors and should not be interpreted as representing official policies, either expressed * or implied, of BetaSteward_at_googlemail.com. */ - package mage.sets.magic2012; import java.util.UUID; - -import mage.constants.CardType; -import mage.constants.Rarity; import mage.abilities.Ability; import mage.abilities.LoyaltyAbility; -import mage.abilities.common.EntersBattlefieldAbility; +import mage.abilities.common.PlanswalkerEntersWithLoyalityCountersAbility; import mage.abilities.dynamicvalue.common.PermanentsOnBattlefieldCount; import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.CreateTokenEffect; -import mage.abilities.effects.common.counter.AddCountersSourceEffect; import mage.cards.CardImpl; +import mage.constants.CardType; import mage.constants.Outcome; -import mage.counters.CounterType; +import mage.constants.Rarity; import mage.filter.common.FilterControlledCreaturePermanent; import mage.filter.common.FilterControlledLandPermanent; import mage.filter.common.FilterControlledPermanent; @@ -56,20 +52,19 @@ import mage.players.Player; * @author Loki */ public class GarrukPrimalHunter extends CardImpl { - + private static final FilterControlledPermanent filter = new FilterControlledLandPermanent(); - public GarrukPrimalHunter (UUID ownerId) { + public GarrukPrimalHunter(UUID ownerId) { super(ownerId, 174, "Garruk, Primal Hunter", Rarity.MYTHIC, new CardType[]{CardType.PLANESWALKER}, "{2}{G}{G}{G}"); this.expansionSetCode = "M12"; this.subtype.add("Garruk"); + this.addAbility(new PlanswalkerEntersWithLoyalityCountersAbility(3)); - this.addAbility(new EntersBattlefieldAbility(new AddCountersSourceEffect(CounterType.LOYALTY.createInstance(3)), false)); - // +1: Put a 3/3 green Beast creature token onto the battlefield. this.addAbility(new LoyaltyAbility(new CreateTokenEffect(new BeastToken()), 1)); - + // -3: Draw cards equal to the greatest power among creatures you control. this.addAbility(new LoyaltyAbility(new GarrukPrimalHunterEffect(), -3)); @@ -77,7 +72,7 @@ public class GarrukPrimalHunter extends CardImpl { this.addAbility(new LoyaltyAbility(new CreateTokenEffect(new WurmToken(), new PermanentsOnBattlefieldCount(filter)), -6)); } - public GarrukPrimalHunter (final GarrukPrimalHunter card) { + public GarrukPrimalHunter(final GarrukPrimalHunter card) { super(card); } @@ -89,6 +84,7 @@ public class GarrukPrimalHunter extends CardImpl { } class GarrukPrimalHunterEffect extends OneShotEffect { + GarrukPrimalHunterEffect() { super(Outcome.DrawCard); staticText = "Draw cards equal to the greatest power among creatures you control"; diff --git a/Mage.Sets/src/mage/sets/magic2012/JaceMemoryAdept.java b/Mage.Sets/src/mage/sets/magic2012/JaceMemoryAdept.java index 58b5b0f98c3..2e687f4f8cb 100644 --- a/Mage.Sets/src/mage/sets/magic2012/JaceMemoryAdept.java +++ b/Mage.Sets/src/mage/sets/magic2012/JaceMemoryAdept.java @@ -27,24 +27,21 @@ */ package mage.sets.magic2012; -import mage.constants.CardType; -import mage.constants.Rarity; +import java.util.UUID; import mage.abilities.Ability; import mage.abilities.LoyaltyAbility; import mage.abilities.Mode; -import mage.abilities.common.EntersBattlefieldAbility; +import mage.abilities.common.PlanswalkerEntersWithLoyalityCountersAbility; import mage.abilities.effects.common.DrawCardSourceControllerEffect; import mage.abilities.effects.common.DrawCardTargetEffect; import mage.abilities.effects.common.PutLibraryIntoGraveTargetEffect; -import mage.abilities.effects.common.counter.AddCountersSourceEffect; import mage.cards.CardImpl; -import mage.counters.CounterType; +import mage.constants.CardType; +import mage.constants.Rarity; import mage.game.Game; import mage.players.Player; import mage.target.TargetPlayer; -import java.util.UUID; - /** * @author nantuko */ @@ -55,8 +52,7 @@ public class JaceMemoryAdept extends CardImpl { this.expansionSetCode = "M12"; this.subtype.add("Jace"); - - this.addAbility(new EntersBattlefieldAbility(new AddCountersSourceEffect(CounterType.LOYALTY.createInstance(4)), false)); + this.addAbility(new PlanswalkerEntersWithLoyalityCountersAbility(4)); // +1: Draw a card. Target player puts the top card of his or her library into his or her graveyard. LoyaltyAbility ability1 = new LoyaltyAbility(new DrawCardSourceControllerEffect(1), 1); @@ -116,5 +112,3 @@ class JaceMemoryAdeptEffect extends DrawCardTargetEffect { return new JaceMemoryAdeptEffect(this); } } - - diff --git a/Mage.Sets/src/mage/sets/magic2012/PhantasmalImage.java b/Mage.Sets/src/mage/sets/magic2012/PhantasmalImage.java index 82de7d6d4e8..23ede410e11 100644 --- a/Mage.Sets/src/mage/sets/magic2012/PhantasmalImage.java +++ b/Mage.Sets/src/mage/sets/magic2012/PhantasmalImage.java @@ -30,23 +30,17 @@ package mage.sets.magic2012; import java.util.UUID; import mage.MageInt; import mage.MageObject; -import mage.abilities.Ability; import mage.abilities.common.BecomesTargetTriggeredAbility; -import mage.abilities.common.SimpleStaticAbility; -import mage.abilities.effects.EntersBattlefieldEffect; -import mage.abilities.effects.OneShotEffect; +import mage.abilities.common.EntersBattlefieldAbility; +import mage.abilities.effects.Effect; +import mage.abilities.effects.common.CopyPermanentEffect; import mage.abilities.effects.common.SacrificeSourceEffect; import mage.cards.CardImpl; import mage.constants.CardType; -import mage.constants.Outcome; import mage.constants.Rarity; -import mage.constants.Zone; import mage.filter.common.FilterCreaturePermanent; import mage.game.Game; import mage.game.permanent.Permanent; -import mage.players.Player; -import mage.target.Target; -import mage.target.TargetPermanent; import mage.util.functions.ApplyToPermanent; /** @@ -55,7 +49,31 @@ import mage.util.functions.ApplyToPermanent; */ public class PhantasmalImage extends CardImpl { - private static final String abilityText = "You may have {this} enter the battlefield as a copy of any creature on the battlefield, except it's an Illusion in addition to its other types and it gains \"When this creature becomes the target of a spell or ability, sacrifice it.\""; + private static final String effectText = "a copy of any creature on the battlefield, except it's an Illusion in addition to its other types and it gains \"When this creature becomes the target of a spell or ability, sacrifice it.\""; + + ApplyToPermanent phantasmalImageApplier = new ApplyToPermanent() { + @Override + public Boolean apply(Game game, Permanent permanent) { + if (!permanent.getSubtype().contains("Illusion")) { + permanent.getSubtype().add("Illusion"); + } + // Add directly because the created permanent is only used to copy from, so there is no need to add the ability to e.g. TriggeredAbilities + permanent.getAbilities().add(new BecomesTargetTriggeredAbility(new SacrificeSourceEffect())); + //permanent.addAbility(new BecomesTargetTriggeredAbility(new SacrificeSourceEffect()), game); + return true; + } + + @Override + public Boolean apply(Game game, MageObject mageObject) { + if (!mageObject.getSubtype().contains("Illusion")) { + mageObject.getSubtype().add("Illusion"); + } + // Add directly because the created permanent is only used to copy from, so there is no need to add the ability to e.g. TriggeredAbilities + mageObject.getAbilities().add(new BecomesTargetTriggeredAbility(new SacrificeSourceEffect())); + //permanent.addAbility(new BecomesTargetTriggeredAbility(new SacrificeSourceEffect()), game); + return true; + } + }; public PhantasmalImage(UUID ownerId) { super(ownerId, 72, "Phantasmal Image", Rarity.RARE, new CardType[]{CardType.CREATURE}, "{1}{U}"); @@ -69,9 +87,9 @@ public class PhantasmalImage extends CardImpl { // You may have Phantasmal Image enter the battlefield as a copy of any creature // on the battlefield, except it's an Illusion in addition to its other types and // it gains "When this creature becomes the target of a spell or ability, sacrifice it." - Ability ability = new SimpleStaticAbility(Zone.BATTLEFIELD, new EntersBattlefieldEffect( - new PhantasmalImageCopyEffect(), abilityText, true)); - this.addAbility(ability); + Effect effect = new CopyPermanentEffect(new FilterCreaturePermanent(), phantasmalImageApplier); + effect.setText(effectText); + this.addAbility(new EntersBattlefieldAbility(effect, true)); } public PhantasmalImage(final PhantasmalImage card) { @@ -83,62 +101,3 @@ public class PhantasmalImage extends CardImpl { return new PhantasmalImage(this); } } - -class PhantasmalImageCopyEffect extends OneShotEffect { - - public PhantasmalImageCopyEffect() { - super(Outcome.Copy); - } - - public PhantasmalImageCopyEffect(final PhantasmalImageCopyEffect effect) { - super(effect); - } - - @Override - public boolean apply(Game game, Ability source) { - Player player = game.getPlayer(source.getControllerId()); - MageObject sourceObject = game.getObject(source.getSourceId()); - if (player != null && sourceObject != null) { - Target target = new TargetPermanent(new FilterCreaturePermanent("creature (you copy from)")); - target.setNotTarget(true); - if (target.canChoose(source.getSourceId(), source.getControllerId(), game)) { - player.choose(Outcome.Copy, target, source.getSourceId(), game); - Permanent copyFromPermanent = game.getPermanent(target.getFirstTarget()); - if (copyFromPermanent != null) { - game.copyPermanent(copyFromPermanent, sourceObject.getId(), source, new ApplyToPermanent() { - @Override - public Boolean apply(Game game, Permanent permanent) { - if (!permanent.getSubtype().contains("Illusion")) { - permanent.getSubtype().add("Illusion"); - } - // Add directly because the created permanent is only used to copy from, so there is no need to add the ability to e.g. TriggeredAbilities - permanent.getAbilities().add(new BecomesTargetTriggeredAbility(new SacrificeSourceEffect())); - //permanent.addAbility(new BecomesTargetTriggeredAbility(new SacrificeSourceEffect()), game); - return true; - } - - @Override - public Boolean apply(Game game, MageObject mageObject) { - if (!mageObject.getSubtype().contains("Illusion")) { - mageObject.getSubtype().add("Illusion"); - } - // Add directly because the created permanent is only used to copy from, so there is no need to add the ability to e.g. TriggeredAbilities - mageObject.getAbilities().add(new BecomesTargetTriggeredAbility(new SacrificeSourceEffect())); - //permanent.addAbility(new BecomesTargetTriggeredAbility(new SacrificeSourceEffect()), game); - return true; - } - - }); - - return true; - } - } - } - return false; - } - - @Override - public PhantasmalImageCopyEffect copy() { - return new PhantasmalImageCopyEffect(this); - } -} diff --git a/Mage.Sets/src/mage/sets/magic2012/SuturedGhoul.java b/Mage.Sets/src/mage/sets/magic2012/SuturedGhoul.java index 44cc9264d27..6f651062b5e 100644 --- a/Mage.Sets/src/mage/sets/magic2012/SuturedGhoul.java +++ b/Mage.Sets/src/mage/sets/magic2012/SuturedGhoul.java @@ -34,7 +34,6 @@ import mage.abilities.common.AsEntersBattlefieldAbility; import mage.abilities.common.SimpleStaticAbility; import mage.abilities.dynamicvalue.DynamicValue; import mage.abilities.effects.Effect; -import mage.abilities.effects.EntersBattlefieldEffect; import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.continuous.BoostSourceEffect; import mage.abilities.keyword.TrampleAbility; @@ -104,7 +103,7 @@ class SuturedGhoulEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { Player controller = game.getPlayer(source.getControllerId()); - Permanent permanent = (Permanent) getValue(EntersBattlefieldEffect.ENTERING_PERMANENT); + Permanent permanent = game.getPermanentEntering(source.getSourceId()); if (permanent == null) { return false; } diff --git a/Mage.Sets/src/mage/sets/magic2013/AjaniCallerOfThePride.java b/Mage.Sets/src/mage/sets/magic2013/AjaniCallerOfThePride.java index 2575cf4bc83..43b20bce5ec 100644 --- a/Mage.Sets/src/mage/sets/magic2013/AjaniCallerOfThePride.java +++ b/Mage.Sets/src/mage/sets/magic2013/AjaniCallerOfThePride.java @@ -28,16 +28,14 @@ package mage.sets.magic2013; import java.util.UUID; -import mage.MageInt; import mage.abilities.Ability; import mage.abilities.LoyaltyAbility; -import mage.abilities.common.EntersBattlefieldAbility; +import mage.abilities.common.PlanswalkerEntersWithLoyalityCountersAbility; import mage.abilities.dynamicvalue.common.ControllerLifeCount; import mage.abilities.effects.Effect; import mage.abilities.effects.Effects; import mage.abilities.effects.common.CreateTokenEffect; import mage.abilities.effects.common.continuous.GainAbilityTargetEffect; -import mage.abilities.effects.common.counter.AddCountersSourceEffect; import mage.abilities.effects.common.counter.AddCountersTargetEffect; import mage.abilities.keyword.DoubleStrikeAbility; import mage.abilities.keyword.FlyingAbility; @@ -64,12 +62,12 @@ public class AjaniCallerOfThePride extends CardImpl { @Override public void build() { - this.addAbility(new EntersBattlefieldAbility(new AddCountersSourceEffect(CounterType.LOYALTY.createInstance(4)), false)); + this.addAbility(new PlanswalkerEntersWithLoyalityCountersAbility(4)); // +1: Put a +1/+1 counter on up to one target creature. Effect effect = new AddCountersTargetEffect(CounterType.P1P1.createInstance()); effect.setText("Put a +1/+1 counter on up to one target creature"); Ability ability = new LoyaltyAbility(effect, 1); - ability.addTarget(new TargetCreaturePermanent(0,1)); + ability.addTarget(new TargetCreaturePermanent(0, 1)); this.addAbility(ability); // -3: Target creature gains flying and double strike until end of turn. Effects effects = new Effects(); diff --git a/Mage.Sets/src/mage/sets/magic2013/LilianaOfTheDarkRealms.java b/Mage.Sets/src/mage/sets/magic2013/LilianaOfTheDarkRealms.java index b706cc764c0..2ae1156c849 100644 --- a/Mage.Sets/src/mage/sets/magic2013/LilianaOfTheDarkRealms.java +++ b/Mage.Sets/src/mage/sets/magic2013/LilianaOfTheDarkRealms.java @@ -28,6 +28,18 @@ package mage.sets.magic2013; import java.util.UUID; +import mage.Mana; +import mage.abilities.Ability; +import mage.abilities.LoyaltyAbility; +import mage.abilities.common.PlanswalkerEntersWithLoyalityCountersAbility; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.costs.common.TapSourceCost; +import mage.abilities.effects.ContinuousEffectImpl; +import mage.abilities.effects.common.GetEmblemEffect; +import mage.abilities.effects.common.continuous.GainAbilityControlledEffect; +import mage.abilities.effects.common.search.SearchLibraryPutInHandEffect; +import mage.abilities.mana.SimpleManaAbility; +import mage.cards.CardImpl; import mage.constants.CardType; import mage.constants.Duration; import mage.constants.Layer; @@ -36,20 +48,6 @@ import mage.constants.Rarity; import mage.constants.SubLayer; import mage.constants.TargetController; import mage.constants.Zone; -import mage.Mana; -import mage.abilities.Ability; -import mage.abilities.LoyaltyAbility; -import mage.abilities.common.EntersBattlefieldAbility; -import mage.abilities.common.SimpleStaticAbility; -import mage.abilities.costs.common.TapSourceCost; -import mage.abilities.effects.ContinuousEffectImpl; -import mage.abilities.effects.common.GetEmblemEffect; -import mage.abilities.effects.common.continuous.GainAbilityControlledEffect; -import mage.abilities.effects.common.counter.AddCountersSourceEffect; -import mage.abilities.effects.common.search.SearchLibraryPutInHandEffect; -import mage.abilities.mana.SimpleManaAbility; -import mage.cards.CardImpl; -import mage.counters.CounterType; import mage.filter.common.FilterLandCard; import mage.filter.common.FilterLandPermanent; import mage.filter.predicate.mageobject.SubtypePredicate; @@ -78,8 +76,7 @@ public class LilianaOfTheDarkRealms extends CardImpl { this.expansionSetCode = "M13"; this.subtype.add("Liliana"); - - this.addAbility(new EntersBattlefieldAbility(new AddCountersSourceEffect(CounterType.LOYALTY.createInstance(3)), false)); + this.addAbility(new PlanswalkerEntersWithLoyalityCountersAbility(3)); // +1: Search your library for a Swamp card, reveal it, and put it into your hand. Then shuffle your library. this.addAbility(new LoyaltyAbility(new SearchLibraryPutInHandEffect(new TargetCardInLibrary(filter), true), 1)); diff --git a/Mage.Sets/src/mage/sets/magic2014/ChandraPyromaster.java b/Mage.Sets/src/mage/sets/magic2014/ChandraPyromaster.java index 8c3d87f6aad..25de8f9d80e 100644 --- a/Mage.Sets/src/mage/sets/magic2014/ChandraPyromaster.java +++ b/Mage.Sets/src/mage/sets/magic2014/ChandraPyromaster.java @@ -33,12 +33,11 @@ import java.util.UUID; import mage.MageObject; import mage.abilities.Ability; import mage.abilities.LoyaltyAbility; -import mage.abilities.common.EntersBattlefieldAbility; +import mage.abilities.common.PlanswalkerEntersWithLoyalityCountersAbility; import mage.abilities.effects.AsThoughEffectImpl; import mage.abilities.effects.ContinuousEffect; import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.combat.CantBlockTargetEffect; -import mage.abilities.effects.common.counter.AddCountersSourceEffect; import mage.cards.Card; import mage.cards.CardImpl; import mage.cards.Cards; @@ -49,7 +48,6 @@ import mage.constants.Duration; import mage.constants.Outcome; import mage.constants.Rarity; import mage.constants.Zone; -import mage.counters.CounterType; import mage.filter.common.FilterCreaturePermanent; import mage.filter.common.FilterInstantOrSorceryCard; import mage.game.Game; @@ -74,7 +72,7 @@ public class ChandraPyromaster extends CardImpl { this.expansionSetCode = "M14"; this.subtype.add("Chandra"); - this.addAbility(new EntersBattlefieldAbility(new AddCountersSourceEffect(CounterType.LOYALTY.createInstance(4)), false)); + this.addAbility(new PlanswalkerEntersWithLoyalityCountersAbility(4)); // +1: Chandra, Pyromaster deals 1 damage to target player and 1 damage to up to one target creature that player controls. That creature can't block this turn. LoyaltyAbility ability1 = new LoyaltyAbility(new ChandraPyromasterEffect1(), 1); diff --git a/Mage.Sets/src/mage/sets/magic2014/GarrukCallerOfBeasts.java b/Mage.Sets/src/mage/sets/magic2014/GarrukCallerOfBeasts.java index 6cf8ee79c45..4784c9168fa 100644 --- a/Mage.Sets/src/mage/sets/magic2014/GarrukCallerOfBeasts.java +++ b/Mage.Sets/src/mage/sets/magic2014/GarrukCallerOfBeasts.java @@ -31,20 +31,18 @@ import java.util.UUID; import mage.ObjectColor; import mage.abilities.Ability; import mage.abilities.LoyaltyAbility; -import mage.abilities.common.EntersBattlefieldAbility; +import mage.abilities.common.PlanswalkerEntersWithLoyalityCountersAbility; import mage.abilities.common.SpellCastControllerTriggeredAbility; import mage.abilities.effects.Effect; import mage.abilities.effects.common.GetEmblemEffect; import mage.abilities.effects.common.PutPermanentOnBattlefieldEffect; import mage.abilities.effects.common.RevealLibraryPutIntoHandEffect; -import mage.abilities.effects.common.counter.AddCountersSourceEffect; import mage.abilities.effects.common.search.SearchLibraryPutInPlayEffect; import mage.cards.CardImpl; import mage.constants.CardType; import mage.constants.Outcome; import mage.constants.Rarity; import mage.constants.Zone; -import mage.counters.CounterType; import mage.filter.FilterSpell; import mage.filter.common.FilterCreatureCard; import mage.filter.predicate.mageobject.CardTypePredicate; @@ -69,11 +67,10 @@ public class GarrukCallerOfBeasts extends CardImpl { this.expansionSetCode = "M14"; this.subtype.add("Garruk"); - - this.addAbility(new EntersBattlefieldAbility(new AddCountersSourceEffect(CounterType.LOYALTY.createInstance(4)), false)); + this.addAbility(new PlanswalkerEntersWithLoyalityCountersAbility(4)); // +1: Reveal the top 5 cards of your library. Put all creature cards revealed this way into your hand and the rest on the bottom of your library in any order. - this.addAbility(new LoyaltyAbility(new RevealLibraryPutIntoHandEffect(5, new FilterCreatureCard("all creature cards"),true), 1)); + this.addAbility(new LoyaltyAbility(new RevealLibraryPutIntoHandEffect(5, new FilterCreatureCard("all creature cards"), true), 1)); // -3: You may put a green creature card from your hand onto the battlefield. this.addAbility(new LoyaltyAbility(new PutPermanentOnBattlefieldEffect(filterGreenCreature), -3)); @@ -94,18 +91,20 @@ public class GarrukCallerOfBeasts extends CardImpl { } /** - * Emblem: "Whenever you cast a creature spell, you may search your library for a creature card, put it onto the battlefield, then shuffle your library." + * Emblem: "Whenever you cast a creature spell, you may search your library for + * a creature card, put it onto the battlefield, then shuffle your library." */ class GarrukCallerOfBeastsEmblem extends Emblem { private static final FilterSpell filter = new FilterSpell("a creature spell"); + static { filter.add(new CardTypePredicate(CardType.CREATURE)); } public GarrukCallerOfBeastsEmblem() { this.setName("EMBLEM: Garruk, Caller of Beasts"); - Effect effect = new SearchLibraryPutInPlayEffect(new TargetCardInLibrary(new FilterCreatureCard("creature card")),false, true, Outcome.PutCreatureInPlay); + Effect effect = new SearchLibraryPutInPlayEffect(new TargetCardInLibrary(new FilterCreatureCard("creature card")), false, true, Outcome.PutCreatureInPlay); Ability ability = new SpellCastControllerTriggeredAbility(Zone.COMMAND, effect, filter, true, false); this.getAbilities().add(ability); } diff --git a/Mage.Sets/src/mage/sets/magic2014/ImposingSovereign.java b/Mage.Sets/src/mage/sets/magic2014/ImposingSovereign.java index 0a7c07a1299..4a7ae5c389f 100644 --- a/Mage.Sets/src/mage/sets/magic2014/ImposingSovereign.java +++ b/Mage.Sets/src/mage/sets/magic2014/ImposingSovereign.java @@ -58,7 +58,7 @@ public class ImposingSovereign extends CardImpl { // Creatures your opponents control enter the battlefield tapped. this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new ImposingSovereignEffect())); - + } public ImposingSovereign(final ImposingSovereign card) { @@ -72,7 +72,7 @@ public class ImposingSovereign extends CardImpl { } class ImposingSovereignEffect extends ReplacementEffectImpl { - + ImposingSovereignEffect() { super(Duration.WhileOnBattlefield, Outcome.Tap); staticText = "Creatures your opponents control enter the battlefield tapped"; @@ -84,7 +84,7 @@ class ImposingSovereignEffect extends ReplacementEffectImpl { @Override public boolean replaceEvent(GameEvent event, Ability source, Game game) { - Permanent target = game.getPermanent(event.getTargetId()); + Permanent target = game.getPermanentEntering(event.getTargetId()); if (target != null) { target.tap(game); } @@ -95,11 +95,11 @@ class ImposingSovereignEffect extends ReplacementEffectImpl { public boolean checksEventType(GameEvent event, Game game) { return event.getType() == GameEvent.EventType.ENTERS_THE_BATTLEFIELD; } - + @Override public boolean applies(GameEvent event, Ability source, Game game) { if (game.getOpponents(source.getControllerId()).contains(event.getPlayerId())) { - Permanent permanent = game.getPermanent(event.getTargetId()); + Permanent permanent = game.getPermanentEntering(event.getTargetId()); if (permanent != null && permanent.getCardType().contains(CardType.CREATURE)) { return true; } diff --git a/Mage.Sets/src/mage/sets/magic2014/SavageSummoning.java b/Mage.Sets/src/mage/sets/magic2014/SavageSummoning.java index fc7db630f25..0736339d5af 100644 --- a/Mage.Sets/src/mage/sets/magic2014/SavageSummoning.java +++ b/Mage.Sets/src/mage/sets/magic2014/SavageSummoning.java @@ -314,7 +314,7 @@ class SavageSummoningEntersBattlefieldEffect extends ReplacementEffectImpl { @Override public boolean replaceEvent(GameEvent event, Ability source, Game game) { - Permanent creature = game.getPermanent(event.getTargetId()); + Permanent creature = game.getPermanentEntering(event.getTargetId()); if (creature != null) { creature.addCounters(CounterType.P1P1.createInstance(), game); } diff --git a/Mage.Sets/src/mage/sets/magic2015/AjaniSteadfast.java b/Mage.Sets/src/mage/sets/magic2015/AjaniSteadfast.java index b9283d50ea6..aee04861911 100644 --- a/Mage.Sets/src/mage/sets/magic2015/AjaniSteadfast.java +++ b/Mage.Sets/src/mage/sets/magic2015/AjaniSteadfast.java @@ -30,7 +30,7 @@ package mage.sets.magic2015; import java.util.UUID; import mage.abilities.Ability; import mage.abilities.LoyaltyAbility; -import mage.abilities.common.EntersBattlefieldAbility; +import mage.abilities.common.PlanswalkerEntersWithLoyalityCountersAbility; import mage.abilities.common.SimpleStaticAbility; import mage.abilities.effects.Effect; import mage.abilities.effects.PreventionEffectImpl; @@ -38,7 +38,6 @@ import mage.abilities.effects.common.GetEmblemEffect; import mage.abilities.effects.common.continuous.BoostTargetEffect; import mage.abilities.effects.common.continuous.GainAbilityTargetEffect; import mage.abilities.effects.common.counter.AddCountersAllEffect; -import mage.abilities.effects.common.counter.AddCountersSourceEffect; import mage.abilities.keyword.FirstStrikeAbility; import mage.abilities.keyword.LifelinkAbility; import mage.abilities.keyword.VigilanceAbility; @@ -66,22 +65,21 @@ import mage.target.common.TargetCreaturePermanent; public class AjaniSteadfast extends CardImpl { private static final FilterPlaneswalkerPermanent filter = new FilterPlaneswalkerPermanent("other planeswalker you control"); - + static { filter.add(new AnotherPredicate()); filter.add(new ControllerPredicate(TargetController.YOU)); } - + public AjaniSteadfast(UUID ownerId) { super(ownerId, 1, "Ajani Steadfast", Rarity.MYTHIC, new CardType[]{CardType.PLANESWALKER}, "{3}{W}"); this.expansionSetCode = "M15"; this.subtype.add("Ajani"); - - this.addAbility(new EntersBattlefieldAbility(new AddCountersSourceEffect(CounterType.LOYALTY.createInstance(4)), false)); + this.addAbility(new PlanswalkerEntersWithLoyalityCountersAbility(4)); // +1: Until end of turn, up to one target creature gets +1/+1 and gains first strike, vigilance, and lifelink. - Effect effect = new BoostTargetEffect(1,1, Duration.EndOfTurn); + Effect effect = new BoostTargetEffect(1, 1, Duration.EndOfTurn); effect.setText("Until end of turn, up to one target creature gets +1/+1"); LoyaltyAbility ability = new LoyaltyAbility(effect, 1); effect = new GainAbilityTargetEffect(FirstStrikeAbility.getInstance(), Duration.EndOfTurn); @@ -93,16 +91,16 @@ public class AjaniSteadfast extends CardImpl { effect = new GainAbilityTargetEffect(LifelinkAbility.getInstance(), Duration.EndOfTurn); effect.setText(", and lifelink"); ability.addEffect(effect); - ability.addTarget(new TargetCreaturePermanent(0,1)); + ability.addTarget(new TargetCreaturePermanent(0, 1)); this.addAbility(ability); - + // -2: Put a +1/+1 counter on each creature you control and a loyalty counter on each other planeswalker you control. ability = new LoyaltyAbility(new AddCountersAllEffect(CounterType.P1P1.createInstance(), new FilterControlledCreaturePermanent()), -2); effect = new AddCountersAllEffect(CounterType.LOYALTY.createInstance(), filter); effect.setText("and a loyalty counter on each other planeswalker you control"); ability.addEffect(effect); this.addAbility(ability); - + // -7: You get an emblem with "If a source would deal damage to you or a planeswalker you control, prevent all but 1 of that damage." this.addAbility(new LoyaltyAbility(new GetEmblemEffect(new AjaniSteadfastEmblem()), -7)); } @@ -121,7 +119,7 @@ class AjaniSteadfastEmblem extends Emblem { public AjaniSteadfastEmblem() { setName("EMBLEM: Ajani Steadfast"); - this.getAbilities().add(new SimpleStaticAbility(Zone.COMMAND, new AjaniSteadfastPreventEffect())); + this.getAbilities().add(new SimpleStaticAbility(Zone.COMMAND, new AjaniSteadfastPreventEffect())); this.setExpansionSetCodeForImage("M15"); } } @@ -143,7 +141,7 @@ class AjaniSteadfastPreventEffect extends PreventionEffectImpl { int damage = event.getAmount(); if (damage > 1) { amountToPrevent = damage - 1; - preventDamageAction(event, source, game); + preventDamageAction(event, source, game); } return false; } diff --git a/Mage.Sets/src/mage/sets/magic2015/GarrukApexPredator.java b/Mage.Sets/src/mage/sets/magic2015/GarrukApexPredator.java index 955c9019f01..dd839d19569 100644 --- a/Mage.Sets/src/mage/sets/magic2015/GarrukApexPredator.java +++ b/Mage.Sets/src/mage/sets/magic2015/GarrukApexPredator.java @@ -32,7 +32,7 @@ import mage.MageInt; import mage.abilities.Ability; import mage.abilities.LoyaltyAbility; import mage.abilities.common.AttackedByCreatureTriggeredAbility; -import mage.abilities.common.EntersBattlefieldAbility; +import mage.abilities.common.PlanswalkerEntersWithLoyalityCountersAbility; import mage.abilities.effects.Effect; import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.CreateTokenEffect; @@ -40,7 +40,6 @@ import mage.abilities.effects.common.DestroyTargetEffect; import mage.abilities.effects.common.GetEmblemTargetPlayerEffect; import mage.abilities.effects.common.continuous.BoostTargetEffect; import mage.abilities.effects.common.continuous.GainAbilityTargetEffect; -import mage.abilities.effects.common.counter.AddCountersSourceEffect; import mage.abilities.keyword.DeathtouchAbility; import mage.abilities.keyword.TrampleAbility; import mage.cards.CardImpl; @@ -50,7 +49,6 @@ import mage.constants.Outcome; import mage.constants.Rarity; import mage.constants.SetTargetPointer; import mage.constants.Zone; -import mage.counters.CounterType; import mage.filter.FilterPermanent; import mage.filter.predicate.mageobject.CardTypePredicate; import mage.filter.predicate.permanent.AnotherPredicate; @@ -81,7 +79,7 @@ public class GarrukApexPredator extends CardImpl { this.expansionSetCode = "M15"; this.subtype.add("Garruk"); - this.addAbility(new EntersBattlefieldAbility(new AddCountersSourceEffect(CounterType.LOYALTY.createInstance(5)), false)); + this.addAbility(new PlanswalkerEntersWithLoyalityCountersAbility(5)); // +1: Destroy another target planeswalker. LoyaltyAbility ability = new LoyaltyAbility(new DestroyTargetEffect(), 1); diff --git a/Mage.Sets/src/mage/sets/magic2015/GenesisHydra.java b/Mage.Sets/src/mage/sets/magic2015/GenesisHydra.java index 703a9f5a0cf..03eda36b2ff 100644 --- a/Mage.Sets/src/mage/sets/magic2015/GenesisHydra.java +++ b/Mage.Sets/src/mage/sets/magic2015/GenesisHydra.java @@ -131,7 +131,7 @@ class GenesisHydraPutOntoBattlefieldEffect extends OneShotEffect { Card card = cards.get(target1.getFirstTarget(), game); if (card != null) { cards.remove(card); - controller.putOntoBattlefieldWithInfo(card, game, Zone.LIBRARY, source.getSourceId()); + controller.moveCards(card, Zone.BATTLEFIELD, source, game); } target1.clearChosen(); } else { @@ -140,11 +140,7 @@ class GenesisHydraPutOntoBattlefieldEffect extends OneShotEffect { } else { game.informPlayers("No nonland permanent card with converted mana cost " + count + " or less to choose."); } - while (cards.size() > 0) { - Card card = cards.get(cards.iterator().next(), game); - cards.remove(card); - card.moveToZone(Zone.LIBRARY, source.getSourceId(), game, true); - } + controller.moveCards(cards, Zone.LIBRARY, source, game); controller.shuffleLibrary(game); return true; } diff --git a/Mage.Sets/src/mage/sets/magic2015/HushwingGryff.java b/Mage.Sets/src/mage/sets/magic2015/HushwingGryff.java index c644c080918..a05440e99db 100644 --- a/Mage.Sets/src/mage/sets/magic2015/HushwingGryff.java +++ b/Mage.Sets/src/mage/sets/magic2015/HushwingGryff.java @@ -108,7 +108,7 @@ class HushwingGryffEffect extends ContinuousRuleModifyingEffectImpl { public boolean applies(GameEvent event, Ability source, Game game) { Ability ability = (Ability) getValue("targetAbility"); if (ability != null && AbilityType.TRIGGERED.equals(ability.getAbilityType())) { - Permanent permanent = game.getPermanent(event.getTargetId()); + Permanent permanent = game.getPermanentEntering(event.getTargetId()); if (permanent != null && permanent.getCardType().contains(CardType.CREATURE)) { return true; } diff --git a/Mage.Sets/src/mage/sets/magic2015/JaceTheLivingGuildpact.java b/Mage.Sets/src/mage/sets/magic2015/JaceTheLivingGuildpact.java index 964c2310133..7d4c32fbbaa 100644 --- a/Mage.Sets/src/mage/sets/magic2015/JaceTheLivingGuildpact.java +++ b/Mage.Sets/src/mage/sets/magic2015/JaceTheLivingGuildpact.java @@ -30,20 +30,18 @@ package mage.sets.magic2015; import java.util.UUID; import mage.abilities.Ability; import mage.abilities.LoyaltyAbility; -import mage.abilities.common.EntersBattlefieldAbility; +import mage.abilities.common.PlanswalkerEntersWithLoyalityCountersAbility; import mage.abilities.dynamicvalue.common.StaticValue; import mage.abilities.effects.Effect; import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.LookLibraryAndPickControllerEffect; import mage.abilities.effects.common.ReturnToHandTargetEffect; -import mage.abilities.effects.common.counter.AddCountersSourceEffect; import mage.cards.Card; import mage.cards.CardImpl; import mage.constants.CardType; import mage.constants.Outcome; import mage.constants.Rarity; import mage.constants.Zone; -import mage.counters.CounterType; import mage.filter.FilterCard; import mage.filter.FilterPermanent; import mage.filter.common.FilterNonlandPermanent; @@ -69,8 +67,7 @@ public class JaceTheLivingGuildpact extends CardImpl { this.expansionSetCode = "M15"; this.subtype.add("Jace"); - - this.addAbility(new EntersBattlefieldAbility(new AddCountersSourceEffect(CounterType.LOYALTY.createInstance(5)), false)); + this.addAbility(new PlanswalkerEntersWithLoyalityCountersAbility(5)); // +1: Look at the top two cards of your library. Put one of them into your graveyard. Effect effect = new LookLibraryAndPickControllerEffect( @@ -78,7 +75,7 @@ public class JaceTheLivingGuildpact extends CardImpl { effect.setText("Look at the top two cards of your library. Put one of them into your graveyard"); this.addAbility(new LoyaltyAbility(effect, 1)); - // -3: Return another target nonland permanent to its owner's hand. + // -3: Return another target nonland permanent to its owner's hand. LoyaltyAbility ability = new LoyaltyAbility(new ReturnToHandTargetEffect(), -3); ability.addTarget(new TargetPermanent(filter)); this.addAbility(ability); @@ -113,15 +110,15 @@ class JaceTheLivingGuildpactEffect extends OneShotEffect { public boolean apply(Game game, Ability source) { Player controller = game.getPlayer(source.getControllerId()); if (controller != null) { - for (UUID playerId: controller.getInRange()) { + for (UUID playerId : controller.getInRange()) { Player player = game.getPlayer(playerId); if (player != null) { - for (Card card: player.getHand().getCards(game)) { + for (Card card : player.getHand().getCards(game)) { card.moveToZone(Zone.LIBRARY, source.getSourceId(), game, true); - } - for (Card card: player.getGraveyard().getCards(game)) { + } + for (Card card : player.getGraveyard().getCards(game)) { card.moveToZone(Zone.LIBRARY, source.getSourceId(), game, true); - } + } player.shuffleLibrary(game); } } diff --git a/Mage.Sets/src/mage/sets/magic2015/MercurialPretender.java b/Mage.Sets/src/mage/sets/magic2015/MercurialPretender.java index 1aa0cb0c7c6..fcfabc49c0f 100644 --- a/Mage.Sets/src/mage/sets/magic2015/MercurialPretender.java +++ b/Mage.Sets/src/mage/sets/magic2015/MercurialPretender.java @@ -29,25 +29,17 @@ package mage.sets.magic2015; import java.util.UUID; import mage.MageInt; -import mage.MageObject; -import mage.abilities.Ability; +import mage.abilities.common.EntersBattlefieldAbility; import mage.abilities.common.SimpleActivatedAbility; -import mage.abilities.common.SimpleStaticAbility; import mage.abilities.costs.mana.ManaCostsImpl; -import mage.abilities.effects.EntersBattlefieldEffect; -import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.Effect; +import mage.abilities.effects.common.CopyPermanentEffect; import mage.abilities.effects.common.ReturnToHandSourceEffect; 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.game.Game; -import mage.game.permanent.Permanent; -import mage.players.Player; -import mage.target.Target; -import mage.target.TargetPermanent; +import mage.filter.common.FilterCreaturePermanent; import mage.util.functions.AbilityApplier; /** @@ -56,7 +48,7 @@ import mage.util.functions.AbilityApplier; */ public class MercurialPretender extends CardImpl { - private static final String abilityText = "You may have {this} enter the battlefield as a copy of any creature you control except it gains \"{2}{U}{U}: Return this creature to its owner's hand.\""; + private static final String effectText = "as a copy of any creature you control except it gains \"{2}{U}{U}: Return this creature to its owner's hand.\""; public MercurialPretender(UUID ownerId) { super(ownerId, 68, "Mercurial Pretender", Rarity.RARE, new CardType[]{CardType.CREATURE}, "{4}{U}"); @@ -69,9 +61,10 @@ public class MercurialPretender extends CardImpl { // You may have Mercurial Pretender enter the battlefield as a copy of any creature you control // except it gains "{2}{U}{U}: Return this creature to its owner's hand." - Ability ability = new SimpleStaticAbility(Zone.BATTLEFIELD, new EntersBattlefieldEffect( - new MercurialPretenderCopyEffect(), abilityText, true)); - this.addAbility(ability); + Effect effect = new CopyPermanentEffect(new FilterCreaturePermanent(), + new AbilityApplier(new SimpleActivatedAbility(Zone.BATTLEFIELD, new ReturnToHandSourceEffect(true), new ManaCostsImpl("{2}{U}{U}")))); + effect.setText(effectText); + this.addAbility(new EntersBattlefieldAbility(effect, true)); } public MercurialPretender(final MercurialPretender card) { @@ -83,41 +76,3 @@ public class MercurialPretender extends CardImpl { return new MercurialPretender(this); } } - -class MercurialPretenderCopyEffect extends OneShotEffect { - - public MercurialPretenderCopyEffect() { - super(Outcome.Copy); - } - - public MercurialPretenderCopyEffect(final MercurialPretenderCopyEffect effect) { - super(effect); - } - - @Override - public boolean apply(Game game, Ability source) { - Player player = game.getPlayer(source.getControllerId()); - MageObject sourceObject = game.getObject(source.getSourceId()); - if (player != null && sourceObject != null) { - Target target = new TargetPermanent(new FilterControlledCreaturePermanent()); - target.setNotTarget(true); - if (target.canChoose(source.getSourceId(), source.getControllerId(), game)) { - player.choose(Outcome.Copy, target, source.getSourceId(), game); - Permanent copyFromPermanent = game.getPermanent(target.getFirstTarget()); - if (copyFromPermanent != null) { - game.copyPermanent(copyFromPermanent, sourceObject.getId(), source, - // {2}{U}{U}: Return this creature to its owner's hand. - new AbilityApplier(new SimpleActivatedAbility(Zone.BATTLEFIELD, new ReturnToHandSourceEffect(true), new ManaCostsImpl("{2}{U}{U}"))) - ); - return true; - } - } - } - return false; - } - - @Override - public MercurialPretenderCopyEffect copy() { - return new MercurialPretenderCopyEffect(this); - } -} diff --git a/Mage.Sets/src/mage/sets/magic2015/NissaWorldwaker.java b/Mage.Sets/src/mage/sets/magic2015/NissaWorldwaker.java index 3c5177de393..00f8de29bc3 100644 --- a/Mage.Sets/src/mage/sets/magic2015/NissaWorldwaker.java +++ b/Mage.Sets/src/mage/sets/magic2015/NissaWorldwaker.java @@ -31,12 +31,11 @@ import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.LoyaltyAbility; -import mage.abilities.common.EntersBattlefieldAbility; +import mage.abilities.common.PlanswalkerEntersWithLoyalityCountersAbility; import mage.abilities.effects.ContinuousEffect; import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.UntapTargetEffect; import mage.abilities.effects.common.continuous.BecomesCreatureTargetEffect; -import mage.abilities.effects.common.counter.AddCountersSourceEffect; import mage.abilities.keyword.TrampleAbility; import mage.cards.Card; import mage.cards.CardImpl; @@ -46,7 +45,6 @@ import mage.constants.Outcome; import mage.constants.Rarity; import mage.constants.TargetController; import mage.constants.Zone; -import mage.counters.CounterType; import mage.filter.FilterPermanent; import mage.filter.common.FilterBasicLandCard; import mage.filter.common.FilterLandPermanent; @@ -79,9 +77,8 @@ public class NissaWorldwaker extends CardImpl { this.expansionSetCode = "M15"; this.subtype.add("Nissa"); + this.addAbility(new PlanswalkerEntersWithLoyalityCountersAbility(3)); - this.addAbility(new EntersBattlefieldAbility(new AddCountersSourceEffect(CounterType.LOYALTY.createInstance(3)), false)); - // +1: Target land you control becomes a 4/4 Elemental creature with trample. It's still a land. LoyaltyAbility ability = new LoyaltyAbility(new BecomesCreatureTargetEffect(new NissaWorldwakerToken(), false, true, Duration.Custom), 1); ability.addTarget(new TargetLandPermanent(filter)); @@ -89,11 +86,11 @@ public class NissaWorldwaker extends CardImpl { // +1: Untap up to four target Forests. ability = new LoyaltyAbility(new UntapTargetEffect(), 1); - ability.addTarget(new TargetPermanent(0,4,filterForest, false)); + ability.addTarget(new TargetPermanent(0, 4, filterForest, false)); this.addAbility(ability); // -7: Search your library for any number of basic land cards, put them onto the battlefield, then shuffle your library. Those lands become 4/4 Elemental creatures with trample. They're still lands. - this.addAbility(new LoyaltyAbility(new NissaWorldwakerSearchEffect(), -7)); + this.addAbility(new LoyaltyAbility(new NissaWorldwakerSearchEffect(), -7)); } public NissaWorldwaker(final NissaWorldwaker card) { @@ -128,17 +125,17 @@ class NissaWorldwakerSearchEffect extends OneShotEffect { if (player == null) { return false; } - TargetCardInLibrary target = new TargetCardInLibrary(0,Integer.MAX_VALUE, new FilterBasicLandCard()); + TargetCardInLibrary target = new TargetCardInLibrary(0, Integer.MAX_VALUE, new FilterBasicLandCard()); if (player.searchLibrary(target, game)) { if (target.getTargets().size() > 0) { - for (UUID cardId: target.getTargets()) { + for (UUID cardId : target.getTargets()) { Card card = player.getLibrary().getCard(cardId, game); if (card != null) { if (player.putOntoBattlefieldWithInfo(card, game, Zone.LIBRARY, source.getSourceId())) { ContinuousEffect effect = new BecomesCreatureTargetEffect(new NissaWorldwakerToken(), false, true, Duration.Custom); effect.setTargetPointer(new FixedTarget(card.getId())); - game.addEffect(effect, source); - } + game.addEffect(effect, source); + } } } } @@ -159,4 +156,4 @@ class NissaWorldwakerToken extends Token { this.toughness = new MageInt(4); this.addAbility(TrampleAbility.getInstance()); } -} \ No newline at end of file +} diff --git a/Mage.Sets/src/mage/sets/magicorigins/ChandraRoaringFlame.java b/Mage.Sets/src/mage/sets/magicorigins/ChandraRoaringFlame.java index 45882a2ddcf..fe48e846fa9 100644 --- a/Mage.Sets/src/mage/sets/magicorigins/ChandraRoaringFlame.java +++ b/Mage.Sets/src/mage/sets/magicorigins/ChandraRoaringFlame.java @@ -33,18 +33,16 @@ import java.util.UUID; import mage.abilities.Ability; import mage.abilities.LoyaltyAbility; import mage.abilities.common.BeginningOfUpkeepTriggeredAbility; -import mage.abilities.common.EntersBattlefieldAbility; +import mage.abilities.common.PlanswalkerEntersWithLoyalityCountersAbility; import mage.abilities.effects.Effect; import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.DamageTargetEffect; -import mage.abilities.effects.common.counter.AddCountersSourceEffect; import mage.cards.CardImpl; import mage.constants.CardType; import mage.constants.Outcome; import mage.constants.Rarity; import mage.constants.TargetController; import mage.constants.Zone; -import mage.counters.CounterType; import mage.game.Game; import mage.game.command.Emblem; import mage.players.Player; @@ -62,25 +60,24 @@ public class ChandraRoaringFlame extends CardImpl { this.expansionSetCode = "ORI"; this.subtype.add("Chandra"); this.color.setRed(true); - + this.nightCard = true; this.canTransform = true; - - this.addAbility(new EntersBattlefieldAbility(new AddCountersSourceEffect(CounterType.LOYALTY.createInstance(4)), false)); - + + this.addAbility(new PlanswalkerEntersWithLoyalityCountersAbility(4)); + // +1: Chandra, Roaring Flame deals 2 damage to target player. LoyaltyAbility loyaltyAbility = new LoyaltyAbility(new DamageTargetEffect(2), 1); loyaltyAbility.addTarget(new TargetPlayer()); - this.addAbility(loyaltyAbility); - + this.addAbility(loyaltyAbility); + //-2: Chandra, Roaring Flame deals 2 damage to target creature. loyaltyAbility = new LoyaltyAbility(new DamageTargetEffect(2), -2); loyaltyAbility.addTarget(new TargetCreaturePermanent()); - this.addAbility(loyaltyAbility); - + this.addAbility(loyaltyAbility); + //-7: Chandra, Roaring Flame deals 6 damage to each opponent. Each player dealt damage this way gets an emblem with "At the beginning of your upkeep, this emblem deals 3 damage to you." this.addAbility(new LoyaltyAbility(new ChandraRoaringFlameEmblemEffect(), -7)); - } @@ -95,27 +92,27 @@ public class ChandraRoaringFlame extends CardImpl { } class ChandraRoaringFlameEmblemEffect extends OneShotEffect { - + public ChandraRoaringFlameEmblemEffect() { super(Outcome.Damage); this.staticText = "{this} deals 6 damage to each opponent. Each player dealt damage this way gets an emblem with \"At the beginning of your upkeep, this emblem deals 3 damage to you.\""; } - + public ChandraRoaringFlameEmblemEffect(final ChandraRoaringFlameEmblemEffect effect) { super(effect); } - + @Override public ChandraRoaringFlameEmblemEffect copy() { return new ChandraRoaringFlameEmblemEffect(this); } - + @Override public boolean apply(Game game, Ability source) { Player controller = game.getPlayer(source.getControllerId()); if (controller != null) { List opponentsEmblem = new ArrayList<>(); - for(UUID playerId: game.getOpponents(controller.getId())) { + for (UUID playerId : game.getOpponents(controller.getId())) { Player opponent = game.getPlayer(playerId); if (opponent != null) { if (opponent.damage(6, source.getSourceId(), game, false, true) > 0) { @@ -132,7 +129,8 @@ class ChandraRoaringFlameEmblemEffect extends OneShotEffect { } /** - * Emblem with "At the beginning of your upkeep, this emblem deals 3 damage to you." + * Emblem with "At the beginning of your upkeep, this emblem deals 3 damage to + * you." */ class ChandraRoaringFlameEmblem extends Emblem { @@ -142,4 +140,4 @@ class ChandraRoaringFlameEmblem extends Emblem { effect.setText("this emblem deals 3 damage to you"); this.getAbilities().add(new BeginningOfUpkeepTriggeredAbility(Zone.COMMAND, effect, TargetController.YOU, false, true)); } -} \ No newline at end of file +} diff --git a/Mage.Sets/src/mage/sets/magicorigins/GideonBattleForged.java b/Mage.Sets/src/mage/sets/magicorigins/GideonBattleForged.java index 926b6fab831..70692bfa083 100644 --- a/Mage.Sets/src/mage/sets/magicorigins/GideonBattleForged.java +++ b/Mage.Sets/src/mage/sets/magicorigins/GideonBattleForged.java @@ -32,14 +32,13 @@ import mage.MageInt; import mage.MageObjectReference; import mage.abilities.Ability; import mage.abilities.LoyaltyAbility; -import mage.abilities.common.EntersBattlefieldAbility; +import mage.abilities.common.PlanswalkerEntersWithLoyalityCountersAbility; import mage.abilities.effects.Effect; import mage.abilities.effects.RequirementEffect; import mage.abilities.effects.common.PreventAllDamageToSourceEffect; import mage.abilities.effects.common.UntapTargetEffect; import mage.abilities.effects.common.continuous.BecomesCreatureSourceEffect; import mage.abilities.effects.common.continuous.GainAbilityTargetEffect; -import mage.abilities.effects.common.counter.AddCountersSourceEffect; import mage.abilities.keyword.IndestructibleAbility; import mage.cards.CardImpl; import mage.constants.CardType; @@ -47,7 +46,6 @@ import mage.constants.Duration; import mage.constants.Rarity; import mage.constants.TargetController; import mage.constants.TurnPhase; -import mage.counters.CounterType; import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.permanent.ControllerPredicate; import mage.game.Game; @@ -77,7 +75,7 @@ public class GideonBattleForged extends CardImpl { this.nightCard = true; this.canTransform = true; - this.addAbility(new EntersBattlefieldAbility(new AddCountersSourceEffect(CounterType.LOYALTY.createInstance(3)), false)); + this.addAbility(new PlanswalkerEntersWithLoyalityCountersAbility(3)); // +2: Up to one target creature an opponent controls attacks Gideon, Battle-Forged during its controller's next turn if able. LoyaltyAbility loyaltyAbility = new LoyaltyAbility(new GideonBattleForgedAttacksIfAbleTargetEffect(Duration.Custom), 2); diff --git a/Mage.Sets/src/mage/sets/magicorigins/HallowedMoonlight.java b/Mage.Sets/src/mage/sets/magicorigins/HallowedMoonlight.java index 069802820e9..c4cb42fc138 100644 --- a/Mage.Sets/src/mage/sets/magicorigins/HallowedMoonlight.java +++ b/Mage.Sets/src/mage/sets/magicorigins/HallowedMoonlight.java @@ -36,6 +36,7 @@ import mage.constants.CardType; import mage.constants.Duration; import mage.constants.Outcome; import mage.constants.Rarity; +import mage.constants.Zone; import mage.game.Game; import mage.game.events.EntersTheBattlefieldEvent; import mage.game.events.GameEvent; @@ -90,8 +91,7 @@ class HallowedMoonlightEffect extends ReplacementEffectImpl { Player controller = game.getPlayer(source.getControllerId()); if (controller != null) { EntersTheBattlefieldEvent entersTheBattlefieldEvent = (EntersTheBattlefieldEvent) event; - controller.moveCardToExileWithInfo(entersTheBattlefieldEvent.getTarget(), null, "", - source.getSourceId(), game, entersTheBattlefieldEvent.getFromZone(), true); + controller.moveCards(entersTheBattlefieldEvent.getTarget(), Zone.EXILED, source, game, false, false, false, null); return true; } return false; diff --git a/Mage.Sets/src/mage/sets/magicorigins/JaceTelepathUnbound.java b/Mage.Sets/src/mage/sets/magicorigins/JaceTelepathUnbound.java index 7fabc195698..7e87bf53d0c 100644 --- a/Mage.Sets/src/mage/sets/magicorigins/JaceTelepathUnbound.java +++ b/Mage.Sets/src/mage/sets/magicorigins/JaceTelepathUnbound.java @@ -30,7 +30,7 @@ package mage.sets.magicorigins; import java.util.UUID; import mage.abilities.Ability; import mage.abilities.LoyaltyAbility; -import mage.abilities.common.EntersBattlefieldAbility; +import mage.abilities.common.PlanswalkerEntersWithLoyalityCountersAbility; import mage.abilities.common.SpellCastControllerTriggeredAbility; import mage.abilities.effects.AsThoughEffectImpl; import mage.abilities.effects.ContinuousEffect; @@ -40,7 +40,6 @@ import mage.abilities.effects.ReplacementEffectImpl; import mage.abilities.effects.common.GetEmblemEffect; import mage.abilities.effects.common.PutTopCardOfLibraryIntoGraveTargetEffect; import mage.abilities.effects.common.continuous.BoostTargetEffect; -import mage.abilities.effects.common.counter.AddCountersSourceEffect; import mage.cards.Card; import mage.cards.CardImpl; import mage.constants.AsThoughEffectType; @@ -49,7 +48,6 @@ import mage.constants.Duration; import mage.constants.Outcome; import mage.constants.Rarity; import mage.constants.Zone; -import mage.counters.CounterType; import mage.filter.FilterSpell; import mage.filter.common.FilterInstantOrSorceryCard; import mage.game.Game; @@ -77,7 +75,7 @@ public class JaceTelepathUnbound extends CardImpl { this.nightCard = true; this.canTransform = true; - this.addAbility(new EntersBattlefieldAbility(new AddCountersSourceEffect(CounterType.LOYALTY.createInstance(5)), false)); + this.addAbility(new PlanswalkerEntersWithLoyalityCountersAbility(5)); // +1: Up to one target creature gets -2/-0 until your next turn. Effect effect = new BoostTargetEffect(-2, 0, Duration.UntilYourNextTurn); diff --git a/Mage.Sets/src/mage/sets/magicorigins/LilianaDefiantNecromancer.java b/Mage.Sets/src/mage/sets/magicorigins/LilianaDefiantNecromancer.java index c3abacd4394..67cdc1e5242 100644 --- a/Mage.Sets/src/mage/sets/magicorigins/LilianaDefiantNecromancer.java +++ b/Mage.Sets/src/mage/sets/magicorigins/LilianaDefiantNecromancer.java @@ -32,7 +32,7 @@ import mage.abilities.Ability; import mage.abilities.DelayedTriggeredAbility; import mage.abilities.LoyaltyAbility; import mage.abilities.common.DiesCreatureTriggeredAbility; -import mage.abilities.common.EntersBattlefieldAbility; +import mage.abilities.common.PlanswalkerEntersWithLoyalityCountersAbility; import mage.abilities.common.delayed.AtTheBeginOfNextEndStepDelayedTriggeredAbility; import mage.abilities.costs.Cost; import mage.abilities.costs.common.PayVariableLoyaltyCost; @@ -40,7 +40,6 @@ import mage.abilities.effects.Effect; import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.GetEmblemEffect; import mage.abilities.effects.common.ReturnFromGraveyardToBattlefieldTargetEffect; -import mage.abilities.effects.common.counter.AddCountersSourceEffect; import mage.abilities.effects.common.discard.DiscardEachPlayerEffect; import mage.cards.Card; import mage.cards.CardImpl; @@ -49,7 +48,6 @@ import mage.constants.Outcome; import mage.constants.Rarity; import mage.constants.TargetController; import mage.constants.Zone; -import mage.counters.CounterType; import mage.filter.Filter; import mage.filter.FilterCard; import mage.filter.common.FilterCreatureCard; @@ -84,7 +82,7 @@ public class LilianaDefiantNecromancer extends CardImpl { this.nightCard = true; - this.addAbility(new EntersBattlefieldAbility(new AddCountersSourceEffect(CounterType.LOYALTY.createInstance(3)), false)); + this.addAbility(new PlanswalkerEntersWithLoyalityCountersAbility(3)); // +2: Each player discards a card. this.addAbility(new LoyaltyAbility(new DiscardEachPlayerEffect(1, false), 2)); diff --git a/Mage.Sets/src/mage/sets/magicorigins/NissaSageAnimist.java b/Mage.Sets/src/mage/sets/magicorigins/NissaSageAnimist.java index d3a209c463a..c1e5a65d797 100644 --- a/Mage.Sets/src/mage/sets/magicorigins/NissaSageAnimist.java +++ b/Mage.Sets/src/mage/sets/magicorigins/NissaSageAnimist.java @@ -31,12 +31,11 @@ import java.util.UUID; import mage.MageObject; import mage.abilities.Ability; import mage.abilities.LoyaltyAbility; -import mage.abilities.common.EntersBattlefieldAbility; +import mage.abilities.common.PlanswalkerEntersWithLoyalityCountersAbility; import mage.abilities.effects.ContinuousEffectImpl; import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.CreateTokenEffect; import mage.abilities.effects.common.UntapTargetEffect; -import mage.abilities.effects.common.counter.AddCountersSourceEffect; import mage.cards.Card; import mage.cards.CardImpl; import mage.cards.CardsImpl; @@ -47,7 +46,6 @@ import mage.constants.Outcome; import mage.constants.Rarity; import mage.constants.SubLayer; import mage.constants.Zone; -import mage.counters.CounterType; import mage.filter.common.FilterLandPermanent; import mage.game.Game; import mage.game.permanent.Permanent; @@ -69,7 +67,7 @@ public class NissaSageAnimist extends CardImpl { this.nightCard = true; - this.addAbility(new EntersBattlefieldAbility(new AddCountersSourceEffect(CounterType.LOYALTY.createInstance(3)), false)); + this.addAbility(new PlanswalkerEntersWithLoyalityCountersAbility(3)); // +1: Reveal the top card of your library. If it's a land card, put it onto the battlefield. Otherwise, put it into your hand. this.addAbility(new LoyaltyAbility(new NissaSageAnimistPlusOneEffect(), 1)); diff --git a/Mage.Sets/src/mage/sets/mirrodin/ProteusStaff.java b/Mage.Sets/src/mage/sets/mirrodin/ProteusStaff.java index 7cfbf933b62..eaf8987852c 100644 --- a/Mage.Sets/src/mage/sets/mirrodin/ProteusStaff.java +++ b/Mage.Sets/src/mage/sets/mirrodin/ProteusStaff.java @@ -76,21 +76,21 @@ public class ProteusStaff extends CardImpl { } class ProteusStaffEffect extends OneShotEffect { - + ProteusStaffEffect() { super(Outcome.PutCreatureInPlay); this.staticText = "Put target creature on the bottom of its owner's library. That creature's controller reveals cards from the top of his or her library until he or she reveals a creature card. The player puts that card onto the battlefield and the rest on the bottom of his or her library in any order."; } - + ProteusStaffEffect(final ProteusStaffEffect effect) { super(effect); } - + @java.lang.Override public ProteusStaffEffect copy() { return new ProteusStaffEffect(this); } - + @java.lang.Override public boolean apply(Game game, Ability source) { Permanent permanent = game.getPermanent(this.getTargetPointer().getFirst(game, source)); @@ -100,7 +100,7 @@ class ProteusStaffEffect extends OneShotEffect { if (owner != null && controller != null) { // Put target creature on the bottom of its owner's library. owner.moveCardToLibraryWithInfo(permanent, source.getSourceId(), game, Zone.BATTLEFIELD, false, true); - + // That creature's controller reveals cards from the top of his or her library until he or she reveals a creature card. Cards cards = new CardsImpl(); while (controller.getLibrary().size() > 0) { @@ -108,16 +108,15 @@ class ProteusStaffEffect extends OneShotEffect { if (card != null) { if (card.getCardType().contains(CardType.CREATURE)) { // The player puts that card onto the battlefield - controller.putOntoBattlefieldWithInfo(card, game, Zone.LIBRARY, source.getSourceId()); + controller.moveCards(card, Zone.BATTLEFIELD, source, game); break; - } - else { + } else { cards.add(card); } } } controller.revealCards("Proteus Staff", cards, game); - + // and the rest on the bottom of his or her library in any order. while (cards.size() > 0 && controller.canRespond()) { if (cards.size() == 1) { @@ -125,9 +124,8 @@ class ProteusStaffEffect extends OneShotEffect { if (card != null) { controller.moveCardToLibraryWithInfo(card, source.getSourceId(), game, Zone.LIBRARY, false, false); cards.remove(card); - } - } - else { + } + } else { TargetCard target = new TargetCard(Zone.LIBRARY, new FilterCard("card to put on bottom of your library (last chosen will be on bottom)")); controller.choose(Outcome.Neutral, cards, target, game); Card card = cards.get(target.getFirstTarget(), game); diff --git a/Mage.Sets/src/mage/sets/mirrodinbesieged/TezzeretAgentOfBolas.java b/Mage.Sets/src/mage/sets/mirrodinbesieged/TezzeretAgentOfBolas.java index df35e2d49d7..90520e0a75a 100644 --- a/Mage.Sets/src/mage/sets/mirrodinbesieged/TezzeretAgentOfBolas.java +++ b/Mage.Sets/src/mage/sets/mirrodinbesieged/TezzeretAgentOfBolas.java @@ -1,16 +1,16 @@ /* * Copyright 2011 BetaSteward_at_googlemail.com. All rights reserved. - * + * * Redistribution and use in source and binary forms, with or without modification, are * permitted provided that the following conditions are met: - * + * * 1. Redistributions of source code must retain the above copyright notice, this list of * conditions and the following disclaimer. - * + * * 2. Redistributions in binary form must reproduce the above copyright notice, this list * of conditions and the following disclaimer in the documentation and/or other materials * provided with the distribution. - * + * * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR @@ -20,16 +20,17 @@ * 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.mirrodinbesieged; +import java.util.UUID; import mage.abilities.Ability; import mage.abilities.LoyaltyAbility; -import mage.abilities.common.EntersBattlefieldAbility; +import mage.abilities.common.PlanswalkerEntersWithLoyalityCountersAbility; import mage.abilities.dynamicvalue.DynamicValue; import mage.abilities.dynamicvalue.common.PermanentsOnBattlefieldCount; import mage.abilities.effects.Effect; @@ -37,13 +38,11 @@ import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.LookLibraryAndPickControllerEffect; import mage.abilities.effects.common.continuous.AddCardTypeTargetEffect; import mage.abilities.effects.common.continuous.SetPowerToughnessTargetEffect; -import mage.abilities.effects.common.counter.AddCountersSourceEffect; import mage.cards.CardImpl; import mage.constants.CardType; import mage.constants.Duration; import mage.constants.Outcome; import mage.constants.Rarity; -import mage.counters.CounterType; import mage.filter.FilterCard; import mage.filter.common.FilterControlledPermanent; import mage.filter.predicate.mageobject.CardTypePredicate; @@ -52,8 +51,6 @@ import mage.players.Player; import mage.target.TargetPlayer; import mage.target.common.TargetArtifactPermanent; -import java.util.UUID; - /** * * @author BetaSteward_at_googlemail.com @@ -61,6 +58,7 @@ import java.util.UUID; public class TezzeretAgentOfBolas extends CardImpl { private static final FilterCard filter = new FilterCard("an artifact card"); + static { filter.add(new CardTypePredicate(CardType.ARTIFACT)); } @@ -70,8 +68,7 @@ public class TezzeretAgentOfBolas extends CardImpl { this.expansionSetCode = "MBS"; this.subtype.add("Tezzeret"); - - this.addAbility(new EntersBattlefieldAbility(new AddCountersSourceEffect(CounterType.LOYALTY.createInstance(3)), false)); + this.addAbility(new PlanswalkerEntersWithLoyalityCountersAbility(3)); // +1: Look at the top five cards of your library. You may reveal an artifact card from among them and put it into your hand. Put the rest on the bottom of your library in any order. this.addAbility(new LoyaltyAbility(new LookLibraryAndPickControllerEffect(5, 1, filter, true), 1)); @@ -80,7 +77,7 @@ public class TezzeretAgentOfBolas extends CardImpl { Effect effect = new AddCardTypeTargetEffect(CardType.CREATURE, Duration.EndOfGame); effect.setText("Target artifact becomes an artifact creature"); LoyaltyAbility ability1 = new LoyaltyAbility(effect, -1); - effect = new SetPowerToughnessTargetEffect(5,5, Duration.EndOfGame); + effect = new SetPowerToughnessTargetEffect(5, 5, Duration.EndOfGame); effect.setText("with base power and toughness 5/5"); ability1.addEffect(effect); ability1.addTarget(new TargetArtifactPermanent()); diff --git a/Mage.Sets/src/mage/sets/modernmasters/Epochrasite.java b/Mage.Sets/src/mage/sets/modernmasters/Epochrasite.java index 61a7cc1e97e..6f652e82b4e 100644 --- a/Mage.Sets/src/mage/sets/modernmasters/Epochrasite.java +++ b/Mage.Sets/src/mage/sets/modernmasters/Epochrasite.java @@ -67,7 +67,7 @@ public class Epochrasite extends CardImpl { // Epochrasite enters the battlefield with three +1/+1 counters on it if you didn't cast it from your hand. this.addAbility(new EntersBattlefieldAbility( new AddCountersSourceEffect(CounterType.P1P1.createInstance(3)), - new InvertCondition(new CastFromHandCondition()), true, + new InvertCondition(new CastFromHandCondition()), "{this} enters the battlefield with three +1/+1 counters on it if you didn't cast it from your hand",""), new CastFromHandWatcher()); diff --git a/Mage.Sets/src/mage/sets/modernmasters2015/WorldheartPhoenix.java b/Mage.Sets/src/mage/sets/modernmasters2015/WorldheartPhoenix.java index 31277520f32..d790518da10 100644 --- a/Mage.Sets/src/mage/sets/modernmasters2015/WorldheartPhoenix.java +++ b/Mage.Sets/src/mage/sets/modernmasters2015/WorldheartPhoenix.java @@ -139,7 +139,7 @@ public class WorldheartPhoenix extends CardImpl { SpellAbility spellAbility = (SpellAbility) getValue(EntersBattlefieldEffect.SOURCE_CAST_SPELL_ABILITY); if (spellAbility != null && spellAbility.getSourceId().equals(source.getSourceId()) - && permanent.getZoneChangeCounter(game) - 1 == spellAbility.getSourceObjectZoneChangeCounter()) { + && permanent.getZoneChangeCounter(game) == spellAbility.getSourceObjectZoneChangeCounter()) { // TODO: No perfect solution because there could be other effects that allow to cast the card for this mana cost if (spellAbility.getManaCosts().getText().equals("{W}{U}{B}{R}{G}")) { permanent.addCounters(CounterType.P1P1.createInstance(2), game); diff --git a/Mage.Sets/src/mage/sets/morningtide/BramblewoodParagon.java b/Mage.Sets/src/mage/sets/morningtide/BramblewoodParagon.java index 51657bef406..039cbc3f889 100644 --- a/Mage.Sets/src/mage/sets/morningtide/BramblewoodParagon.java +++ b/Mage.Sets/src/mage/sets/morningtide/BramblewoodParagon.java @@ -52,8 +52,9 @@ import mage.game.permanent.Permanent; * @author emerald000 */ public class BramblewoodParagon extends CardImpl { - + private static final FilterControlledCreaturePermanent filter = new FilterControlledCreaturePermanent("Each creature you control with a +1/+1 counter on it"); + static { filter.add(new CounterPredicate(CounterType.P1P1)); } @@ -68,15 +69,15 @@ public class BramblewoodParagon extends CardImpl { // Each other Warrior creature you control enters the battlefield with an additional +1/+1 counter on it. this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new BramblewoodParagonReplacementEffect())); - + // Each creature you control with a +1/+1 counter on it has trample. this.addAbility(new SimpleStaticAbility( - Zone.BATTLEFIELD, + Zone.BATTLEFIELD, new GainAbilityAllEffect( - TrampleAbility.getInstance(), - Duration.WhileOnBattlefield, + TrampleAbility.getInstance(), + Duration.WhileOnBattlefield, filter))); - + } public BramblewoodParagon(final BramblewoodParagon card) { @@ -99,16 +100,16 @@ class BramblewoodParagonReplacementEffect extends ReplacementEffectImpl { BramblewoodParagonReplacementEffect(BramblewoodParagonReplacementEffect effect) { super(effect); } - + @Override public boolean checksEventType(GameEvent event, Game game) { return event.getType() == GameEvent.EventType.ENTERS_THE_BATTLEFIELD; } - + @Override public boolean applies(GameEvent event, Ability source, Game game) { - Permanent creature = game.getPermanent(event.getTargetId()); - return creature != null && creature.getControllerId().equals(source.getControllerId()) + Permanent creature = game.getPermanentEntering(event.getTargetId()); + return creature != null && creature.getControllerId().equals(source.getControllerId()) && creature.getCardType().contains(CardType.CREATURE) && creature.hasSubtype("Warrior") && !event.getTargetId().equals(source.getSourceId()); @@ -116,14 +117,13 @@ class BramblewoodParagonReplacementEffect extends ReplacementEffectImpl { @Override public boolean replaceEvent(GameEvent event, Ability source, Game game) { - Permanent creature = game.getPermanent(event.getTargetId()); + Permanent creature = game.getPermanentEntering(event.getTargetId()); if (creature != null) { creature.addCounters(CounterType.P1P1.createInstance(), game); } return false; } - @Override public BramblewoodParagonReplacementEffect copy() { return new BramblewoodParagonReplacementEffect(this); diff --git a/Mage.Sets/src/mage/sets/morningtide/OonasBlackguard.java b/Mage.Sets/src/mage/sets/morningtide/OonasBlackguard.java index 624ac5cf2dc..2199b73e735 100644 --- a/Mage.Sets/src/mage/sets/morningtide/OonasBlackguard.java +++ b/Mage.Sets/src/mage/sets/morningtide/OonasBlackguard.java @@ -102,7 +102,7 @@ class OonasBlackguardReplacementEffect extends ReplacementEffectImpl { @Override public boolean applies(GameEvent event, Ability source, Game game) { - Permanent creature = game.getPermanent(event.getTargetId()); + Permanent creature = game.getPermanentEntering(event.getTargetId()); if (creature != null && creature.getControllerId().equals(source.getControllerId()) && creature.getCardType().contains(CardType.CREATURE) && creature.hasSubtype("Rogue") @@ -119,7 +119,7 @@ class OonasBlackguardReplacementEffect extends ReplacementEffectImpl { @Override public boolean replaceEvent(GameEvent event, Ability source, Game game) { - Permanent creature = game.getPermanent(event.getTargetId()); + Permanent creature = game.getPermanentEntering(event.getTargetId()); if (creature != null) { creature.addCounters(CounterType.P1P1.createInstance(), game); } diff --git a/Mage.Sets/src/mage/sets/morningtide/RecrossThePaths.java b/Mage.Sets/src/mage/sets/morningtide/RecrossThePaths.java index a1fdaf96195..e4841e300df 100644 --- a/Mage.Sets/src/mage/sets/morningtide/RecrossThePaths.java +++ b/Mage.Sets/src/mage/sets/morningtide/RecrossThePaths.java @@ -54,9 +54,9 @@ public class RecrossThePaths extends CardImpl { super(ownerId, 133, "Recross the Paths", Rarity.UNCOMMON, new CardType[]{CardType.SORCERY}, "{2}{G}"); this.expansionSetCode = "MOR"; - // Reveal cards from the top of your library until you reveal a land card. Put that card onto the battlefield and the rest on the bottom of your library in any order. + // Reveal cards from the top of your library until you reveal a land card. Put that card onto the battlefield and the rest on the bottom of your library in any order. this.getSpellAbility().addEffect(new RecrossThePathsEffect()); - + // Clash with an opponent. If you win, return Recross the Paths to its owner's hand. this.getSpellAbility().addEffect(ClashWinReturnToHandSpellEffect.getInstance()); } @@ -96,23 +96,23 @@ class RecrossThePathsEffect extends OneShotEffect { if (controller == null || sourceObject == null) { return false; } - + Cards cards = new CardsImpl(); Card cardFound = null; while (controller.getLibrary().size() > 0) { Card card = controller.getLibrary().removeFromTop(game); if (card != null) { - cards.add(card); - if (filter.match(card, game)){ + cards.add(card); + if (filter.match(card, game)) { cardFound = card; break; } - } + } } if (!cards.isEmpty()) { - controller.revealCards(sourceObject.getName(), cards, game); + controller.revealCards(sourceObject.getIdName(), cards, game); if (cardFound != null) { - controller.putOntoBattlefieldWithInfo(cardFound, game, Zone.LIBRARY, source.getSourceId()); + controller.moveCards(cardFound, Zone.BATTLEFIELD, source, game); cards.remove(cardFound); } controller.putCardsOnBottomOfLibrary(cards, game, source, true); diff --git a/Mage.Sets/src/mage/sets/morningtide/SageOfFables.java b/Mage.Sets/src/mage/sets/morningtide/SageOfFables.java index c7a423909b4..a634409057b 100644 --- a/Mage.Sets/src/mage/sets/morningtide/SageOfFables.java +++ b/Mage.Sets/src/mage/sets/morningtide/SageOfFables.java @@ -64,7 +64,7 @@ public class SageOfFables extends CardImpl { // Each other Wizard creature you control enters the battlefield with an additional +1/+1 counter on it. this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new SageOfFablesReplacementEffect())); - + // {2}, Remove a +1/+1 counter from a creature you control: Draw a card. Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new DrawCardSourceControllerEffect(1), new GenericManaCost(2)); ability.addCost(new RemoveCounterCost(new TargetControlledCreaturePermanent(), CounterType.P1P1)); @@ -91,16 +91,16 @@ class SageOfFablesReplacementEffect extends ReplacementEffectImpl { SageOfFablesReplacementEffect(SageOfFablesReplacementEffect effect) { super(effect); } - + @Override public boolean checksEventType(GameEvent event, Game game) { return event.getType() == GameEvent.EventType.ENTERS_THE_BATTLEFIELD; } - + @Override public boolean applies(GameEvent event, Ability source, Game game) { - Permanent creature = game.getPermanent(event.getTargetId()); - return creature != null && creature.getControllerId().equals(source.getControllerId()) + Permanent creature = game.getPermanentEntering(event.getTargetId()); + return creature != null && creature.getControllerId().equals(source.getControllerId()) && creature.getCardType().contains(CardType.CREATURE) && creature.getSubtype().contains("Wizard") && !event.getTargetId().equals(source.getSourceId()); @@ -113,14 +113,13 @@ class SageOfFablesReplacementEffect extends ReplacementEffectImpl { @Override public boolean replaceEvent(GameEvent event, Ability source, Game game) { - Permanent creature = game.getPermanent(event.getTargetId()); + Permanent creature = game.getPermanentEntering(event.getTargetId()); if (creature != null) { creature.addCounters(CounterType.P1P1.createInstance(), game); } return false; } - @Override public SageOfFablesReplacementEffect copy() { return new SageOfFablesReplacementEffect(this); diff --git a/Mage.Sets/src/mage/sets/nemesis/ParallaxWave.java b/Mage.Sets/src/mage/sets/nemesis/ParallaxWave.java index 6b1311d8f0e..f2c46b36031 100644 --- a/Mage.Sets/src/mage/sets/nemesis/ParallaxWave.java +++ b/Mage.Sets/src/mage/sets/nemesis/ParallaxWave.java @@ -36,7 +36,6 @@ import mage.abilities.costs.common.RemoveCountersSourceCost; import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.ExileTargetForSourceEffect; import mage.abilities.keyword.FadingAbility; -import mage.cards.Card; import mage.cards.CardImpl; import mage.constants.CardType; import mage.constants.Outcome; @@ -60,10 +59,9 @@ public class ParallaxWave extends CardImpl { super(ownerId, 17, "Parallax Wave", Rarity.RARE, new CardType[]{CardType.ENCHANTMENT}, "{2}{W}{W}"); this.expansionSetCode = "NMS"; - // Fading 5 this.addAbility(new FadingAbility(5, this)); - + // Remove a fade counter from Parallax Wave: Exile target creature. Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new ExileTargetForSourceEffect(), new RemoveCountersSourceCost(CounterType.FADE.createInstance())); ability.addTarget(new TargetCreaturePermanent()); @@ -103,21 +101,16 @@ class ParallaxWaveEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { MageObject sourceObject = source.getSourceObject(game); - if (sourceObject != null) { - int zoneChangeCounter = (sourceObject instanceof PermanentToken) ? source.getSourceObjectZoneChangeCounter() : source.getSourceObjectZoneChangeCounter() -1; + Player controller = game.getPlayer(source.getControllerId()); + if (sourceObject != null && controller != null) { + int zoneChangeCounter = (sourceObject instanceof PermanentToken) ? source.getSourceObjectZoneChangeCounter() : source.getSourceObjectZoneChangeCounter() - 1; UUID exileZoneId = CardUtil.getExileZoneId(game, source.getSourceId(), zoneChangeCounter); if (exileZoneId != null) { ExileZone exileZone = game.getExile().getExileZone(exileZoneId); if (exileZone != null) { - for (Card card: exileZone.getCards(game)) { - Player player = game.getPlayer(card.getOwnerId()); - if (player != null) { - player.putOntoBattlefieldWithInfo(card, game, Zone.EXILED, source.getSourceId()); - } - } - exileZone.clear(); + return controller.moveCards(exileZone.getCards(game), Zone.BATTLEFIELD, source, game, false, false, true, null); } - return true; + return true; } } return false; diff --git a/Mage.Sets/src/mage/sets/newphyrexia/DueRespect.java b/Mage.Sets/src/mage/sets/newphyrexia/DueRespect.java index 2fef2672aa1..d7cdb54f046 100644 --- a/Mage.Sets/src/mage/sets/newphyrexia/DueRespect.java +++ b/Mage.Sets/src/mage/sets/newphyrexia/DueRespect.java @@ -28,14 +28,14 @@ package mage.sets.newphyrexia; 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.effects.ReplacementEffectImpl; import mage.abilities.effects.common.DrawCardSourceControllerEffect; 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.events.GameEvent; import mage.game.permanent.Permanent; @@ -50,7 +50,6 @@ public class DueRespect extends CardImpl { super(ownerId, 8, "Due Respect", Rarity.UNCOMMON, new CardType[]{CardType.INSTANT}, "{1}{W}"); this.expansionSetCode = "NPH"; - // Permanents enter the battlefield tapped this turn. this.getSpellAbility().addEffect(new DueRespectEffect()); // Draw a card. @@ -85,18 +84,18 @@ class DueRespectEffect extends ReplacementEffectImpl { @Override public boolean replaceEvent(GameEvent event, Ability source, Game game) { - Permanent permanent = game.getPermanent(event.getTargetId()); + Permanent permanent = game.getPermanentEntering(event.getTargetId()); if (permanent != null) { permanent.setTapped(true); } return false; } - + @Override public boolean checksEventType(GameEvent event, Game game) { return event.getType() == GameEvent.EventType.ENTERS_THE_BATTLEFIELD; } - + @Override public boolean applies(GameEvent event, Ability source, Game game) { return true; diff --git a/Mage.Sets/src/mage/sets/newphyrexia/KarnLiberated.java b/Mage.Sets/src/mage/sets/newphyrexia/KarnLiberated.java index 5b5a30d8035..e51d4c7d16e 100644 --- a/Mage.Sets/src/mage/sets/newphyrexia/KarnLiberated.java +++ b/Mage.Sets/src/mage/sets/newphyrexia/KarnLiberated.java @@ -34,11 +34,10 @@ import mage.MageObject; import mage.abilities.Ability; import mage.abilities.DelayedTriggeredAbility; import mage.abilities.LoyaltyAbility; -import mage.abilities.common.EntersBattlefieldAbility; +import mage.abilities.common.PlanswalkerEntersWithLoyalityCountersAbility; import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.ExileFromZoneTargetEffect; import mage.abilities.effects.common.ExileTargetEffect; -import mage.abilities.effects.common.counter.AddCountersSourceEffect; import mage.cards.Card; import mage.cards.CardImpl; import mage.cards.Cards; @@ -47,7 +46,6 @@ import mage.constants.CardType; import mage.constants.Outcome; import mage.constants.Rarity; import mage.constants.Zone; -import mage.counters.CounterType; import mage.filter.FilterCard; import mage.game.ExileZone; import mage.game.Game; @@ -72,7 +70,7 @@ public class KarnLiberated extends CardImpl { super(ownerId, 1, "Karn Liberated", Rarity.MYTHIC, new CardType[]{CardType.PLANESWALKER}, "{7}"); this.expansionSetCode = "NPH"; this.subtype.add("Karn"); - this.addAbility(new EntersBattlefieldAbility(new AddCountersSourceEffect(CounterType.LOYALTY.createInstance(6)), false)); + this.addAbility(new PlanswalkerEntersWithLoyalityCountersAbility(6)); // +4: Target player exiles a card from his or her hand. LoyaltyAbility ability1 = new LoyaltyAbility(new ExileFromZoneTargetEffect(Zone.HAND, exileId, this.getIdName(), new FilterCard()), 4); diff --git a/Mage.Sets/src/mage/sets/newphyrexia/OmenMachine.java b/Mage.Sets/src/mage/sets/newphyrexia/OmenMachine.java index 5f88e32d91f..6f7bf4cf1a4 100644 --- a/Mage.Sets/src/mage/sets/newphyrexia/OmenMachine.java +++ b/Mage.Sets/src/mage/sets/newphyrexia/OmenMachine.java @@ -28,11 +28,6 @@ package mage.sets.newphyrexia; 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.common.BeginningOfDrawTriggeredAbility; import mage.abilities.common.SimpleStaticAbility; @@ -40,7 +35,12 @@ import mage.abilities.effects.ContinuousRuleModifyingEffectImpl; import mage.abilities.effects.OneShotEffect; import mage.cards.Card; 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.game.Game; import mage.game.events.GameEvent; import mage.game.events.GameEvent.EventType; @@ -125,9 +125,8 @@ class OmenMachineEffect2 extends OneShotEffect { if (card != null) { player.moveCardToExileWithInfo(card, null, "", source.getSourceId(), game, Zone.LIBRARY, true); if (card.getCardType().contains(CardType.LAND)) { - player.putOntoBattlefieldWithInfo(card, game, Zone.EXILED, source.getSourceId()); - } - else { + player.moveCards(card, Zone.BATTLEFIELD, source, game); + } else { if (card.getSpellAbility().canChooseTarget(game)) { player.cast(card.getSpellAbility(), game, true); } diff --git a/Mage.Sets/src/mage/sets/newphyrexia/TorporOrb.java b/Mage.Sets/src/mage/sets/newphyrexia/TorporOrb.java index 59519623423..eb91ef9938c 100644 --- a/Mage.Sets/src/mage/sets/newphyrexia/TorporOrb.java +++ b/Mage.Sets/src/mage/sets/newphyrexia/TorporOrb.java @@ -40,6 +40,7 @@ import mage.constants.Outcome; import mage.constants.Rarity; import mage.constants.Zone; import mage.game.Game; +import mage.game.events.EntersTheBattlefieldEvent; import mage.game.events.GameEvent; import mage.game.permanent.Permanent; @@ -77,23 +78,24 @@ class TorporOrbEffect extends ContinuousRuleModifyingEffectImpl { TorporOrbEffect(final TorporOrbEffect effect) { super(effect); } - + @Override public boolean checksEventType(GameEvent event, Game game) { return event.getType() == GameEvent.EventType.ENTERS_THE_BATTLEFIELD; } - + @Override public boolean applies(GameEvent event, Ability source, Game game) { Ability ability = (Ability) getValue("targetAbility"); if (ability != null && AbilityType.TRIGGERED.equals(ability.getAbilityType())) { - Permanent p = game.getPermanent(event.getTargetId()); - if (p != null && p.getCardType().contains(CardType.CREATURE)) { + Permanent permanent = ((EntersTheBattlefieldEvent) event).getTarget(); + if (permanent != null && permanent.getCardType().contains(CardType.CREATURE)) { return true; } } return false; } + @Override public String getInfoMessage(Ability source, GameEvent event, Game game) { MageObject mageObject = game.getObject(event.getSourceId()); @@ -103,7 +105,7 @@ class TorporOrbEffect extends ContinuousRuleModifyingEffectImpl { } return null; } - + @Override public TorporOrbEffect copy() { return new TorporOrbEffect(this); diff --git a/Mage.Sets/src/mage/sets/newphyrexia/UrabraskTheHidden.java b/Mage.Sets/src/mage/sets/newphyrexia/UrabraskTheHidden.java index 45d79931645..6dd467f88fb 100644 --- a/Mage.Sets/src/mage/sets/newphyrexia/UrabraskTheHidden.java +++ b/Mage.Sets/src/mage/sets/newphyrexia/UrabraskTheHidden.java @@ -28,16 +28,18 @@ package mage.sets.newphyrexia; import java.util.UUID; - -import mage.constants.*; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.SimpleStaticAbility; import mage.abilities.effects.ReplacementEffectImpl; import mage.abilities.effects.common.continuous.GainAbilityControlledEffect; import mage.abilities.keyword.HasteAbility; -import mage.cards.Card; import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.Outcome; +import mage.constants.Rarity; +import mage.constants.Zone; import mage.filter.common.FilterControlledCreaturePermanent; import mage.game.Game; import mage.game.events.GameEvent; @@ -74,6 +76,7 @@ public class UrabraskTheHidden extends CardImpl { } class UrabraskTheHiddenEffect extends ReplacementEffectImpl { + UrabraskTheHiddenEffect() { super(Duration.WhileOnBattlefield, Outcome.Tap); staticText = "Creatures your opponents control enter the battlefield tapped"; @@ -85,7 +88,7 @@ class UrabraskTheHiddenEffect extends ReplacementEffectImpl { @Override public boolean replaceEvent(GameEvent event, Ability source, Game game) { - Permanent target = game.getPermanent(event.getTargetId()); + Permanent target = game.getPermanentEntering(event.getTargetId()); if (target != null) { target.setTapped(true); } @@ -96,21 +99,20 @@ class UrabraskTheHiddenEffect extends ReplacementEffectImpl { public boolean checksEventType(GameEvent event, Game game) { return event.getType() == EventType.ENTERS_THE_BATTLEFIELD; } - + @Override public boolean applies(GameEvent event, Ability source, Game game) { if (game.getOpponents(source.getControllerId()).contains(event.getPlayerId())) { - Card card = game.getCard(event.getTargetId()); - if (card != null && card.getCardType().contains(CardType.CREATURE)) { + Permanent permanent = game.getPermanentEntering(event.getTargetId()); + if (permanent != null && permanent.getCardType().contains(CardType.CREATURE)) { return true; } } return false; } - @Override public UrabraskTheHiddenEffect copy() { return new UrabraskTheHiddenEffect(this); } -} \ No newline at end of file +} diff --git a/Mage.Sets/src/mage/sets/planarchaos/FrozenAEther.java b/Mage.Sets/src/mage/sets/planarchaos/FrozenAEther.java index 39c827a0a17..e06118df4fa 100644 --- a/Mage.Sets/src/mage/sets/planarchaos/FrozenAEther.java +++ b/Mage.Sets/src/mage/sets/planarchaos/FrozenAEther.java @@ -67,6 +67,7 @@ public class FrozenAEther extends CardImpl { } class FrozenAEtherTapEffect extends ReplacementEffectImpl { + FrozenAEtherTapEffect() { super(Duration.WhileOnBattlefield, Outcome.Tap); staticText = "Artifacts, creatures, and lands your opponents control enter the battlefield tapped"; @@ -78,7 +79,7 @@ class FrozenAEtherTapEffect extends ReplacementEffectImpl { @Override public boolean replaceEvent(GameEvent event, Ability source, Game game) { - Permanent target = game.getPermanent(event.getTargetId()); + Permanent target = game.getPermanentEntering(event.getTargetId()); if (target != null) { target.setTapped(true); } @@ -89,15 +90,15 @@ class FrozenAEtherTapEffect extends ReplacementEffectImpl { public boolean checksEventType(GameEvent event, Game game) { return event.getType() == EventType.ENTERS_THE_BATTLEFIELD; } - + @Override public boolean applies(GameEvent event, Ability source, Game game) { if (game.getOpponents(source.getControllerId()).contains(event.getPlayerId())) { - Permanent permanent = game.getPermanent(event.getTargetId()); - if (permanent != null && - (permanent.getCardType().contains(CardType.CREATURE) || - permanent.getCardType().contains(CardType.LAND) || - permanent.getCardType().contains(CardType.ARTIFACT))) { + Permanent permanent = game.getPermanentEntering(event.getTargetId()); + if (permanent != null + && (permanent.getCardType().contains(CardType.CREATURE) + || permanent.getCardType().contains(CardType.LAND) + || permanent.getCardType().contains(CardType.ARTIFACT))) { return true; } } diff --git a/Mage.Sets/src/mage/sets/planarchaos/VoidstoneGargoyle.java b/Mage.Sets/src/mage/sets/planarchaos/VoidstoneGargoyle.java index 4505e346779..92ebfdb6731 100644 --- a/Mage.Sets/src/mage/sets/planarchaos/VoidstoneGargoyle.java +++ b/Mage.Sets/src/mage/sets/planarchaos/VoidstoneGargoyle.java @@ -34,7 +34,6 @@ import mage.abilities.Ability; import mage.abilities.common.AsEntersBattlefieldAbility; import mage.abilities.common.SimpleStaticAbility; import mage.abilities.effects.ContinuousRuleModifyingEffectImpl; -import mage.abilities.effects.EntersBattlefieldEffect; import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.NameACardEffect; import mage.abilities.keyword.FlyingAbility; @@ -102,7 +101,7 @@ class VoidstoneGargoyleChooseCardEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { Player controller = game.getPlayer(source.getControllerId()); - Permanent permanent = (Permanent) getValue(EntersBattlefieldEffect.ENTERING_PERMANENT); + Permanent permanent = game.getPermanentEntering(source.getSourceId()); if (controller != null && permanent != null) { Choice cardChoice = new ChoiceImpl(); cardChoice.setChoices(CardRepository.instance.getNonLandNames()); diff --git a/Mage.Sets/src/mage/sets/planechase2012/PrimalPlasma.java b/Mage.Sets/src/mage/sets/planechase2012/PrimalPlasma.java index 4d91881eea1..78d965850c7 100644 --- a/Mage.Sets/src/mage/sets/planechase2012/PrimalPlasma.java +++ b/Mage.Sets/src/mage/sets/planechase2012/PrimalPlasma.java @@ -66,7 +66,7 @@ public class PrimalPlasma extends CardImpl { this.toughness = new MageInt(0); // As Primal Plasma enters the battlefield, it becomes your choice of a 3/3 creature, a 2/2 creature with flying, or a 1/6 creature with defender. - this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new PrimalPlasmaReplacementEffect())); + this.addAbility(new SimpleStaticAbility(Zone.ALL, new PrimalPlasmaReplacementEffect())); } public PrimalPlasma(final PrimalPlasma card) { @@ -102,7 +102,7 @@ class PrimalPlasmaReplacementEffect extends ReplacementEffectImpl { @Override public boolean applies(GameEvent event, Ability source, Game game) { if (event.getTargetId().equals(source.getSourceId())) { - Permanent sourcePermanent = game.getPermanent(source.getSourceId()); + Permanent sourcePermanent = game.getPermanentEntering(source.getSourceId()); if (sourcePermanent != null && !sourcePermanent.isFaceDown(game)) { return true; } @@ -117,7 +117,7 @@ class PrimalPlasmaReplacementEffect extends ReplacementEffectImpl { @Override public boolean replaceEvent(GameEvent event, Ability source, Game game) { - Permanent permanent = game.getPermanent(source.getSourceId()); + Permanent permanent = game.getPermanentEntering(source.getSourceId()); if (permanent != null) { Choice choice = new ChoiceImpl(true); choice.setMessage("Choose what " + permanent.getIdName() + " becomes to"); diff --git a/Mage.Sets/src/mage/sets/planechase2012/SakashimasStudent.java b/Mage.Sets/src/mage/sets/planechase2012/SakashimasStudent.java index e16d11cbd58..2797a6b8908 100644 --- a/Mage.Sets/src/mage/sets/planechase2012/SakashimasStudent.java +++ b/Mage.Sets/src/mage/sets/planechase2012/SakashimasStudent.java @@ -29,19 +29,16 @@ package mage.sets.planechase2012; import java.util.UUID; import mage.MageInt; -import mage.MageObject; -import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.common.EntersBattlefieldAbility; import mage.abilities.costs.mana.ManaCostsImpl; -import mage.abilities.effects.EntersBattlefieldEffect; +import mage.abilities.effects.Effect; import mage.abilities.effects.common.CopyPermanentEffect; import mage.abilities.keyword.NinjutsuAbility; import mage.cards.CardImpl; import mage.constants.CardType; import mage.constants.Rarity; -import mage.constants.Zone; -import mage.game.Game; -import mage.game.permanent.Permanent; -import mage.util.functions.ApplyToPermanent; +import mage.filter.common.FilterCreaturePermanent; +import mage.util.functions.AddSubtypeApplier; /** * @@ -60,11 +57,11 @@ public class SakashimasStudent extends CardImpl { // Ninjutsu {1}{U} this.addAbility(new NinjutsuAbility(new ManaCostsImpl("{1}{U}"))); + // You may have Sakashima's Student enter the battlefield as a copy of any creature on the battlefield, except it's still a Ninja in addition to its other creature types. - this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new EntersBattlefieldEffect( - new CopyPermanentEffect(new SakashimasStudentApplyToPermanent()), - "You may have {this} enter the battlefield as a copy of any creature on the battlefield, except it's still a Ninja in addition to its other creature types", - true))); + Effect effect = new CopyPermanentEffect(new FilterCreaturePermanent(), new AddSubtypeApplier("Ninja")); + effect.setText("as a copy of any creature on the battlefield, except it's still a Ninja in addition to its other creature types"); + this.addAbility(new EntersBattlefieldAbility(effect, true)); } @@ -77,23 +74,3 @@ public class SakashimasStudent extends CardImpl { return new SakashimasStudent(this); } } - -class SakashimasStudentApplyToPermanent extends ApplyToPermanent { - - @Override - public Boolean apply(Game game, Permanent permanent) { - if (!permanent.getSubtype().contains("Ninja")) { - permanent.getSubtype().add("Ninja"); - } - return true; - } - - @Override - public Boolean apply(Game game, MageObject mageObject) { - if (!mageObject.getSubtype().contains("Ninja")) { - mageObject.getSubtype().add("Ninja"); - } - return true; - } - -} diff --git a/Mage.Sets/src/mage/sets/planeshift/ArcticMerfolk.java b/Mage.Sets/src/mage/sets/planeshift/ArcticMerfolk.java index 0125728af80..0bdfbb25581 100644 --- a/Mage.Sets/src/mage/sets/planeshift/ArcticMerfolk.java +++ b/Mage.Sets/src/mage/sets/planeshift/ArcticMerfolk.java @@ -61,8 +61,7 @@ public class ArcticMerfolk extends CardImpl { // If Arctic Merfolk was kicked, it enters the battlefield with a +1/+1 counter on it. this.addAbility(new EntersBattlefieldAbility( new AddCountersSourceEffect(CounterType.P1P1.createInstance()), - KickedCondition.getInstance(), - true,"If Arctic Merfolk was kicked, it enters the battlefield with a +1/+1 counter on it.","")); + KickedCondition.getInstance(),"If Arctic Merfolk was kicked, it enters the battlefield with a +1/+1 counter on it.","")); } public ArcticMerfolk(final ArcticMerfolk card) { diff --git a/Mage.Sets/src/mage/sets/planeshift/DralnusPet.java b/Mage.Sets/src/mage/sets/planeshift/DralnusPet.java index 5a94ca0d4ee..bf5b2311558 100644 --- a/Mage.Sets/src/mage/sets/planeshift/DralnusPet.java +++ b/Mage.Sets/src/mage/sets/planeshift/DralnusPet.java @@ -75,7 +75,7 @@ public class DralnusPet extends CardImpl { kickerCosts.add(new DiscardCardCost(new FilterCreatureCard())); this.addAbility(new KickerAbility(kickerCosts)); // If Dralnu's Pet was kicked, it enters the battlefield with flying and with X +1/+1 counters on it, where X is the discarded card's converted mana cost. - Ability ability = new EntersBattlefieldAbility(new DralnusPetEffect(), KickedCondition.getInstance(), true, + Ability ability = new EntersBattlefieldAbility(new DralnusPetEffect(), KickedCondition.getInstance(), "If {this} was kicked, it enters the battlefield with flying and with X +1/+1 counters on it, where X is the discarded card's converted mana cost", ""); ability.addEffect(new GainAbilitySourceEffect(FlyingAbility.getInstance(), Duration.WhileOnBattlefield)); this.addAbility(ability); @@ -115,7 +115,7 @@ class DralnusPetEffect extends OneShotEffect { SpellAbility spellAbility = (SpellAbility) getValue(EntersBattlefieldEffect.SOURCE_CAST_SPELL_ABILITY); if (spellAbility != null && spellAbility.getSourceId().equals(source.getSourceId()) - && permanent.getZoneChangeCounter(game) - 1 == spellAbility.getSourceObjectZoneChangeCounter()) { + && permanent.getZoneChangeCounter(game) == spellAbility.getSourceObjectZoneChangeCounter()) { int cmc = 0; for (Cost cost : spellAbility.getCosts()) { if (cost instanceof DiscardCardCost && ((DiscardCardCost) cost).getCards().size() > 0) { diff --git a/Mage.Sets/src/mage/sets/planeshift/PhyrexianScuta.java b/Mage.Sets/src/mage/sets/planeshift/PhyrexianScuta.java index 5a43de13839..8dae36a679d 100644 --- a/Mage.Sets/src/mage/sets/planeshift/PhyrexianScuta.java +++ b/Mage.Sets/src/mage/sets/planeshift/PhyrexianScuta.java @@ -56,8 +56,7 @@ public class PhyrexianScuta extends CardImpl { // Kicker-Pay 3 life. this.addAbility(new KickerAbility(new PayLifeCost(3))); // If Phyrexian Scuta was kicked, it enters the battlefield with two +1/+1 counters on it. - this.addAbility(new EntersBattlefieldAbility(new AddCountersSourceEffect(CounterType.P1P1.createInstance(2)), KickedCondition.getInstance(), - true, "If Phyrexian Scuta was kicked, it enters the battlefield with two +1/+1 counters on it.", "")); + this.addAbility(new EntersBattlefieldAbility(new AddCountersSourceEffect(CounterType.P1P1.createInstance(2)), KickedCondition.getInstance(), "If Phyrexian Scuta was kicked, it enters the battlefield with two +1/+1 counters on it.", "")); } public PhyrexianScuta(final PhyrexianScuta card) { diff --git a/Mage.Sets/src/mage/sets/ravnica/CopyEnchantment.java b/Mage.Sets/src/mage/sets/ravnica/CopyEnchantment.java index f8c469ed658..e1a02355e1b 100644 --- a/Mage.Sets/src/mage/sets/ravnica/CopyEnchantment.java +++ b/Mage.Sets/src/mage/sets/ravnica/CopyEnchantment.java @@ -30,16 +30,14 @@ package mage.sets.ravnica; import java.util.UUID; import mage.abilities.Ability; import mage.abilities.SpellAbility; -import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.common.EntersBattlefieldAbility; import mage.abilities.effects.Effect; -import mage.abilities.effects.EntersBattlefieldEffect; import mage.abilities.effects.common.AttachEffect; import mage.abilities.effects.common.CopyPermanentEffect; import mage.cards.CardImpl; import mage.constants.CardType; import mage.constants.Outcome; import mage.constants.Rarity; -import mage.constants.Zone; import mage.filter.FilterPermanent; import mage.filter.common.FilterEnchantmentPermanent; import mage.game.Game; @@ -58,13 +56,8 @@ public class CopyEnchantment extends CardImpl { super(ownerId, 42, "Copy Enchantment", Rarity.RARE, new CardType[]{CardType.ENCHANTMENT}, "{2}{U}"); this.expansionSetCode = "RAV"; - // You may have Copy Enchantment enter the battlefield as a copy of any enchantment on the battlefield. - Ability ability = new SimpleStaticAbility(Zone.BATTLEFIELD, new EntersBattlefieldEffect( - new CopyEnchantmentEffect(new FilterEnchantmentPermanent()), - "You may have {this} enter the battlefield as a copy of any enchantment on the battlefield", - true)); - this.addAbility(ability); + this.addAbility(new EntersBattlefieldAbility(new CopyEnchantmentEffect(new FilterEnchantmentPermanent("any enchantment")), true)); } public CopyEnchantment(final CopyEnchantment card) { @@ -82,15 +75,15 @@ class CopyEnchantmentEffect extends CopyPermanentEffect { public CopyEnchantmentEffect(FilterPermanent filter) { super(filter, new EmptyApplyToPermanent()); } - + public CopyEnchantmentEffect(final CopyEnchantmentEffect effect) { super(effect); } - + @Override public boolean apply(Game game, Ability source) { Player controller = game.getPlayer(source.getControllerId()); - Permanent sourcePermanent = game.getPermanent(source.getSourceId()); + Permanent sourcePermanent = game.getPermanentEntering(source.getSourceId()); if (controller != null && sourcePermanent != null) { if (super.apply(game, source)) { Permanent permanentToCopy = getBluePrintPermanent(); @@ -98,9 +91,10 @@ class CopyEnchantmentEffect extends CopyPermanentEffect { if (permanentToCopy.getSubtype().contains("Aura")) { Target target = getBluePrintPermanent().getSpellAbility().getTargets().get(0); Outcome auraOutcome = Outcome.BoostCreature; - Ability: for (Ability ability: getBluePrintPermanent().getAbilities()) { + Ability: + for (Ability ability : getBluePrintPermanent().getAbilities()) { if (ability instanceof SpellAbility) { - for (Effect effect: ability.getEffects()) { + for (Effect effect : ability.getEffects()) { if (effect instanceof AttachEffect) { auraOutcome = effect.getOutcome(); break Ability; @@ -108,6 +102,7 @@ class CopyEnchantmentEffect extends CopyPermanentEffect { } } } + target.setNotTarget(true); if (controller.choose(auraOutcome, target, source.getSourceId(), game)) { UUID targetId = target.getFirstTarget(); Permanent targetPermanent = game.getPermanent(targetId); @@ -127,10 +122,10 @@ class CopyEnchantmentEffect extends CopyPermanentEffect { } return false; } - + @Override public CopyEnchantmentEffect copy() { return new CopyEnchantmentEffect(this); } - + } diff --git a/Mage.Sets/src/mage/sets/ravnica/LoxodonGatekeeper.java b/Mage.Sets/src/mage/sets/ravnica/LoxodonGatekeeper.java index 5b4297fba72..fd8a62fde94 100644 --- a/Mage.Sets/src/mage/sets/ravnica/LoxodonGatekeeper.java +++ b/Mage.Sets/src/mage/sets/ravnica/LoxodonGatekeeper.java @@ -30,20 +30,19 @@ package mage.sets.ravnica; import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; -import mage.cards.CardImpl; -import mage.constants.CardType; -import mage.constants.Rarity; import mage.abilities.common.SimpleStaticAbility; import mage.abilities.effects.ReplacementEffectImpl; +import mage.cards.CardImpl; +import mage.constants.CardType; import mage.constants.Duration; import mage.constants.Outcome; +import mage.constants.Rarity; import mage.constants.Zone; import mage.game.Game; import mage.game.events.GameEvent; import mage.game.events.GameEvent.EventType; import mage.game.permanent.Permanent; - /** * * @author fireshoes @@ -75,6 +74,7 @@ public class LoxodonGatekeeper extends CardImpl { } class LoxodonGatekeeperTapEffect extends ReplacementEffectImpl { + LoxodonGatekeeperTapEffect() { super(Duration.WhileOnBattlefield, Outcome.Tap); staticText = "Artifacts, creatures, and lands your opponents control enter the battlefield tapped"; @@ -86,26 +86,26 @@ class LoxodonGatekeeperTapEffect extends ReplacementEffectImpl { @Override public boolean replaceEvent(GameEvent event, Ability source, Game game) { - Permanent target = game.getPermanent(event.getTargetId()); + Permanent target = game.getPermanentEntering(event.getTargetId()); if (target != null) { target.setTapped(true); } return false; } - + @Override public boolean checksEventType(GameEvent event, Game game) { return event.getType() == EventType.ENTERS_THE_BATTLEFIELD; } - + @Override public boolean applies(GameEvent event, Ability source, Game game) { if (game.getOpponents(source.getControllerId()).contains(event.getPlayerId())) { - Permanent permanent = game.getPermanent(event.getTargetId()); - if (permanent != null && - (permanent.getCardType().contains(CardType.CREATURE) || - permanent.getCardType().contains(CardType.LAND) || - permanent.getCardType().contains(CardType.ARTIFACT))) { + Permanent permanent = game.getPermanentEntering(event.getTargetId()); + if (permanent != null + && (permanent.getCardType().contains(CardType.CREATURE) + || permanent.getCardType().contains(CardType.LAND) + || permanent.getCardType().contains(CardType.ARTIFACT))) { return true; } } diff --git a/Mage.Sets/src/mage/sets/returntoravnica/CorpsejackMenace.java b/Mage.Sets/src/mage/sets/returntoravnica/CorpsejackMenace.java index 91dd5a1a86c..10bf030e45a 100644 --- a/Mage.Sets/src/mage/sets/returntoravnica/CorpsejackMenace.java +++ b/Mage.Sets/src/mage/sets/returntoravnica/CorpsejackMenace.java @@ -28,30 +28,30 @@ package mage.sets.returntoravnica; 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.MageInt; import mage.abilities.Ability; import mage.abilities.common.SimpleStaticAbility; import mage.abilities.effects.ReplacementEffectImpl; import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.Outcome; +import mage.constants.Rarity; +import mage.constants.Zone; import mage.counters.CounterType; import mage.game.Game; import mage.game.events.GameEvent; import mage.game.permanent.Permanent; /** - * http://www.wizards.com/magic/magazine/article.aspx?x=mtg/faq/rtr + * http://www.wizards.com/magic/magazine/article.aspx?x=mtg/faq/rtr * - * If a creature you control would enter the battlefield with a number of +1/+1 - * counters on it, it enters with twice that many instead. + * If a creature you control would enter the battlefield with a number of +1/+1 + * counters on it, it enters with twice that many instead. * - * If you control two Corpsejack Menaces, the number of +1/+1 counters placed - * is four times the original number. Three Corpsejack Menaces multiplies the - * original number by eight, and so on. + * If you control two Corpsejack Menaces, the number of +1/+1 counters placed is + * four times the original number. Three Corpsejack Menaces multiplies the + * original number by eight, and so on. * * @author LevelX2 */ @@ -80,8 +80,8 @@ public class CorpsejackMenace extends CardImpl { } } - class CorpsejackMenaceReplacementEffect extends ReplacementEffectImpl { + CorpsejackMenaceReplacementEffect() { super(Duration.WhileOnBattlefield, Outcome.BoostCreature, false); staticText = "If one or more +1/+1 counters would be placed on a creature you control, twice that many +1/+1 counters are placed on it instead"; @@ -93,24 +93,30 @@ class CorpsejackMenaceReplacementEffect extends ReplacementEffectImpl { @Override public boolean replaceEvent(GameEvent event, Ability source, Game game) { - Permanent p = game.getPermanent(event.getTargetId()); - if (p != null) { - p.addCounters(CounterType.P1P1.createInstance(event.getAmount()*2), game, event.getAppliedEffects()); + Permanent permanent = game.getPermanent(event.getTargetId()); + if (permanent == null) { + permanent = game.getPermanentEntering(event.getTargetId()); + } + if (permanent != null) { + permanent.addCounters(CounterType.P1P1.createInstance(event.getAmount() * 2), game, event.getAppliedEffects()); } return true; } - + @Override public boolean checksEventType(GameEvent event, Game game) { return event.getType() == GameEvent.EventType.ADD_COUNTERS; } - + @Override public boolean applies(GameEvent event, Ability source, Game game) { if (event.getData().equals(CounterType.P1P1.getName())) { - Permanent target = game.getPermanent(event.getTargetId()); - if (target != null && target.getControllerId().equals(source.getControllerId()) - && target.getCardType().contains(CardType.CREATURE)) { + Permanent permanent = game.getPermanent(event.getTargetId()); + if (permanent == null) { + permanent = game.getPermanentEntering(event.getTargetId()); + } + if (permanent != null && permanent.getControllerId().equals(source.getControllerId()) + && permanent.getCardType().contains(CardType.CREATURE)) { return true; } } diff --git a/Mage.Sets/src/mage/sets/returntoravnica/JaceArchitectOfThought.java b/Mage.Sets/src/mage/sets/returntoravnica/JaceArchitectOfThought.java index 93753306a08..cdce3f264d5 100644 --- a/Mage.Sets/src/mage/sets/returntoravnica/JaceArchitectOfThought.java +++ b/Mage.Sets/src/mage/sets/returntoravnica/JaceArchitectOfThought.java @@ -34,11 +34,10 @@ import java.util.UUID; import mage.abilities.Ability; import mage.abilities.DelayedTriggeredAbility; import mage.abilities.LoyaltyAbility; -import mage.abilities.common.EntersBattlefieldAbility; +import mage.abilities.common.PlanswalkerEntersWithLoyalityCountersAbility; import mage.abilities.effects.Effect; import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.continuous.BoostTargetEffect; -import mage.abilities.effects.common.counter.AddCountersSourceEffect; import mage.cards.Card; import mage.cards.CardImpl; import mage.cards.Cards; @@ -48,7 +47,6 @@ import mage.constants.Duration; import mage.constants.Outcome; import mage.constants.Rarity; import mage.constants.Zone; -import mage.counters.CounterType; import mage.filter.FilterCard; import mage.filter.common.FilterNonlandCard; import mage.game.ExileZone; @@ -76,7 +74,7 @@ public class JaceArchitectOfThought extends CardImpl { this.expansionSetCode = "RTR"; this.subtype.add("Jace"); - this.addAbility(new EntersBattlefieldAbility(new AddCountersSourceEffect(CounterType.LOYALTY.createInstance(4)), false)); + this.addAbility(new PlanswalkerEntersWithLoyalityCountersAbility(4)); // +1: Until your next turn, whenever a creature an opponent controls attacks, it gets -1/-0 until end of turn. this.addAbility(new LoyaltyAbility(new JaceArchitectOfThoughtStartEffect1(), 1)); diff --git a/Mage.Sets/src/mage/sets/returntoravnica/TabletOfTheGuilds.java b/Mage.Sets/src/mage/sets/returntoravnica/TabletOfTheGuilds.java index c13d4cf6131..5d838ca5ddd 100644 --- a/Mage.Sets/src/mage/sets/returntoravnica/TabletOfTheGuilds.java +++ b/Mage.Sets/src/mage/sets/returntoravnica/TabletOfTheGuilds.java @@ -32,7 +32,6 @@ import mage.ObjectColor; import mage.abilities.Ability; import mage.abilities.common.AsEntersBattlefieldAbility; import mage.abilities.common.SpellCastControllerTriggeredAbility; -import mage.abilities.effects.EntersBattlefieldEffect; import mage.abilities.effects.OneShotEffect; import mage.cards.CardImpl; import mage.choices.ChoiceColor; @@ -86,7 +85,7 @@ class TabletOfTheGuildsEntersBattlefieldEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { Player player = game.getPlayer(source.getControllerId()); - Permanent permanent = (Permanent) getValue(EntersBattlefieldEffect.ENTERING_PERMANENT); + Permanent permanent = game.getPermanentEntering(source.getSourceId()); if (player != null && permanent != null) { String colors; ChoiceColor colorChoice = new ChoiceColor(); diff --git a/Mage.Sets/src/mage/sets/returntoravnica/VraskaTheUnseen.java b/Mage.Sets/src/mage/sets/returntoravnica/VraskaTheUnseen.java index 3c890808dd2..776fd85498b 100644 --- a/Mage.Sets/src/mage/sets/returntoravnica/VraskaTheUnseen.java +++ b/Mage.Sets/src/mage/sets/returntoravnica/VraskaTheUnseen.java @@ -33,13 +33,12 @@ import mage.abilities.Ability; import mage.abilities.LoyaltyAbility; import mage.abilities.TriggeredAbilityImpl; import mage.abilities.common.DealsCombatDamageToAPlayerTriggeredAbility; -import mage.abilities.common.EntersBattlefieldAbility; +import mage.abilities.common.PlanswalkerEntersWithLoyalityCountersAbility; import mage.abilities.effects.ContinuousEffectImpl; import mage.abilities.effects.Effect; import mage.abilities.effects.common.CreateTokenEffect; import mage.abilities.effects.common.DestroyTargetEffect; import mage.abilities.effects.common.LoseGameTargetPlayerEffect; -import mage.abilities.effects.common.counter.AddCountersSourceEffect; import mage.cards.CardImpl; import mage.constants.CardType; import mage.constants.Duration; @@ -48,7 +47,6 @@ import mage.constants.Outcome; import mage.constants.Rarity; import mage.constants.SubLayer; import mage.constants.Zone; -import mage.counters.CounterType; import mage.game.Game; import mage.game.events.DamagedPlaneswalkerEvent; import mage.game.events.GameEvent; @@ -76,7 +74,7 @@ public class VraskaTheUnseen extends CardImpl { this.expansionSetCode = "RTR"; this.subtype.add("Vraska"); - this.addAbility(new EntersBattlefieldAbility(new AddCountersSourceEffect(CounterType.LOYALTY.createInstance(5)), false)); + this.addAbility(new PlanswalkerEntersWithLoyalityCountersAbility(5)); // +1: Until your next turn, whenever a creature deals combat damage to Vraska the Unseen, destroy that creature. this.addAbility(new LoyaltyAbility(new VraskaTheUnseenGainAbilityEffect(new VraskaTheUnseenTriggeredAbility()), 1)); diff --git a/Mage.Sets/src/mage/sets/riseoftheeldrazi/GideonJura.java b/Mage.Sets/src/mage/sets/riseoftheeldrazi/GideonJura.java index 45fdec326b5..52140b5319a 100644 --- a/Mage.Sets/src/mage/sets/riseoftheeldrazi/GideonJura.java +++ b/Mage.Sets/src/mage/sets/riseoftheeldrazi/GideonJura.java @@ -1,16 +1,16 @@ /* * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. - * + * * Redistribution and use in source and binary forms, with or without modification, are * permitted provided that the following conditions are met: - * + * * 1. Redistributions of source code must retain the above copyright notice, this list of * conditions and the following disclaimer. - * + * * 2. Redistributions in binary form must reproduce the above copyright notice, this list * of conditions and the following disclaimer in the documentation and/or other materials * provided with the distribution. - * + * * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR @@ -20,12 +20,11 @@ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * + * * The views and conclusions contained in the software and documentation are those of the * authors and should not be interpreted as representing official policies, either expressed * or implied, of BetaSteward_at_googlemail.com. */ - package mage.sets.riseoftheeldrazi; import java.util.UUID; @@ -33,19 +32,17 @@ import mage.MageInt; import mage.MageObjectReference; import mage.abilities.Ability; import mage.abilities.LoyaltyAbility; -import mage.abilities.common.EntersBattlefieldAbility; +import mage.abilities.common.PlanswalkerEntersWithLoyalityCountersAbility; import mage.abilities.effects.Effect; import mage.abilities.effects.RequirementEffect; import mage.abilities.effects.common.DestroyTargetEffect; import mage.abilities.effects.common.PreventAllDamageToSourceEffect; import mage.abilities.effects.common.continuous.BecomesCreatureSourceEffect; -import mage.abilities.effects.common.counter.AddCountersSourceEffect; import mage.cards.CardImpl; import mage.constants.CardType; import mage.constants.Duration; import mage.constants.Rarity; import mage.constants.TurnPhase; -import mage.counters.CounterType; import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.permanent.TappedPredicate; import mage.game.Game; @@ -71,9 +68,8 @@ public class GideonJura extends CardImpl { this.expansionSetCode = "ROE"; this.subtype.add("Gideon"); + this.addAbility(new PlanswalkerEntersWithLoyalityCountersAbility(6)); - this.addAbility(new EntersBattlefieldAbility(new AddCountersSourceEffect(CounterType.LOYALTY.createInstance(6)), false)); - // +2: During target opponent's next turn, creatures that player controls attack Gideon Jura if able. LoyaltyAbility ability1 = new LoyaltyAbility(new GideonJuraEffect(), 2); ability1.addTarget(new TargetOpponent()); @@ -148,9 +144,9 @@ class GideonJuraEffect extends RequirementEffect { @Override public boolean isInactive(Ability source, Game game) { - return (startingTurn != game.getTurnNum() && - (game.getPhase().getType() == TurnPhase.END && - game.getActivePlayerId().equals(source.getFirstTarget()))) + return (startingTurn != game.getTurnNum() + && (game.getPhase().getType() == TurnPhase.END + && game.getActivePlayerId().equals(source.getFirstTarget()))) || // 6/15/2010: If a creature controlled by the affected player can't attack Gideon Jura (because he's no longer on the battlefield, for example), that player may have it attack you, another one of your planeswalkers, or nothing at all. creatingPermanent.getPermanent(game) == null; } @@ -169,4 +165,4 @@ class GideonJuraEffect extends RequirementEffect { public boolean mustBlock(Game game) { return false; } -} \ No newline at end of file +} diff --git a/Mage.Sets/src/mage/sets/riseoftheeldrazi/SarkhanTheMad.java b/Mage.Sets/src/mage/sets/riseoftheeldrazi/SarkhanTheMad.java index 8cdd3585f79..8252432060e 100644 --- a/Mage.Sets/src/mage/sets/riseoftheeldrazi/SarkhanTheMad.java +++ b/Mage.Sets/src/mage/sets/riseoftheeldrazi/SarkhanTheMad.java @@ -33,9 +33,8 @@ import mage.MageInt; import mage.MageObject; import mage.abilities.Ability; import mage.abilities.LoyaltyAbility; -import mage.abilities.common.EntersBattlefieldAbility; +import mage.abilities.common.PlanswalkerEntersWithLoyalityCountersAbility; import mage.abilities.effects.OneShotEffect; -import mage.abilities.effects.common.counter.AddCountersSourceEffect; import mage.cards.Card; import mage.cards.CardImpl; import mage.cards.CardsImpl; @@ -43,7 +42,6 @@ import mage.constants.CardType; import mage.constants.Outcome; import mage.constants.Rarity; import mage.constants.Zone; -import mage.counters.CounterType; import mage.filter.common.FilterControlledPermanent; import mage.filter.predicate.mageobject.CardTypePredicate; import mage.filter.predicate.mageobject.SubtypePredicate; @@ -65,7 +63,7 @@ public class SarkhanTheMad extends CardImpl { super(ownerId, 214, "Sarkhan the Mad", Rarity.MYTHIC, new CardType[]{CardType.PLANESWALKER}, "{3}{B}{R}"); this.expansionSetCode = "ROE"; this.subtype.add("Sarkhan"); - this.addAbility(new EntersBattlefieldAbility(new AddCountersSourceEffect(CounterType.LOYALTY.createInstance(7)), false)); + this.addAbility(new PlanswalkerEntersWithLoyalityCountersAbility(7)); this.addAbility(new LoyaltyAbility(new SarkhanTheMadRevealAndDrawEffect(), 0)); diff --git a/Mage.Sets/src/mage/sets/riseoftheeldrazi/WallOfOmens.java b/Mage.Sets/src/mage/sets/riseoftheeldrazi/WallOfOmens.java index 2b68b4fc8c4..67375b8e9c8 100644 --- a/Mage.Sets/src/mage/sets/riseoftheeldrazi/WallOfOmens.java +++ b/Mage.Sets/src/mage/sets/riseoftheeldrazi/WallOfOmens.java @@ -1,16 +1,16 @@ /* * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. - * + * * Redistribution and use in source and binary forms, with or without modification, are * permitted provided that the following conditions are met: - * + * * 1. Redistributions of source code must retain the above copyright notice, this list of * conditions and the following disclaimer. - * + * * 2. Redistributions in binary form must reproduce the above copyright notice, this list * of conditions and the following disclaimer in the documentation and/or other materials * provided with the distribution. - * + * * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR @@ -20,22 +20,21 @@ * 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.riseoftheeldrazi; import java.util.UUID; -import mage.constants.CardType; -import mage.constants.Rarity; import mage.MageInt; import mage.abilities.common.EntersBattlefieldTriggeredAbility; import mage.abilities.effects.common.DrawCardSourceControllerEffect; import mage.abilities.keyword.DefenderAbility; import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.Rarity; /** * @@ -51,7 +50,10 @@ public class WallOfOmens extends CardImpl { this.power = new MageInt(0); this.toughness = new MageInt(4); + // Defender this.addAbility(DefenderAbility.getInstance()); + + // When Wall of Omens enters the battlefield, draw a card. this.addAbility(new EntersBattlefieldTriggeredAbility(new DrawCardSourceControllerEffect(1), false)); } diff --git a/Mage.Sets/src/mage/sets/saviorsofkamigawa/SakashimaTheImpostor.java b/Mage.Sets/src/mage/sets/saviorsofkamigawa/SakashimaTheImpostor.java index 3a4232607be..f468e0e748b 100644 --- a/Mage.Sets/src/mage/sets/saviorsofkamigawa/SakashimaTheImpostor.java +++ b/Mage.Sets/src/mage/sets/saviorsofkamigawa/SakashimaTheImpostor.java @@ -30,26 +30,21 @@ package mage.sets.saviorsofkamigawa; import java.util.UUID; import mage.MageInt; import mage.MageObject; -import mage.abilities.Ability; +import mage.abilities.common.EntersBattlefieldAbility; import mage.abilities.common.SimpleActivatedAbility; -import mage.abilities.common.SimpleStaticAbility; import mage.abilities.common.delayed.AtTheBeginOfNextEndStepDelayedTriggeredAbility; import mage.abilities.costs.mana.ManaCostsImpl; -import mage.abilities.effects.EntersBattlefieldEffect; -import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.Effect; +import mage.abilities.effects.common.CopyPermanentEffect; import mage.abilities.effects.common.CreateDelayedTriggeredAbilityEffect; import mage.abilities.effects.common.ReturnToHandSourceEffect; import mage.cards.CardImpl; import mage.constants.CardType; -import mage.constants.Outcome; import mage.constants.Rarity; import mage.constants.Zone; import mage.filter.common.FilterCreaturePermanent; import mage.game.Game; import mage.game.permanent.Permanent; -import mage.players.Player; -import mage.target.Target; -import mage.target.TargetPermanent; import mage.util.functions.ApplyToPermanent; /** @@ -58,8 +53,6 @@ import mage.util.functions.ApplyToPermanent; */ public class SakashimaTheImpostor extends CardImpl { - private static final String abilityText = "You may have {this} enter the battlefield as a copy of any creature on the battlefield, except its name is still Sakashima the Impostor, it's legendary in addition to its other types, and it gains \"{2}{U}{U}: Return Sakashima the Impostor to its owner's hand at the beginning of the next end step.\""; - public SakashimaTheImpostor(UUID ownerId) { super(ownerId, 53, "Sakashima the Impostor", Rarity.RARE, new CardType[]{CardType.CREATURE}, "{2}{U}{U}"); this.expansionSetCode = "SOK"; @@ -70,9 +63,9 @@ public class SakashimaTheImpostor extends CardImpl { this.toughness = new MageInt(1); // You may have Sakashima the Impostor enter the battlefield as a copy of any creature on the battlefield, except its name is still Sakashima the Impostor, it's legendary in addition to its other types, and it gains "{2}{U}{U}: Return Sakashima the Impostor to its owner's hand at the beginning of the next end step." - Ability ability = new SimpleStaticAbility(Zone.BATTLEFIELD, new EntersBattlefieldEffect( - new SakashimaTheImpostorCopyEffect(), abilityText, true)); - this.addAbility(ability); + Effect effect = new CopyPermanentEffect(new FilterCreaturePermanent(), new SakashimaTheImpostorApplier()); + effect.setText("as a copy of any creature on the battlefield, except its name is still Sakashima the Impostor, it's legendary in addition to its other types, and it gains \"{2}{U}{U}: Return {this} to its owner's hand at the beginning of the next end step.\""); + this.addAbility(new EntersBattlefieldAbility(effect, true)); } public SakashimaTheImpostor(final SakashimaTheImpostor card) { @@ -85,67 +78,34 @@ public class SakashimaTheImpostor extends CardImpl { } } -class SakashimaTheImpostorCopyEffect extends OneShotEffect { - - public SakashimaTheImpostorCopyEffect() { - super(Outcome.Copy); - } - - public SakashimaTheImpostorCopyEffect(final SakashimaTheImpostorCopyEffect effect) { - super(effect); - } +class SakashimaTheImpostorApplier extends ApplyToPermanent { @Override - public boolean apply(Game game, Ability source) { - Player player = game.getPlayer(source.getControllerId()); - MageObject sourceObject = game.getObject(source.getSourceId()); - if (player != null && sourceObject != null) { - Target target = new TargetPermanent(new FilterCreaturePermanent()); - target.setNotTarget(true); - if (target.canChoose(source.getSourceId(), source.getControllerId(), game)) { - player.choose(Outcome.Copy, target, source.getSourceId(), game); - Permanent copyFromPermanent = game.getPermanent(target.getFirstTarget()); - if (copyFromPermanent != null) { - game.copyPermanent(copyFromPermanent, sourceObject.getId(), source, new ApplyToPermanent() { - @Override - public Boolean apply(Game game, Permanent permanent) { - if (!permanent.getSupertype().contains("Legendary")) { - permanent.getSubtype().add("Legendary"); - } - permanent.setName("Sakashima the Impostor"); - // {2}{U}{U}: Return Sakashima the Impostor to its owner's hand at the beginning of the next end step - permanent.addAbility(new SimpleActivatedAbility(Zone.BATTLEFIELD, - new CreateDelayedTriggeredAbilityEffect(new AtTheBeginOfNextEndStepDelayedTriggeredAbility(new ReturnToHandSourceEffect(true)), false), - new ManaCostsImpl("{2}{U}{U}") - ), game); - return true; - } - - @Override - public Boolean apply(Game game, MageObject mageObject) { - if (!mageObject.getSupertype().contains("Legendary")) { - mageObject.getSubtype().add("Legendary"); - } - mageObject.setName("Sakashima the Impostor"); - // {2}{U}{U}: Return Sakashima the Impostor to its owner's hand at the beginning of the next end step - mageObject.getAbilities().add(new SimpleActivatedAbility(Zone.BATTLEFIELD, - new CreateDelayedTriggeredAbilityEffect(new AtTheBeginOfNextEndStepDelayedTriggeredAbility(new ReturnToHandSourceEffect(true)), false), - new ManaCostsImpl("{2}{U}{U}") - )); - return true; - } - - }); - - return true; - } - } + public Boolean apply(Game game, Permanent permanent) { + if (!permanent.getSupertype().contains("Legendary")) { + permanent.getSubtype().add("Legendary"); } - return false; + permanent.setName("Sakashima the Impostor"); + // {2}{U}{U}: Return Sakashima the Impostor to its owner's hand at the beginning of the next end step + permanent.addAbility(new SimpleActivatedAbility(Zone.BATTLEFIELD, + new CreateDelayedTriggeredAbilityEffect(new AtTheBeginOfNextEndStepDelayedTriggeredAbility(new ReturnToHandSourceEffect(true)), false), + new ManaCostsImpl("{2}{U}{U}") + ), game); + return true; } @Override - public SakashimaTheImpostorCopyEffect copy() { - return new SakashimaTheImpostorCopyEffect(this); + public Boolean apply(Game game, MageObject mageObject) { + if (!mageObject.getSupertype().contains("Legendary")) { + mageObject.getSubtype().add("Legendary"); + } + mageObject.setName("Sakashima the Impostor"); + // {2}{U}{U}: Return Sakashima the Impostor to its owner's hand at the beginning of the next end step + mageObject.getAbilities().add(new SimpleActivatedAbility(Zone.BATTLEFIELD, + new CreateDelayedTriggeredAbilityEffect(new AtTheBeginOfNextEndStepDelayedTriggeredAbility(new ReturnToHandSourceEffect(true)), false), + new ManaCostsImpl("{2}{U}{U}") + )); + return true; } + } diff --git a/Mage.Sets/src/mage/sets/scarsofmirrodin/ElspethTirel.java b/Mage.Sets/src/mage/sets/scarsofmirrodin/ElspethTirel.java index 9de094b78e4..893edc2be14 100644 --- a/Mage.Sets/src/mage/sets/scarsofmirrodin/ElspethTirel.java +++ b/Mage.Sets/src/mage/sets/scarsofmirrodin/ElspethTirel.java @@ -25,20 +25,18 @@ * authors and should not be interpreted as representing official policies, either expressed * or implied, of BetaSteward_at_googlemail.com. */ - package mage.sets.scarsofmirrodin; -import mage.constants.CardType; -import mage.constants.Rarity; +import java.util.UUID; import mage.abilities.Ability; import mage.abilities.LoyaltyAbility; -import mage.abilities.common.EntersBattlefieldAbility; +import mage.abilities.common.PlanswalkerEntersWithLoyalityCountersAbility; import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.CreateTokenEffect; -import mage.abilities.effects.common.counter.AddCountersSourceEffect; import mage.cards.CardImpl; +import mage.constants.CardType; import mage.constants.Outcome; -import mage.counters.CounterType; +import mage.constants.Rarity; import mage.filter.common.FilterCreaturePermanent; import mage.game.Game; import mage.game.permanent.Permanent; @@ -46,28 +44,25 @@ import mage.game.permanent.PermanentToken; import mage.game.permanent.token.SoldierToken; import mage.players.Player; -import java.util.UUID; - /** * * @author Loki */ public class ElspethTirel extends CardImpl { - public ElspethTirel (UUID ownerId) { + public ElspethTirel(UUID ownerId) { super(ownerId, 6, "Elspeth Tirel", Rarity.MYTHIC, new CardType[]{CardType.PLANESWALKER}, "{3}{W}{W}"); this.expansionSetCode = "SOM"; this.subtype.add("Elspeth"); - this.addAbility(new EntersBattlefieldAbility(new AddCountersSourceEffect(CounterType.LOYALTY.createInstance(4)), false)); - + this.addAbility(new PlanswalkerEntersWithLoyalityCountersAbility(4)); this.addAbility(new LoyaltyAbility(new ElspethTirelFirstEffect(), 2)); this.addAbility(new LoyaltyAbility(new CreateTokenEffect(new SoldierToken(), 3), -2)); this.addAbility(new LoyaltyAbility(new ElspethTirelThirdEffect(), -5)); } - public ElspethTirel (final ElspethTirel card) { + public ElspethTirel(final ElspethTirel card) { super(card); } @@ -78,6 +73,7 @@ public class ElspethTirel extends CardImpl { } class ElspethTirelFirstEffect extends OneShotEffect { + public ElspethTirelFirstEffect() { super(Outcome.GainLife); staticText = "You gain 1 life for each creature you control"; @@ -105,6 +101,7 @@ class ElspethTirelFirstEffect extends OneShotEffect { } class ElspethTirelThirdEffect extends OneShotEffect { + public ElspethTirelThirdEffect() { super(Outcome.DestroyPermanent); staticText = "Destroy all other permanents except for lands and tokens"; @@ -116,9 +113,10 @@ class ElspethTirelThirdEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { - for (Permanent perm: game.getBattlefield().getActivePermanents(source.getControllerId(), game)) { - if (!perm.getId().equals(source.getSourceId()) && !(perm instanceof PermanentToken) && ! (perm.getCardType().contains(CardType.LAND))) + for (Permanent perm : game.getBattlefield().getActivePermanents(source.getControllerId(), game)) { + if (!perm.getId().equals(source.getSourceId()) && !(perm instanceof PermanentToken) && !(perm.getCardType().contains(CardType.LAND))) { perm.destroy(source.getSourceId(), game, false); + } } return true; } @@ -128,4 +126,4 @@ class ElspethTirelThirdEffect extends OneShotEffect { return new ElspethTirelThirdEffect(this); } -} \ No newline at end of file +} diff --git a/Mage.Sets/src/mage/sets/scarsofmirrodin/KothOfTheHammer.java b/Mage.Sets/src/mage/sets/scarsofmirrodin/KothOfTheHammer.java index c9c727992b0..1af105c5b8e 100644 --- a/Mage.Sets/src/mage/sets/scarsofmirrodin/KothOfTheHammer.java +++ b/Mage.Sets/src/mage/sets/scarsofmirrodin/KothOfTheHammer.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.scarsofmirrodin; import java.util.UUID; @@ -33,7 +32,7 @@ import mage.MageInt; import mage.Mana; import mage.abilities.Ability; import mage.abilities.LoyaltyAbility; -import mage.abilities.common.EntersBattlefieldAbility; +import mage.abilities.common.PlanswalkerEntersWithLoyalityCountersAbility; import mage.abilities.common.SimpleActivatedAbility; import mage.abilities.common.SimpleStaticAbility; import mage.abilities.costs.common.TapSourceCost; @@ -44,7 +43,6 @@ import mage.abilities.effects.common.DynamicManaEffect; import mage.abilities.effects.common.GetEmblemEffect; import mage.abilities.effects.common.UntapTargetEffect; import mage.abilities.effects.common.continuous.BecomesCreatureTargetEffect; -import mage.abilities.effects.common.counter.AddCountersSourceEffect; import mage.cards.CardImpl; import mage.constants.CardType; import mage.constants.Duration; @@ -54,7 +52,6 @@ import mage.constants.Rarity; import mage.constants.SubLayer; import mage.constants.TargetController; import mage.constants.Zone; -import mage.counters.CounterType; import mage.filter.common.FilterLandPermanent; import mage.filter.predicate.mageobject.SubtypePredicate; import mage.filter.predicate.permanent.ControllerPredicate; @@ -70,6 +67,7 @@ import mage.target.common.TargetLandPermanent; * @author Loki, North */ public class KothOfTheHammer extends CardImpl { + static final FilterLandPermanent filter = new FilterLandPermanent("Mountain"); private static final FilterLandPermanent filterCount = new FilterLandPermanent("Mountain you control"); @@ -80,15 +78,13 @@ public class KothOfTheHammer extends CardImpl { filterCount.add(new ControllerPredicate(TargetController.YOU)); } - public KothOfTheHammer (UUID ownerId) { + public KothOfTheHammer(UUID ownerId) { super(ownerId, 94, "Koth of the Hammer", Rarity.MYTHIC, new CardType[]{CardType.PLANESWALKER}, "{2}{R}{R}"); this.expansionSetCode = "SOM"; this.subtype.add("Koth"); + this.addAbility(new PlanswalkerEntersWithLoyalityCountersAbility(3)); - - this.addAbility(new EntersBattlefieldAbility(new AddCountersSourceEffect(CounterType.LOYALTY.createInstance(3)), false)); - // +1: Untap target Mountain. It becomes a 4/4 red Elemental creature until end of turn. It's still a land. Ability ability = new LoyaltyAbility(new UntapTargetEffect(), 1); ability.addEffect(new BecomesCreatureTargetEffect(new KothOfTheHammerToken(), false, true, Duration.EndOfTurn)); @@ -102,7 +98,7 @@ public class KothOfTheHammer extends CardImpl { this.addAbility(new LoyaltyAbility(new GetEmblemEffect(new KothOfTheHammerEmblem()), -5)); } - public KothOfTheHammer (final KothOfTheHammer card) { + public KothOfTheHammer(final KothOfTheHammer card) { super(card); } @@ -111,6 +107,7 @@ public class KothOfTheHammer extends CardImpl { return new KothOfTheHammer(this); } } + class KothOfTheHammerToken extends Token { public KothOfTheHammerToken() { @@ -125,7 +122,9 @@ class KothOfTheHammerToken extends Token { } class KothOfTheHammerEmblem extends Emblem { + // "Mountains you control have '{T}: This land deals 1 damage to target creature or player.'" + public KothOfTheHammerEmblem() { this.setName("EMBLEM: Koth of the Hammer"); this.getAbilities().add(new SimpleStaticAbility(Zone.COMMAND, new KothOfTheHammerThirdEffect())); @@ -133,6 +132,7 @@ class KothOfTheHammerEmblem extends Emblem { } class KothOfTheHammerThirdEffect extends ContinuousEffectImpl { + public KothOfTheHammerThirdEffect() { super(Duration.EndOfGame, Outcome.AddAbility); staticText = "You get an emblem with \"Mountains you control have '{T}: This land deals 1 damage to target creature or player.'\""; diff --git a/Mage.Sets/src/mage/sets/scarsofmirrodin/VenserTheSojourner.java b/Mage.Sets/src/mage/sets/scarsofmirrodin/VenserTheSojourner.java index 2f4def3ecfd..b3d27b48775 100644 --- a/Mage.Sets/src/mage/sets/scarsofmirrodin/VenserTheSojourner.java +++ b/Mage.Sets/src/mage/sets/scarsofmirrodin/VenserTheSojourner.java @@ -32,7 +32,7 @@ import mage.MageObject; import mage.abilities.Ability; import mage.abilities.LoyaltyAbility; import mage.abilities.TriggeredAbilityImpl; -import mage.abilities.common.EntersBattlefieldAbility; +import mage.abilities.common.PlanswalkerEntersWithLoyalityCountersAbility; import mage.abilities.common.delayed.AtTheBeginOfNextEndStepDelayedTriggeredAbility; import mage.abilities.effects.Effect; import mage.abilities.effects.OneShotEffect; @@ -40,7 +40,6 @@ import mage.abilities.effects.common.ExileTargetEffect; import mage.abilities.effects.common.GetEmblemEffect; import mage.abilities.effects.common.ReturnFromExileEffect; import mage.abilities.effects.common.combat.CantBeBlockedAllEffect; -import mage.abilities.effects.common.counter.AddCountersSourceEffect; import mage.cards.CardImpl; import mage.constants.CardType; import mage.constants.Duration; @@ -48,7 +47,6 @@ import mage.constants.Outcome; import mage.constants.Rarity; import mage.constants.TargetController; import mage.constants.Zone; -import mage.counters.CounterType; import mage.filter.FilterPermanent; import mage.filter.FilterSpell; import mage.filter.common.FilterCreaturePermanent; @@ -80,7 +78,7 @@ public class VenserTheSojourner extends CardImpl { this.expansionSetCode = "SOM"; this.subtype.add("Venser"); - this.addAbility(new EntersBattlefieldAbility(new AddCountersSourceEffect(CounterType.LOYALTY.createInstance(3)), false)); + this.addAbility(new PlanswalkerEntersWithLoyalityCountersAbility(3)); // +2: Exile target permanent you own. Return it to the battlefield under your control at the beginning of the next end step. LoyaltyAbility ability1 = new LoyaltyAbility(new VenserTheSojournerEffect(), 2); diff --git a/Mage.Sets/src/mage/sets/shadowmoor/FlourishingDefenses.java b/Mage.Sets/src/mage/sets/shadowmoor/FlourishingDefenses.java index 43423eb386c..9e94853f483 100644 --- a/Mage.Sets/src/mage/sets/shadowmoor/FlourishingDefenses.java +++ b/Mage.Sets/src/mage/sets/shadowmoor/FlourishingDefenses.java @@ -51,7 +51,6 @@ public class FlourishingDefenses extends CardImpl { super(ownerId, 114, "Flourishing Defenses", Rarity.UNCOMMON, new CardType[]{CardType.ENCHANTMENT}, "{4}{G}"); this.expansionSetCode = "SHM"; - // Whenever a -1/-1 counter is placed on a creature, you may put a 1/1 green Elf Warrior creature token onto the battlefield. this.addAbility(new FlourishingDefensesTriggeredAbility()); @@ -91,7 +90,10 @@ class FlourishingDefensesTriggeredAbility extends TriggeredAbilityImpl { public boolean checkTrigger(GameEvent event, Game game) { if (event.getData().equals(CounterType.M1M1.getName())) { Permanent permanent = game.getPermanentOrLKIBattlefield(event.getTargetId()); - if (permanent.getCardType().contains(CardType.CREATURE)) { + if (permanent == null) { + permanent = game.getPermanentEntering(event.getTargetId()); + } + if (permanent != null && permanent.getCardType().contains(CardType.CREATURE)) { return true; } } diff --git a/Mage.Sets/src/mage/sets/shadowmoor/GlamerSpinners.java b/Mage.Sets/src/mage/sets/shadowmoor/GlamerSpinners.java index e94e6b2e98e..1f031527630 100644 --- a/Mage.Sets/src/mage/sets/shadowmoor/GlamerSpinners.java +++ b/Mage.Sets/src/mage/sets/shadowmoor/GlamerSpinners.java @@ -126,7 +126,8 @@ class GlamerSpinnersEffect extends OneShotEffect { LinkedList auras = new LinkedList<>(); auras.addAll(targetPermanent.getAttachments()); - if (controller.choose(Outcome.Neutral, chosenPermanentToAttachAuras, source.getSourceId(), game)) { + if (chosenPermanentToAttachAuras.canChoose(source.getSourceId(), source.getControllerId(), game) + && controller.choose(Outcome.Neutral, chosenPermanentToAttachAuras, source.getSourceId(), game)) { Permanent permanentToAttachAuras = game.getPermanent(chosenPermanentToAttachAuras.getFirstTarget()); if (permanentToAttachAuras != null) { for (UUID auraId : auras) { @@ -163,7 +164,7 @@ class GlamerSpinnersEffect extends OneShotEffect { } return true; } - + return false; } } diff --git a/Mage.Sets/src/mage/sets/shardsofalara/AjaniVengeant.java b/Mage.Sets/src/mage/sets/shardsofalara/AjaniVengeant.java index ee4ee7cc2ca..a21eeaa672c 100644 --- a/Mage.Sets/src/mage/sets/shardsofalara/AjaniVengeant.java +++ b/Mage.Sets/src/mage/sets/shardsofalara/AjaniVengeant.java @@ -1,46 +1,43 @@ /* -* 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.sets.shardsofalara; import java.util.UUID; -import mage.constants.CardType; -import mage.constants.Rarity; import mage.abilities.LoyaltyAbility; -import mage.abilities.common.EntersBattlefieldAbility; +import mage.abilities.common.PlanswalkerEntersWithLoyalityCountersAbility; import mage.abilities.effects.Effects; import mage.abilities.effects.common.DamageTargetEffect; import mage.abilities.effects.common.DestroyAllControlledTargetEffect; -import mage.abilities.effects.common.GainLifeEffect; import mage.abilities.effects.common.DontUntapInControllersNextUntapStepTargetEffect; -import mage.abilities.effects.common.counter.AddCountersSourceEffect; +import mage.abilities.effects.common.GainLifeEffect; import mage.cards.CardImpl; -import mage.counters.CounterType; +import mage.constants.CardType; +import mage.constants.Rarity; import mage.filter.FilterPermanent; import mage.filter.predicate.mageobject.CardTypePredicate; import mage.target.TargetPermanent; @@ -52,7 +49,7 @@ import mage.target.common.TargetCreatureOrPlayer; * @author BetaSteward_at_googlemail.com */ public class AjaniVengeant extends CardImpl { - + private static final FilterPermanent filter = new FilterPermanent("lands"); static { @@ -64,8 +61,7 @@ public class AjaniVengeant extends CardImpl { this.expansionSetCode = "ALA"; this.subtype.add("Ajani"); - - this.addAbility(new EntersBattlefieldAbility(new AddCountersSourceEffect(CounterType.LOYALTY.createInstance(3)), false)); + this.addAbility(new PlanswalkerEntersWithLoyalityCountersAbility(3)); // +1: Target permanent doesn't untap during its controller's next untap step. LoyaltyAbility ability1 = new LoyaltyAbility(new DontUntapInControllersNextUntapStepTargetEffect(), 1); @@ -85,7 +81,6 @@ public class AjaniVengeant extends CardImpl { ability3.addTarget(new TargetPlayer()); this.addAbility(ability3); - } public AjaniVengeant(final AjaniVengeant card) { diff --git a/Mage.Sets/src/mage/sets/shardsofalara/ElspethKnightErrant.java b/Mage.Sets/src/mage/sets/shardsofalara/ElspethKnightErrant.java index b37b88c0d95..6cd0c9bdef5 100644 --- a/Mage.Sets/src/mage/sets/shardsofalara/ElspethKnightErrant.java +++ b/Mage.Sets/src/mage/sets/shardsofalara/ElspethKnightErrant.java @@ -1,16 +1,16 @@ /* * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. - * + * * Redistribution and use in source and binary forms, with or without modification, are * permitted provided that the following conditions are met: - * + * * 1. Redistributions of source code must retain the above copyright notice, this list of * conditions and the following disclaimer. - * + * * 2. Redistributions in binary form must reproduce the above copyright notice, this list * of conditions and the following disclaimer in the documentation and/or other materials * provided with the distribution. - * + * * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR @@ -20,21 +20,16 @@ * 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.shardsofalara; import java.util.UUID; -import mage.constants.CardType; -import mage.constants.Duration; -import mage.constants.Rarity; -import mage.constants.Zone; import mage.abilities.LoyaltyAbility; -import mage.abilities.common.EntersBattlefieldAbility; +import mage.abilities.common.PlanswalkerEntersWithLoyalityCountersAbility; import mage.abilities.common.SimpleStaticAbility; import mage.abilities.effects.Effect; import mage.abilities.effects.Effects; @@ -43,11 +38,13 @@ import mage.abilities.effects.common.GetEmblemEffect; import mage.abilities.effects.common.continuous.BoostTargetEffect; import mage.abilities.effects.common.continuous.GainAbilityAllEffect; import mage.abilities.effects.common.continuous.GainAbilityTargetEffect; -import mage.abilities.effects.common.counter.AddCountersSourceEffect; import mage.abilities.keyword.FlyingAbility; import mage.abilities.keyword.IndestructibleAbility; import mage.cards.CardImpl; -import mage.counters.CounterType; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.Rarity; +import mage.constants.Zone; import mage.filter.common.FilterControlledPermanent; import mage.filter.predicate.Predicates; import mage.filter.predicate.mageobject.CardTypePredicate; @@ -67,8 +64,7 @@ public class ElspethKnightErrant extends CardImpl { this.expansionSetCode = "ALA"; this.subtype.add("Elspeth"); - - this.addAbility(new EntersBattlefieldAbility(new AddCountersSourceEffect(CounterType.LOYALTY.createInstance(4)), false)); + this.addAbility(new PlanswalkerEntersWithLoyalityCountersAbility(4)); // +1: Put a 1/1 white Soldier creature token onto the battlefield. Token token = new SoldierToken(); diff --git a/Mage.Sets/src/mage/sets/shardsofalara/SarkhanVol.java b/Mage.Sets/src/mage/sets/shardsofalara/SarkhanVol.java index 4377e3fb628..43196e13e7b 100644 --- a/Mage.Sets/src/mage/sets/shardsofalara/SarkhanVol.java +++ b/Mage.Sets/src/mage/sets/shardsofalara/SarkhanVol.java @@ -1,50 +1,47 @@ /* -* 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.sets.shardsofalara; -import mage.abilities.effects.common.continuous.GainAbilityTargetEffect; -import mage.abilities.effects.common.continuous.BoostControlledEffect; import java.util.UUID; +import mage.abilities.LoyaltyAbility; +import mage.abilities.common.PlanswalkerEntersWithLoyalityCountersAbility; +import mage.abilities.effects.Effects; +import mage.abilities.effects.common.CreateTokenEffect; +import mage.abilities.effects.common.UntapTargetEffect; +import mage.abilities.effects.common.continuous.BoostControlledEffect; +import mage.abilities.effects.common.continuous.GainAbilityControlledEffect; +import mage.abilities.effects.common.continuous.GainAbilityTargetEffect; +import mage.abilities.effects.common.continuous.GainControlTargetEffect; +import mage.abilities.keyword.HasteAbility; +import mage.cards.CardImpl; import mage.constants.CardType; import mage.constants.Duration; import mage.constants.Rarity; -import mage.abilities.LoyaltyAbility; -import mage.abilities.common.EntersBattlefieldAbility; -import mage.abilities.effects.Effects; -import mage.abilities.effects.common.CreateTokenEffect; -import mage.abilities.effects.common.continuous.GainAbilityControlledEffect; -import mage.abilities.effects.common.continuous.GainControlTargetEffect; -import mage.abilities.effects.common.counter.AddCountersSourceEffect; -import mage.abilities.effects.common.UntapTargetEffect; -import mage.abilities.keyword.HasteAbility; -import mage.cards.CardImpl; -import mage.counters.CounterType; import mage.filter.common.FilterCreaturePermanent; import mage.game.permanent.token.DragonToken; import mage.target.common.TargetCreaturePermanent; @@ -62,8 +59,7 @@ public class SarkhanVol extends CardImpl { this.expansionSetCode = "ALA"; this.subtype.add("Sarkhan"); - - this.addAbility(new EntersBattlefieldAbility(new AddCountersSourceEffect(CounterType.LOYALTY.createInstance(4)), false)); + this.addAbility(new PlanswalkerEntersWithLoyalityCountersAbility(4)); // +1: Creatures you control get +1/+1 and gain haste until end of turn. Effects effects1 = new Effects(); diff --git a/Mage.Sets/src/mage/sets/shardsofalara/TezzeretTheSeeker.java b/Mage.Sets/src/mage/sets/shardsofalara/TezzeretTheSeeker.java index 9cae9ec46d7..af865ed4cee 100644 --- a/Mage.Sets/src/mage/sets/shardsofalara/TezzeretTheSeeker.java +++ b/Mage.Sets/src/mage/sets/shardsofalara/TezzeretTheSeeker.java @@ -31,13 +31,12 @@ import java.util.List; import java.util.UUID; import mage.abilities.Ability; import mage.abilities.LoyaltyAbility; -import mage.abilities.common.EntersBattlefieldAbility; +import mage.abilities.common.PlanswalkerEntersWithLoyalityCountersAbility; import mage.abilities.costs.Cost; import mage.abilities.costs.common.PayVariableLoyaltyCost; import mage.abilities.effects.ContinuousEffectImpl; import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.UntapTargetEffect; -import mage.abilities.effects.common.counter.AddCountersSourceEffect; import mage.cards.Card; import mage.cards.CardImpl; import mage.constants.CardType; @@ -47,7 +46,6 @@ import mage.constants.Outcome; import mage.constants.Rarity; import mage.constants.SubLayer; import mage.constants.Zone; -import mage.counters.CounterType; import mage.filter.Filter.ComparisonType; import mage.filter.common.FilterArtifactCard; import mage.filter.common.FilterArtifactPermanent; @@ -69,7 +67,7 @@ public class TezzeretTheSeeker extends CardImpl { this.expansionSetCode = "ALA"; this.subtype.add("Tezzeret"); - this.addAbility(new EntersBattlefieldAbility(new AddCountersSourceEffect(CounterType.LOYALTY.createInstance(4)), false)); + this.addAbility(new PlanswalkerEntersWithLoyalityCountersAbility(4)); // +1: Untap up to two target artifacts. LoyaltyAbility ability = new LoyaltyAbility(new UntapTargetEffect(), 1); diff --git a/Mage.Sets/src/mage/sets/speedvscunning/AquamorphEntity.java b/Mage.Sets/src/mage/sets/speedvscunning/AquamorphEntity.java index 803b119ff50..3d57c2229d3 100644 --- a/Mage.Sets/src/mage/sets/speedvscunning/AquamorphEntity.java +++ b/Mage.Sets/src/mage/sets/speedvscunning/AquamorphEntity.java @@ -65,11 +65,10 @@ public class AquamorphEntity extends CardImpl { this.toughness = new MageInt(0); // As Aquamorph Entity enters the battlefield or is turned face up, it becomes your choice of 5/1 or 1/5. - Ability ability = new SimpleStaticAbility(Zone.BATTLEFIELD, new AquamorphEntityReplacementEffect()); + Ability ability = new SimpleStaticAbility(Zone.ALL, new AquamorphEntityReplacementEffect()); ability.setWorksFaceDown(true); this.addAbility(ability); - // Morph {2}{U} this.addAbility(new MorphAbility(this, new ManaCostsImpl("{2}{U}"))); } @@ -84,7 +83,6 @@ public class AquamorphEntity extends CardImpl { } } - class AquamorphEntityReplacementEffect extends ReplacementEffectImpl { private final String choice51 = "a 5/1 creature"; @@ -101,7 +99,7 @@ class AquamorphEntityReplacementEffect extends ReplacementEffectImpl { @Override public boolean checksEventType(GameEvent event, Game game) { - switch(event.getType()) { + switch (event.getType()) { case ENTERS_THE_BATTLEFIELD: case TURNFACEUP: return true; @@ -114,7 +112,7 @@ class AquamorphEntityReplacementEffect extends ReplacementEffectImpl { public boolean applies(GameEvent event, Ability source, Game game) { if (event.getType() == EventType.ENTERS_THE_BATTLEFIELD) { if (event.getTargetId().equals(source.getSourceId())) { - Permanent sourcePermanent = game.getPermanent(source.getSourceId()); + Permanent sourcePermanent = game.getPermanentEntering(source.getSourceId()); if (sourcePermanent != null && !sourcePermanent.isFaceDown(game)) { return true; } @@ -135,7 +133,7 @@ class AquamorphEntityReplacementEffect extends ReplacementEffectImpl { @Override public boolean replaceEvent(GameEvent event, Ability source, Game game) { - Permanent permanent = game.getPermanent(source.getSourceId()); + Permanent permanent = game.getPermanentEntering(source.getSourceId()); if (permanent != null) { Choice choice = new ChoiceImpl(true); choice.setMessage("Choose what the creature becomes to"); @@ -143,7 +141,7 @@ class AquamorphEntityReplacementEffect extends ReplacementEffectImpl { choice.getChoices().add(choice15); Player controller = game.getPlayer(source.getControllerId()); if (controller != null) { - while(!choice.isChosen()) { + while (!choice.isChosen()) { controller.choose(Outcome.Neutral, choice, game); if (!controller.canRespond()) { return false; @@ -168,7 +166,7 @@ class AquamorphEntityReplacementEffect extends ReplacementEffectImpl { } } return false; - + } @Override diff --git a/Mage.Sets/src/mage/sets/tempest/Dracoplasm.java b/Mage.Sets/src/mage/sets/tempest/Dracoplasm.java index a53c41a32c6..33b9e60a024 100644 --- a/Mage.Sets/src/mage/sets/tempest/Dracoplasm.java +++ b/Mage.Sets/src/mage/sets/tempest/Dracoplasm.java @@ -69,10 +69,10 @@ public class Dracoplasm extends CardImpl { // Flying this.addAbility(FlyingAbility.getInstance()); - + // As Dracoplasm enters the battlefield, sacrifice any number of creatures. Dracoplasm's power becomes the total power of those creatures and its toughness becomes their total toughness. - this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new DracoplasmEffect())); - + this.addAbility(new SimpleStaticAbility(Zone.ALL, new DracoplasmEffect())); + // {R}: Dracoplasm gets +1/+0 until end of turn. this.addAbility(new SimpleActivatedAbility(Zone.BATTLEFIELD, new BoostSourceEffect(1, 0, Duration.EndOfTurn), new ColoredManaCost(ColoredManaSymbol.R))); } @@ -88,41 +88,41 @@ public class Dracoplasm extends CardImpl { } class DracoplasmEffect extends ReplacementEffectImpl { - + private static final FilterControlledCreaturePermanent filter = new FilterControlledCreaturePermanent(); - + static { filter.add(new AnotherPredicate()); } - + public DracoplasmEffect() { - super(Duration.WhileOnBattlefield, Outcome.BoostCreature); + super(Duration.EndOfGame, Outcome.BoostCreature); this.staticText = "As {this} enters the battlefield, sacrifice any number of creatures. {this}'s power becomes the total power of those creatures and its toughness becomes their total toughness"; } - + public DracoplasmEffect(final DracoplasmEffect effect) { super(effect); } - + @Override public DracoplasmEffect copy() { return new DracoplasmEffect(this); } - + @Override public boolean checksEventType(GameEvent event, Game game) { return event.getType() == GameEvent.EventType.ENTERS_THE_BATTLEFIELD; } - + @Override public boolean applies(GameEvent event, Ability source, Game game) { - return event.getTargetId().equals(source.getSourceId()); + return event.getTargetId().equals(source.getSourceId()); } - + @Override public boolean replaceEvent(GameEvent event, Ability source, Game game) { - Permanent creature = game.getPermanent(event.getTargetId()); + Permanent creature = game.getPermanentEntering(event.getTargetId()); Player controller = game.getPlayer(source.getControllerId()); if (creature != null && controller != null) { Target target = new TargetControlledPermanent(0, Integer.MAX_VALUE, filter, true); @@ -133,7 +133,7 @@ class DracoplasmEffect extends ReplacementEffectImpl { if (target.getTargets().size() > 0) { int power = 0; int toughness = 0; - for (UUID targetId: target.getTargets()) { + for (UUID targetId : target.getTargets()) { Permanent targetCreature = game.getPermanent(targetId); if (targetCreature != null && targetCreature.sacrifice(source.getSourceId(), game)) { power += targetCreature.getPower().getValue(); @@ -146,5 +146,5 @@ class DracoplasmEffect extends ReplacementEffectImpl { } return false; } - + } diff --git a/Mage.Sets/src/mage/sets/tempest/RootMaze.java b/Mage.Sets/src/mage/sets/tempest/RootMaze.java index 36109448c25..26835f74da4 100644 --- a/Mage.Sets/src/mage/sets/tempest/RootMaze.java +++ b/Mage.Sets/src/mage/sets/tempest/RootMaze.java @@ -67,6 +67,7 @@ public class RootMaze extends CardImpl { } class RootMazeEffect extends ReplacementEffectImpl { + RootMazeEffect() { super(Duration.WhileOnBattlefield, Outcome.Tap); staticText = "Artifacts and lands enter the battlefield tapped"; @@ -78,21 +79,21 @@ class RootMazeEffect extends ReplacementEffectImpl { @Override public boolean replaceEvent(GameEvent event, Ability source, Game game) { - Permanent target = game.getPermanent(event.getTargetId()); + Permanent target = game.getPermanentEntering(event.getTargetId()); if (target != null) { target.setTapped(true); } return false; } - + @Override public boolean checksEventType(GameEvent event, Game game) { return event.getType() == EventType.ENTERS_THE_BATTLEFIELD; } - + @Override public boolean applies(GameEvent event, Ability source, Game game) { - Permanent permanent = game.getPermanent(event.getTargetId()); + Permanent permanent = game.getPermanentEntering(event.getTargetId()); return permanent != null && (permanent.getCardType().contains(CardType.LAND) || permanent.getCardType().contains(CardType.ARTIFACT)); } diff --git a/Mage.Sets/src/mage/sets/tenthedition/Clone.java b/Mage.Sets/src/mage/sets/tenthedition/Clone.java index 2412dacd079..6869479699a 100644 --- a/Mage.Sets/src/mage/sets/tenthedition/Clone.java +++ b/Mage.Sets/src/mage/sets/tenthedition/Clone.java @@ -25,19 +25,15 @@ * authors and should not be interpreted as representing official policies, either expressed * or implied, of BetaSteward_at_googlemail.com. */ - package mage.sets.tenthedition; 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.common.SimpleStaticAbility; -import mage.abilities.effects.EntersBattlefieldEffect; +import mage.abilities.common.EntersBattlefieldAbility; import mage.abilities.effects.common.CopyPermanentEffect; import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.Rarity; /** * @@ -54,11 +50,12 @@ public class Clone extends CardImpl { this.toughness = new MageInt(0); // You may have Clone enter the battlefield as a copy of any creature on the battlefield. - Ability ability = new SimpleStaticAbility(Zone.BATTLEFIELD, new EntersBattlefieldEffect( - new CopyPermanentEffect(), - "You may have {this} enter the battlefield as a copy of any creature on the battlefield", - true)); - this.addAbility(ability); +// ; +// Ability ability = new SimpleStaticAbility(Zone.BATTLEFIELD, new EntersBattlefieldEffect( +// new CopyPermanentEffect(), +// "You may have {this} enter the battlefield as a copy of any creature on the battlefield", +// true)); + this.addAbility(new EntersBattlefieldAbility(new CopyPermanentEffect(), true)); } public Clone(final Clone card) { diff --git a/Mage.Sets/src/mage/sets/tenthedition/SculptingSteel.java b/Mage.Sets/src/mage/sets/tenthedition/SculptingSteel.java index eb3d8d91876..7edca1e49b4 100644 --- a/Mage.Sets/src/mage/sets/tenthedition/SculptingSteel.java +++ b/Mage.Sets/src/mage/sets/tenthedition/SculptingSteel.java @@ -28,14 +28,11 @@ package mage.sets.tenthedition; import java.util.UUID; -import mage.constants.CardType; -import mage.constants.Rarity; -import mage.constants.Zone; -import mage.abilities.Ability; -import mage.abilities.common.SimpleStaticAbility; -import mage.abilities.effects.EntersBattlefieldEffect; +import mage.abilities.common.EntersBattlefieldAbility; import mage.abilities.effects.common.CopyPermanentEffect; import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.Rarity; import mage.filter.FilterPermanent; import mage.filter.predicate.mageobject.CardTypePredicate; @@ -44,9 +41,9 @@ import mage.filter.predicate.mageobject.CardTypePredicate; * @author jeffwadsworth */ public class SculptingSteel extends CardImpl { - + private static final FilterPermanent filter = new FilterPermanent("artifact"); - + static { filter.add(new CardTypePredicate(CardType.ARTIFACT)); } @@ -56,11 +53,7 @@ public class SculptingSteel extends CardImpl { this.expansionSetCode = "10E"; // You may have Sculpting Steel enter the battlefield as a copy of any artifact on the battlefield. - Ability ability = new SimpleStaticAbility(Zone.BATTLEFIELD, new EntersBattlefieldEffect( - new CopyPermanentEffect(filter), - "You may have {this} enter the battlefield as a copy of any artifact on the battlefield", - true)); - this.addAbility(ability); + this.addAbility(new EntersBattlefieldAbility(new CopyPermanentEffect(filter), true)); } public SculptingSteel(final SculptingSteel card) { diff --git a/Mage.Sets/src/mage/sets/theros/AshiokNightmareWeaver.java b/Mage.Sets/src/mage/sets/theros/AshiokNightmareWeaver.java index 25c3342c95b..18d2eaee092 100644 --- a/Mage.Sets/src/mage/sets/theros/AshiokNightmareWeaver.java +++ b/Mage.Sets/src/mage/sets/theros/AshiokNightmareWeaver.java @@ -31,12 +31,11 @@ import java.util.UUID; import mage.MageObject; import mage.abilities.Ability; import mage.abilities.LoyaltyAbility; -import mage.abilities.common.EntersBattlefieldAbility; +import mage.abilities.common.PlanswalkerEntersWithLoyalityCountersAbility; import mage.abilities.costs.Cost; import mage.abilities.costs.common.PayVariableLoyaltyCost; import mage.abilities.effects.ContinuousEffectImpl; import mage.abilities.effects.OneShotEffect; -import mage.abilities.effects.common.counter.AddCountersSourceEffect; import mage.cards.Card; import mage.cards.CardImpl; import mage.cards.Cards; @@ -48,7 +47,6 @@ import mage.constants.Outcome; import mage.constants.Rarity; import mage.constants.SubLayer; import mage.constants.Zone; -import mage.counters.CounterType; import mage.filter.Filter; import mage.filter.FilterCard; import mage.filter.common.FilterCreatureCard; @@ -73,7 +71,7 @@ public class AshiokNightmareWeaver extends CardImpl { this.expansionSetCode = "THS"; this.subtype.add("Ashiok"); - this.addAbility(new EntersBattlefieldAbility(new AddCountersSourceEffect(CounterType.LOYALTY.createInstance(3)), false)); + this.addAbility(new PlanswalkerEntersWithLoyalityCountersAbility(3)); // +2: Exile the top three cards of target opponent's library. LoyaltyAbility ability = new LoyaltyAbility(new AshiokNightmareWeaverExileEffect(), 2); diff --git a/Mage.Sets/src/mage/sets/theros/ElspethSunsChampion.java b/Mage.Sets/src/mage/sets/theros/ElspethSunsChampion.java index ec4d805c92a..1710de8c1c3 100644 --- a/Mage.Sets/src/mage/sets/theros/ElspethSunsChampion.java +++ b/Mage.Sets/src/mage/sets/theros/ElspethSunsChampion.java @@ -30,21 +30,19 @@ package mage.sets.theros; import java.util.UUID; import mage.abilities.Ability; import mage.abilities.LoyaltyAbility; -import mage.abilities.common.EntersBattlefieldAbility; +import mage.abilities.common.PlanswalkerEntersWithLoyalityCountersAbility; import mage.abilities.common.SimpleStaticAbility; import mage.abilities.effects.common.CreateTokenEffect; import mage.abilities.effects.common.DestroyAllEffect; import mage.abilities.effects.common.GetEmblemEffect; import mage.abilities.effects.common.continuous.BoostControlledEffect; import mage.abilities.effects.common.continuous.GainAbilityControlledEffect; -import mage.abilities.effects.common.counter.AddCountersSourceEffect; import mage.abilities.keyword.FlyingAbility; import mage.cards.CardImpl; import mage.constants.CardType; import mage.constants.Duration; import mage.constants.Rarity; import mage.constants.Zone; -import mage.counters.CounterType; import mage.filter.Filter; import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.mageobject.PowerPredicate; @@ -58,6 +56,7 @@ import mage.game.permanent.token.SoldierToken; public class ElspethSunsChampion extends CardImpl { private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("creatures with power 4 or greater"); + static { filter.add(new PowerPredicate(Filter.ComparisonType.GreaterThan, 3)); } @@ -67,8 +66,7 @@ public class ElspethSunsChampion extends CardImpl { this.expansionSetCode = "THS"; this.subtype.add("Elspeth"); - - this.addAbility(new EntersBattlefieldAbility(new AddCountersSourceEffect(CounterType.LOYALTY.createInstance(4)), false)); + this.addAbility(new PlanswalkerEntersWithLoyalityCountersAbility(4)); // +1: Put three 1/1 white Soldier creature tokens onto the battlefield. this.addAbility(new LoyaltyAbility(new CreateTokenEffect(new SoldierToken(), 3), 1)); @@ -95,7 +93,7 @@ class ElspethSunsChampionEmblem extends Emblem { public ElspethSunsChampionEmblem() { this.setName("EMBLEM: Elspeth, Sun's Champion"); - Ability ability = new SimpleStaticAbility(Zone.COMMAND, new BoostControlledEffect(2,2, Duration.WhileOnBattlefield, filter, false)); + Ability ability = new SimpleStaticAbility(Zone.COMMAND, new BoostControlledEffect(2, 2, Duration.WhileOnBattlefield, filter, false)); ability.addEffect(new GainAbilityControlledEffect(FlyingAbility.getInstance(), Duration.WhileOnBattlefield, filter)); this.getAbilities().add(ability); diff --git a/Mage.Sets/src/mage/sets/theros/XenagosTheReveler.java b/Mage.Sets/src/mage/sets/theros/XenagosTheReveler.java index 0166753702c..b71a4b0cc07 100644 --- a/Mage.Sets/src/mage/sets/theros/XenagosTheReveler.java +++ b/Mage.Sets/src/mage/sets/theros/XenagosTheReveler.java @@ -34,10 +34,9 @@ import mage.MageInt; import mage.Mana; import mage.abilities.Ability; import mage.abilities.LoyaltyAbility; -import mage.abilities.common.EntersBattlefieldAbility; +import mage.abilities.common.PlanswalkerEntersWithLoyalityCountersAbility; import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.CreateTokenEffect; -import mage.abilities.effects.common.counter.AddCountersSourceEffect; import mage.abilities.keyword.HasteAbility; import mage.cards.Card; import mage.cards.CardImpl; @@ -49,7 +48,6 @@ import mage.constants.CardType; import mage.constants.Outcome; import mage.constants.Rarity; import mage.constants.Zone; -import mage.counters.CounterType; import mage.filter.FilterCard; import mage.filter.common.FilterControlledCreaturePermanent; import mage.filter.predicate.Predicates; @@ -70,20 +68,17 @@ public class XenagosTheReveler extends CardImpl { this.expansionSetCode = "THS"; this.subtype.add("Xenagos"); - - this.addAbility(new EntersBattlefieldAbility(new AddCountersSourceEffect(CounterType.LOYALTY.createInstance(3)), false)); + this.addAbility(new PlanswalkerEntersWithLoyalityCountersAbility(3)); // +1: Add X mana in any combination of {R} and/or {G} to your mana pool, where X is the number of creatures you control. this.addAbility(new LoyaltyAbility(new XenagosManaEffect(), +1)); - + // 0: Put a 2/2 red and green Satyr creature token with haste onto the battlefield. this.addAbility(new LoyaltyAbility(new CreateTokenEffect(new XenagosSatyrToken()), 0)); // -6: Exile the top seven cards of your library. You may put any number of creature and/or land cards from among them onto the battlefield. this.addAbility(new LoyaltyAbility(new XenagosExileEffect(), -6)); - - } public XenagosTheReveler(final XenagosTheReveler card) { @@ -115,7 +110,7 @@ class XenagosManaEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { Player player = game.getPlayer(source.getControllerId()); - if (player != null){ + if (player != null) { int x = game.getBattlefield().count(new FilterControlledCreaturePermanent(), source.getSourceId(), source.getControllerId(), game); Choice manaChoice = new ChoiceImpl(); Set choices = new LinkedHashSet<>(); @@ -124,7 +119,7 @@ class XenagosManaEffect extends OneShotEffect { manaChoice.setChoices(choices); manaChoice.setMessage("Select color of mana to add"); - for (int i = 0; i < x; i++){ + for (int i = 0; i < x; i++) { Mana mana = new Mana(); while (!player.choose(Outcome.Benefit, manaChoice, game)) { if (!player.canRespond()) { @@ -150,7 +145,6 @@ class XenagosManaEffect extends OneShotEffect { } } - class XenagosSatyrToken extends Token { public XenagosSatyrToken() { @@ -167,7 +161,6 @@ class XenagosSatyrToken extends Token { } - class XenagosExileEffect extends OneShotEffect { public XenagosExileEffect() { @@ -197,12 +190,12 @@ class XenagosExileEffect extends OneShotEffect { } FilterCard filter = new FilterCard("creature and/or land cards to put onto the battlefield"); filter.add(Predicates.or(new CardTypePredicate(CardType.CREATURE), - new CardTypePredicate(CardType.LAND))); + new CardTypePredicate(CardType.LAND))); TargetCard target1 = new TargetCard(0, Integer.MAX_VALUE, Zone.EXILED, filter); if (cards.size() > 0 && target1.canChoose(source.getSourceId(), source.getControllerId(), game) && player.choose(Outcome.PutCardInPlay, cards, target1, game)) { - for (UUID targetId: target1.getTargets()) { + for (UUID targetId : target1.getTargets()) { Card card = cards.get(targetId, game); if (card != null) { player.putOntoBattlefieldWithInfo(card, game, Zone.EXILED, source.getSourceId()); diff --git a/Mage.Sets/src/mage/sets/timespiral/Hypergenesis.java b/Mage.Sets/src/mage/sets/timespiral/Hypergenesis.java index de7538b305a..d2b840b0cb1 100644 --- a/Mage.Sets/src/mage/sets/timespiral/Hypergenesis.java +++ b/Mage.Sets/src/mage/sets/timespiral/Hypergenesis.java @@ -60,7 +60,7 @@ public class Hypergenesis extends CardImpl { // Suspend 3-{1}{G}{G} this.addAbility(new SuspendAbility(3, new ManaCostsImpl("{1}{G}{G}"), this)); - + // Starting with you, each player may put an artifact, creature, enchantment, or land card from his or her hand onto the battlefield. Repeat this process until no one puts a card onto the battlefield. this.getSpellAbility().addEffect(new HypergenesisEffect()); } @@ -77,8 +77,9 @@ public class Hypergenesis extends CardImpl { @SuppressWarnings("unchecked") class HypergenesisEffect extends OneShotEffect { - + private static final FilterCard filter = new FilterCard("an artifact, creature, enchantment, or land card"); + static { filter.add(Predicates.or(new CardTypePredicate(CardType.ARTIFACT), new CardTypePredicate(CardType.CREATURE), new CardTypePredicate(CardType.ENCHANTMENT), new CardTypePredicate(CardType.LAND))); } @@ -109,7 +110,7 @@ class HypergenesisEffect extends OneShotEffect { UUID firstInactivePlayer = null; Target target = new TargetCardInHand(filter); - while (controller.canRespond()) { + while (controller.canRespond()) { if (currentPlayer != null && currentPlayer.canRespond() && controller.getInRange().contains(currentPlayer.getId())) { if (firstInactivePlayer == null) { firstInactivePlayer = currentPlayer.getId(); @@ -120,7 +121,7 @@ class HypergenesisEffect extends OneShotEffect { if (target.chooseTarget(outcome, currentPlayer.getId(), source, game)) { Card card = game.getCard(target.getFirstTarget()); if (card != null) { - currentPlayer.putOntoBattlefieldWithInfo(card, game, Zone.HAND, source.getSourceId()); + currentPlayer.moveCards(card, Zone.BATTLEFIELD, source, game); firstInactivePlayer = null; } } diff --git a/Mage.Sets/src/mage/sets/timespiral/Vesuva.java b/Mage.Sets/src/mage/sets/timespiral/Vesuva.java index 197107be0c8..99f6571e913 100644 --- a/Mage.Sets/src/mage/sets/timespiral/Vesuva.java +++ b/Mage.Sets/src/mage/sets/timespiral/Vesuva.java @@ -28,14 +28,14 @@ package mage.sets.timespiral; import java.util.UUID; -import mage.constants.CardType; -import mage.constants.Rarity; -import mage.constants.Zone; -import mage.abilities.common.SimpleStaticAbility; -import mage.abilities.effects.EntersBattlefieldEffect; +import mage.abilities.Ability; +import mage.abilities.common.EntersBattlefieldAbility; +import mage.abilities.effects.Effect; import mage.abilities.effects.common.CopyPermanentEffect; import mage.abilities.effects.common.TapSourceEffect; import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.Rarity; import mage.filter.FilterPermanent; import mage.filter.predicate.mageobject.CardTypePredicate; @@ -56,12 +56,13 @@ public class Vesuva extends CardImpl { this.expansionSetCode = "TSP"; // You may have Vesuva enter the battlefield tapped as a copy of any land on the battlefield. - EntersBattlefieldEffect effect = new EntersBattlefieldEffect( - new TapSourceEffect(true), - "You may have {this} enter the battlefield tapped as a copy of any land on the battlefield", - true); - effect.addEffect(new CopyPermanentEffect(filter)); - this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, effect)); + Effect effect = new TapSourceEffect(true); + effect.setText("tapped"); + Ability ability = new EntersBattlefieldAbility(effect, true); + effect = new CopyPermanentEffect(filter); + effect.setText("as a copy of any land on the battlefield"); + ability.addEffect(effect); + this.addAbility(ability); } public Vesuva(final Vesuva card) { diff --git a/Mage.Sets/src/mage/sets/urzasdestiny/AcademyRector.java b/Mage.Sets/src/mage/sets/urzasdestiny/AcademyRector.java index 393033b9be8..502842da895 100644 --- a/Mage.Sets/src/mage/sets/urzasdestiny/AcademyRector.java +++ b/Mage.Sets/src/mage/sets/urzasdestiny/AcademyRector.java @@ -106,7 +106,7 @@ class AcademyRectorEffect extends OneShotEffect { controller.searchLibrary(target, game); Card targetCard = game.getCard(target.getFirstTarget()); if (targetCard != null) { - controller.putOntoBattlefieldWithInfo(targetCard, game, Zone.LIBRARY, source.getSourceId()); + controller.moveCards(targetCard, Zone.BATTLEFIELD, source, game); } controller.shuffleLibrary(game); return true; diff --git a/Mage.Sets/src/mage/sets/vintagemasters/DacksDuplicate.java b/Mage.Sets/src/mage/sets/vintagemasters/DacksDuplicate.java index 467c548ca54..476ad0d3747 100644 --- a/Mage.Sets/src/mage/sets/vintagemasters/DacksDuplicate.java +++ b/Mage.Sets/src/mage/sets/vintagemasters/DacksDuplicate.java @@ -30,15 +30,15 @@ package mage.sets.vintagemasters; import java.util.UUID; import mage.MageInt; import mage.MageObject; -import mage.abilities.common.SimpleStaticAbility; -import mage.abilities.effects.EntersBattlefieldEffect; +import mage.abilities.common.EntersBattlefieldAbility; +import mage.abilities.effects.Effect; import mage.abilities.effects.common.CopyPermanentEffect; import mage.abilities.keyword.DethroneAbility; import mage.abilities.keyword.HasteAbility; import mage.cards.CardImpl; import mage.constants.CardType; import mage.constants.Rarity; -import mage.constants.Zone; +import mage.filter.common.FilterCreaturePermanent; import mage.game.Game; import mage.game.permanent.Permanent; import mage.util.functions.ApplyToPermanent; @@ -58,11 +58,9 @@ public class DacksDuplicate extends CardImpl { this.toughness = new MageInt(0); // You may have Dack's Duplicate enter the battlefield as a copy of any creature on the battlefield except it gains haste and dethrone. - this.addAbility(new SimpleStaticAbility( - Zone.BATTLEFIELD, - new EntersBattlefieldEffect(new CopyPermanentEffect(new DacksDuplicateApplyToPermanent()), - "You may have {this} enter the battlefield as a copy of any creature on the battlefield except it gains haste and dethrone", - true))); + Effect effect = new CopyPermanentEffect(new FilterCreaturePermanent(), new DacksDuplicateApplyToPermanent()); + effect.setText("as a copy of any creature on the battlefield except it gains haste and dethrone"); + this.addAbility(new EntersBattlefieldAbility(effect, true)); } public DacksDuplicate(final DacksDuplicate card) { diff --git a/Mage.Sets/src/mage/sets/weatherlight/CallOfTheWild.java b/Mage.Sets/src/mage/sets/weatherlight/CallOfTheWild.java index bc0509a505a..5dbc70aa620 100644 --- a/Mage.Sets/src/mage/sets/weatherlight/CallOfTheWild.java +++ b/Mage.Sets/src/mage/sets/weatherlight/CallOfTheWild.java @@ -28,11 +28,7 @@ package mage.sets.weatherlight; import java.util.UUID; - -import mage.constants.CardType; -import mage.constants.Outcome; -import mage.constants.Rarity; -import mage.constants.Zone; +import mage.MageObject; import mage.abilities.Ability; import mage.abilities.common.SimpleActivatedAbility; import mage.abilities.costs.mana.ManaCostsImpl; @@ -41,6 +37,10 @@ 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.game.Game; import mage.players.Player; @@ -68,7 +68,6 @@ public class CallOfTheWild extends CardImpl { } } - class CallOfTheWildEffect extends OneShotEffect { public CallOfTheWildEffect() { @@ -87,22 +86,21 @@ class CallOfTheWildEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { - Player player = game.getPlayer(source.getControllerId()); - if (player == null) { + Player controller = game.getPlayer(source.getControllerId()); + MageObject sourceObject = source.getSourceObject(game); + if (controller == null || sourceObject == null) { return false; } - if (player.getLibrary().size() > 0) { - Card card = player.getLibrary().getFromTop(game); - Cards cards = new CardsImpl(); - cards.add(card); - player.revealCards("Call of the Wild", cards, game); - + if (controller.getLibrary().size() > 0) { + Card card = controller.getLibrary().getFromTop(game); if (card != null) { + Cards cards = new CardsImpl(card); + controller.revealCards(sourceObject.getIdName(), cards, game); if (card.getCardType().contains(CardType.CREATURE)) { - player.putOntoBattlefieldWithInfo(card, game, Zone.LIBRARY, source.getSourceId()); + controller.moveCards(card, Zone.BATTLEFIELD, source, game); } else { - player.moveCards(card, Zone.LIBRARY, Zone.GRAVEYARD, source, game); + controller.moveCards(card, Zone.GRAVEYARD, source, game); } } } diff --git a/Mage.Sets/src/mage/sets/worldwake/JaceTheMindSculptor.java b/Mage.Sets/src/mage/sets/worldwake/JaceTheMindSculptor.java index 77ae649901b..d68cd5c7eda 100644 --- a/Mage.Sets/src/mage/sets/worldwake/JaceTheMindSculptor.java +++ b/Mage.Sets/src/mage/sets/worldwake/JaceTheMindSculptor.java @@ -1,16 +1,16 @@ /* * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. - * + * * Redistribution and use in source and binary forms, with or without modification, are * permitted provided that the following conditions are met: - * + * * 1. Redistributions of source code must retain the above copyright notice, this list of * conditions and the following disclaimer. - * + * * 2. Redistributions in binary form must reproduce the above copyright notice, this list * of conditions and the following disclaimer in the documentation and/or other materials * provided with the distribution. - * + * * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR @@ -20,21 +20,19 @@ * 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.worldwake; import java.util.UUID; import mage.abilities.Ability; import mage.abilities.LoyaltyAbility; -import mage.abilities.common.EntersBattlefieldAbility; +import mage.abilities.common.PlanswalkerEntersWithLoyalityCountersAbility; import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.ReturnToHandTargetEffect; -import mage.abilities.effects.common.counter.AddCountersSourceEffect; import mage.cards.Card; import mage.cards.CardImpl; import mage.cards.Cards; @@ -43,8 +41,6 @@ import mage.constants.CardType; import mage.constants.Outcome; import mage.constants.Rarity; import mage.constants.Zone; -import mage.counters.CounterType; -import mage.game.ExileZone; import mage.game.Game; import mage.players.Player; import mage.target.TargetPlayer; @@ -56,13 +52,12 @@ import mage.target.common.TargetCreaturePermanent; */ public class JaceTheMindSculptor extends CardImpl { - public JaceTheMindSculptor(UUID ownerId) { super(ownerId, 31, "Jace, the Mind Sculptor", Rarity.MYTHIC, new CardType[]{CardType.PLANESWALKER}, "{2}{U}{U}"); this.expansionSetCode = "WWK"; this.subtype.add("Jace"); - this.addAbility(new EntersBattlefieldAbility(new AddCountersSourceEffect(CounterType.LOYALTY.createInstance(3)), false)); + this.addAbility(new PlanswalkerEntersWithLoyalityCountersAbility(3)); // +2: Look at the top card of target player's library. You may put that card on the bottom of that player's library. LoyaltyAbility ability1 = new LoyaltyAbility(new JaceTheMindSculptorEffect1(), 2); @@ -77,7 +72,7 @@ public class JaceTheMindSculptor extends CardImpl { LoyaltyAbility ability3 = new LoyaltyAbility(new ReturnToHandTargetEffect(), -1); ability3.addTarget(new TargetCreaturePermanent()); this.addAbility(ability3); - + // −12: Exile all cards from target player's library, then that player shuffles his or her hand into his or her library. LoyaltyAbility ability4 = new LoyaltyAbility(new JaceTheMindSculptorEffect3(), -12); ability4.addTarget(new TargetPlayer()); @@ -123,7 +118,7 @@ class JaceTheMindSculptorEffect1 extends OneShotEffect { cards.add(card); controller.lookAtCards("Jace, the Mind Sculptor", cards, game); if (controller.chooseUse(outcome, "Do you wish to put card on the bottom of player's library?", source, game)) { - controller.moveCardToLibraryWithInfo(card, source.getSourceId(), game, Zone.LIBRARY, false, false); + controller.moveCardToLibraryWithInfo(card, source.getSourceId(), game, Zone.LIBRARY, false, false); } else { game.informPlayers(controller.getLogName() + " puts the card back on top of the library."); } diff --git a/Mage.Sets/src/mage/sets/worldwake/JwariShapeshifter.java b/Mage.Sets/src/mage/sets/worldwake/JwariShapeshifter.java index c436a967e92..75eaeeef964 100644 --- a/Mage.Sets/src/mage/sets/worldwake/JwariShapeshifter.java +++ b/Mage.Sets/src/mage/sets/worldwake/JwariShapeshifter.java @@ -28,15 +28,12 @@ package mage.sets.worldwake; 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.common.SimpleStaticAbility; -import mage.abilities.effects.EntersBattlefieldEffect; +import mage.abilities.common.EntersBattlefieldAbility; import mage.abilities.effects.common.CopyPermanentEffect; import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.Rarity; import mage.filter.FilterPermanent; import mage.filter.predicate.mageobject.CardTypePredicate; import mage.filter.predicate.mageobject.SubtypePredicate; @@ -47,9 +44,9 @@ import mage.filter.predicate.permanent.AnotherPredicate; * @author jeffwadsworth */ public class JwariShapeshifter extends CardImpl { - + private static final FilterPermanent filter = new FilterPermanent("Ally creature"); - + static { filter.add(new SubtypePredicate("Ally")); filter.add(new CardTypePredicate(CardType.CREATURE)); @@ -66,11 +63,7 @@ public class JwariShapeshifter extends CardImpl { this.toughness = new MageInt(0); // You may have Jwari Shapeshifter enter the battlefield as a copy of any Ally creature on the battlefield. - Ability ability = new SimpleStaticAbility( - Zone.BATTLEFIELD, - new EntersBattlefieldEffect(new CopyPermanentEffect(filter), null, - "You may have {this} enter the battlefield as a copy of any Ally creature on the battlefield", true, true)); - this.addAbility(ability); + this.addAbility(new EntersBattlefieldAbility(new CopyPermanentEffect(filter), true)); } public JwariShapeshifter(final JwariShapeshifter card) { diff --git a/Mage.Sets/src/mage/sets/zendikar/AetherFigment.java b/Mage.Sets/src/mage/sets/zendikar/AetherFigment.java index da7a28bd75e..d5b4caaa4a7 100644 --- a/Mage.Sets/src/mage/sets/zendikar/AetherFigment.java +++ b/Mage.Sets/src/mage/sets/zendikar/AetherFigment.java @@ -1,16 +1,16 @@ /* * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. - * + * * Redistribution and use in source and binary forms, with or without modification, are * permitted provided that the following conditions are met: - * + * * 1. Redistributions of source code must retain the above copyright notice, this list of * conditions and the following disclaimer. - * + * * 2. Redistributions in binary form must reproduce the above copyright notice, this list * of conditions and the following disclaimer in the documentation and/or other materials * provided with the distribution. - * + * * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR @@ -20,36 +20,31 @@ * 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.zendikar; import java.util.UUID; -import mage.constants.CardType; -import mage.constants.Rarity; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.EntersBattlefieldAbility; import mage.abilities.condition.common.KickedCondition; -import mage.abilities.decorator.ConditionalOneShotEffect; import mage.abilities.effects.common.counter.AddCountersSourceEffect; -import mage.abilities.keyword.KickerAbility; import mage.abilities.keyword.CantBeBlockedSourceAbility; +import mage.abilities.keyword.KickerAbility; import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.Rarity; import mage.counters.CounterType; - /** * @author nantuko, BetaSteward_at_googlemail.com */ public class AetherFigment extends CardImpl { - private static final String staticText = "with two +1/+1 counters on it, if it was kicked"; - public AetherFigment(UUID ownerId) { super(ownerId, 40, "AEther Figment", Rarity.UNCOMMON, new CardType[]{CardType.CREATURE}, "{1}{U}"); this.expansionSetCode = "ZEN"; @@ -65,7 +60,11 @@ public class AetherFigment extends CardImpl { this.addAbility(new KickerAbility("{3}")); // If AEther Figment was kicked, it enters the battlefield with two +1/+1 counters on it - Ability ability = new EntersBattlefieldAbility(new ConditionalOneShotEffect(new AddCountersSourceEffect(CounterType.P1P1.createInstance(2)), KickedCondition.getInstance(), ""), staticText); + Ability ability = new EntersBattlefieldAbility( + new AddCountersSourceEffect(CounterType.P1P1.createInstance(2)), + KickedCondition.getInstance(), + "If {this} was kicked, it enters the battlefield with two +1/+1 counters on it", + ""); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/sets/zendikar/ChandraAblaze.java b/Mage.Sets/src/mage/sets/zendikar/ChandraAblaze.java index a64697b5814..7caa34f04f9 100644 --- a/Mage.Sets/src/mage/sets/zendikar/ChandraAblaze.java +++ b/Mage.Sets/src/mage/sets/zendikar/ChandraAblaze.java @@ -32,18 +32,16 @@ import java.util.UUID; import mage.ObjectColor; import mage.abilities.Ability; import mage.abilities.LoyaltyAbility; -import mage.abilities.common.EntersBattlefieldAbility; +import mage.abilities.common.PlanswalkerEntersWithLoyalityCountersAbility; import mage.abilities.effects.Effect; import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.DrawCardAllEffect; -import mage.abilities.effects.common.counter.AddCountersSourceEffect; import mage.abilities.effects.common.discard.DiscardHandAllEffect; import mage.cards.Card; import mage.cards.CardImpl; import mage.constants.CardType; import mage.constants.Outcome; import mage.constants.Rarity; -import mage.counters.CounterType; import mage.filter.FilterCard; import mage.filter.predicate.Predicates; import mage.filter.predicate.mageobject.CardTypePredicate; @@ -66,7 +64,7 @@ public class ChandraAblaze extends CardImpl { this.expansionSetCode = "ZEN"; this.subtype.add("Chandra"); - this.addAbility(new EntersBattlefieldAbility(new AddCountersSourceEffect(CounterType.LOYALTY.createInstance(5)), false)); + this.addAbility(new PlanswalkerEntersWithLoyalityCountersAbility(5)); // +1: Discard a card. If a red card is discarded this way, Chandra Ablaze deals 4 damage to target creature or player. LoyaltyAbility ability = new LoyaltyAbility(new ChandraAblazeEffect1(), 1); diff --git a/Mage.Sets/src/mage/sets/zendikar/NissaRevane.java b/Mage.Sets/src/mage/sets/zendikar/NissaRevane.java index 1a24adaacdf..2306fb65d75 100644 --- a/Mage.Sets/src/mage/sets/zendikar/NissaRevane.java +++ b/Mage.Sets/src/mage/sets/zendikar/NissaRevane.java @@ -28,17 +28,15 @@ package mage.sets.zendikar; import java.util.UUID; +import mage.abilities.Ability; +import mage.abilities.LoyaltyAbility; +import mage.abilities.common.PlanswalkerEntersWithLoyalityCountersAbility; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.search.SearchLibraryPutInPlayEffect; +import mage.cards.CardImpl; import mage.constants.CardType; import mage.constants.Outcome; import mage.constants.Rarity; -import mage.abilities.Ability; -import mage.abilities.LoyaltyAbility; -import mage.abilities.common.EntersBattlefieldAbility; -import mage.abilities.effects.OneShotEffect; -import mage.abilities.effects.common.counter.AddCountersSourceEffect; -import mage.abilities.effects.common.search.SearchLibraryPutInPlayEffect; -import mage.cards.CardImpl; -import mage.counters.CounterType; import mage.filter.FilterCard; import mage.filter.common.FilterControlledCreaturePermanent; import mage.filter.predicate.mageobject.NamePredicate; @@ -62,11 +60,10 @@ public class NissaRevane extends CardImpl { } public NissaRevane(UUID ownerId) { - super(ownerId, 170, "Nissa Revane", Rarity.MYTHIC, new CardType[]{ CardType.PLANESWALKER }, "{2}{G}{G}"); + super(ownerId, 170, "Nissa Revane", Rarity.MYTHIC, new CardType[]{CardType.PLANESWALKER}, "{2}{G}{G}"); this.expansionSetCode = "ZEN"; this.subtype.add("Nissa"); - this.addAbility(new EntersBattlefieldAbility(new AddCountersSourceEffect(CounterType.LOYALTY.createInstance(2)), false)); - + this.addAbility(new PlanswalkerEntersWithLoyalityCountersAbility(2)); LoyaltyAbility ability1 = new LoyaltyAbility(new SearchLibraryPutInPlayEffect(new TargetCardInLibrary(1, nissasChosenFilter)), 1); this.addAbility(ability1); diff --git a/Mage.Sets/src/mage/sets/zendikar/SorinMarkov.java b/Mage.Sets/src/mage/sets/zendikar/SorinMarkov.java index 5ecb9fe0b4c..309684109aa 100644 --- a/Mage.Sets/src/mage/sets/zendikar/SorinMarkov.java +++ b/Mage.Sets/src/mage/sets/zendikar/SorinMarkov.java @@ -27,27 +27,24 @@ */ package mage.sets.zendikar; -import mage.constants.CardType; -import mage.constants.Rarity; +import java.util.UUID; import mage.abilities.Ability; import mage.abilities.LoyaltyAbility; -import mage.abilities.common.EntersBattlefieldAbility; +import mage.abilities.common.PlanswalkerEntersWithLoyalityCountersAbility; import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.DamageTargetEffect; import mage.abilities.effects.common.GainLifeEffect; -import mage.abilities.effects.common.counter.AddCountersSourceEffect; import mage.abilities.effects.common.turn.ControlTargetPlayerNextTurnEffect; import mage.cards.CardImpl; +import mage.constants.CardType; import mage.constants.Outcome; -import mage.counters.CounterType; +import mage.constants.Rarity; import mage.game.Game; import mage.players.Player; import mage.target.TargetPlayer; import mage.target.common.TargetCreatureOrPlayer; import mage.target.common.TargetOpponent; -import java.util.UUID; - /** * * @author nantuko @@ -59,8 +56,7 @@ public class SorinMarkov extends CardImpl { this.expansionSetCode = "ZEN"; this.subtype.add("Sorin"); - - this.addAbility(new EntersBattlefieldAbility(new AddCountersSourceEffect(CounterType.LOYALTY.createInstance(4)), false)); + this.addAbility(new PlanswalkerEntersWithLoyalityCountersAbility(4)); // +2: Sorin Markov deals 2 damage to target creature or player and you gain 2 life. LoyaltyAbility ability1 = new LoyaltyAbility(new DamageTargetEffect(2), 2); diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/abilities/enters/MasterBiomancerTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/abilities/enters/MasterBiomancerTest.java index ebea5c555aa..41fdc97851c 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/abilities/enters/MasterBiomancerTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/abilities/enters/MasterBiomancerTest.java @@ -9,23 +9,19 @@ import org.mage.test.serverside.base.CardTestPlayerBase; * * @author LevelX2 */ - - public class MasterBiomancerTest extends CardTestPlayerBase { /* Master Biomancer {2}{G}{U} * Creature - Elf Wizard * 2/4 - * Each other creature you control enters the battlefield with a number of additional +1/+1 counters + * Each other creature you control enters the battlefield with a number of additional +1/+1 counters * on it equal to Master Biomancer's power and as a Mutant in addition to its other types. * */ - @Test public void testCreatureGetsCounters() { // a creature enters the battlefield and gets a counter for each point of power of Master Biomancer - addCard(Zone.BATTLEFIELD, playerA, "Island", 5); addCard(Zone.BATTLEFIELD, playerA, "Master Biomancer", 1); addCard(Zone.HAND, playerA, "Mindeye Drake"); @@ -52,12 +48,12 @@ public class MasterBiomancerTest extends CardTestPlayerBase { // a creature enters the battlefield and gets a counter for each point of power of Master Biomancer // doubled by Corpsejack Menace (when he ist cast, his own ability will not apply) // http://blogs.magicjudges.org/rulestips/2013/03/corpsejack-menace-and-master-biomancer/ - addCard(Zone.BATTLEFIELD, playerA, "Island", 2); addCard(Zone.BATTLEFIELD, playerA, "Forest", 2); addCard(Zone.BATTLEFIELD, playerA, "Swamp", 1); addCard(Zone.BATTLEFIELD, playerA, "Master Biomancer", 1); + // If one or more +1/+1 counters would be placed on a creature you control, twice that many +1/+1 counters are placed on it instead. addCard(Zone.HAND, playerA, "Corpsejack Menace"); addCard(Zone.HAND, playerA, "Mindeye Drake"); @@ -83,30 +79,28 @@ public class MasterBiomancerTest extends CardTestPlayerBase { assertPowerToughness(playerA, "Mindeye Drake", 6, 9); } - /** - * Progenitor Mimic - * Creature - Shapeshifter - * 0/0 - * You may have Progenitor Mimic enter the battlefield as a copy of any creature on - * the battlefield except it gains "At the beginning of your upkeep, if this creature - * isn't a token, put a token onto the battlefield that's a copy of this creature." + * Progenitor Mimic Creature - Shapeshifter 0/0 You may have Progenitor + * Mimic enter the battlefield as a copy of any creature on the battlefield + * except it gains "At the beginning of your upkeep, if this creature isn't + * a token, put a token onto the battlefield that's a copy of this + * creature." * - * If Progenitor Mimic comes into play, it gets two +1/+1 counters from - * the Master Biomancer already in play. It copies the Master Biomancer and - * is therfore a 4/6 creature. - * The Token generated next round from Progenitor Mimic has to get 2 + 4 counters - * and is therefore a 8/10 creature. + * If Progenitor Mimic comes into play, it gets two +1/+1 counters from the + * Master Biomancer already in play. It copies the Master Biomancer and is + * therfore a 4/6 creature. The Token generated next round from Progenitor + * Mimic has to get 2 + 4 counters and is therefore a 8/10 creature. */ - @Test public void testWithProgenitorMimic() { // a creature enters the battlefield and gets a counter for each point of power of Master Biomancer - addCard(Zone.BATTLEFIELD, playerA, "Island", 3); addCard(Zone.BATTLEFIELD, playerA, "Forest", 3); addCard(Zone.BATTLEFIELD, playerA, "Master Biomancer", 1); + // You may have Progenitor Mimic enter the battlefield as a copy of any creature on the battlefield + // except it gains "At the beginning of your upkeep, if this creature isn't a token, + // put a token onto the battlefield that's a copy of this creature." addCard(Zone.HAND, playerA, "Progenitor Mimic"); castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Progenitor Mimic"); diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/abilities/keywords/SuspendTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/abilities/keywords/SuspendTest.java index 98e3294b084..9ed98cca08f 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/abilities/keywords/SuspendTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/abilities/keywords/SuspendTest.java @@ -49,6 +49,8 @@ public class SuspendTest extends CardTestPlayerBase { public void testEpochrasite() { addCard(Zone.BATTLEFIELD, playerA, "Plains", 2); + // Epochrasite enters the battlefield with three +1/+1 counters on it if you didn't cast it from your hand. + // When Epochrasite dies, exile it with three time counters on it and it gains suspend. addCard(Zone.HAND, playerA, "Epochrasite", 1); addCard(Zone.HAND, playerB, "Lightning Bolt", 1); addCard(Zone.BATTLEFIELD, playerB, "Mountain", 1); 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 ff78a4dcf31..6567fa4edd3 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 @@ -157,7 +157,7 @@ public class KikiJikiMirrorBreakerTest extends CardTestPlayerBase { addCard(Zone.BATTLEFIELD, playerB, "Island", 5); 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. + // You may have Body Double enter the battlefield as a copy of any creature card in a graveyard. addCard(Zone.HAND, playerB, "Body Double", 1); // {4}{U} castSpell(2, PhaseStep.PRECOMBAT_MAIN, playerB, "Body Double"); diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/copy/VesuvaTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/copy/VesuvaTest.java index 48fc3962b1f..fe600b1e415 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/copy/VesuvaTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/copy/VesuvaTest.java @@ -92,7 +92,6 @@ public class VesuvaTest extends CardTestPlayerBase { execute(); assertPermanentCount(playerB, "Dark Depths", 1); - assertPermanentCount(playerA, "Vesuva", 0); assertPermanentCount(playerA, "Dark Depths", 1); Permanent darkDepth = getPermanent("Dark Depths", playerA); diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/replacement/PillarOfFlameTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/replacement/PillarOfFlameTest.java index 6c1e294d57c..082e3440095 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/replacement/PillarOfFlameTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/replacement/PillarOfFlameTest.java @@ -6,22 +6,30 @@ import org.junit.Test; import org.mage.test.serverside.base.CardTestPlayerBase; /** - * Pillar of Flame: - * Pillar of Flame deals 2 damage to target creature or player. If a creature dealt damage this way would die this turn, exile it instead. + * Pillar of Flame: Pillar of Flame deals 2 damage to target creature or player. + * If a creature dealt damage this way would die this turn, exile it instead. * * @author LevelX2 */ public class PillarOfFlameTest extends CardTestPlayerBase { /** - * Tests when cast Pillar of Flame targeting opponent there is no influence on dying creature of opponent + * Tests when cast Pillar of Flame targeting opponent there is no influence + * on dying creature of opponent */ @Test public void testNotTriggeringExileItInstead() { - addCard(Zone.BATTLEFIELD, playerA, "Lightning Mauler"); - addCard(Zone.BATTLEFIELD, playerA, "Rakdos Cackler"); + // Soulbond + // As long as Lightning Mauler is paired with another creature, both creatures have haste. + addCard(Zone.BATTLEFIELD, playerA, "Lightning Mauler"); // 2/1 + // Unleash (You may have this creature enter the battlefield with a +1/+1 counter on it. It can't block as long as it has a +1/+1 counter on it.) + addCard(Zone.BATTLEFIELD, playerA, "Rakdos Cackler"); // 1/1 + // Pillar of Flame deals 2 damage to target creature or player. + // If a creature dealt damage this way would die this turn, exile it instead. addCard(Zone.HAND, playerA, "Pillar of Flame"); + // Soulbond + // As long as Stonewright is paired with another creature, each of those creatures has "{R}: This creature gets +1/+0 until end of turn." addCard(Zone.HAND, playerA, "Stonewright"); addCard(Zone.BATTLEFIELD, playerA, "Mountain", 3); @@ -49,7 +57,8 @@ public class PillarOfFlameTest extends CardTestPlayerBase { } /** - * Tests when cast Pillar of Flame targeting creature it goes to exile if dying later + * Tests when cast Pillar of Flame targeting creature it goes to exile if + * dying later */ @Test public void testTriggeringExileItInstead() { diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/replacement/TorporOrbTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/replacement/TorporOrbTest.java index 441d68754b9..c8694f3540b 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/replacement/TorporOrbTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/replacement/TorporOrbTest.java @@ -6,8 +6,8 @@ import org.junit.Test; import org.mage.test.serverside.base.CardTestPlayerBase; /** - * Torpor Orb: - * Creatures entering the battlefield don't cause abilities to trigger. + * Torpor Orb: Creatures entering the battlefield don't cause abilities to + * trigger. * * @author noxx */ @@ -15,7 +15,10 @@ public class TorporOrbTest extends CardTestPlayerBase { @Test public void testWallOfOmens() { + // Creatures entering the battlefield don't cause abilities to trigger. addCard(Zone.BATTLEFIELD, playerA, "Torpor Orb"); + // Defender + // When Wall of Omens enters the battlefield, draw a card. addCard(Zone.HAND, playerA, "Wall of Omens"); addCard(Zone.BATTLEFIELD, playerA, "Plains", 2); @@ -33,7 +36,8 @@ public class TorporOrbTest extends CardTestPlayerBase { } /** - * Treacherous Pit-Dweller doesnt function properly with Torpor Orb and Hushwing Gryff + * Treacherous Pit-Dweller doesnt function properly with Torpor Orb and + * Hushwing Gryff */ @Test public void testPitTweller() { @@ -42,8 +46,8 @@ public class TorporOrbTest extends CardTestPlayerBase { addCard(Zone.HAND, playerA, "Lightning Bolt"); addCard(Zone.BATTLEFIELD, playerA, "Mountain", 1); - - attack(2, playerB, "Treacherous Pit-Dweller"); + + attack(2, playerB, "Treacherous Pit-Dweller"); castSpell(2, PhaseStep.DECLARE_ATTACKERS, playerA, "Lightning Bolt", "Treacherous Pit-Dweller"); setStopAt(2, PhaseStep.POSTCOMBAT_MAIN); @@ -53,9 +57,9 @@ public class TorporOrbTest extends CardTestPlayerBase { assertLife(playerB, 20); assertGraveyardCount(playerA, "Lightning Bolt", 1); - + assertPermanentCount(playerB, "Treacherous Pit-Dweller", 1); - assertPowerToughness(playerB, "Treacherous Pit-Dweller", 5,4); + assertPowerToughness(playerB, "Treacherous Pit-Dweller", 5, 4); } - + } diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/triggers/FathomMageTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/triggers/FathomMageTest.java index 5d8f468f12c..fe610fe9b3c 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/triggers/FathomMageTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/triggers/FathomMageTest.java @@ -13,14 +13,16 @@ public class FathomMageTest extends CardTestPlayerBase { /** * Fathom Mage - Creature — Human Wizard 1/1, 2UG * - * Evolve (Whenever a creature enters the battlefield under your control, if that creature has greater power or toughness than this creature, put a +1/+1 counter on this creature.) - * Whenever a +1/+1 counter is placed on Fathom Mage, you may draw a card. + * Evolve (Whenever a creature enters the battlefield under your control, if + * that creature has greater power or toughness than this creature, put a + * +1/+1 counter on this creature.) Whenever a +1/+1 counter is placed on + * Fathom Mage, you may draw a card. + * * - */ @Test public void testDrawCardsAddedCounters() { - // card draw triggered ability will trigger once for each of those counters from Blessings of Nature. + // card draw triggered ability will trigger once for each of those counters from Blessings of Nature. addCard(Zone.HAND, playerA, "Blessings of Nature"); addCard(Zone.BATTLEFIELD, playerA, "Fathom Mage", 1); @@ -38,14 +40,14 @@ public class FathomMageTest extends CardTestPlayerBase { @Test public void testDrawCardsEntersTheBattlefield() { - // card draw triggered ability will trigger once for each of those counters from Master Biomancer. + // card draw triggered ability will trigger once for each of those counters from Master Biomancer. addCard(Zone.HAND, playerA, "Fathom Mage"); addCard(Zone.BATTLEFIELD, playerA, "Master Biomancer", 1); - addCard(Zone.BATTLEFIELD, playerA, "Forest", 4); - addCard(Zone.BATTLEFIELD, playerA, "Island", 4); + addCard(Zone.BATTLEFIELD, playerA, "Forest", 2); + addCard(Zone.BATTLEFIELD, playerA, "Island", 2); - castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Fathom Mage"); + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Fathom Mage"); // {2}{G}{U} setStopAt(1, PhaseStep.END_TURN); execute(); diff --git a/Mage.Tests/src/test/java/org/mage/test/player/TestPlayer.java b/Mage.Tests/src/test/java/org/mage/test/player/TestPlayer.java index 5d0df67f11a..702e99ba355 100644 --- a/Mage.Tests/src/test/java/org/mage/test/player/TestPlayer.java +++ b/Mage.Tests/src/test/java/org/mage/test/player/TestPlayer.java @@ -1970,11 +1970,26 @@ public class TestPlayer implements Player { return computerPlayer.scry(value, source, game); } + @Override + public boolean moveCards(Card card, Zone toZone, Ability source, Game game) { + return computerPlayer.moveCards(card, toZone, source, game); + } + @Override public boolean moveCards(Card card, Zone toZone, Ability source, Game game, boolean tapped, boolean faceDown, boolean byOwner, ArrayList appliedEffects) { return computerPlayer.moveCards(card, toZone, source, game, tapped, faceDown, byOwner, appliedEffects); } + @Override + public boolean moveCards(Cards cards, Zone toZone, Ability source, Game game) { + return computerPlayer.moveCards(cards, toZone, source, game); + } + + @Override + public boolean moveCards(Set cards, Zone toZone, Ability source, Game game) { + return computerPlayer.moveCards(cards, toZone, source, game); + } + @Override public boolean moveCards(Set cards, Zone toZone, Ability source, Game game, boolean tapped, boolean faceDown, boolean byOwner, ArrayList appliedEffects) { return computerPlayer.moveCards(cards, toZone, source, game, tapped, faceDown, byOwner, appliedEffects); diff --git a/Mage.Tests/src/test/java/org/mage/test/serverside/base/impl/CardTestPlayerAPIImpl.java b/Mage.Tests/src/test/java/org/mage/test/serverside/base/impl/CardTestPlayerAPIImpl.java index 77d726faea7..8611baa943c 100644 --- a/Mage.Tests/src/test/java/org/mage/test/serverside/base/impl/CardTestPlayerAPIImpl.java +++ b/Mage.Tests/src/test/java/org/mage/test/serverside/base/impl/CardTestPlayerAPIImpl.java @@ -533,10 +533,10 @@ public abstract class CardTestPlayerAPIImpl extends MageTestPlayerBase implement if (flag) { Assert.assertTrue("No such ability=" + ability.toString() + ", player=" + player.getName() - + ", cardName" + cardName, found.getAbilities().containsRule(ability)); + + ", cardName" + cardName, found.getAbilities(currentGame).containsRule(ability)); } else { Assert.assertFalse("Card shouldn't have such ability=" + ability.toString() + ", player=" + player.getName() - + ", cardName" + cardName, found.getAbilities().containsRule(ability)); + + ", cardName" + cardName, found.getAbilities(currentGame).containsRule(ability)); } } @@ -574,7 +574,7 @@ public abstract class CardTestPlayerAPIImpl extends MageTestPlayerBase implement } } } - Assert.assertEquals("(Battlefield) Card counts for " + player.getName() + " are not equal (" + cardName + ")", count, actualCount); + Assert.assertEquals("(Battlefield) Permanents counts for " + player.getName() + " are not equal (" + cardName + ")", count, actualCount); } @Override diff --git a/Mage/src/mage/abilities/AbilityImpl.java b/Mage/src/mage/abilities/AbilityImpl.java index 821abd34d61..619a400685d 100644 --- a/Mage/src/mage/abilities/AbilityImpl.java +++ b/Mage/src/mage/abilities/AbilityImpl.java @@ -958,6 +958,10 @@ public abstract class AbilityImpl implements Ability { if (object instanceof Permanent) { return false; } else { + Permanent permanent = game.getPermanentEntering(getSourceId()); + if (permanent != null && permanent.getAbilities().contains(this)) { + return true; + } // check if it's an ability that is temporary gained to a card Abilities otherAbilities = game.getState().getAllOtherAbilities(this.getSourceId()); if (otherAbilities == null || !otherAbilities.contains(this)) { diff --git a/Mage/src/mage/abilities/common/DiesTriggeredAbility.java b/Mage/src/mage/abilities/common/DiesTriggeredAbility.java index aac46fbe9d8..0efbd80e31e 100644 --- a/Mage/src/mage/abilities/common/DiesTriggeredAbility.java +++ b/Mage/src/mage/abilities/common/DiesTriggeredAbility.java @@ -71,7 +71,7 @@ public class DiesTriggeredAbility extends ZoneChangeTriggeredAbility { if (super.checkEventType(event, game)) { return ((ZoneChangeEvent) event).getFromZone().equals(Zone.BATTLEFIELD) && ((ZoneChangeEvent) event).getToZone().equals(Zone.GRAVEYARD); } - return event.getType() == GameEvent.EventType.ZONE_CHANGE; + return false; } @Override diff --git a/Mage/src/mage/abilities/common/EntersBattlefieldAbility.java b/Mage/src/mage/abilities/common/EntersBattlefieldAbility.java index 64bd2c40fe5..40231800591 100644 --- a/Mage/src/mage/abilities/common/EntersBattlefieldAbility.java +++ b/Mage/src/mage/abilities/common/EntersBattlefieldAbility.java @@ -40,44 +40,50 @@ import mage.constants.Zone; public class EntersBattlefieldAbility extends StaticAbility { protected String abilityRule; + protected boolean optional; public EntersBattlefieldAbility(Effect effect) { - this(effect, true); + this(effect, false); } /** * * @param effect effect that happens when the permanent enters the - * battlefield - * @param showRule show the rule for this ability + * battlefiely + * @param optional */ - public EntersBattlefieldAbility(Effect effect, Boolean showRule) { - this(effect, null, showRule, null, null); + public EntersBattlefieldAbility(Effect effect, boolean optional) { + this(effect, optional, null, null, null); } public EntersBattlefieldAbility(Effect effect, String effectText) { - this(effect, null, true, null, effectText); + this(effect, null, null, effectText); + } + + public EntersBattlefieldAbility(Effect effect, Condition condition, String abilityRule, String effectText) { + this(effect, false, condition, abilityRule, effectText); } /** * * @param effect effect that happens when the permanent enters the * battlefield + * @param optional * @param condition only if this condition is true, the effect will happen - * @param ruleVisible show the rule for this ability * @param abilityRule rule for this ability (no text from effects will be * added) * @param effectText this text will be used for the EnterBattlefieldEffect */ - public EntersBattlefieldAbility(Effect effect, Condition condition, Boolean ruleVisible, String abilityRule, String effectText) { - super(Zone.ALL, new EntersBattlefieldEffect(effect, condition, effectText)); - this.setRuleVisible(ruleVisible); + public EntersBattlefieldAbility(Effect effect, boolean optional, Condition condition, String abilityRule, String effectText) { + super(Zone.ALL, new EntersBattlefieldEffect(effect, condition, effectText, true, optional)); this.abilityRule = abilityRule; + this.optional = optional; } public EntersBattlefieldAbility(final EntersBattlefieldAbility ability) { super(ability); this.abilityRule = ability.abilityRule; + this.optional = ability.optional; } @Override @@ -99,12 +105,9 @@ public class EntersBattlefieldAbility extends StaticAbility { @Override public String getRule() { - if (!ruleVisible) { - return ""; - } if (abilityRule != null && !abilityRule.isEmpty()) { return abilityRule; } - return "{this} enters the battlefield " + super.getRule(); + return (optional ? "you may have " : "") + "{this} enter" + (optional ? "" : "s") + " the battlefield " + super.getRule(); } } diff --git a/Mage/src/mage/abilities/common/PlanswalkerEntersWithLoyalityCountersAbility.java b/Mage/src/mage/abilities/common/PlanswalkerEntersWithLoyalityCountersAbility.java new file mode 100644 index 00000000000..aad230eaf2d --- /dev/null +++ b/Mage/src/mage/abilities/common/PlanswalkerEntersWithLoyalityCountersAbility.java @@ -0,0 +1,30 @@ +/* + * To change this license header, choose License Headers in Project Properties. + * To change this template file, choose Tools | Templates + * and open the template in the editor. + */ +package mage.abilities.common; + +import mage.abilities.effects.common.counter.AddCountersSourceEffect; +import mage.counters.CounterType; + +/** + * + * @author LevelX2 + */ +public class PlanswalkerEntersWithLoyalityCountersAbility extends EntersBattlefieldAbility { + + public PlanswalkerEntersWithLoyalityCountersAbility(int loyality) { + super(new AddCountersSourceEffect(CounterType.LOYALTY.createInstance(loyality))); + setRuleVisible(false); + } + + public PlanswalkerEntersWithLoyalityCountersAbility(final PlanswalkerEntersWithLoyalityCountersAbility ability) { + super(ability); + } + + @Override + public EntersBattlefieldAbility copy() { + return new PlanswalkerEntersWithLoyalityCountersAbility(this); + } +} diff --git a/Mage/src/mage/abilities/condition/common/CastFromHandCondition.java b/Mage/src/mage/abilities/condition/common/CastFromHandCondition.java index 27811130bdc..1abc7306f5f 100644 --- a/Mage/src/mage/abilities/condition/common/CastFromHandCondition.java +++ b/Mage/src/mage/abilities/condition/common/CastFromHandCondition.java @@ -12,10 +12,14 @@ import mage.watchers.Watcher; * @author Loki */ public class CastFromHandCondition implements Condition { + @Override public boolean apply(Game game, Ability source) { - Permanent p = game.getPermanent(source.getSourceId()); - if (p != null) { + Permanent permanent = game.getPermanent(source.getSourceId()); + if (permanent == null) { + permanent = game.getPermanentEntering(source.getSourceId()); + } + if (permanent != null) { Watcher watcher = game.getState().getWatchers().get("CastFromHand", source.getSourceId()); if (watcher != null && watcher.conditionMet()) { return true; @@ -29,5 +33,4 @@ public class CastFromHandCondition implements Condition { return "you cast it from your hand"; } - } diff --git a/Mage/src/mage/abilities/costs/AlternativeCost2Impl.java b/Mage/src/mage/abilities/costs/AlternativeCost2Impl.java index 03a0be13f47..b69b73b278c 100644 --- a/Mage/src/mage/abilities/costs/AlternativeCost2Impl.java +++ b/Mage/src/mage/abilities/costs/AlternativeCost2Impl.java @@ -125,8 +125,6 @@ public class AlternativeCost2Impl> extends Cos activated = true; } - ; - /** * Reset the activate and count information * diff --git a/Mage/src/mage/abilities/effects/ContinuousEffects.java b/Mage/src/mage/abilities/effects/ContinuousEffects.java index c5b4661816b..2f35dbd4901 100644 --- a/Mage/src/mage/abilities/effects/ContinuousEffects.java +++ b/Mage/src/mage/abilities/effects/ContinuousEffects.java @@ -879,7 +879,7 @@ public class ContinuousEffects implements Serializable { // For example: Vesuva copying a Dark Depth (VesuvaTest:testDarkDepth) // This call should be removed if possible as replacement effects of EntersTheBattlefield events // do no longer work correctly because the entering permanents are not yet on the battlefield (before they were). - game.applyEffects(); + // game.applyEffects(); } while (true); return caught; } diff --git a/Mage/src/mage/abilities/effects/EntersBattlefieldEffect.java b/Mage/src/mage/abilities/effects/EntersBattlefieldEffect.java index ef6bb795d16..052d4ee5d4b 100644 --- a/Mage/src/mage/abilities/effects/EntersBattlefieldEffect.java +++ b/Mage/src/mage/abilities/effects/EntersBattlefieldEffect.java @@ -34,7 +34,6 @@ import mage.abilities.condition.Condition; import mage.constants.Duration; import mage.constants.Zone; import mage.game.Game; -import mage.game.events.EntersTheBattlefieldEvent; import mage.game.events.GameEvent; import mage.game.events.GameEvent.EventType; import mage.game.stack.Spell; @@ -52,7 +51,6 @@ public class EntersBattlefieldEffect extends ReplacementEffectImpl { protected Condition condition; protected boolean optional; - public static final String ENTERING_PERMANENT = "enteringPermanent"; public static final String SOURCE_CAST_SPELL_ABILITY = "sourceCastSpellAbility"; public EntersBattlefieldEffect(Effect baseEffect) { @@ -67,10 +65,6 @@ public class EntersBattlefieldEffect extends ReplacementEffectImpl { this(baseEffect, null, text, true, optional); } - public EntersBattlefieldEffect(Effect baseEffect, Condition condition, String text) { - this(baseEffect, condition, text, true, false); - } - public EntersBattlefieldEffect(Effect baseEffect, Condition condition, String text, boolean selfScope, boolean optional) { super(Duration.WhileOnBattlefield, baseEffect.getOutcome(), selfScope); this.baseEffects.add(baseEffect); @@ -126,18 +120,16 @@ public class EntersBattlefieldEffect extends ReplacementEffectImpl { } } for (Effect effect : baseEffects) { - if (source.activate(game, false)) { - if (effect instanceof ContinuousEffect) { - game.addEffect((ContinuousEffect) effect, source); - } else { - if (spell != null) { - effect.setValue(SOURCE_CAST_SPELL_ABILITY, spell.getSpellAbility()); - } - // Because the permanent is not on the battlefield yet, it has to be taken from the event - effect.setValue(ENTERING_PERMANENT, ((EntersTheBattlefieldEvent) event).getTarget()); - effect.apply(game, source); + // if (source.activate(game, false)) { // Why is this needed???? + if (effect instanceof ContinuousEffect) { + game.addEffect((ContinuousEffect) effect, source); + } else { + if (spell != null) { + effect.setValue(SOURCE_CAST_SPELL_ABILITY, spell.getSpellAbility()); } + effect.apply(game, source); } + // } } return false; } diff --git a/Mage/src/mage/abilities/effects/common/AddManaInAnyCombinationEffect.java b/Mage/src/mage/abilities/effects/common/AddManaInAnyCombinationEffect.java index 4a87a976677..722fc0468d9 100644 --- a/Mage/src/mage/abilities/effects/common/AddManaInAnyCombinationEffect.java +++ b/Mage/src/mage/abilities/effects/common/AddManaInAnyCombinationEffect.java @@ -25,7 +25,6 @@ * authors and should not be interpreted as representing official policies, either expressed * or implied, of BetaSteward_at_googlemail.com. */ - package mage.abilities.effects.common; import java.util.ArrayList; @@ -62,17 +61,17 @@ public class AddManaInAnyCombinationEffect extends ManaEffect { this.amount = amount; this.staticText = setText(); } - + public AddManaInAnyCombinationEffect(int amount, String text) { this(amount); this.staticText = text; } - + public AddManaInAnyCombinationEffect(int amount, String text, ColoredManaSymbol... coloredManaSymbols) { this(amount, coloredManaSymbols); this.staticText = text; } - + public AddManaInAnyCombinationEffect(DynamicValue amount, String text, ColoredManaSymbol... coloredManaSymbols) { this(amount, coloredManaSymbols); this.staticText = text; @@ -92,13 +91,13 @@ public class AddManaInAnyCombinationEffect extends ManaEffect { @Override public boolean apply(Game game, Ability source) { Player player = game.getPlayer(source.getControllerId()); - if (player != null){ + if (player != null) { Mana mana = new Mana(); int amountOfManaLeft = amount.calculate(game, source, this); while (amountOfManaLeft > 0 && player.canRespond()) { - for (ColoredManaSymbol coloredManaSymbol: manaSymbols) { - int number = player.getAmount(0, amountOfManaLeft, new StringBuilder("How many ").append(coloredManaSymbol.name()).append(" mana?").toString(), game); + for (ColoredManaSymbol coloredManaSymbol : manaSymbols) { + int number = player.getAmount(0, amountOfManaLeft, "How many " + coloredManaSymbol.getColorName() + " mana?", game); if (number > 0) { for (int i = 0; i < number; i++) { mana.add(new Mana(coloredManaSymbol)); @@ -111,7 +110,7 @@ public class AddManaInAnyCombinationEffect extends ManaEffect { } } checkToFirePossibleEvents(mana, game, source); - player.getManaPool().addMana(mana, game, source); + player.getManaPool().addMana(mana, game, source); return true; } return false; @@ -130,7 +129,7 @@ public class AddManaInAnyCombinationEffect extends ManaEffect { sb.append("colors"); } else { int i = 0; - for (ColoredManaSymbol coloredManaSymbol: manaSymbols) { + for (ColoredManaSymbol coloredManaSymbol : manaSymbols) { i++; if (i > 1) { sb.append(" and/or "); diff --git a/Mage/src/mage/abilities/effects/common/AmplifyEffect.java b/Mage/src/mage/abilities/effects/common/AmplifyEffect.java index a06e008ad7a..dcae2105843 100644 --- a/Mage/src/mage/abilities/effects/common/AmplifyEffect.java +++ b/Mage/src/mage/abilities/effects/common/AmplifyEffect.java @@ -19,6 +19,7 @@ import mage.filter.common.FilterCreatureCard; import mage.filter.predicate.Predicates; import mage.filter.predicate.mageobject.SubtypePredicate; import mage.game.Game; +import mage.game.events.EntersTheBattlefieldEvent; import mage.game.events.GameEvent; import mage.game.permanent.Permanent; import mage.players.Player; @@ -27,15 +28,13 @@ import mage.target.common.TargetCardInHand; /** * Effect for the AmplifyAbility * - * 702.37. Amplify - * 702.37a Amplify is a static ability. “Amplify N” means “As - * this object enters the battlefield, reveal any number of cards from your hand - * that share a creature type with it. This permanent enters the battlefield - * with N +1/+1 counters on it for each card revealed this way. You can’t reveal - * this card or any other cards that are entering the battlefield at the same - * time as this card.” - * 702.37b If a creature has multiple instances of amplify, - * each one works separately. + * 702.37. Amplify 702.37a Amplify is a static ability. “Amplify N” means “As + * this object enters the battlefield, reveal any number of cards from your hand + * that share a creature type with it. This permanent enters the battlefield + * with N +1/+1 counters on it for each card revealed this way. You can’t reveal + * this card or any other cards that are entering the battlefield at the same + * time as this card.” 702.37b If a creature has multiple instances of amplify, + * each one works separately. * * * @author FenrisulfrX @@ -45,6 +44,7 @@ public class AmplifyEffect extends ReplacementEffectImpl { private final AmplifyFactor amplifyFactor; public enum AmplifyFactor { + Amplify1("Amplify 1", "put one +1/+1 counters on it", 1), Amplify2("Amplify 2", "put two +1/+1 counters on it", 2), Amplify3("Amplify 3", "put three +1/+1 counters on it", 3); @@ -95,7 +95,7 @@ public class AmplifyEffect extends ReplacementEffectImpl { @Override public boolean replaceEvent(GameEvent event, Ability source, Game game) { - Permanent sourceCreature = game.getPermanent(event.getTargetId()); + Permanent sourceCreature = ((EntersTheBattlefieldEvent) event).getTarget(); Player controller = game.getPlayer(source.getControllerId()); if (controller != null && sourceCreature != null) { FilterCreatureCard filter = new FilterCreatureCard("creatures cards to reveal"); @@ -108,7 +108,7 @@ public class AmplifyEffect extends ReplacementEffectImpl { } else if (filterSubtypes.size() == 1) { filter.add(filterSubtypes.get(0)); } - if (controller.getHand().count(filter, source.getSourceId(), source.getControllerId(), game) > 0){ + if (controller.getHand().count(filter, source.getSourceId(), source.getControllerId(), game) > 0) { if (controller.chooseUse(outcome, "Reveal cards to Amplify?", source, game)) { TargetCardInHand target = new TargetCardInHand(0, Integer.MAX_VALUE, filter); if (controller.chooseTarget(outcome, target, source, game) && !target.getTargets().isEmpty()) { @@ -128,11 +128,11 @@ public class AmplifyEffect extends ReplacementEffectImpl { public String getText(Mode mode) { StringBuilder sb = new StringBuilder(amplifyFactor.toString()); sb.append("(As this enter the battlefield, "); - sb.append(amplifyFactor.getRuleText()).append(" for each card" + - " you reveal that shares a type with it in your hand.)"); + sb.append(amplifyFactor.getRuleText()).append(" for each card" + + " you reveal that shares a type with it in your hand.)"); return sb.toString(); } - + @Override public AmplifyEffect copy() { return new AmplifyEffect(this); diff --git a/Mage/src/mage/abilities/effects/common/ChooseBasicLandTypeEffect.java b/Mage/src/mage/abilities/effects/common/ChooseBasicLandTypeEffect.java index 07c1e706e9b..5d73e8dd40e 100644 --- a/Mage/src/mage/abilities/effects/common/ChooseBasicLandTypeEffect.java +++ b/Mage/src/mage/abilities/effects/common/ChooseBasicLandTypeEffect.java @@ -7,7 +7,6 @@ package mage.abilities.effects.common; import mage.MageObject; import mage.abilities.Ability; -import mage.abilities.effects.EntersBattlefieldEffect; import mage.abilities.effects.OneShotEffect; import mage.choices.ChoiceImpl; import mage.constants.Outcome; @@ -41,7 +40,7 @@ public class ChooseBasicLandTypeEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { Player controller = game.getPlayer(source.getControllerId()); - MageObject mageObject = (Permanent) getValue(EntersBattlefieldEffect.ENTERING_PERMANENT); + MageObject mageObject = game.getPermanentEntering(source.getSourceId()); if (mageObject == null) { mageObject = game.getObject(source.getSourceId()); } diff --git a/Mage/src/mage/abilities/effects/common/ChooseColorEffect.java b/Mage/src/mage/abilities/effects/common/ChooseColorEffect.java index 2fe01116753..161dec6767e 100644 --- a/Mage/src/mage/abilities/effects/common/ChooseColorEffect.java +++ b/Mage/src/mage/abilities/effects/common/ChooseColorEffect.java @@ -29,7 +29,6 @@ package mage.abilities.effects.common; import mage.MageObject; import mage.abilities.Ability; -import mage.abilities.effects.EntersBattlefieldEffect; import mage.abilities.effects.OneShotEffect; import mage.choices.ChoiceColor; import mage.constants.Outcome; @@ -56,7 +55,7 @@ public class ChooseColorEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { Player controller = game.getPlayer(source.getControllerId()); - MageObject mageObject = (Permanent) getValue(EntersBattlefieldEffect.ENTERING_PERMANENT); + MageObject mageObject = game.getPermanentEntering(source.getSourceId()); if (mageObject == null) { mageObject = game.getObject(source.getSourceId()); } diff --git a/Mage/src/mage/abilities/effects/common/ChooseCreatureTypeEffect.java b/Mage/src/mage/abilities/effects/common/ChooseCreatureTypeEffect.java index 06178b02843..b1d4b0e6f62 100644 --- a/Mage/src/mage/abilities/effects/common/ChooseCreatureTypeEffect.java +++ b/Mage/src/mage/abilities/effects/common/ChooseCreatureTypeEffect.java @@ -29,7 +29,6 @@ package mage.abilities.effects.common; import mage.MageObject; import mage.abilities.Ability; -import mage.abilities.effects.EntersBattlefieldEffect; import mage.abilities.effects.OneShotEffect; import mage.cards.repository.CardRepository; import mage.choices.Choice; @@ -58,7 +57,7 @@ public class ChooseCreatureTypeEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { Player controller = game.getPlayer(source.getControllerId()); - MageObject mageObject = (Permanent) getValue(EntersBattlefieldEffect.ENTERING_PERMANENT); + MageObject mageObject = game.getPermanentEntering(source.getSourceId()); if (mageObject == null) { mageObject = game.getObject(source.getSourceId()); } diff --git a/Mage/src/mage/abilities/effects/common/ChooseLandTypeEffect.java b/Mage/src/mage/abilities/effects/common/ChooseLandTypeEffect.java index 52259dbac52..bd59c25c334 100644 --- a/Mage/src/mage/abilities/effects/common/ChooseLandTypeEffect.java +++ b/Mage/src/mage/abilities/effects/common/ChooseLandTypeEffect.java @@ -7,7 +7,6 @@ package mage.abilities.effects.common; import mage.MageObject; import mage.abilities.Ability; -import mage.abilities.effects.EntersBattlefieldEffect; import mage.abilities.effects.OneShotEffect; import mage.cards.repository.CardRepository; import mage.choices.Choice; @@ -36,7 +35,7 @@ public class ChooseLandTypeEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { Player controller = game.getPlayer(source.getControllerId()); - MageObject mageObject = (Permanent) getValue(EntersBattlefieldEffect.ENTERING_PERMANENT); + MageObject mageObject = game.getPermanentEntering(source.getSourceId()); if (mageObject == null) { mageObject = game.getObject(source.getSourceId()); } diff --git a/Mage/src/mage/abilities/effects/common/ChooseOpponentEffect.java b/Mage/src/mage/abilities/effects/common/ChooseOpponentEffect.java index 9ac1910128e..bdb32a34a13 100644 --- a/Mage/src/mage/abilities/effects/common/ChooseOpponentEffect.java +++ b/Mage/src/mage/abilities/effects/common/ChooseOpponentEffect.java @@ -7,7 +7,6 @@ package mage.abilities.effects.common; import mage.MageObject; import mage.abilities.Ability; -import mage.abilities.effects.EntersBattlefieldEffect; import mage.abilities.effects.OneShotEffect; import mage.constants.Outcome; import mage.game.Game; @@ -41,7 +40,7 @@ public class ChooseOpponentEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { Player controller = game.getPlayer(source.getControllerId()); - MageObject mageObject = (Permanent) getValue(EntersBattlefieldEffect.ENTERING_PERMANENT); + MageObject mageObject = game.getPermanentEntering(source.getSourceId()); if (mageObject == null) { mageObject = game.getObject(source.getSourceId()); } diff --git a/Mage/src/mage/abilities/effects/common/ChoosePlayerEffect.java b/Mage/src/mage/abilities/effects/common/ChoosePlayerEffect.java index 7e5c6402c1b..7f8ce4c72cc 100644 --- a/Mage/src/mage/abilities/effects/common/ChoosePlayerEffect.java +++ b/Mage/src/mage/abilities/effects/common/ChoosePlayerEffect.java @@ -7,7 +7,6 @@ package mage.abilities.effects.common; import mage.MageObject; import mage.abilities.Ability; -import mage.abilities.effects.EntersBattlefieldEffect; import mage.abilities.effects.OneShotEffect; import mage.constants.Outcome; import mage.game.Game; @@ -39,7 +38,7 @@ public class ChoosePlayerEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { Player controller = game.getPlayer(source.getControllerId()); - MageObject mageObject = (Permanent) getValue(EntersBattlefieldEffect.ENTERING_PERMANENT); + MageObject mageObject = game.getPermanentEntering(source.getSourceId()); if (mageObject == null) { mageObject = game.getObject(source.getSourceId()); } diff --git a/Mage/src/mage/abilities/effects/common/CopyEffect.java b/Mage/src/mage/abilities/effects/common/CopyEffect.java index 86bc3f060fb..9b6becb7198 100644 --- a/Mage/src/mage/abilities/effects/common/CopyEffect.java +++ b/Mage/src/mage/abilities/effects/common/CopyEffect.java @@ -33,6 +33,7 @@ import mage.MageObjectReference; import mage.abilities.Ability; import mage.abilities.effects.ContinuousEffectImpl; import mage.cards.Card; +import mage.constants.AbilityType; import mage.constants.CardType; import mage.constants.Duration; import mage.constants.Layer; @@ -54,10 +55,10 @@ public class CopyEffect extends ContinuousEffectImpl { /** * Object we copy from */ - private MageObject copyFromObject; + protected MageObject copyFromObject; - private UUID copyToObjectId; - private ApplyToPermanent applier; + protected UUID copyToObjectId; + protected ApplyToPermanent applier; public CopyEffect(MageObject copyFromObject, UUID copyToObjectId) { this(Duration.Custom, copyFromObject, copyToObjectId); @@ -82,14 +83,23 @@ public class CopyEffect extends ContinuousEffectImpl { if (!(copyFromObject instanceof Permanent) && (copyFromObject instanceof Card)) { this.copyFromObject = new PermanentCard((Card) copyFromObject, source.getControllerId(), game); } - + Permanent permanent = game.getPermanent(copyToObjectId); + if (permanent != null) { + affectedObjectList.add(new MageObjectReference(permanent, game)); + } else if (source.getAbilityType().equals(AbilityType.STATIC)) { + // for replacement effects that let a permanent enter the battlefield as a copy of another permanent we need to apply that copy + // before the permanent is added to the battlefield + permanent = game.getPermanentEntering(copyToObjectId); + if (permanent != null) { + copyToPermanent(permanent, game, source); + // set reference to the permanent later on the battlefield so we have to add already one to the zone change counter + affectedObjectList.add(new MageObjectReference(permanent.getId(), game.getState().getZoneChangeCounter(copyToObjectId) + 1, game)); + } + } } @Override public boolean apply(Game game, Ability source) { - if (affectedObjectList.isEmpty()) { - affectedObjectList.add(new MageObjectReference(getSourceId(), game)); - } Permanent permanent = affectedObjectList.get(0).getPermanent(game); if (permanent == null) { permanent = (Permanent) game.getLastKnownInformation(getSourceId(), Zone.BATTLEFIELD, source.getSourceObjectZoneChangeCounter()); @@ -99,6 +109,10 @@ public class CopyEffect extends ContinuousEffectImpl { return false; } } + return copyToPermanent(permanent, game, source); + } + + protected boolean copyToPermanent(Permanent permanent, Game game, Ability source) { permanent.setCopy(true); permanent.setName(copyFromObject.getName()); permanent.getColor(game).setColor(copyFromObject.getColor(game)); diff --git a/Mage/src/mage/abilities/effects/common/CopyPermanentEffect.java b/Mage/src/mage/abilities/effects/common/CopyPermanentEffect.java index f6318632ac6..bf1ef297244 100644 --- a/Mage/src/mage/abilities/effects/common/CopyPermanentEffect.java +++ b/Mage/src/mage/abilities/effects/common/CopyPermanentEffect.java @@ -73,7 +73,7 @@ public class CopyPermanentEffect extends OneShotEffect { this.applier = applier; this.filter = filter; this.useTargetOfAbility = useTarget; - this.staticText = "You may have {this} enter the battlefield as a copy of any " + filter.getMessage() + " on the battlefield"; + this.staticText = "as a copy of any " + filter.getMessage() + " on the battlefield"; } public CopyPermanentEffect(final CopyPermanentEffect effect) { @@ -87,7 +87,10 @@ public class CopyPermanentEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { Player player = game.getPlayer(source.getControllerId()); - MageObject sourceObject = game.getObject(source.getSourceId()); + MageObject sourceObject = game.getPermanentEntering(source.getSourceId()); + if (sourceObject == null) { + sourceObject = game.getObject(source.getSourceId()); + } if (player != null && sourceObject != null) { Permanent copyFromPermanent = null; if (useTargetOfAbility) { diff --git a/Mage/src/mage/abilities/effects/common/DevourEffect.java b/Mage/src/mage/abilities/effects/common/DevourEffect.java index 1d02ab1733d..b2baf9ef7c0 100644 --- a/Mage/src/mage/abilities/effects/common/DevourEffect.java +++ b/Mage/src/mage/abilities/effects/common/DevourEffect.java @@ -47,30 +47,32 @@ import mage.target.common.TargetControlledCreaturePermanent; /** * Effect for the DevourAbility - * - * 702.81. Devour - * 702.81a Devour is a static ability. "Devour N" means "As this object enters the battlefield, - * you may sacrifice any number of creatures. This permanent enters the battlefield with N +1/+1 - * counters on it for each creature sacrificed this way." - * 702.81b Some objects have abilities that refer to the number of creatures the permanent devoured. - * "It devoured" means "sacrificed as a result of its devour ability as it entered the battlefield." * - * + * 702.81. Devour 702.81a Devour is a static ability. "Devour N" means "As this + * object enters the battlefield, you may sacrifice any number of creatures. + * This permanent enters the battlefield with N +1/+1 counters on it for each + * creature sacrificed this way." 702.81b Some objects have abilities that refer + * to the number of creatures the permanent devoured. "It devoured" means + * "sacrificed as a result of its devour ability as it entered the battlefield." + * + * * @author LevelX2 */ public class DevourEffect extends ReplacementEffectImpl { private static final FilterControlledCreaturePermanent filter = new FilterControlledCreaturePermanent("creatures to devour"); + static { filter.add(new AnotherPredicate()); } private final DevourFactor devourFactor; public enum DevourFactor { - Devour1 ("Devour 1", "that many +1/+1 counters on it", 1), - Devour2 ("Devour 2", "twice that many +1/+1 counters on it", 2), - Devour3 ("Devour 3", "three times that many +1/+1 counters on it", 3), - DevourX ("Devour X, where X is the number of creatures devoured this way", "X +1/+1 counters on it for each of those creatures", Integer.MAX_VALUE); + + Devour1("Devour 1", "that many +1/+1 counters on it", 1), + Devour2("Devour 2", "twice that many +1/+1 counters on it", 2), + Devour3("Devour 3", "three times that many +1/+1 counters on it", 3), + DevourX("Devour X, where X is the number of creatures devoured this way", "X +1/+1 counters on it for each of those creatures", Integer.MAX_VALUE); private final String text; private final String ruleText; @@ -114,9 +116,9 @@ public class DevourEffect extends ReplacementEffectImpl { @Override public boolean applies(GameEvent event, Ability source, Game game) { if (event.getTargetId().equals(source.getSourceId())) { - Permanent sourcePermanent = game.getPermanent(source.getSourceId()); - game.getState().setValue(sourcePermanent.getId().toString() + "devoured", null); - return true; + Permanent sourcePermanent = game.getPermanentEntering(source.getSourceId()); + game.getState().setValue(sourcePermanent.getId().toString() + "devoured", null); + return true; } return false; } @@ -128,7 +130,7 @@ public class DevourEffect extends ReplacementEffectImpl { @Override public boolean replaceEvent(GameEvent event, Ability source, Game game) { - Permanent creature = game.getPermanent(event.getTargetId()); + Permanent creature = game.getPermanentEntering(event.getTargetId()); Player controller = game.getPlayer(source.getControllerId()); if (creature != null && controller != null) { Target target = new TargetControlledCreaturePermanent(1, Integer.MAX_VALUE, filter, true); @@ -141,9 +143,10 @@ public class DevourEffect extends ReplacementEffectImpl { if (target.getTargets().size() > 0) { List> cardSubtypes = new ArrayList<>(); int devouredCreatures = target.getTargets().size(); - if (!game.isSimulation()) - game.informPlayers(new StringBuilder(creature.getName()).append(" devours ").append(devouredCreatures).append(" creatures").toString()); - for (UUID targetId: target.getTargets()) { + if (!game.isSimulation()) { + game.informPlayers(creature.getLogName() + " devours " + devouredCreatures + " creatures"); + } + for (UUID targetId : target.getTargets()) { Permanent targetCreature = game.getPermanent(targetId); if (targetCreature != null) { cardSubtypes.add((ArrayList) targetCreature.getSubtype()); @@ -172,7 +175,7 @@ public class DevourEffect extends ReplacementEffectImpl { StringBuilder sb = new StringBuilder(devourFactor.toString()); sb.append(" (As this enters the battlefield, you may sacrifice any number of creatures. This creature enters the battlefield with "); sb.append(devourFactor.getRuleText()).append(")"); - return sb.toString(); + return sb.toString(); } public List> getSubtypes(Game game, UUID permanentId) { diff --git a/Mage/src/mage/abilities/effects/common/DiscardOntoBattlefieldEffect.java b/Mage/src/mage/abilities/effects/common/DiscardOntoBattlefieldEffect.java index 137b33c5145..1a82af11cdf 100644 --- a/Mage/src/mage/abilities/effects/common/DiscardOntoBattlefieldEffect.java +++ b/Mage/src/mage/abilities/effects/common/DiscardOntoBattlefieldEffect.java @@ -34,8 +34,8 @@ import mage.constants.Duration; import mage.constants.Outcome; import mage.constants.Zone; import mage.game.Game; -import mage.game.events.GameEvent.EventType; import mage.game.events.GameEvent; +import mage.game.events.GameEvent.EventType; import mage.game.events.ZoneChangeEvent; import mage.game.stack.StackObject; import mage.players.Player; @@ -85,7 +85,7 @@ public class DiscardOntoBattlefieldEffect extends ReplacementEffectImpl { if (card != null) { Player owner = game.getPlayer(card.getOwnerId()); if (owner != null) { - if (owner.putOntoBattlefieldWithInfo(card, game, Zone.HAND, source.getSourceId())) { + if (owner.moveCards(card, Zone.BATTLEFIELD, source, game)) { return true; } } diff --git a/Mage/src/mage/abilities/effects/common/EntersBattlefieldWithXCountersEffect.java b/Mage/src/mage/abilities/effects/common/EntersBattlefieldWithXCountersEffect.java index 7451cd90dbb..9c704852225 100644 --- a/Mage/src/mage/abilities/effects/common/EntersBattlefieldWithXCountersEffect.java +++ b/Mage/src/mage/abilities/effects/common/EntersBattlefieldWithXCountersEffect.java @@ -31,6 +31,7 @@ import mage.abilities.Ability; import mage.abilities.SpellAbility; import mage.abilities.effects.EntersBattlefieldEffect; import mage.abilities.effects.OneShotEffect; +import mage.constants.AbilityType; import mage.constants.Outcome; import mage.counters.Counter; import mage.game.Game; @@ -60,13 +61,15 @@ public class EntersBattlefieldWithXCountersEffect extends OneShotEffect { public boolean apply(Game game, Ability source) { Permanent permanent = game.getPermanent(source.getSourceId()); if (permanent == null) { - permanent = (Permanent) getValue(EntersBattlefieldEffect.ENTERING_PERMANENT); + if (permanent == null && source.getAbilityType().equals(AbilityType.STATIC)) { + permanent = game.getPermanentEntering(source.getSourceId()); + } } if (permanent != null) { SpellAbility spellAbility = (SpellAbility) getValue(EntersBattlefieldEffect.SOURCE_CAST_SPELL_ABILITY); if (spellAbility != null && spellAbility.getSourceId().equals(source.getSourceId()) - && permanent.getZoneChangeCounter(game) - 1 == spellAbility.getSourceObjectZoneChangeCounter()) { + && permanent.getZoneChangeCounter(game) == spellAbility.getSourceObjectZoneChangeCounter()) { if (spellAbility.getSourceId().equals(source.getSourceId())) { // put into play by normal cast int amount = spellAbility.getManaCostsToPay().getX(); if (amount > 0) { diff --git a/Mage/src/mage/abilities/effects/common/ExileAndReturnTransformedSourceEffect.java b/Mage/src/mage/abilities/effects/common/ExileAndReturnTransformedSourceEffect.java index 6e99909a49e..72874fb2fd0 100644 --- a/Mage/src/mage/abilities/effects/common/ExileAndReturnTransformedSourceEffect.java +++ b/Mage/src/mage/abilities/effects/common/ExileAndReturnTransformedSourceEffect.java @@ -66,7 +66,7 @@ public class ExileAndReturnTransformedSourceEffect extends OneShotEffect { Player owner = game.getPlayer(card.getOwnerId()); if (owner != null) { game.getState().setValue(TransformAbility.VALUE_KEY_ENTER_TRANSFORMED + source.getSourceId(), Boolean.TRUE); - owner.putOntoBattlefieldWithInfo(card, game, Zone.EXILED, source.getSourceId()); + owner.moveCards(card, Zone.BATTLEFIELD, source, game); if (additionalEffect != null) { if (additionalEffect instanceof ContinuousEffect) { game.addEffect((ContinuousEffect) additionalEffect, source); diff --git a/Mage/src/mage/abilities/effects/common/LookLibraryAndPickControllerEffect.java b/Mage/src/mage/abilities/effects/common/LookLibraryAndPickControllerEffect.java index 89b065c0306..529760e039b 100644 --- a/Mage/src/mage/abilities/effects/common/LookLibraryAndPickControllerEffect.java +++ b/Mage/src/mage/abilities/effects/common/LookLibraryAndPickControllerEffect.java @@ -29,7 +29,6 @@ */ package mage.abilities.effects.common; -import java.util.UUID; import mage.abilities.Ability; import mage.abilities.Mode; import mage.abilities.dynamicvalue.DynamicValue; @@ -128,28 +127,13 @@ public class LookLibraryAndPickControllerEffect extends LookLibraryControllerEff if (!optional || player.chooseUse(Outcome.DrawCard, getMayText(), source, game)) { FilterCard pickFilter = filter.copy(); pickFilter.setMessage(getPickText()); - TargetCard target = new TargetCard((upTo ? 0 : numberToPick.calculate(game, source, this)), numberToPick.calculate(game, source, this), Zone.PICK, pickFilter); + TargetCard target = new TargetCard((upTo ? 0 : numberToPick.calculate(game, source, this)), numberToPick.calculate(game, source, this), Zone.LIBRARY, pickFilter); if (player.choose(Outcome.DrawCard, cards, target, game)) { - Cards reveal = new CardsImpl(); - for (UUID cardId : target.getTargets()) { - Card card = cards.get(cardId, game); - if (card != null) { - cards.remove(card); - if (targetZoneLookedCards.equals(Zone.BATTLEFIELD)) { - player.putOntoBattlefieldWithInfo(card, game, Zone.LIBRARY, source.getSourceId()); - } else { - card.moveToZone(targetPickedCards, source.getSourceId(), game, false); - if (!game.isSimulation()) { - game.informPlayers(player.getLogName() + " moves a card to " + targetPickedCards.toString().toLowerCase()); - } - } - if (revealPickedCards) { - reveal.add(card); - } - } - } + Cards pickedCards = new CardsImpl(target.getTargets()); + cards.removeAll(pickedCards); + player.moveCards(pickedCards.getCards(game), targetPickedCards, source, game); if (revealPickedCards) { - player.revealCards(windowName, reveal, game); + player.revealCards(windowName, pickedCards, game); } } diff --git a/Mage/src/mage/abilities/effects/common/NameACardEffect.java b/Mage/src/mage/abilities/effects/common/NameACardEffect.java index b75279a993f..1a642fac0f0 100644 --- a/Mage/src/mage/abilities/effects/common/NameACardEffect.java +++ b/Mage/src/mage/abilities/effects/common/NameACardEffect.java @@ -29,7 +29,6 @@ package mage.abilities.effects.common; import mage.MageObject; import mage.abilities.Ability; -import mage.abilities.effects.EntersBattlefieldEffect; import mage.abilities.effects.OneShotEffect; import mage.cards.repository.CardRepository; import mage.choices.Choice; @@ -72,7 +71,7 @@ public class NameACardEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { Player controller = game.getPlayer(source.getControllerId()); - MageObject sourceObject = (Permanent) getValue(EntersBattlefieldEffect.ENTERING_PERMANENT); + MageObject sourceObject = game.getPermanentEntering(source.getSourceId()); if (sourceObject == null) { game.getObject(source.getSourceId()); } diff --git a/Mage/src/mage/abilities/effects/common/PutPermanentOnBattlefieldEffect.java b/Mage/src/mage/abilities/effects/common/PutPermanentOnBattlefieldEffect.java index 12a208ab190..f559340ecce 100644 --- a/Mage/src/mage/abilities/effects/common/PutPermanentOnBattlefieldEffect.java +++ b/Mage/src/mage/abilities/effects/common/PutPermanentOnBattlefieldEffect.java @@ -48,10 +48,9 @@ public class PutPermanentOnBattlefieldEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { Player player; - if(useTargetController) { + if (useTargetController) { player = game.getPlayer(getTargetPointer().getFirst(game, source)); - } - else { + } else { player = game.getPlayer(source.getControllerId()); } String choiceText = "Put " + filter.getMessage() + " from your hand onto the battlefield?"; @@ -63,23 +62,21 @@ public class PutPermanentOnBattlefieldEffect extends OneShotEffect { if (player.choose(Outcome.PutCreatureInPlay, target, source.getSourceId(), game)) { Card card = game.getCard(target.getFirstTarget()); if (card != null) { - player.putOntoBattlefieldWithInfo(card, game, Zone.HAND, source.getSourceId()); - return true; + return player.moveCards(card, Zone.BATTLEFIELD, source, game); } } - return false; + return true; } @Override public String getText(Mode mode) { - if(this.staticText != null && !this.staticText.isEmpty()) { + if (this.staticText != null && !this.staticText.isEmpty()) { return staticText; } - if(useTargetController) { + if (useTargetController) { return "that player may put " + filter.getMessage() + " from his or her hand onto the battlefield"; - } - else { + } else { return "you may put " + filter.getMessage() + " from your hand onto the battlefield"; } } diff --git a/Mage/src/mage/abilities/effects/common/ReturnToBattlefieldUnderYourControlTargetEffect.java b/Mage/src/mage/abilities/effects/common/ReturnToBattlefieldUnderYourControlTargetEffect.java index d386e7d944f..650e1c32cbe 100644 --- a/Mage/src/mage/abilities/effects/common/ReturnToBattlefieldUnderYourControlTargetEffect.java +++ b/Mage/src/mage/abilities/effects/common/ReturnToBattlefieldUnderYourControlTargetEffect.java @@ -88,8 +88,7 @@ public class ReturnToBattlefieldUnderYourControlTargetEffect extends OneShotEffe card = game.getCard(getTargetPointer().getFirst(game, source)); } if (card != null) { - Zone currentZone = game.getState().getZone(card.getId()); - controller.putOntoBattlefieldWithInfo(card, game, currentZone, source.getSourceId()); + controller.moveCards(card, Zone.BATTLEFIELD, source, game); } return true; } diff --git a/Mage/src/mage/abilities/effects/common/TapSourceEffect.java b/Mage/src/mage/abilities/effects/common/TapSourceEffect.java index aa655d15bfe..e510ae4844c 100644 --- a/Mage/src/mage/abilities/effects/common/TapSourceEffect.java +++ b/Mage/src/mage/abilities/effects/common/TapSourceEffect.java @@ -28,7 +28,6 @@ package mage.abilities.effects.common; import mage.abilities.Ability; -import mage.abilities.effects.EntersBattlefieldEffect; import mage.abilities.effects.OneShotEffect; import mage.constants.Outcome; import mage.game.Game; @@ -66,7 +65,7 @@ public class TapSourceEffect extends OneShotEffect { public boolean apply(Game game, Ability source) { Permanent permanent = game.getPermanent(source.getSourceId()); if (permanent == null) { - permanent = (Permanent) getValue(EntersBattlefieldEffect.ENTERING_PERMANENT); + permanent = game.getPermanentEntering(source.getSourceId()); } if (permanent != null) { if (withoutTrigger) { diff --git a/Mage/src/mage/abilities/effects/common/TapSourceUnlessPaysEffect.java b/Mage/src/mage/abilities/effects/common/TapSourceUnlessPaysEffect.java index 0d2e474b159..15fbc93dbff 100644 --- a/Mage/src/mage/abilities/effects/common/TapSourceUnlessPaysEffect.java +++ b/Mage/src/mage/abilities/effects/common/TapSourceUnlessPaysEffect.java @@ -29,8 +29,8 @@ package mage.abilities.effects.common; import mage.abilities.Ability; import mage.abilities.costs.Cost; -import mage.abilities.effects.EntersBattlefieldEffect; import mage.abilities.effects.OneShotEffect; +import mage.constants.AbilityType; import mage.constants.Outcome; import mage.game.Game; import mage.game.permanent.Permanent; @@ -59,8 +59,8 @@ public class TapSourceUnlessPaysEffect extends OneShotEffect { public boolean apply(Game game, Ability source) { Player player = game.getPlayer(source.getControllerId()); Permanent permanent = game.getPermanent(source.getSourceId()); - if (permanent == null) { - permanent = (Permanent) getValue(EntersBattlefieldEffect.ENTERING_PERMANENT); + if (permanent == null && source.getAbilityType().equals(AbilityType.STATIC)) { + permanent = game.getPermanentEntering(source.getSourceId()); } if (player != null && permanent != null) { if (cost.canPay(source, source.getSourceId(), source.getControllerId(), game) diff --git a/Mage/src/mage/abilities/effects/common/continuous/GainAbilitySourceEffect.java b/Mage/src/mage/abilities/effects/common/continuous/GainAbilitySourceEffect.java index 6d37cfc4bad..609ad65d290 100644 --- a/Mage/src/mage/abilities/effects/common/continuous/GainAbilitySourceEffect.java +++ b/Mage/src/mage/abilities/effects/common/continuous/GainAbilitySourceEffect.java @@ -30,7 +30,6 @@ package mage.abilities.effects.common.continuous; import mage.MageObjectReference; import mage.abilities.Ability; import mage.abilities.effects.ContinuousEffectImpl; -import mage.abilities.effects.EntersBattlefieldEffect; import mage.cards.Card; import mage.constants.Duration; import mage.constants.Layer; @@ -94,7 +93,7 @@ public class GainAbilitySourceEffect extends ContinuousEffectImpl implements Sou public void init(Ability source, Game game) { super.init(source, game); if (affectedObjectsSet) { - Permanent permanent = (Permanent) getValue(EntersBattlefieldEffect.ENTERING_PERMANENT); + Permanent permanent = game.getPermanentEntering(source.getSourceId()); if (permanent != null) { affectedObjectList.add(new MageObjectReference(source.getSourceId(), game.getState().getZoneChangeCounter(source.getSourceId()) + 1, game)); } else { diff --git a/Mage/src/mage/abilities/effects/common/counter/AddCountersSourceEffect.java b/Mage/src/mage/abilities/effects/common/counter/AddCountersSourceEffect.java index 0633ff60c63..a39c2b7de8b 100644 --- a/Mage/src/mage/abilities/effects/common/counter/AddCountersSourceEffect.java +++ b/Mage/src/mage/abilities/effects/common/counter/AddCountersSourceEffect.java @@ -30,9 +30,9 @@ package mage.abilities.effects.common.counter; import mage.abilities.Ability; import mage.abilities.dynamicvalue.DynamicValue; import mage.abilities.dynamicvalue.common.StaticValue; -import mage.abilities.effects.EntersBattlefieldEffect; import mage.abilities.effects.OneShotEffect; import mage.cards.Card; +import mage.constants.AbilityType; import mage.constants.Outcome; import mage.counters.Counter; import mage.game.Game; @@ -115,8 +115,8 @@ public class AddCountersSourceEffect extends OneShotEffect { } } else { Permanent permanent = game.getPermanent(source.getSourceId()); - if (permanent == null) { - permanent = (Permanent) getValue(EntersBattlefieldEffect.ENTERING_PERMANENT); + if (permanent == null && source.getAbilityType().equals(AbilityType.STATIC)) { + permanent = game.getPermanentEntering(source.getSourceId()); } if (permanent != null) { if (counter != null) { diff --git a/Mage/src/mage/abilities/keyword/AmplifyAbility.java b/Mage/src/mage/abilities/keyword/AmplifyAbility.java index 22a427c8402..a9cc43d60fc 100644 --- a/Mage/src/mage/abilities/keyword/AmplifyAbility.java +++ b/Mage/src/mage/abilities/keyword/AmplifyAbility.java @@ -39,13 +39,13 @@ import mage.constants.Zone; public class AmplifyAbility extends SimpleStaticAbility { public AmplifyAbility(AmplifyFactor amplifyFactor) { - super(Zone.BATTLEFIELD, new AmplifyEffect(amplifyFactor)); + super(Zone.ALL, new AmplifyEffect(amplifyFactor)); } - + public AmplifyAbility(final AmplifyAbility ability) { super(ability); } - + @Override public AmplifyAbility copy() { return new AmplifyAbility(this); diff --git a/Mage/src/mage/abilities/keyword/AuraSwapAbility.java b/Mage/src/mage/abilities/keyword/AuraSwapAbility.java index ea4ddd1a6aa..385703b6691 100644 --- a/Mage/src/mage/abilities/keyword/AuraSwapAbility.java +++ b/Mage/src/mage/abilities/keyword/AuraSwapAbility.java @@ -104,9 +104,9 @@ class AuraSwapEffect extends OneShotEffect { if (controller.choose(Outcome.PutCardInPlay, target, source.getSourceId(), game)) { Card auraInHand = game.getCard(target.getFirstTarget()); if (auraInHand != null) { - controller.putOntoBattlefieldWithInfo(auraInHand, game, Zone.HAND, source.getSourceId()); + controller.moveCards(auraInHand, Zone.BATTLEFIELD, source, game); enchantedPermanent.addAttachment(auraInHand.getId(), game); - controller.moveCards(auraPermanent, null, Zone.HAND, source, game); + controller.moveCards(auraPermanent, Zone.HAND, source, game); return true; } } diff --git a/Mage/src/mage/abilities/keyword/BloodthirstAbility.java b/Mage/src/mage/abilities/keyword/BloodthirstAbility.java index a7ae3282a18..0b8f4d29c61 100644 --- a/Mage/src/mage/abilities/keyword/BloodthirstAbility.java +++ b/Mage/src/mage/abilities/keyword/BloodthirstAbility.java @@ -2,7 +2,6 @@ package mage.abilities.keyword; import mage.abilities.Ability; import mage.abilities.common.EntersBattlefieldAbility; -import mage.abilities.effects.EntersBattlefieldEffect; import mage.abilities.effects.OneShotEffect; import mage.constants.Outcome; import mage.counters.CounterType; @@ -56,7 +55,7 @@ class BloodthirstEffect extends OneShotEffect { BloodthirstEffect(int amount) { super(Outcome.BoostCreature); this.amount = amount; - staticText = new StringBuilder("this permanent comes into play with ").append(this.amount).append(" +1/+1 counters on it").toString(); + staticText = "this permanent comes into play with " + this.amount + " +1/+1 counters on it"; } BloodthirstEffect(final BloodthirstEffect effect) { @@ -70,10 +69,9 @@ class BloodthirstEffect extends OneShotEffect { if (player != null) { BloodthirstWatcher watcher = (BloodthirstWatcher) game.getState().getWatchers().get("DamagedOpponents", source.getControllerId()); if (watcher != null && watcher.conditionMet()) { - Permanent permanent = (Permanent) getValue(EntersBattlefieldEffect.ENTERING_PERMANENT); + Permanent permanent = game.getPermanentEntering(source.getSourceId()); if (permanent != null) { permanent.addCounters(CounterType.P1P1.createInstance(amount), game); - } } return true; diff --git a/Mage/src/mage/abilities/keyword/DashAbility.java b/Mage/src/mage/abilities/keyword/DashAbility.java index 4a2d96170f0..b6a876053b0 100644 --- a/Mage/src/mage/abilities/keyword/DashAbility.java +++ b/Mage/src/mage/abilities/keyword/DashAbility.java @@ -76,10 +76,10 @@ public class DashAbility extends StaticAbility implements AlternativeSourceCosts this.addDashCost(manaString); Ability ability = new EntersBattlefieldAbility( new GainAbilitySourceEffect(HasteAbility.getInstance(), Duration.Custom, false), - DashedCondition.getInstance(), false, "", ""); + DashedCondition.getInstance(), "", ""); ability.addEffect(new DashAddDelayedTriggeredAbilityEffect()); addSubAbility(ability); - + } public DashAbility(final DashAbility ability) { @@ -226,16 +226,18 @@ class DashAddDelayedTriggeredAbilityEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { - Effect effect = new ReturnToHandTargetEffect(); - effect.setText("return the dashed creature from the battlefield to its owner's hand"); - effect.setTargetPointer(new FixedTarget(source.getSourceId())); - // init target pointer now because the dashed creature will only be returned from current zone - effect.getTargetPointer().init(game, source); - DelayedTriggeredAbility delayedAbility = new AtTheBeginOfNextEndStepDelayedTriggeredAbility(effect); - delayedAbility.setSourceId(source.getSourceId()); - delayedAbility.setControllerId(source.getControllerId()); - delayedAbility.setSourceObject(source.getSourceObject(game), game); - game.addDelayedTriggeredAbility(delayedAbility); + if (game.getPermanentEntering(source.getSourceId()) != null) { + Effect effect = new ReturnToHandTargetEffect(); + effect.setText("return the dashed creature from the battlefield to its owner's hand"); + // init target pointer now because the dashed creature will only be returned from battlefield zone (now in entering state so zone change counter is not raised yet) + effect.setTargetPointer(new FixedTarget(source.getSourceId(), game.getState().getZoneChangeCounter(source.getSourceId()) + 1)); + DelayedTriggeredAbility delayedAbility = new AtTheBeginOfNextEndStepDelayedTriggeredAbility(effect); + 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/src/mage/abilities/keyword/DevourAbility.java b/Mage/src/mage/abilities/keyword/DevourAbility.java index 1d4cdcfa822..ec3148a990a 100644 --- a/Mage/src/mage/abilities/keyword/DevourAbility.java +++ b/Mage/src/mage/abilities/keyword/DevourAbility.java @@ -27,51 +27,51 @@ */ package mage.abilities.keyword; -import mage.constants.Zone; import mage.abilities.common.SimpleStaticAbility; import mage.abilities.effects.common.DevourEffect; import mage.abilities.effects.common.DevourEffect.DevourFactor; +import mage.constants.Zone; /** * 502.82. Devour * - * 502.82a Devour is a static ability. "Devour N" means "As this object comes into play, - * you may sacrifice any number of creatures. This permanent comes into play with N +1/+1 - * counters on it for each creature sacrificed this way." + * 502.82a Devour is a static ability. "Devour N" means "As this object comes + * into play, you may sacrifice any number of creatures. This permanent comes + * into play with N +1/+1 counters on it for each creature sacrificed this way." * - * 502.82b Some objects have abilities that refer to the number of creatures the permanent - * devoured. "It devoured" means "sacrificed as a result of its devour ability as it came - * into play." + * 502.82b Some objects have abilities that refer to the number of creatures the + * permanent devoured. "It devoured" means "sacrificed as a result of its devour + * ability as it came into play." * * Devour appears only on creature cards. * - * A creature with devour can devour other creatures no matter how it comes into play. + * A creature with devour can devour other creatures no matter how it comes into + * play. * * You may choose to not sacrifice any creatures. * - * If you play a creature with devour as a spell, you choose how many and which creatures - * to devour as part of the resolution of that spell. (It can't be countered at this point.) - * The same is true of a spell or ability that lets you put a creature with devour into play. + * If you play a creature with devour as a spell, you choose how many and which + * creatures to devour as part of the resolution of that spell. (It can't be + * countered at this point.) The same is true of a spell or ability that lets + * you put a creature with devour into play. * - * You may sacrifice only creatures that are already in play. If a creature with devour and - * another creature are coming into play under your control at the same time, the creature - * with devour can't devour that other creature. The creature with devour also can't devour - * itself. + * You may sacrifice only creatures that are already in play. If a creature with + * devour and another creature are coming into play under your control at the + * same time, the creature with devour can't devour that other creature. The + * creature with devour also can't devour itself. * - * If multiple creatures with devour are coming into play under your control at the same time, - * you may use each one's devour ability. A creature you already control can be devoured by - * only one of them, however. (In other words, you can't sacrifice the same creature to satisfy - * multiple devour abilities.) All creatures devoured this way are sacrificed at the same time. + * If multiple creatures with devour are coming into play under your control at + * the same time, you may use each one's devour ability. A creature you already + * control can be devoured by only one of them, however. (In other words, you + * can't sacrifice the same creature to satisfy multiple devour abilities.) All + * creatures devoured this way are sacrificed at the same time. * * @author LevelX2 */ +public class DevourAbility extends SimpleStaticAbility { - public class DevourAbility extends SimpleStaticAbility { - - - - public DevourAbility(DevourFactor devourFactor) { - super(Zone.BATTLEFIELD, new DevourEffect(devourFactor)); + public DevourAbility(DevourFactor devourFactor) { + super(Zone.ALL, new DevourEffect(devourFactor)); } public DevourAbility(final DevourAbility ability) { @@ -82,4 +82,4 @@ import mage.abilities.effects.common.DevourEffect.DevourFactor; public DevourAbility copy() { return new DevourAbility(this); } -} \ No newline at end of file +} diff --git a/Mage/src/mage/abilities/keyword/EvolveAbility.java b/Mage/src/mage/abilities/keyword/EvolveAbility.java index 16c1b316e01..00712d973c8 100644 --- a/Mage/src/mage/abilities/keyword/EvolveAbility.java +++ b/Mage/src/mage/abilities/keyword/EvolveAbility.java @@ -25,7 +25,6 @@ * authors and should not be interpreted as representing official policies, either expressed * or implied, of BetaSteward_at_googlemail.com. */ - package mage.abilities.keyword; import mage.abilities.Ability; @@ -44,46 +43,53 @@ import mage.target.targetpointer.FixedTarget; * FAQ 2013/01/11 * * 702.98. Evolve - * - * 702.98a Evolve is a triggered ability. "Evolve" means "Whenever a creature enters - * the battlefield under your control, if that creature's power is greater than this - * creature's power and/or that creature's toughness is greater than this creature's - * toughness, put a +1/+1 counter on this creature." * - * 702.98b If a creature has multiple instances of evolve, each triggers separately - * + * 702.98a Evolve is a triggered ability. "Evolve" means "Whenever a creature + * enters the battlefield under your control, if that creature's power is + * greater than this creature's power and/or that creature's toughness is + * greater than this creature's toughness, put a +1/+1 counter on this + * creature." + * + * 702.98b If a creature has multiple instances of evolve, each triggers + * separately + * * Rulings - * - * When comparing the stats of the two creatures, you always compare power to power and toughness to toughness. - * Whenever a creature enters the battlefield under your control, check its power and toughness against - * the power and toughness of the creature with evolve. If neither stat of the new creature is greater, - * evolve won't trigger at all. For example, if you control a 2/3 creature with evolve and a 2/2 creature - * enters the battlefield under your control, you won't have the opportunity to cast a spell like Giant Growth - * to make the 2/2 creature large enough to cause evolve to trigger. - * If evolve triggers, the stat comparison will happen again when the ability tries to resolve. If - * neither stat of the new creature is greater, the ability will do nothing. If the creature that - * entered the battlefield leaves the battlefield before evolve tries to resolve, use its last known - * power and toughness to compare the stats. - * If a creature enters the battlefield with +1/+1 counters on it, consider those counters when determining - * if evolve will trigger. For example, a 1/1 creature that enters the battlefield with two +1/+1 counters - * on it will cause the evolve ability of a 2/2 creature to trigger. - * If multiple creatures enter the battlefield at the same time, evolve may trigger multiple times, although the stat - * comparison will take place each time one of those abilities tries to resolve. For example, if you control a 2/2 - * creature with evolve and two 3/3 creatures enter the battlefield, evolve will trigger twice. The first ability - * will resolve and put a +1/+1 counter on the creature with evolve. When the second ability tries to resolve, - * neither the power nor the toughness of the new creature is greater than that of the creature with evolve, - * so that ability does nothing. - * When comparing the stats as the evolve ability resolves, it's possible that the stat that's greater changes - * from power to toughness or vice versa. If this happens, the ability will still resolve and you'll put a +1/+1 - * counter on the creature with evolve. For example, if you control a 2/2 creature with evolve and a 1/3 creature - * enters the battlefield under your control, it toughness is greater so evolve will trigger. In response, the 1/3 - * creature gets +2/-2. When the evolve trigger tries to resolve, its power is greater. You'll put a +1/+1 - * counter on the creature with evolve. - * + * + * When comparing the stats of the two creatures, you always compare power to + * power and toughness to toughness. Whenever a creature enters the battlefield + * under your control, check its power and toughness against the power and + * toughness of the creature with evolve. If neither stat of the new creature is + * greater, evolve won't trigger at all. For example, if you control a 2/3 + * creature with evolve and a 2/2 creature enters the battlefield under your + * control, you won't have the opportunity to cast a spell like Giant Growth to + * make the 2/2 creature large enough to cause evolve to trigger. If evolve + * triggers, the stat comparison will happen again when the ability tries to + * resolve. If neither stat of the new creature is greater, the ability will do + * nothing. If the creature that entered the battlefield leaves the battlefield + * before evolve tries to resolve, use its last known power and toughness to + * compare the stats. If a creature enters the battlefield with +1/+1 counters + * on it, consider those counters when determining if evolve will trigger. For + * example, a 1/1 creature that enters the battlefield with two +1/+1 counters + * on it will cause the evolve ability of a 2/2 creature to trigger. If multiple + * creatures enter the battlefield at the same time, evolve may trigger multiple + * times, although the stat comparison will take place each time one of those + * abilities tries to resolve. For example, if you control a 2/2 creature with + * evolve and two 3/3 creatures enter the battlefield, evolve will trigger + * twice. The first ability will resolve and put a +1/+1 counter on the creature + * with evolve. When the second ability tries to resolve, neither the power nor + * the toughness of the new creature is greater than that of the creature with + * evolve, so that ability does nothing. When comparing the stats as the evolve + * ability resolves, it's possible that the stat that's greater changes from + * power to toughness or vice versa. If this happens, the ability will still + * resolve and you'll put a +1/+1 counter on the creature with evolve. For + * example, if you control a 2/2 creature with evolve and a 1/3 creature enters + * the battlefield under your control, it toughness is greater so evolve will + * trigger. In response, the 1/3 creature gets +2/-2. When the evolve trigger + * tries to resolve, its power is greater. You'll put a +1/+1 counter on the + * creature with evolve. + * * @author LevelX2 */ - - public class EvolveAbility extends TriggeredAbilityImpl { public EvolveAbility() { @@ -169,4 +175,3 @@ class EvolveEffect extends OneShotEffect { return false; } } - diff --git a/Mage/src/mage/abilities/keyword/GraftAbility.java b/Mage/src/mage/abilities/keyword/GraftAbility.java index 45eed19b928..14132f4f128 100644 --- a/Mage/src/mage/abilities/keyword/GraftAbility.java +++ b/Mage/src/mage/abilities/keyword/GraftAbility.java @@ -1,30 +1,30 @@ /* -* Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. -* -* Redistribution and use in source and binary forms, with or without modification, are -* permitted provided that the following conditions are met: -* -* 1. Redistributions of source code must retain the above copyright notice, this list of -* conditions and the following disclaimer. -* -* 2. Redistributions in binary form must reproduce the above copyright notice, this list -* of conditions and the following disclaimer in the documentation and/or other materials -* provided with the distribution. -* -* THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED -* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND -* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR -* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR -* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON -* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING -* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF -* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -* -* The views and conclusions contained in the software and documentation are those of the -* authors and should not be interpreted as representing official policies, either expressed -* or implied, of BetaSteward_at_googlemail.com. -*/ + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ package mage.abilities.keyword; import java.util.Locale; @@ -48,18 +48,19 @@ import mage.target.targetpointer.FixedTarget; import mage.util.CardUtil; /** - * 702.56. Graft - * 702.56a. Graft represents both a static ability and a triggered ability. Graft N means, - * "This permanent enters the battlefield with N +1/+1 counters on it" and, "Whenever - * another creature enters the battlefield, if this permanent has a +1/+1 counter on it, - * you may move a +1/+1 counter from this permanent onto that creature." + * 702.56. Graft 702.56a. Graft represents both a static ability and a triggered + * ability. Graft N means, "This permanent enters the battlefield with N +1/+1 + * counters on it" and, "Whenever another creature enters the battlefield, if + * this permanent has a +1/+1 counter on it, you may move a +1/+1 counter from + * this permanent onto that creature." * - * 702.56b. If a creature has multiple instances of graft, each one works separately. + * 702.56b. If a creature has multiple instances of graft, each one works + * separately. * * @author LevelX2 */ - public class GraftAbility extends TriggeredAbilityImpl { + private static final FilterCreaturePermanent filter = new FilterCreaturePermanent(); private int amount; @@ -112,10 +113,10 @@ public class GraftAbility extends TriggeredAbilityImpl { @Override public String getRule() { StringBuilder sb = new StringBuilder("Graft"); - sb.append(" ").append(amount).append(" (This ").append(cardtype).append(" enters the battlefield with ") - .append(amount == 1 ? "a": CardUtil.numberToText(amount)) - .append(" +1/+1 counter on it. Whenever a creature enters the battlefield, you may move a +1/+1 counter from this ") - .append(cardtype).append(" onto it.)"); + sb.append(" ").append(amount).append(" (This ").append(cardtype).append(" enters the battlefield with ") + .append(amount == 1 ? "a" : CardUtil.numberToText(amount)) + .append(" +1/+1 counter on it. Whenever a creature enters the battlefield, you may move a +1/+1 counter from this ") + .append(cardtype).append(" onto it.)"); return sb.toString(); } @@ -126,7 +127,7 @@ class GraftStaticAbility extends StaticAbility { private String ruleText; public GraftStaticAbility(int amount) { - super(Zone.BATTLEFIELD, new EntersBattlefieldEffect(new AddCountersSourceEffect(CounterType.P1P1.createInstance(amount)))); + super(Zone.ALL, new EntersBattlefieldEffect(new AddCountersSourceEffect(CounterType.P1P1.createInstance(amount)))); ruleText = new StringBuilder("This enters the battlefield with ").append(amount).append(" +1/+1 counter on it.").toString(); this.setRuleVisible(false); } @@ -147,7 +148,6 @@ class GraftStaticAbility extends StaticAbility { } } - class GraftDistributeCounterEffect extends OneShotEffect { public GraftDistributeCounterEffect() { diff --git a/Mage/src/mage/abilities/keyword/HideawayAbility.java b/Mage/src/mage/abilities/keyword/HideawayAbility.java index 57ff119d397..b312fc9f3fb 100644 --- a/Mage/src/mage/abilities/keyword/HideawayAbility.java +++ b/Mage/src/mage/abilities/keyword/HideawayAbility.java @@ -65,7 +65,7 @@ import mage.util.CardUtil; public class HideawayAbility extends StaticAbility { public HideawayAbility() { - super(Zone.BATTLEFIELD, new EntersBattlefieldEffect(new TapSourceEffect(true))); + super(Zone.ALL, new EntersBattlefieldEffect(new TapSourceEffect(true))); Ability ability = new EntersBattlefieldTriggeredAbility(new HideawayExileEffect(), false); ability.setRuleVisible(false); addSubAbility(ability); @@ -115,17 +115,17 @@ class HideawayExileEffect extends OneShotEffect { if (hideawaySource == null || controller == null) { return false; } - + Cards cards = new CardsImpl(Zone.LIBRARY); - cards.addAll(controller.getLibrary().getTopCards(game, 4)); + cards.addAll(controller.getLibrary().getTopCards(game, 4)); if (cards.size() > 0) { TargetCard target1 = new TargetCard(Zone.LIBRARY, filter1); if (controller.choose(Outcome.Detriment, cards, target1, game)) { Card card = cards.get(target1.getFirstTarget(), game); if (card != null) { cards.remove(card); - controller.moveCardToExileWithInfo(card, CardUtil.getCardExileZoneId(game, source), - "Hideaway (" + hideawaySource.getIdName() +")", source.getSourceId(), game, Zone.LIBRARY, false); + controller.moveCardToExileWithInfo(card, CardUtil.getCardExileZoneId(game, source), + "Hideaway (" + hideawaySource.getIdName() + ")", source.getSourceId(), game, Zone.LIBRARY, false); card.setFaceDown(true, game); } } @@ -159,7 +159,7 @@ class HideawayLookAtFaceDownCardEffect extends AsThoughEffectImpl { @Override public boolean applies(UUID objectId, Ability source, UUID affectedControllerId, Game game) { - if (game.getState().getZone(objectId) != Zone.EXILED + if (game.getState().getZone(objectId) != Zone.EXILED || !game.getState().getCardState(objectId).isFaceDown()) { return false; } @@ -180,4 +180,3 @@ class HideawayLookAtFaceDownCardEffect extends AsThoughEffectImpl { return false; } } - diff --git a/Mage/src/mage/abilities/keyword/KickerAbility.java b/Mage/src/mage/abilities/keyword/KickerAbility.java index f7bc6c8ff84..138189fc086 100644 --- a/Mage/src/mage/abilities/keyword/KickerAbility.java +++ b/Mage/src/mage/abilities/keyword/KickerAbility.java @@ -203,7 +203,7 @@ public class KickerAbility extends StaticAbility implements OptionalAdditionalSo if (zcc == 0) { zcc = game.getState().getZoneChangeCounter(source.getSourceId()); } - if (zcc > 0 && (source.getAbilityType().equals(AbilityType.TRIGGERED) || source.getAbilityType().equals(AbilityType.STATIC))) { + if (zcc > 0 && (source.getAbilityType().equals(AbilityType.TRIGGERED))) { --zcc; } return String.valueOf(zcc) + ((kickerCosts.size() > 1) ? costText : ""); diff --git a/Mage/src/mage/abilities/keyword/ModularAbility.java b/Mage/src/mage/abilities/keyword/ModularAbility.java index 3d9133f57ec..5efdb7a01a7 100644 --- a/Mage/src/mage/abilities/keyword/ModularAbility.java +++ b/Mage/src/mage/abilities/keyword/ModularAbility.java @@ -108,7 +108,7 @@ class ModularStaticAbility extends StaticAbility { private String ruleText; public ModularStaticAbility(int amount) { - super(Zone.BATTLEFIELD, new EntersBattlefieldEffect(new AddCountersSourceEffect(CounterType.P1P1.createInstance(amount)))); + super(Zone.ALL, new EntersBattlefieldEffect(new AddCountersSourceEffect(CounterType.P1P1.createInstance(amount)))); ruleText = "This enters the battlefield with " + CardUtil.numberToText(amount, "a") + " +1/+1 counter" + (amount != 1 ? "s" : "") + " on it."; this.setRuleVisible(false); } diff --git a/Mage/src/mage/abilities/keyword/SunburstAbility.java b/Mage/src/mage/abilities/keyword/SunburstAbility.java index bc4a9319046..ba1b59adcee 100644 --- a/Mage/src/mage/abilities/keyword/SunburstAbility.java +++ b/Mage/src/mage/abilities/keyword/SunburstAbility.java @@ -31,7 +31,6 @@ import mage.abilities.Ability; import mage.abilities.common.EntersBattlefieldAbility; import mage.abilities.dynamicvalue.DynamicValue; import mage.abilities.dynamicvalue.common.SunburstCount; -import mage.abilities.effects.EntersBattlefieldEffect; import mage.abilities.effects.OneShotEffect; import mage.cards.Card; import mage.constants.CardType; @@ -89,7 +88,7 @@ class SunburstEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { - Permanent permanent = (Permanent) getValue(EntersBattlefieldEffect.ENTERING_PERMANENT); + Permanent permanent = game.getPermanentEntering(source.getSourceId()); if (permanent != null) { Counter counter; if (permanent.getCardType().contains(CardType.CREATURE)) { diff --git a/Mage/src/mage/abilities/keyword/TributeAbility.java b/Mage/src/mage/abilities/keyword/TributeAbility.java index f752865498b..5cf0b1cf8e5 100644 --- a/Mage/src/mage/abilities/keyword/TributeAbility.java +++ b/Mage/src/mage/abilities/keyword/TributeAbility.java @@ -30,7 +30,6 @@ package mage.abilities.keyword; import java.util.UUID; import mage.abilities.Ability; import mage.abilities.common.EntersBattlefieldAbility; -import mage.abilities.effects.EntersBattlefieldEffect; import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.counter.AddCountersSourceEffect; import mage.constants.Outcome; @@ -51,7 +50,7 @@ public class TributeAbility extends EntersBattlefieldAbility { private int tributeValue; public TributeAbility(int tributeValue) { - super(new TributeEffect(tributeValue), false); + super(new TributeEffect(tributeValue)); this.tributeValue = tributeValue; } @@ -98,7 +97,7 @@ class TributeEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { Player controller = game.getPlayer(source.getControllerId()); - Permanent sourcePermanent = (Permanent) getValue(EntersBattlefieldEffect.ENTERING_PERMANENT); + Permanent sourcePermanent = game.getPermanentEntering(source.getSourceId()); if (controller != null && sourcePermanent != null) { UUID opponentId; if (game.getOpponents(controller.getId()).size() == 1) { diff --git a/Mage/src/mage/abilities/keyword/UnleashAbility.java b/Mage/src/mage/abilities/keyword/UnleashAbility.java index 45112f075b2..07cccfe4880 100644 --- a/Mage/src/mage/abilities/keyword/UnleashAbility.java +++ b/Mage/src/mage/abilities/keyword/UnleashAbility.java @@ -26,14 +26,14 @@ * or implied, of BetaSteward_at_googlemail.com. */ package mage.abilities.keyword; - -import mage.constants.Duration; -import mage.constants.Outcome; + import mage.abilities.Ability; import mage.abilities.Mode; import mage.abilities.common.SimpleStaticAbility; import mage.abilities.effects.ReplacementEffectImpl; import mage.abilities.effects.RestrictionEffect; +import mage.constants.Duration; +import mage.constants.Outcome; import mage.constants.Zone; import mage.counters.CounterType; import mage.game.Game; @@ -41,49 +41,41 @@ import mage.game.events.GameEvent; import mage.game.events.GameEvent.EventType; import mage.game.permanent.Permanent; import mage.players.Player; - -/** - * - * @author LevelX2 - */ - // // 702.96. Unleash // -// 702.96a Unleash is a keyword that represents two static abilities. +// 702.96a Unleash is a keyword that represents two static abilities. // "Unleash" means "You may have this permanent enter the battlefield with an additional +1/+1 counter on it" // and "This permanent can’t block as long as it has a +1/+1 counter on it." +public class UnleashAbility extends SimpleStaticAbility { - - public class UnleashAbility extends SimpleStaticAbility { - public UnleashAbility() { super(Zone.ALL, new UnleashReplacementEffect()); this.addEffect(new UnleashRestrictionEffect()); } - + public UnleashAbility(final UnleashAbility ability) { super(ability); } - + @Override public UnleashAbility copy() { return new UnleashAbility(this); } - + @Override public String getRule() { return "Unleash (You may have this creature enter the battlefield with a +1/+1 counter on it. It can't block as long as it has a +1/+1 counter on it.)"; } } - + class UnleashReplacementEffect extends ReplacementEffectImpl { - + public UnleashReplacementEffect() { super(Duration.EndOfGame, Outcome.Detriment); } - + public UnleashReplacementEffect(UnleashReplacementEffect effect) { super(effect); } @@ -95,53 +87,51 @@ class UnleashReplacementEffect extends ReplacementEffectImpl { @Override public boolean applies(GameEvent event, Ability source, Game game) { - if (event.getTargetId().equals(source.getSourceId())) { - return true; - } - return false; + return event.getTargetId().equals(source.getSourceId()); } - + @Override public boolean apply(Game game, Ability source) { return false; } - + @Override public boolean replaceEvent(GameEvent event, Ability source, Game game) { - Permanent creature = game.getPermanent(event.getTargetId()); + Permanent creature = game.getPermanentEntering(source.getSourceId()); Player controller = game.getPlayer(source.getControllerId()); if (creature != null && controller != null) { - if (controller.chooseUse(outcome, "Unleash "+ creature.getName() +"?", source, game)) { - if (!game.isSimulation()) + if (controller.chooseUse(outcome, "Unleash " + creature.getName() + "?", source, game)) { + if (!game.isSimulation()) { game.informPlayers(controller.getLogName() + " unleashes " + creature.getName()); + } creature.addCounters(CounterType.P1P1.createInstance(), game); } } return false; } - + @Override public String getText(Mode mode) { return staticText; } - + @Override public UnleashReplacementEffect copy() { return new UnleashReplacementEffect(this); } - + } - + class UnleashRestrictionEffect extends RestrictionEffect { - + public UnleashRestrictionEffect() { super(Duration.WhileOnBattlefield); } - + public UnleashRestrictionEffect(final UnleashRestrictionEffect effect) { super(effect); } - + @Override public boolean applies(Permanent permanent, Ability source, Game game) { if (permanent != null && permanent.getId().equals(source.getSourceId())) { @@ -151,14 +141,14 @@ class UnleashRestrictionEffect extends RestrictionEffect { } return false; } - + @Override public boolean canBlock(Permanent attacker, Permanent blocker, Ability source, Game game) { return false; } - + @Override public UnleashRestrictionEffect copy() { return new UnleashRestrictionEffect(this); } -} \ No newline at end of file +} diff --git a/Mage/src/mage/cards/CardImpl.java b/Mage/src/mage/cards/CardImpl.java index 2d3fa165cfe..a24fc9323df 100644 --- a/Mage/src/mage/cards/CardImpl.java +++ b/Mage/src/mage/cards/CardImpl.java @@ -512,7 +512,12 @@ public abstract class CardImpl extends MageObjectImpl implements Card { } break; case STACK: - StackObject stackObject = game.getStack().getSpell(getSpellAbility().getId()); + StackObject stackObject; + if (getSpellAbility() != null) { + stackObject = game.getStack().getSpell(getSpellAbility().getId()); + } else { + stackObject = game.getStack().getSpell(this.getId()); + } if (stackObject == null && (this instanceof SplitCard)) { // handle if half of Split cast is on the stack stackObject = game.getStack().getSpell(((SplitCard) this).getLeftHalfCard().getId()); if (stackObject == null) { diff --git a/Mage/src/mage/game/Game.java b/Mage/src/mage/game/Game.java index b75ea6a76e5..432ade1bf80 100644 --- a/Mage/src/mage/game/Game.java +++ b/Mage/src/mage/game/Game.java @@ -115,6 +115,10 @@ public interface Game extends MageItem, Serializable { Permanent getPermanentOrLKIBattlefield(UUID permanentId); + Permanent getPermanentEntering(UUID permanentId); + + Map getPermanentsEntering(); + Map> getLKI(); Card getCard(UUID cardId); diff --git a/Mage/src/mage/game/GameImpl.java b/Mage/src/mage/game/GameImpl.java index f67b6387437..816db0ded7b 100644 --- a/Mage/src/mage/game/GameImpl.java +++ b/Mage/src/mage/game/GameImpl.java @@ -176,6 +176,9 @@ public abstract class GameImpl implements Game, Serializable { // Used to check if an object was moved by the current effect in resolution (so Wrath like effect can be handled correctly) protected Map> shortLivingLKI = new EnumMap<>(Zone.class); + // Permanents entering the Battlefield while handling replacement effects before they are added to the battlefield + protected Map permanentsEntering = new HashMap<>(); + protected GameState state; private transient Stack savedStates = new Stack<>(); protected transient GameStates gameStates = new GameStates(); @@ -244,6 +247,7 @@ public abstract class GameImpl implements Game, Serializable { this.lki.putAll(game.lki); this.lkiExtended.putAll(game.lkiExtended); this.shortLivingLKI.putAll(game.shortLivingLKI); + this.permanentsEntering.putAll(game.permanentsEntering); if (logger.isDebugEnabled()) { copyCount++; copyTime += (System.currentTimeMillis() - t1); @@ -501,6 +505,16 @@ public abstract class GameImpl implements Game, Serializable { return permanent; } + @Override + public Permanent getPermanentEntering(UUID permanentId) { + return permanentsEntering.get(permanentId); + } + + @Override + public Map getPermanentsEntering() { + return permanentsEntering; + } + @Override public Card getCard(UUID cardId) { if (cardId == null) { @@ -891,7 +905,7 @@ public abstract class GameImpl implements Game, Serializable { return; } getState().setChoosingPlayerId(choosingPlayerId); // needed to start/stop the timer if active - if (choosingPlayer != null && choosingPlayer.choose(Outcome.Benefit, targetPlayer, null, this)) { + if (choosingPlayer.choose(Outcome.Benefit, targetPlayer, null, this)) { startingPlayerId = targetPlayer.getTargets().get(0); } else if (getState().getPlayers().size() < 3) { // not possible to choose starting player, choosing player has probably conceded, so stop here @@ -2539,8 +2553,10 @@ public abstract class GameImpl implements Game, Serializable { card.setZone(Zone.BATTLEFIELD, this); card.setOwnerId(ownerId); PermanentCard permanent = new PermanentCard(card.getCard(), ownerId, this); - getBattlefield().addPermanent(permanent); + getPermanentsEntering().put(permanent.getId(), permanent); permanent.entersBattlefield(permanent.getId(), this, Zone.OUTSIDE, false); + getBattlefield().addPermanent(permanent); + getPermanentsEntering().remove(permanent.getId()); ((PermanentImpl) permanent).removeSummoningSickness(); if (card.isTapped()) { permanent.setTapped(true); diff --git a/Mage/src/mage/game/permanent/PermanentImpl.java b/Mage/src/mage/game/permanent/PermanentImpl.java index 783801dc7f2..3b767772abc 100644 --- a/Mage/src/mage/game/permanent/PermanentImpl.java +++ b/Mage/src/mage/game/permanent/PermanentImpl.java @@ -647,6 +647,9 @@ public abstract class PermanentImpl extends CardImpl implements Permanent { if (!game.replaceEvent(new GameEvent(GameEvent.EventType.ATTACH, objectId, permanentId, controllerId))) { this.attachments.add(permanentId); Permanent attachment = game.getPermanent(permanentId); + if (attachment == null) { + attachment = game.getPermanentEntering(permanentId); + } if (attachment != null) { attachment.attachTo(objectId, game); game.fireEvent(new GameEvent(GameEvent.EventType.ATTACHED, objectId, permanentId, controllerId)); diff --git a/Mage/src/mage/game/permanent/token/Token.java b/Mage/src/mage/game/permanent/token/Token.java index e60605b0892..5f9686cf8a9 100644 --- a/Mage/src/mage/game/permanent/token/Token.java +++ b/Mage/src/mage/game/permanent/token/Token.java @@ -42,6 +42,7 @@ import mage.game.Game; import mage.game.events.GameEvent; import mage.game.events.GameEvent.EventType; import mage.game.events.ZoneChangeEvent; +import mage.game.permanent.Permanent; import mage.game.permanent.PermanentToken; import mage.players.Player; @@ -148,31 +149,43 @@ public class Token extends MageObjectImpl { GameEvent event = new GameEvent(EventType.CREATE_TOKEN, null, sourceId, controllerId, amount, this.getCardType().contains(CardType.CREATURE)); if (!game.replaceEvent(event)) { amount = event.getAmount(); + + List permanents = new ArrayList<>(); + List permanentsEntered = new ArrayList<>(); + for (int i = 0; i < amount; i++) { PermanentToken newToken = new PermanentToken(this, event.getPlayerId(), setCode, game); // use event.getPlayerId() because it can be replaced by replacement effect game.getState().addCard(newToken); - game.addPermanent(newToken); - if (tapped) { - newToken.setTapped(true); - } - this.lastAddedTokenIds.add(newToken.getId()); - this.lastAddedTokenId = newToken.getId(); - game.setScopeRelevant(true); - game.applyEffects(); - boolean entered = newToken.entersBattlefield(sourceId, game, Zone.OUTSIDE, true); - game.setScopeRelevant(false); - game.applyEffects(); - if (entered) { - game.fireEvent(new ZoneChangeEvent(newToken, event.getPlayerId(), Zone.OUTSIDE, Zone.BATTLEFIELD)); - if (attacking && game.getCombat() != null) { - game.getCombat().addAttackingCreature(newToken.getId(), game); - } - if (!game.isSimulation()) { - game.informPlayers(controller.getLogName() + " puts a " + newToken.getLogName() + " token onto the battlefield"); - } + permanents.add(newToken); + game.getPermanentsEntering().put(newToken.getId(), newToken); + newToken.setTapped(tapped); + } + game.setScopeRelevant(true); + for (Permanent permanent : permanents) { + if (permanent.entersBattlefield(sourceId, game, Zone.OUTSIDE, true)) { + permanentsEntered.add(permanent); + } else { + game.getPermanentsEntering().remove(permanent.getId()); } } + game.setScopeRelevant(false); + for (Permanent permanent : permanentsEntered) { + game.addPermanent(permanent); + permanent.setZone(Zone.BATTLEFIELD, game); + game.getPermanentsEntering().remove(permanent.getId()); + this.lastAddedTokenIds.add(permanent.getId()); + this.lastAddedTokenId = permanent.getId(); + game.addSimultaneousEvent(new ZoneChangeEvent(permanent, permanent.getControllerId(), Zone.OUTSIDE, Zone.BATTLEFIELD)); + if (attacking && game.getCombat() != null) { + game.getCombat().addAttackingCreature(permanent.getId(), game); + } + if (!game.isSimulation()) { + game.informPlayers(controller.getLogName() + " puts a " + permanent.getLogName() + " token onto the battlefield"); + } + + } + game.applyEffects(); return true; } return false; diff --git a/Mage/src/mage/game/stack/Spell.java b/Mage/src/mage/game/stack/Spell.java index 482bfb8451e..83b99d90d46 100644 --- a/Mage/src/mage/game/stack/Spell.java +++ b/Mage/src/mage/game/stack/Spell.java @@ -232,7 +232,7 @@ public class Spell extends StackObjImpl implements Card { card.getCardType().remove(CardType.CREATURE); card.getSubtype().add("Aura"); } - if (card.putOntoBattlefield(game, Zone.STACK, ability.getSourceId(), controllerId)) { + if (controller.moveCards(card, Zone.BATTLEFIELD, ability, game, false, faceDown, false, null)) { if (bestow) { // card will be copied during putOntoBattlefield, so the card of CardPermanent has to be changed // TODO: Find a better way to prevent bestow creatures from being effected by creature affecting abilities @@ -253,8 +253,7 @@ public class Spell extends StackObjImpl implements Card { // Aura has no legal target and its a bestow enchantment -> Add it to battlefield as creature if (this.getSpellAbility() instanceof BestowAbility) { updateOptionalCosts(0); - result = card.putOntoBattlefield(game, Zone.STACK, ability.getSourceId(), controllerId); - return result; + return controller.moveCards(card, Zone.BATTLEFIELD, ability, game, false, faceDown, false, null); } else { //20091005 - 608.2b if (!game.isSimulation()) { @@ -265,9 +264,7 @@ public class Spell extends StackObjImpl implements Card { } } else { updateOptionalCosts(0); -// return controller.moveCards(card, Zone.BATTLEFIELD, ability, game, false, faceDown, false, null); - result = card.putOntoBattlefield(game, Zone.STACK, ability.getSourceId(), controllerId, false, faceDown); - return result; + return controller.moveCards(card, Zone.BATTLEFIELD, ability, game, false, faceDown, false, null); } } diff --git a/Mage/src/mage/players/Player.java b/Mage/src/mage/players/Player.java index b484fb8ccf9..60edef58aba 100644 --- a/Mage/src/mage/players/Player.java +++ b/Mage/src/mage/players/Player.java @@ -629,15 +629,26 @@ public interface Player extends MageItem, Copyable { * @param game * @return */ + @Deprecated boolean moveCards(Cards cards, Zone fromZone, Zone toZone, Ability source, Game game); + @Deprecated boolean moveCards(Card card, Zone fromZone, Zone toZone, Ability source, Game game); + @Deprecated boolean moveCards(Set cards, Zone fromZone, Zone toZone, Ability source, Game game); + boolean moveCards(Card card, Zone toZone, Ability source, Game game); + boolean moveCards(Card card, Zone toZone, Ability source, Game game, boolean tapped, boolean faceDown, boolean byOwner, ArrayList appliedEffects); + boolean moveCards(Cards cards, Zone toZone, Ability source, Game game); + + boolean moveCards(Set cards, Zone toZone, Ability source, Game game); + /** + * Iniversal method to move cards from one zone to another. Do not mix + * objects from different from zones to move. * * @param cards * @param toZone @@ -740,6 +751,7 @@ public interface Player extends MageItem, Copyable { * @param sourceId * @return */ + @Deprecated boolean putOntoBattlefieldWithInfo(Card card, Game game, Zone fromZone, UUID sourceId); /** diff --git a/Mage/src/mage/players/PlayerImpl.java b/Mage/src/mage/players/PlayerImpl.java index 011d716acd2..2330bd54541 100644 --- a/Mage/src/mage/players/PlayerImpl.java +++ b/Mage/src/mage/players/PlayerImpl.java @@ -773,6 +773,9 @@ public abstract class PlayerImpl implements Player, Serializable { public boolean addAttachment(UUID permanentId, Game game) { if (!this.attachments.contains(permanentId)) { Permanent aura = game.getPermanent(permanentId); + if (aura == null) { + aura = game.getPermanentEntering(permanentId); + } if (aura != null) { if (!game.replaceEvent(new GameEvent(GameEvent.EventType.ENCHANT_PLAYER, playerId, permanentId, aura.getControllerId()))) { this.attachments.add(permanentId); @@ -1016,8 +1019,7 @@ public abstract class PlayerImpl implements Player, Serializable { //20091005 - 305.1 if (!game.replaceEvent(GameEvent.getEvent(GameEvent.EventType.PLAY_LAND, card.getId(), card.getId(), playerId))) { // int bookmark = game.bookmarkState(); - Zone zone = game.getState().getZone(card.getId()); - if (card.putOntoBattlefield(game, zone, null, playerId)) { + if (moveCards(card, Zone.BATTLEFIELD, playLandAbility, game, false, false, false, null)) { landsPlayed++; game.fireEvent(GameEvent.getEvent(GameEvent.EventType.LAND_PLAYED, card.getId(), card.getId(), playerId)); game.fireInformEvent(getLogName() + " plays " + card.getLogName()); @@ -2980,40 +2982,12 @@ public abstract class PlayerImpl implements Player, Serializable { @Override public boolean moveCards(Set cards, Zone fromZone, Zone toZone, Ability source, Game game) { - if (cards.isEmpty()) { - return true; - } - Set successfulMovedCards = new LinkedHashSet<>(); - switch (toZone) { - case EXILED: - for (Card card : cards) { - fromZone = game.getState().getZone(card.getId()); - boolean withName = (fromZone.equals(Zone.BATTLEFIELD) || fromZone.equals(Zone.STACK)) || !card.isFaceDown(game); - if (moveCardToExileWithInfo(card, null, "", source == null ? null : source.getSourceId(), game, fromZone, withName)) { - successfulMovedCards.add(card); - } - } - break; - case GRAVEYARD: - successfulMovedCards = moveCardsToGraveyardWithInfo(cards, source, game, fromZone); - break; - case HAND: - case BATTLEFIELD: - return moveCards(cards, toZone, source, game, false, false, false, null); - case LIBRARY: - for (Card card : cards) { - fromZone = game.getState().getZone(card.getId()); - boolean hideCard = fromZone.equals(Zone.HAND) || fromZone.equals(Zone.LIBRARY); - if (moveCardToLibraryWithInfo(card, source == null ? null : source.getSourceId(), game, fromZone, true, !hideCard)) { - successfulMovedCards.add(card); - } - } - break; - default: - throw new UnsupportedOperationException("to Zone not supported yet"); - } - game.fireEvent(new ZoneChangeGroupEvent(successfulMovedCards, source == null ? null : source.getSourceId(), this.getId(), fromZone, toZone)); - return successfulMovedCards.size() > 0; + return moveCards(cards, toZone, source, game, false, false, false, null); + } + + @Override + public boolean moveCards(Card card, Zone toZone, Ability source, Game game) { + return moveCards(card, toZone, source, game, false, false, false, null); } @Override @@ -3025,6 +2999,16 @@ public abstract class PlayerImpl implements Player, Serializable { return moveCards(cardList, toZone, source, game, tapped, faceDown, byOwner, appliedEffects); } + @Override + public boolean moveCards(Cards cards, Zone toZone, Ability source, Game game) { + return moveCards(cards.getCards(game), toZone, source, game); + } + + @Override + public boolean moveCards(Set cards, Zone toZone, Ability source, Game game) { + return moveCards(cards, toZone, source, game, false, false, false, null); + } + @Override public boolean moveCards(Set cards, Zone toZone, Ability source, Game game, boolean tapped, boolean faceDown, boolean byOwner, ArrayList appliedEffects) { if (cards.isEmpty()) { @@ -3033,7 +3017,11 @@ public abstract class PlayerImpl implements Player, Serializable { Set successfulMovedCards = new LinkedHashSet<>(); Zone fromZone = null; switch (toZone) { - case BATTLEFIELD: + case GRAVEYARD: + fromZone = game.getState().getZone(cards.iterator().next().getId()); + successfulMovedCards = moveCardsToGraveyardWithInfo(cards, source, game, fromZone); + break; + case BATTLEFIELD: // new logic that does not yet add the permanents to battlefield while replacement effects are handled List permanents = new ArrayList<>(); List permanentsEntered = new ArrayList<>(); for (Card card : cards) { @@ -3047,6 +3035,7 @@ public abstract class PlayerImpl implements Player, Serializable { // get permanent Permanent permanent = new PermanentCard(card, event.getPlayerId(), game);// controlling player can be replaced so use event player now permanents.add(permanent); + game.getPermanentsEntering().put(permanent.getId(), permanent); card.checkForCountersToAdd(permanent, game); permanent.setTapped(tapped); permanent.setFaceDown(faceDown, game); @@ -3060,6 +3049,8 @@ public abstract class PlayerImpl implements Player, Serializable { fromZone = game.getState().getZone(permanent.getId()); if (permanent.entersBattlefield(source.getSourceId(), game, fromZone, true)) { permanentsEntered.add(permanent); + } else { + game.getPermanentsEntering().remove(permanent.getId()); } } game.setScopeRelevant(false); @@ -3071,11 +3062,16 @@ public abstract class PlayerImpl implements Player, Serializable { game.getContinuousEffects().setController(permanent.getId(), permanent.getControllerId()); game.addPermanent(permanent); permanent.setZone(Zone.BATTLEFIELD, game); - // check if there are counters to add to the permanent (e.g. from non replacement effects like Persist) - + game.getPermanentsEntering().remove(permanent.getId()); game.setScopeRelevant(true); successfulMovedCards.add(permanent); game.addSimultaneousEvent(new ZoneChangeEvent(permanent, permanent.getControllerId(), fromZone, Zone.BATTLEFIELD)); + if (!game.isSimulation()) { + game.informPlayers(this.getLogName() + " puts " + (faceDown ? "a card face down " : permanent.getLogName()) + + " from " + fromZone.toString().toLowerCase(Locale.ENGLISH) + " onto the Battlefield"); + } + } else { + game.getPermanentsEntering().remove(permanent.getId()); } } game.applyEffects(); @@ -3090,8 +3086,26 @@ public abstract class PlayerImpl implements Player, Serializable { } } break; + case EXILED: + for (Card card : cards) { + fromZone = game.getState().getZone(card.getId()); + boolean withName = (fromZone.equals(Zone.BATTLEFIELD) || fromZone.equals(Zone.STACK)) || !card.isFaceDown(game); + if (moveCardToExileWithInfo(card, null, "", source == null ? null : source.getSourceId(), game, fromZone, withName)) { + successfulMovedCards.add(card); + } + } + break; + case LIBRARY: + for (Card card : cards) { + fromZone = game.getState().getZone(card.getId()); + boolean hideCard = fromZone.equals(Zone.HAND) || fromZone.equals(Zone.LIBRARY); + if (moveCardToLibraryWithInfo(card, source == null ? null : source.getSourceId(), game, fromZone, true, !hideCard)) { + successfulMovedCards.add(card); + } + } + break; default: - throw new UnsupportedOperationException("to Zone not supported yet"); + throw new UnsupportedOperationException("to Zone" + toZone.toString() + " not supported yet"); } game.fireEvent(new ZoneChangeGroupEvent(successfulMovedCards, source == null ? null : source.getSourceId(), this.getId(), fromZone, toZone)); @@ -3293,16 +3307,19 @@ public abstract class PlayerImpl implements Player, Serializable { return result; } + @Deprecated @Override public boolean putOntoBattlefieldWithInfo(Card card, Game game, Zone fromZone, UUID sourceId) { return this.putOntoBattlefieldWithInfo(card, game, fromZone, sourceId, false, false); } + @Deprecated @Override public boolean putOntoBattlefieldWithInfo(Card card, Game game, Zone fromZone, UUID sourceId, boolean tapped) { return this.putOntoBattlefieldWithInfo(card, game, fromZone, sourceId, tapped, false); } + @Deprecated @Override public boolean putOntoBattlefieldWithInfo(Card card, Game game, Zone fromZone, UUID sourceId, boolean tapped, boolean facedown) { boolean result = false; diff --git a/Mage/src/mage/util/functions/AddSubtypeApplier.java b/Mage/src/mage/util/functions/AddSubtypeApplier.java new file mode 100644 index 00000000000..a007b6a9f31 --- /dev/null +++ b/Mage/src/mage/util/functions/AddSubtypeApplier.java @@ -0,0 +1,40 @@ +/* + * To change this license header, choose License Headers in Project Properties. + * To change this template file, choose Tools | Templates + * and open the template in the editor. + */ +package mage.util.functions; + +import mage.MageObject; +import mage.game.Game; +import mage.game.permanent.Permanent; + +/** + * + * @author LevelX2 + */ +public class AddSubtypeApplier extends ApplyToPermanent { + + private final String subtype; + + public AddSubtypeApplier(String subtype) { + this.subtype = subtype; + } + + @Override + public Boolean apply(Game game, Permanent permanent) { + if (!permanent.getSubtype().contains(subtype)) { + permanent.getSubtype().add(subtype); + } + return true; + } + + @Override + public Boolean apply(Game game, MageObject mageObject) { + if (!mageObject.getSubtype().contains(subtype)) { + mageObject.getSubtype().add(subtype); + } + return true; + } + +} diff --git a/Mage/src/mage/util/functions/CardTypeApplier.java b/Mage/src/mage/util/functions/CardTypeApplier.java index dcb8eeb8c33..48a3eb54130 100644 --- a/Mage/src/mage/util/functions/CardTypeApplier.java +++ b/Mage/src/mage/util/functions/CardTypeApplier.java @@ -27,10 +27,36 @@ */ package mage.util.functions; +import mage.MageObject; +import mage.constants.CardType; +import mage.game.Game; +import mage.game.permanent.Permanent; + /** * * @author LevelX2 */ -public class CardTypeApplier { +public class CardTypeApplier extends ApplyToPermanent { + private final CardType cardType; + + public CardTypeApplier(CardType cardType) { + this.cardType = cardType; + } + + @Override + public Boolean apply(Game game, Permanent permanent) { + if (!permanent.getCardType().contains(cardType)) { + permanent.getCardType().add(cardType); + } + return true; + } + + @Override + public Boolean apply(Game game, MageObject mageObject) { + if (!mageObject.getCardType().contains(cardType)) { + mageObject.getCardType().add(cardType); + } + return true; + } } From 3f771feb522298a498925b98cab367abb51d2059 Mon Sep 17 00:00:00 2001 From: LevelX2 Date: Sat, 17 Oct 2015 16:45:44 +0200 Subject: [PATCH 168/268] Some minor changes. --- Mage.Sets/src/mage/sets/coldsnap/BraidOfFire.java | 10 +++------- .../src/mage/sets/darksteel/SurestrikeTrident.java | 13 ++++++------- 2 files changed, 9 insertions(+), 14 deletions(-) diff --git a/Mage.Sets/src/mage/sets/coldsnap/BraidOfFire.java b/Mage.Sets/src/mage/sets/coldsnap/BraidOfFire.java index 7cb6a494524..e08dc4e32f9 100644 --- a/Mage.Sets/src/mage/sets/coldsnap/BraidOfFire.java +++ b/Mage.Sets/src/mage/sets/coldsnap/BraidOfFire.java @@ -82,16 +82,12 @@ class BraidOfFireCost extends CostImpl { @Override public boolean canPay(Ability ability, UUID sourceId, UUID controllerId, Game game) { - Player player = game.getPlayer(controllerId); - if (player != null) { - return true; - } - return false; + return game.getPlayer(controllerId) != null; } - + @Override public BraidOfFireCost copy() { return new BraidOfFireCost(this); } -} \ No newline at end of file +} diff --git a/Mage.Sets/src/mage/sets/darksteel/SurestrikeTrident.java b/Mage.Sets/src/mage/sets/darksteel/SurestrikeTrident.java index 4640efecad6..b3606a11a03 100644 --- a/Mage.Sets/src/mage/sets/darksteel/SurestrikeTrident.java +++ b/Mage.Sets/src/mage/sets/darksteel/SurestrikeTrident.java @@ -36,18 +36,17 @@ import mage.abilities.costs.common.TapSourceCost; import mage.abilities.costs.mana.GenericManaCost; import mage.abilities.dynamicvalue.DynamicValue; import mage.abilities.dynamicvalue.common.SourcePermanentPowerCount; +import mage.abilities.effects.Effect; +import mage.abilities.effects.common.DamageTargetEffect; import mage.abilities.effects.common.continuous.GainAbilityAttachedEffect; import mage.abilities.keyword.EquipAbility; import mage.abilities.keyword.FirstStrikeAbility; 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.Zone; -import mage.abilities.effects.Effect; -import mage.abilities.effects.common.DamageTargetEffect; import mage.game.Game; import mage.game.permanent.Permanent; import mage.target.TargetPlayer; @@ -63,7 +62,7 @@ public class SurestrikeTrident extends CardImpl { this.expansionSetCode = "DST"; this.subtype.add("Equipment"); - // Equipped creature has first strike and "{tap}, Unattach Surestrike Trident: This creature deals damage equal to its power to target player." + // Equipped creature has first strike and "{T}, Unattach Surestrike Trident: This creature deals damage equal to its power to target player." Ability ability = new SimpleStaticAbility(Zone.BATTLEFIELD, new GainAbilityAttachedEffect(FirstStrikeAbility.getInstance(), AttachmentType.EQUIPMENT)); DynamicValue xValue = new SourcePermanentPowerCount(); Effect effect = new DamageTargetEffect(xValue); @@ -75,7 +74,7 @@ public class SurestrikeTrident extends CardImpl { effect.setText("and \"{T}, Unattach {this}: This creature deals damage equal to its power to target player.\""); ability.addEffect(effect); this.addAbility(ability); - + // Equip {4} this.addAbility(new EquipAbility(Outcome.Benefit, new GenericManaCost(4))); } @@ -117,7 +116,7 @@ class SurestrikeTridentUnattachCost extends CostImpl { } } } - + } return paid; } @@ -142,4 +141,4 @@ class SurestrikeTridentUnattachCost extends CostImpl { return new SurestrikeTridentUnattachCost(this); } -} \ No newline at end of file +} From d145885d2d20ca8a617b0a65f5723073e76a8d9f Mon Sep 17 00:00:00 2001 From: LevelX2 Date: Sun, 18 Oct 2015 10:21:12 +0200 Subject: [PATCH 169/268] * Sylvan Library - Fixed that a player that controlled a Sylvan Library from another player was not forced to play life for cards he kept from Sylvan Library's triggered ability (fixes #1307). --- .../mage/sets/fifthedition/SylvanLibrary.java | 37 ++++++----- .../ExileAndReturnUnderYourControl.java | 62 ++++++++++++++++--- 2 files changed, 73 insertions(+), 26 deletions(-) diff --git a/Mage.Sets/src/mage/sets/fifthedition/SylvanLibrary.java b/Mage.Sets/src/mage/sets/fifthedition/SylvanLibrary.java index afa1cd28900..d20b20c4158 100644 --- a/Mage.Sets/src/mage/sets/fifthedition/SylvanLibrary.java +++ b/Mage.Sets/src/mage/sets/fifthedition/SylvanLibrary.java @@ -27,7 +27,9 @@ */ package mage.sets.fifthedition; -import java.util.HashSet; +import java.util.HashMap; +import java.util.LinkedHashSet; +import java.util.Map; import java.util.Set; import java.util.UUID; import mage.MageObject; @@ -64,7 +66,8 @@ public class SylvanLibrary extends CardImpl { this.expansionSetCode = "5ED"; // At the beginning of your draw step, you may draw two additional cards. If you do, choose two cards in your hand drawn this turn. For each of those cards, pay 4 life or put the card on top of your library. - this.addAbility(new BeginningOfDrawTriggeredAbility(new SylvanLibraryEffect(), TargetController.YOU, true), new CardsDrawnThisTurnWatcher()); + this.addAbility(new BeginningOfDrawTriggeredAbility(new SylvanLibraryEffect(), TargetController.YOU, true), + new CardsDrawnThisTurnWatcher()); } @@ -99,11 +102,11 @@ class SylvanLibraryEffect extends OneShotEffect { Player controller = game.getPlayer(source.getControllerId()); if (controller != null) { controller.drawCards(2, game); - CardsDrawnThisTurnWatcher watcher = (CardsDrawnThisTurnWatcher) game.getState().getWatchers().get("CardsDrawnThisTurnWatcher", source.getControllerId()); + CardsDrawnThisTurnWatcher watcher = (CardsDrawnThisTurnWatcher) game.getState().getWatchers().get("CardsDrawnThisTurnWatcher"); if (watcher != null) { Cards cards = new CardsImpl(); for (UUID cardId : controller.getHand()) { - if (watcher.getCardsDrawnThisTurn().contains(cardId)) { + if (watcher.getCardsDrawnThisTurn(controller.getId()).contains(cardId)) { Card card = game.getCard(cardId); if (card != null) { cards.add(card); @@ -161,26 +164,31 @@ class SylvanLibraryEffect extends OneShotEffect { class CardsDrawnThisTurnWatcher extends Watcher { - private final Set cardsDrawnThisTurn = new HashSet(); + private final Map> cardsDrawnThisTurn = new HashMap<>(); public CardsDrawnThisTurnWatcher() { - super("CardsDrawnThisTurnWatcher", WatcherScope.PLAYER); + super("CardsDrawnThisTurnWatcher", WatcherScope.GAME); } public CardsDrawnThisTurnWatcher(final CardsDrawnThisTurnWatcher watcher) { super(watcher); - this.cardsDrawnThisTurn.addAll(watcher.cardsDrawnThisTurn); + this.cardsDrawnThisTurn.putAll(watcher.cardsDrawnThisTurn); } @Override public void watch(GameEvent event, Game game) { - if (event.getType() == GameEvent.EventType.DREW_CARD && event.getPlayerId().equals(this.getControllerId())) { - cardsDrawnThisTurn.add(event.getTargetId()); + if (event.getType() == GameEvent.EventType.DREW_CARD) { + if (!cardsDrawnThisTurn.containsKey(event.getPlayerId())) { + Set cardsDrawn = new LinkedHashSet<>(); + cardsDrawnThisTurn.put(event.getPlayerId(), cardsDrawn); + } + Set cardsDrawn = cardsDrawnThisTurn.get(event.getPlayerId()); + cardsDrawn.add(event.getTargetId()); } } - public Set getCardsDrawnThisTurn() { - return cardsDrawnThisTurn; + public Set getCardsDrawnThisTurn(UUID playerId) { + return cardsDrawnThisTurn.get(playerId); } @Override @@ -195,7 +203,6 @@ class CardsDrawnThisTurnWatcher extends Watcher { } } - class CardIdPredicate implements Predicate { private final Cards cardsId; @@ -206,10 +213,8 @@ class CardIdPredicate implements Predicate { @Override public boolean apply(MageObject input, Game game) { - for(UUID uuid : cardsId) - { - if(uuid.equals(input.getId())) - { + for (UUID uuid : cardsId) { + if (uuid.equals(input.getId())) { return true; } } diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/control/ExileAndReturnUnderYourControl.java b/Mage.Tests/src/test/java/org/mage/test/cards/control/ExileAndReturnUnderYourControl.java index 5f1c950fb75..13f434621e6 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/control/ExileAndReturnUnderYourControl.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/control/ExileAndReturnUnderYourControl.java @@ -7,11 +7,12 @@ import org.junit.Test; import org.mage.test.serverside.base.CardTestPlayerBase; /** - * Tests the effect: - * - Exile target creature you control, then return that card to the battlefield under your control + * Tests the effect: - Exile target creature you control, then return that card + * to the battlefield under your control * - * This effect grants you permanent control over the returned creature. - * So you mail steal opponent's creature with "Act of Treason" and then use this effect for permanent control effect. + * This effect grants you permanent control over the returned creature. So you + * mail steal opponent's creature with "Act of Treason" and then use this effect + * for permanent control effect. * * @author noxx */ @@ -67,7 +68,7 @@ public class ExileAndReturnUnderYourControl extends CardTestPlayerBase { Assert.assertTrue("player A should play with top card revealed", playerA.isTopCardRevealed()); Assert.assertFalse("player B should play NOT with top card revealed", playerB.isTopCardRevealed()); } - + @Test public void testVillainousWealthExilesBoost() { // Villainous Wealth {X}{B}{G}{U} @@ -76,14 +77,14 @@ public class ExileAndReturnUnderYourControl extends CardTestPlayerBase { // their mana costs. addCard(Zone.HAND, playerA, "Villainous Wealth"); addCard(Zone.HAND, playerA, "Master of Pearls"); - + addCard(Zone.BATTLEFIELD, playerA, "Swamp", 4); addCard(Zone.BATTLEFIELD, playerA, "Forest", 4); addCard(Zone.BATTLEFIELD, playerA, "Island", 4); // Secret Plans {G}{U} // Face-down creatures you control get +0/+1. - // Whenever a permanent you control is turned face up, draw a card. + // Whenever a permanent you control is turned face up, draw a card. addCard(Zone.LIBRARY, playerB, "Secret Plans"); skipInitShuffling(); // to keep this card on top of library @@ -101,9 +102,50 @@ public class ExileAndReturnUnderYourControl extends CardTestPlayerBase { assertExileCount(playerB, 2); assertExileCount("Secret Plans", 0); assertPermanentCount(playerA, "Secret Plans", 1); - + assertPermanentCount(playerA, "", 1); - assertPowerToughness(playerA, "", 2, 3); - } + assertPowerToughness(playerA, "", 2, 3); + } + + /** + * My opponent cast Villainous Wealth and took control of my Sylvan Library. + * On his next turn, when Sylvan Library's trigger resolved, he kept the two + * extra cards without paying life. + */ + @Test + public void testVillainousWealthExilesSylvanLibrary() { + // Villainous Wealth {X}{B}{G}{U} + // Target opponent exiles the top X cards of his or her library. You may cast any number + // of nonland cards with converted mana cost X or less from among them without paying + // their mana costs. + addCard(Zone.HAND, playerA, "Villainous Wealth"); + addCard(Zone.BATTLEFIELD, playerA, "Swamp", 3); + addCard(Zone.BATTLEFIELD, playerA, "Forest", 3); + addCard(Zone.BATTLEFIELD, playerA, "Island", 3); + + // At the beginning of your draw step, you may draw two additional cards. + // If you do, choose two cards in your hand drawn this turn. + // For each of those cards, pay 4 life or put the card on top of your library. + addCard(Zone.LIBRARY, playerB, "Sylvan Library"); + skipInitShuffling(); // to keep this card on top of library + + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Villainous Wealth", playerB); + setChoice(playerA, "X=3"); + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Sylvan Library"); + + setStopAt(3, PhaseStep.PRECOMBAT_MAIN); + execute(); + + assertGraveyardCount(playerA, "Villainous Wealth", 1); + assertExileCount(playerB, 2); + assertExileCount("Sylvan Library", 0); + assertPermanentCount(playerA, "Sylvan Library", 1); + + assertHandCount(playerB, 1); + assertHandCount(playerA, 3); + assertLife(playerA, 12); + assertLife(playerB, 20); + + } } From 4216fbab8c4ef86723f616b5e89c7f89e8b81a2d Mon Sep 17 00:00:00 2001 From: LevelX2 Date: Sun, 18 Oct 2015 11:11:48 +0200 Subject: [PATCH 170/268] * Some more changes for tework ENTERS_THE_BATTLEFIELD event for replacement effects. --- .../sets/betrayersofkamigawa/OrbOfDreams.java | 3 ++- .../championsofkamigawa/OtherworldlyJourney.java | 3 ++- .../ShimatsuTheBloodcloaked.java | 3 ++- .../mage/sets/commander/ChorusOfTheConclave.java | 3 ++- .../src/mage/sets/commander2013/OpalPalace.java | 3 ++- .../mage/sets/commander2014/ScrapMastery.java | 15 +++++++-------- Mage.Sets/src/mage/sets/fifthedition/Kismet.java | 5 +++-- .../src/mage/sets/fifthedition/PrimalClay.java | 5 +++-- .../src/mage/sets/gatecrash/BlindObedience.java | 5 +++-- .../src/mage/sets/gatecrash/MasterBiomancer.java | 2 +- .../src/mage/sets/gatecrash/ZameckGuildmage.java | 5 +++-- .../src/mage/sets/innistrad/DearlyDeparted.java | 5 +++-- .../mage/sets/innistrad/EssenceOfTheWild.java | 5 +++-- .../mage/sets/judgment/WorldgorgerDragon.java | 2 +- .../mage/sets/magic2014/ImposingSovereign.java | 5 +++-- .../src/mage/sets/magic2014/SavageSummoning.java | 3 ++- .../src/mage/sets/magic2015/HushwingGryff.java | 3 ++- .../sets/morningtide/BramblewoodParagon.java | 5 +++-- .../mage/sets/morningtide/OonasBlackguard.java | 5 +++-- .../src/mage/sets/morningtide/SageOfFables.java | 5 +++-- .../src/mage/sets/newphyrexia/DueRespect.java | 3 ++- .../mage/sets/newphyrexia/UrabraskTheHidden.java | 5 +++-- .../src/mage/sets/planarchaos/FrozenAEther.java | 5 +++-- .../mage/sets/planechase2012/PrimalPlasma.java | 5 +++-- .../src/mage/sets/ravnica/LoxodonGatekeeper.java | 5 +++-- .../mage/sets/ravnica/SistersOfStoneDeath.java | 10 +++++----- .../sets/returntoravnica/CorpsejackMenace.java | 5 +++-- .../mage/sets/scarsofmirrodin/TunnelIgnus.java | 9 +++++---- .../sets/shadowmoor/FlourishingDefenses.java | 3 --- .../sets/speedvscunning/AquamorphEntity.java | 5 +++-- Mage.Sets/src/mage/sets/tempest/Dracoplasm.java | 3 ++- Mage.Sets/src/mage/sets/tempest/LivingDeath.java | 10 ++++++---- Mage.Sets/src/mage/sets/tempest/RootMaze.java | 5 +++-- .../src/mage/sets/theros/PyxisOfPandemonium.java | 2 +- .../src/mage/sets/theros/XenagosTheReveler.java | 2 +- .../src/mage/sets/timespiral/LivingEnd.java | 10 +++++----- .../mage/test/cards/triggers/FathomMageTest.java | 2 +- .../abilities/effects/common/AmplifyEffect.java | 2 +- .../abilities/effects/common/DevourEffect.java | 5 +++-- .../continuous/AddCardSubTypeTargetEffect.java | 3 +-- .../SetPowerToughnessSourceEffect.java | 16 +++++++++------- .../mage/abilities/keyword/UnleashAbility.java | 5 +++-- 42 files changed, 119 insertions(+), 91 deletions(-) diff --git a/Mage.Sets/src/mage/sets/betrayersofkamigawa/OrbOfDreams.java b/Mage.Sets/src/mage/sets/betrayersofkamigawa/OrbOfDreams.java index 00f69ecb32e..487d04fcf35 100644 --- a/Mage.Sets/src/mage/sets/betrayersofkamigawa/OrbOfDreams.java +++ b/Mage.Sets/src/mage/sets/betrayersofkamigawa/OrbOfDreams.java @@ -38,6 +38,7 @@ import mage.constants.Outcome; import mage.constants.Rarity; import mage.constants.Zone; import mage.game.Game; +import mage.game.events.EntersTheBattlefieldEvent; import mage.game.events.GameEvent; import mage.game.permanent.Permanent; @@ -82,7 +83,7 @@ public class OrbOfDreams extends CardImpl { @Override public boolean replaceEvent(GameEvent event, Ability source, Game game) { - Permanent permanent = game.getPermanentEntering(event.getTargetId()); + Permanent permanent = ((EntersTheBattlefieldEvent) event).getTarget(); if (permanent != null) { permanent.setTapped(true); } diff --git a/Mage.Sets/src/mage/sets/championsofkamigawa/OtherworldlyJourney.java b/Mage.Sets/src/mage/sets/championsofkamigawa/OtherworldlyJourney.java index 1444229d62b..248b962c6f1 100644 --- a/Mage.Sets/src/mage/sets/championsofkamigawa/OtherworldlyJourney.java +++ b/Mage.Sets/src/mage/sets/championsofkamigawa/OtherworldlyJourney.java @@ -44,6 +44,7 @@ import mage.constants.Zone; import mage.counters.CounterType; import mage.game.ExileZone; import mage.game.Game; +import mage.game.events.EntersTheBattlefieldEvent; import mage.game.events.GameEvent; import mage.game.events.GameEvent.EventType; import mage.game.permanent.Permanent; @@ -185,7 +186,7 @@ class OtherworldlyJourneyEntersBattlefieldEffect extends ReplacementEffectImpl { @Override public boolean replaceEvent(GameEvent event, Ability source, Game game) { - Permanent permanent = game.getPermanentEntering(event.getTargetId()); + Permanent permanent = ((EntersTheBattlefieldEvent) event).getTarget(); if (permanent != null) { permanent.addCounters(CounterType.P1P1.createInstance(), game); discard(); // use only once diff --git a/Mage.Sets/src/mage/sets/championsofkamigawa/ShimatsuTheBloodcloaked.java b/Mage.Sets/src/mage/sets/championsofkamigawa/ShimatsuTheBloodcloaked.java index f25c4609992..958837afe7a 100644 --- a/Mage.Sets/src/mage/sets/championsofkamigawa/ShimatsuTheBloodcloaked.java +++ b/Mage.Sets/src/mage/sets/championsofkamigawa/ShimatsuTheBloodcloaked.java @@ -41,6 +41,7 @@ import mage.constants.Zone; import mage.counters.CounterType; import mage.filter.common.FilterControlledPermanent; import mage.game.Game; +import mage.game.events.EntersTheBattlefieldEvent; import mage.game.events.GameEvent; import mage.game.permanent.Permanent; import mage.players.Player; @@ -105,7 +106,7 @@ class ShimatsuTheBloodcloakedEffect extends ReplacementEffectImpl { @Override public boolean replaceEvent(GameEvent event, Ability source, Game game) { - Permanent creature = game.getPermanentEntering(event.getTargetId()); + Permanent creature = ((EntersTheBattlefieldEvent) event).getTarget(); Player controller = game.getPlayer(source.getControllerId()); if (creature != null && controller != null) { Target target = new TargetControlledPermanent(0, Integer.MAX_VALUE, new FilterControlledPermanent(), true); diff --git a/Mage.Sets/src/mage/sets/commander/ChorusOfTheConclave.java b/Mage.Sets/src/mage/sets/commander/ChorusOfTheConclave.java index 466966ec6dd..4875d2aca7e 100644 --- a/Mage.Sets/src/mage/sets/commander/ChorusOfTheConclave.java +++ b/Mage.Sets/src/mage/sets/commander/ChorusOfTheConclave.java @@ -46,6 +46,7 @@ import mage.constants.Rarity; import mage.constants.Zone; import mage.counters.CounterType; import mage.game.Game; +import mage.game.events.EntersTheBattlefieldEvent; import mage.game.events.GameEvent; import mage.game.permanent.Permanent; import mage.players.Player; @@ -193,7 +194,7 @@ class ChorusOfTheConclaveReplacementEffect2 extends ReplacementEffectImpl { @Override public boolean replaceEvent(GameEvent event, Ability source, Game game) { - Permanent creature = game.getPermanentEntering(event.getSourceId()); + Permanent creature = ((EntersTheBattlefieldEvent) event).getTarget(); Map spellX = (Map) game.getState().getValue("spellX" + source.getSourceId()); MageObject sourceObject = source.getSourceObject(game); if (sourceObject != null && creature != null && spellX != null) { diff --git a/Mage.Sets/src/mage/sets/commander2013/OpalPalace.java b/Mage.Sets/src/mage/sets/commander2013/OpalPalace.java index 0086d731e92..53bb7eb50b8 100644 --- a/Mage.Sets/src/mage/sets/commander2013/OpalPalace.java +++ b/Mage.Sets/src/mage/sets/commander2013/OpalPalace.java @@ -47,6 +47,7 @@ import mage.constants.WatcherScope; import mage.constants.Zone; import mage.counters.CounterType; import mage.game.Game; +import mage.game.events.EntersTheBattlefieldEvent; import mage.game.events.GameEvent; import mage.game.events.GameEvent.EventType; import mage.game.permanent.Permanent; @@ -163,7 +164,7 @@ class OpalPalaceEntersBattlefieldEffect extends ReplacementEffectImpl { @Override public boolean replaceEvent(GameEvent event, Ability source, Game game) { - Permanent permanent = game.getPermanentEntering(event.getTargetId()); + Permanent permanent = ((EntersTheBattlefieldEvent) event).getTarget(); if (permanent != null) { Integer castCount = (Integer) game.getState().getValue(permanent.getId() + "_castCount"); if (castCount != null && castCount > 0) { diff --git a/Mage.Sets/src/mage/sets/commander2014/ScrapMastery.java b/Mage.Sets/src/mage/sets/commander2014/ScrapMastery.java index 95c2ae286fc..280abdd9587 100644 --- a/Mage.Sets/src/mage/sets/commander2014/ScrapMastery.java +++ b/Mage.Sets/src/mage/sets/commander2014/ScrapMastery.java @@ -56,7 +56,6 @@ public class ScrapMastery extends CardImpl { super(ownerId, 38, "Scrap Mastery", Rarity.RARE, new CardType[]{CardType.SORCERY}, "{3}{R}{R}"); this.expansionSetCode = "C14"; - // Each player exiles all artifact cards from his or her graveyard, then sacrifices all artifacts he or she controls, then puts all cards he or she exiled this way onto the battlefield. this.getSpellAbility().addEffect(new ScrapMasteryEffect()); } @@ -93,11 +92,11 @@ class ScrapMasteryEffect extends OneShotEffect { if (controller != null) { Map> exiledCards = new HashMap<>(); // exile artifacts from graveyard - for (UUID playerId: controller.getInRange()) { + for (UUID playerId : controller.getInRange()) { Player player = game.getPlayer(playerId); if (player != null) { Set cards = new HashSet<>(); - for (Card card: player.getGraveyard().getCards(new FilterArtifactCard(), game)) { + for (Card card : player.getGraveyard().getCards(new FilterArtifactCard(), game)) { cards.add(card.getId()); player.moveCardToExileWithInfo(card, null, "", source.getSourceId(), game, Zone.GRAVEYARD, true); } @@ -105,22 +104,22 @@ class ScrapMasteryEffect extends OneShotEffect { } } // sacrifice all artifacts - for (UUID playerId: controller.getInRange()) { + for (UUID playerId : controller.getInRange()) { Player player = game.getPlayer(playerId); if (player != null) { - for (Permanent permanent: game.getBattlefield().getAllActivePermanents(new FilterArtifactPermanent(), playerId, game)) { + for (Permanent permanent : game.getBattlefield().getAllActivePermanents(new FilterArtifactPermanent(), playerId, game)) { permanent.sacrifice(source.getSourceId(), game); } } } // puts all cards he or she exiled this way onto the battlefield - for (UUID playerId: controller.getInRange()) { + for (UUID playerId : controller.getInRange()) { Player player = game.getPlayer(playerId); if (player != null) { - for (UUID cardId: exiledCards.get(playerId)) { + for (UUID cardId : exiledCards.get(playerId)) { Card card = game.getCard(cardId); if (card != null) { - player.putOntoBattlefieldWithInfo(card, game, Zone.EXILED, cardId); + controller.moveCards(card, Zone.EXILED, source, game); } } } diff --git a/Mage.Sets/src/mage/sets/fifthedition/Kismet.java b/Mage.Sets/src/mage/sets/fifthedition/Kismet.java index 673526b4b61..a4319c15b6b 100644 --- a/Mage.Sets/src/mage/sets/fifthedition/Kismet.java +++ b/Mage.Sets/src/mage/sets/fifthedition/Kismet.java @@ -38,6 +38,7 @@ import mage.constants.Outcome; import mage.constants.Rarity; import mage.constants.Zone; import mage.game.Game; +import mage.game.events.EntersTheBattlefieldEvent; import mage.game.events.GameEvent; import mage.game.events.GameEvent.EventType; import mage.game.permanent.Permanent; @@ -79,7 +80,7 @@ class KismetEffect extends ReplacementEffectImpl { @Override public boolean replaceEvent(GameEvent event, Ability source, Game game) { - Permanent target = game.getPermanentEntering(event.getTargetId()); + Permanent target = ((EntersTheBattlefieldEvent) event).getTarget(); if (target != null) { target.setTapped(true); } @@ -94,7 +95,7 @@ class KismetEffect extends ReplacementEffectImpl { @Override public boolean applies(GameEvent event, Ability source, Game game) { if (game.getOpponents(source.getControllerId()).contains(event.getPlayerId())) { - Permanent permanent = game.getPermanent(event.getTargetId()); + Permanent permanent = ((EntersTheBattlefieldEvent) event).getTarget(); if (permanent != null && (permanent.getCardType().contains(CardType.ARTIFACT) || permanent.getCardType().contains(CardType.CREATURE) || permanent.getCardType().contains(CardType.LAND))) { diff --git a/Mage.Sets/src/mage/sets/fifthedition/PrimalClay.java b/Mage.Sets/src/mage/sets/fifthedition/PrimalClay.java index 998dd517b31..9ac15c4a2c1 100644 --- a/Mage.Sets/src/mage/sets/fifthedition/PrimalClay.java +++ b/Mage.Sets/src/mage/sets/fifthedition/PrimalClay.java @@ -45,6 +45,7 @@ import mage.constants.Outcome; import mage.constants.Rarity; import mage.constants.Zone; import mage.game.Game; +import mage.game.events.EntersTheBattlefieldEvent; import mage.game.events.GameEvent; import mage.game.events.GameEvent.EventType; import mage.game.permanent.Permanent; @@ -101,7 +102,7 @@ class PrimalPlasmaReplacementEffect extends ReplacementEffectImpl { @Override public boolean applies(GameEvent event, Ability source, Game game) { if (event.getTargetId().equals(source.getSourceId())) { - Permanent sourcePermanent = game.getPermanentEntering(event.getTargetId()); + Permanent sourcePermanent = ((EntersTheBattlefieldEvent) event).getTarget(); if (sourcePermanent != null && !sourcePermanent.isFaceDown(game)) { return true; } @@ -116,7 +117,7 @@ class PrimalPlasmaReplacementEffect extends ReplacementEffectImpl { @Override public boolean replaceEvent(GameEvent event, Ability source, Game game) { - Permanent permanent = game.getPermanentEntering(event.getTargetId()); + Permanent permanent = ((EntersTheBattlefieldEvent) event).getTarget(); if (permanent != null) { Choice choice = new ChoiceImpl(true); choice.setMessage("Choose what " + permanent.getIdName() + " becomes to"); diff --git a/Mage.Sets/src/mage/sets/gatecrash/BlindObedience.java b/Mage.Sets/src/mage/sets/gatecrash/BlindObedience.java index 537b7304668..9178c73592d 100644 --- a/Mage.Sets/src/mage/sets/gatecrash/BlindObedience.java +++ b/Mage.Sets/src/mage/sets/gatecrash/BlindObedience.java @@ -39,6 +39,7 @@ import mage.constants.Outcome; import mage.constants.Rarity; import mage.constants.Zone; import mage.game.Game; +import mage.game.events.EntersTheBattlefieldEvent; import mage.game.events.GameEvent; import mage.game.permanent.Permanent; @@ -83,7 +84,7 @@ class BlindObedienceTapEffect extends ReplacementEffectImpl { @Override public boolean replaceEvent(GameEvent event, Ability source, Game game) { - Permanent target = game.getPermanentEntering(event.getTargetId()); + Permanent target = ((EntersTheBattlefieldEvent) event).getTarget(); if (target != null) { target.setTapped(true); } @@ -98,7 +99,7 @@ class BlindObedienceTapEffect extends ReplacementEffectImpl { @Override public boolean applies(GameEvent event, Ability source, Game game) { if (game.getOpponents(source.getControllerId()).contains(event.getPlayerId())) { - Permanent permanent = game.getPermanentEntering(event.getTargetId()); + Permanent permanent = ((EntersTheBattlefieldEvent) event).getTarget(); if (permanent != null && (permanent.getCardType().contains(CardType.CREATURE) || permanent.getCardType().contains(CardType.ARTIFACT))) { return true; } diff --git a/Mage.Sets/src/mage/sets/gatecrash/MasterBiomancer.java b/Mage.Sets/src/mage/sets/gatecrash/MasterBiomancer.java index 34fcc5b6294..8a7a9c32ef9 100644 --- a/Mage.Sets/src/mage/sets/gatecrash/MasterBiomancer.java +++ b/Mage.Sets/src/mage/sets/gatecrash/MasterBiomancer.java @@ -111,7 +111,7 @@ class MasterBiomancerEntersBattlefieldEffect extends ReplacementEffectImpl { creature.addCounters(CounterType.P1P1.createInstance(power), game); } ContinuousEffect effect = new AddCardSubTypeTargetEffect("Mutant", Duration.Custom); - effect.setTargetPointer(new FixedTarget(creature.getId())); + effect.setTargetPointer(new FixedTarget(creature.getId(), creature.getZoneChangeCounter(game) + 1)); game.addEffect(effect, source); } return false; diff --git a/Mage.Sets/src/mage/sets/gatecrash/ZameckGuildmage.java b/Mage.Sets/src/mage/sets/gatecrash/ZameckGuildmage.java index cf831b2939c..41bc52a2399 100644 --- a/Mage.Sets/src/mage/sets/gatecrash/ZameckGuildmage.java +++ b/Mage.Sets/src/mage/sets/gatecrash/ZameckGuildmage.java @@ -43,6 +43,7 @@ import mage.constants.Rarity; import mage.constants.Zone; import mage.counters.CounterType; import mage.game.Game; +import mage.game.events.EntersTheBattlefieldEvent; import mage.game.events.GameEvent; import mage.game.permanent.Permanent; import mage.target.common.TargetControlledCreaturePermanent; @@ -99,7 +100,7 @@ class ZameckGuildmageEntersBattlefieldEffect extends ReplacementEffectImpl { @Override public boolean applies(GameEvent event, Ability source, Game game) { - Permanent permanent = game.getPermanentEntering(event.getTargetId()); + Permanent permanent = ((EntersTheBattlefieldEvent) event).getTarget(); return permanent != null && permanent.getControllerId().equals(source.getControllerId()) && permanent.getCardType().contains(CardType.CREATURE); } @@ -110,7 +111,7 @@ class ZameckGuildmageEntersBattlefieldEffect extends ReplacementEffectImpl { @Override public boolean replaceEvent(GameEvent event, Ability source, Game game) { - Permanent target = game.getPermanentEntering(event.getTargetId()); + Permanent target = ((EntersTheBattlefieldEvent) event).getTarget(); if (target != null) { target.addCounters(CounterType.P1P1.createInstance(), game); } diff --git a/Mage.Sets/src/mage/sets/innistrad/DearlyDeparted.java b/Mage.Sets/src/mage/sets/innistrad/DearlyDeparted.java index 71d69e1ebc2..aa0a1f54fef 100644 --- a/Mage.Sets/src/mage/sets/innistrad/DearlyDeparted.java +++ b/Mage.Sets/src/mage/sets/innistrad/DearlyDeparted.java @@ -41,6 +41,7 @@ import mage.constants.Rarity; import mage.constants.Zone; import mage.counters.CounterType; import mage.game.Game; +import mage.game.events.EntersTheBattlefieldEvent; import mage.game.events.GameEvent; import mage.game.events.GameEvent.EventType; import mage.game.permanent.Permanent; @@ -92,7 +93,7 @@ class DearlyDepartedEntersBattlefieldEffect extends ReplacementEffectImpl { @Override public boolean applies(GameEvent event, Ability source, Game game) { - Permanent permanent = game.getPermanentEntering(event.getTargetId()); + Permanent permanent = ((EntersTheBattlefieldEvent) event).getTarget(); if (permanent != null && permanent.getControllerId().equals(source.getControllerId()) && permanent.hasSubtype("Human")) { return true; } @@ -101,7 +102,7 @@ class DearlyDepartedEntersBattlefieldEffect extends ReplacementEffectImpl { @Override public boolean replaceEvent(GameEvent event, Ability source, Game game) { - Permanent target = game.getPermanentEntering(event.getTargetId()); + Permanent target = ((EntersTheBattlefieldEvent) event).getTarget(); if (target != null) { target.addCounters(CounterType.P1P1.createInstance(), game); } diff --git a/Mage.Sets/src/mage/sets/innistrad/EssenceOfTheWild.java b/Mage.Sets/src/mage/sets/innistrad/EssenceOfTheWild.java index 1e5aebd4ea2..68b0c47ceb9 100644 --- a/Mage.Sets/src/mage/sets/innistrad/EssenceOfTheWild.java +++ b/Mage.Sets/src/mage/sets/innistrad/EssenceOfTheWild.java @@ -40,6 +40,7 @@ import mage.constants.Outcome; import mage.constants.Rarity; import mage.constants.Zone; import mage.game.Game; +import mage.game.events.EntersTheBattlefieldEvent; import mage.game.events.GameEvent; import mage.game.events.GameEvent.EventType; import mage.game.permanent.Permanent; @@ -90,13 +91,13 @@ class EssenceOfTheWildEffect extends ReplacementEffectImpl { @Override public boolean applies(GameEvent event, Ability source, Game game) { - Permanent perm = game.getPermanentEntering(event.getTargetId()); + Permanent perm = ((EntersTheBattlefieldEvent) event).getTarget(); return perm != null && perm.getCardType().contains(CardType.CREATURE) && perm.getControllerId().equals(source.getControllerId()); } @Override public boolean replaceEvent(GameEvent event, Ability source, Game game) { - Permanent sourceObject = game.getPermanent(source.getSourceId()); + Permanent sourceObject = ((EntersTheBattlefieldEvent) event).getTarget(); if (sourceObject != null) { game.addEffect(new CopyEffect(Duration.Custom, sourceObject, event.getTargetId()), source); } diff --git a/Mage.Sets/src/mage/sets/judgment/WorldgorgerDragon.java b/Mage.Sets/src/mage/sets/judgment/WorldgorgerDragon.java index ea74b1f8925..0256568c9cd 100644 --- a/Mage.Sets/src/mage/sets/judgment/WorldgorgerDragon.java +++ b/Mage.Sets/src/mage/sets/judgment/WorldgorgerDragon.java @@ -152,7 +152,7 @@ class WorldgorgerDragonLeavesEffect extends OneShotEffect { for (UUID cardId : exile) { Card card = game.getCard(cardId); if (card != null) { - controller.putOntoBattlefieldWithInfo(card, game, Zone.EXILED, source.getSourceId()); + controller.moveCards(card, Zone.EXILED, source, game); } } return true; diff --git a/Mage.Sets/src/mage/sets/magic2014/ImposingSovereign.java b/Mage.Sets/src/mage/sets/magic2014/ImposingSovereign.java index 4a7ae5c389f..fc3aca583e9 100644 --- a/Mage.Sets/src/mage/sets/magic2014/ImposingSovereign.java +++ b/Mage.Sets/src/mage/sets/magic2014/ImposingSovereign.java @@ -39,6 +39,7 @@ import mage.constants.Outcome; import mage.constants.Rarity; import mage.constants.Zone; import mage.game.Game; +import mage.game.events.EntersTheBattlefieldEvent; import mage.game.events.GameEvent; import mage.game.permanent.Permanent; @@ -84,7 +85,7 @@ class ImposingSovereignEffect extends ReplacementEffectImpl { @Override public boolean replaceEvent(GameEvent event, Ability source, Game game) { - Permanent target = game.getPermanentEntering(event.getTargetId()); + Permanent target = ((EntersTheBattlefieldEvent) event).getTarget(); if (target != null) { target.tap(game); } @@ -99,7 +100,7 @@ class ImposingSovereignEffect extends ReplacementEffectImpl { @Override public boolean applies(GameEvent event, Ability source, Game game) { if (game.getOpponents(source.getControllerId()).contains(event.getPlayerId())) { - Permanent permanent = game.getPermanentEntering(event.getTargetId()); + Permanent permanent = ((EntersTheBattlefieldEvent) event).getTarget(); if (permanent != null && permanent.getCardType().contains(CardType.CREATURE)) { return true; } diff --git a/Mage.Sets/src/mage/sets/magic2014/SavageSummoning.java b/Mage.Sets/src/mage/sets/magic2014/SavageSummoning.java index 0736339d5af..3f129598184 100644 --- a/Mage.Sets/src/mage/sets/magic2014/SavageSummoning.java +++ b/Mage.Sets/src/mage/sets/magic2014/SavageSummoning.java @@ -50,6 +50,7 @@ import mage.constants.WatcherScope; import mage.counters.CounterType; import mage.game.Game; import mage.game.command.Commander; +import mage.game.events.EntersTheBattlefieldEvent; import mage.game.events.GameEvent; import mage.game.events.GameEvent.EventType; import mage.game.permanent.Permanent; @@ -314,7 +315,7 @@ class SavageSummoningEntersBattlefieldEffect extends ReplacementEffectImpl { @Override public boolean replaceEvent(GameEvent event, Ability source, Game game) { - Permanent creature = game.getPermanentEntering(event.getTargetId()); + Permanent creature = ((EntersTheBattlefieldEvent) event).getTarget(); if (creature != null) { creature.addCounters(CounterType.P1P1.createInstance(), game); } diff --git a/Mage.Sets/src/mage/sets/magic2015/HushwingGryff.java b/Mage.Sets/src/mage/sets/magic2015/HushwingGryff.java index a05440e99db..2938b8d6ca6 100644 --- a/Mage.Sets/src/mage/sets/magic2015/HushwingGryff.java +++ b/Mage.Sets/src/mage/sets/magic2015/HushwingGryff.java @@ -43,6 +43,7 @@ import mage.constants.Outcome; import mage.constants.Rarity; import mage.constants.Zone; import mage.game.Game; +import mage.game.events.EntersTheBattlefieldEvent; import mage.game.events.GameEvent; import mage.game.permanent.Permanent; @@ -108,7 +109,7 @@ class HushwingGryffEffect extends ContinuousRuleModifyingEffectImpl { public boolean applies(GameEvent event, Ability source, Game game) { Ability ability = (Ability) getValue("targetAbility"); if (ability != null && AbilityType.TRIGGERED.equals(ability.getAbilityType())) { - Permanent permanent = game.getPermanentEntering(event.getTargetId()); + Permanent permanent = ((EntersTheBattlefieldEvent) event).getTarget(); if (permanent != null && permanent.getCardType().contains(CardType.CREATURE)) { return true; } diff --git a/Mage.Sets/src/mage/sets/morningtide/BramblewoodParagon.java b/Mage.Sets/src/mage/sets/morningtide/BramblewoodParagon.java index 039cbc3f889..7d9eb88b969 100644 --- a/Mage.Sets/src/mage/sets/morningtide/BramblewoodParagon.java +++ b/Mage.Sets/src/mage/sets/morningtide/BramblewoodParagon.java @@ -44,6 +44,7 @@ import mage.counters.CounterType; import mage.filter.common.FilterControlledCreaturePermanent; import mage.filter.predicate.permanent.CounterPredicate; import mage.game.Game; +import mage.game.events.EntersTheBattlefieldEvent; import mage.game.events.GameEvent; import mage.game.permanent.Permanent; @@ -108,7 +109,7 @@ class BramblewoodParagonReplacementEffect extends ReplacementEffectImpl { @Override public boolean applies(GameEvent event, Ability source, Game game) { - Permanent creature = game.getPermanentEntering(event.getTargetId()); + Permanent creature = ((EntersTheBattlefieldEvent) event).getTarget(); return creature != null && creature.getControllerId().equals(source.getControllerId()) && creature.getCardType().contains(CardType.CREATURE) && creature.hasSubtype("Warrior") @@ -117,7 +118,7 @@ class BramblewoodParagonReplacementEffect extends ReplacementEffectImpl { @Override public boolean replaceEvent(GameEvent event, Ability source, Game game) { - Permanent creature = game.getPermanentEntering(event.getTargetId()); + Permanent creature = ((EntersTheBattlefieldEvent) event).getTarget(); if (creature != null) { creature.addCounters(CounterType.P1P1.createInstance(), game); } diff --git a/Mage.Sets/src/mage/sets/morningtide/OonasBlackguard.java b/Mage.Sets/src/mage/sets/morningtide/OonasBlackguard.java index 2199b73e735..e652196c9d1 100644 --- a/Mage.Sets/src/mage/sets/morningtide/OonasBlackguard.java +++ b/Mage.Sets/src/mage/sets/morningtide/OonasBlackguard.java @@ -45,6 +45,7 @@ import mage.constants.Zone; import mage.counters.CounterType; import mage.game.Game; import mage.game.events.DamagedPlayerEvent; +import mage.game.events.EntersTheBattlefieldEvent; import mage.game.events.GameEvent; import mage.game.events.GameEvent.EventType; import mage.game.permanent.Permanent; @@ -102,7 +103,7 @@ class OonasBlackguardReplacementEffect extends ReplacementEffectImpl { @Override public boolean applies(GameEvent event, Ability source, Game game) { - Permanent creature = game.getPermanentEntering(event.getTargetId()); + Permanent creature = ((EntersTheBattlefieldEvent) event).getTarget(); if (creature != null && creature.getControllerId().equals(source.getControllerId()) && creature.getCardType().contains(CardType.CREATURE) && creature.hasSubtype("Rogue") @@ -119,7 +120,7 @@ class OonasBlackguardReplacementEffect extends ReplacementEffectImpl { @Override public boolean replaceEvent(GameEvent event, Ability source, Game game) { - Permanent creature = game.getPermanentEntering(event.getTargetId()); + Permanent creature = ((EntersTheBattlefieldEvent) event).getTarget(); if (creature != null) { creature.addCounters(CounterType.P1P1.createInstance(), game); } diff --git a/Mage.Sets/src/mage/sets/morningtide/SageOfFables.java b/Mage.Sets/src/mage/sets/morningtide/SageOfFables.java index a634409057b..ee007b91f51 100644 --- a/Mage.Sets/src/mage/sets/morningtide/SageOfFables.java +++ b/Mage.Sets/src/mage/sets/morningtide/SageOfFables.java @@ -44,6 +44,7 @@ import mage.constants.Rarity; import mage.constants.Zone; import mage.counters.CounterType; import mage.game.Game; +import mage.game.events.EntersTheBattlefieldEvent; import mage.game.events.GameEvent; import mage.game.permanent.Permanent; import mage.target.common.TargetControlledCreaturePermanent; @@ -99,7 +100,7 @@ class SageOfFablesReplacementEffect extends ReplacementEffectImpl { @Override public boolean applies(GameEvent event, Ability source, Game game) { - Permanent creature = game.getPermanentEntering(event.getTargetId()); + Permanent creature = ((EntersTheBattlefieldEvent) event).getTarget(); return creature != null && creature.getControllerId().equals(source.getControllerId()) && creature.getCardType().contains(CardType.CREATURE) && creature.getSubtype().contains("Wizard") @@ -113,7 +114,7 @@ class SageOfFablesReplacementEffect extends ReplacementEffectImpl { @Override public boolean replaceEvent(GameEvent event, Ability source, Game game) { - Permanent creature = game.getPermanentEntering(event.getTargetId()); + Permanent creature = ((EntersTheBattlefieldEvent) event).getTarget(); if (creature != null) { creature.addCounters(CounterType.P1P1.createInstance(), game); } diff --git a/Mage.Sets/src/mage/sets/newphyrexia/DueRespect.java b/Mage.Sets/src/mage/sets/newphyrexia/DueRespect.java index d7cdb54f046..d59865ecdbd 100644 --- a/Mage.Sets/src/mage/sets/newphyrexia/DueRespect.java +++ b/Mage.Sets/src/mage/sets/newphyrexia/DueRespect.java @@ -37,6 +37,7 @@ import mage.constants.Duration; import mage.constants.Outcome; import mage.constants.Rarity; import mage.game.Game; +import mage.game.events.EntersTheBattlefieldEvent; import mage.game.events.GameEvent; import mage.game.permanent.Permanent; @@ -84,7 +85,7 @@ class DueRespectEffect extends ReplacementEffectImpl { @Override public boolean replaceEvent(GameEvent event, Ability source, Game game) { - Permanent permanent = game.getPermanentEntering(event.getTargetId()); + Permanent permanent = ((EntersTheBattlefieldEvent) event).getTarget(); if (permanent != null) { permanent.setTapped(true); } diff --git a/Mage.Sets/src/mage/sets/newphyrexia/UrabraskTheHidden.java b/Mage.Sets/src/mage/sets/newphyrexia/UrabraskTheHidden.java index 6dd467f88fb..9c0a62aa76d 100644 --- a/Mage.Sets/src/mage/sets/newphyrexia/UrabraskTheHidden.java +++ b/Mage.Sets/src/mage/sets/newphyrexia/UrabraskTheHidden.java @@ -42,6 +42,7 @@ import mage.constants.Rarity; import mage.constants.Zone; import mage.filter.common.FilterControlledCreaturePermanent; import mage.game.Game; +import mage.game.events.EntersTheBattlefieldEvent; import mage.game.events.GameEvent; import mage.game.events.GameEvent.EventType; import mage.game.permanent.Permanent; @@ -88,7 +89,7 @@ class UrabraskTheHiddenEffect extends ReplacementEffectImpl { @Override public boolean replaceEvent(GameEvent event, Ability source, Game game) { - Permanent target = game.getPermanentEntering(event.getTargetId()); + Permanent target = ((EntersTheBattlefieldEvent) event).getTarget(); if (target != null) { target.setTapped(true); } @@ -103,7 +104,7 @@ class UrabraskTheHiddenEffect extends ReplacementEffectImpl { @Override public boolean applies(GameEvent event, Ability source, Game game) { if (game.getOpponents(source.getControllerId()).contains(event.getPlayerId())) { - Permanent permanent = game.getPermanentEntering(event.getTargetId()); + Permanent permanent = ((EntersTheBattlefieldEvent) event).getTarget(); if (permanent != null && permanent.getCardType().contains(CardType.CREATURE)) { return true; } diff --git a/Mage.Sets/src/mage/sets/planarchaos/FrozenAEther.java b/Mage.Sets/src/mage/sets/planarchaos/FrozenAEther.java index e06118df4fa..5c84fa60d09 100644 --- a/Mage.Sets/src/mage/sets/planarchaos/FrozenAEther.java +++ b/Mage.Sets/src/mage/sets/planarchaos/FrozenAEther.java @@ -38,6 +38,7 @@ import mage.constants.Outcome; import mage.constants.Rarity; import mage.constants.Zone; import mage.game.Game; +import mage.game.events.EntersTheBattlefieldEvent; import mage.game.events.GameEvent; import mage.game.events.GameEvent.EventType; import mage.game.permanent.Permanent; @@ -79,7 +80,7 @@ class FrozenAEtherTapEffect extends ReplacementEffectImpl { @Override public boolean replaceEvent(GameEvent event, Ability source, Game game) { - Permanent target = game.getPermanentEntering(event.getTargetId()); + Permanent target = ((EntersTheBattlefieldEvent) event).getTarget(); if (target != null) { target.setTapped(true); } @@ -94,7 +95,7 @@ class FrozenAEtherTapEffect extends ReplacementEffectImpl { @Override public boolean applies(GameEvent event, Ability source, Game game) { if (game.getOpponents(source.getControllerId()).contains(event.getPlayerId())) { - Permanent permanent = game.getPermanentEntering(event.getTargetId()); + Permanent permanent = ((EntersTheBattlefieldEvent) event).getTarget(); if (permanent != null && (permanent.getCardType().contains(CardType.CREATURE) || permanent.getCardType().contains(CardType.LAND) diff --git a/Mage.Sets/src/mage/sets/planechase2012/PrimalPlasma.java b/Mage.Sets/src/mage/sets/planechase2012/PrimalPlasma.java index 78d965850c7..55b7eb6adb2 100644 --- a/Mage.Sets/src/mage/sets/planechase2012/PrimalPlasma.java +++ b/Mage.Sets/src/mage/sets/planechase2012/PrimalPlasma.java @@ -45,6 +45,7 @@ import mage.constants.Outcome; import mage.constants.Rarity; import mage.constants.Zone; import mage.game.Game; +import mage.game.events.EntersTheBattlefieldEvent; import mage.game.events.GameEvent; import mage.game.events.GameEvent.EventType; import mage.game.permanent.Permanent; @@ -102,7 +103,7 @@ class PrimalPlasmaReplacementEffect extends ReplacementEffectImpl { @Override public boolean applies(GameEvent event, Ability source, Game game) { if (event.getTargetId().equals(source.getSourceId())) { - Permanent sourcePermanent = game.getPermanentEntering(source.getSourceId()); + Permanent sourcePermanent = ((EntersTheBattlefieldEvent) event).getTarget(); if (sourcePermanent != null && !sourcePermanent.isFaceDown(game)) { return true; } @@ -117,7 +118,7 @@ class PrimalPlasmaReplacementEffect extends ReplacementEffectImpl { @Override public boolean replaceEvent(GameEvent event, Ability source, Game game) { - Permanent permanent = game.getPermanentEntering(source.getSourceId()); + Permanent permanent = ((EntersTheBattlefieldEvent) event).getTarget(); if (permanent != null) { Choice choice = new ChoiceImpl(true); choice.setMessage("Choose what " + permanent.getIdName() + " becomes to"); diff --git a/Mage.Sets/src/mage/sets/ravnica/LoxodonGatekeeper.java b/Mage.Sets/src/mage/sets/ravnica/LoxodonGatekeeper.java index fd8a62fde94..b11584bdd31 100644 --- a/Mage.Sets/src/mage/sets/ravnica/LoxodonGatekeeper.java +++ b/Mage.Sets/src/mage/sets/ravnica/LoxodonGatekeeper.java @@ -39,6 +39,7 @@ import mage.constants.Outcome; import mage.constants.Rarity; import mage.constants.Zone; import mage.game.Game; +import mage.game.events.EntersTheBattlefieldEvent; import mage.game.events.GameEvent; import mage.game.events.GameEvent.EventType; import mage.game.permanent.Permanent; @@ -86,7 +87,7 @@ class LoxodonGatekeeperTapEffect extends ReplacementEffectImpl { @Override public boolean replaceEvent(GameEvent event, Ability source, Game game) { - Permanent target = game.getPermanentEntering(event.getTargetId()); + Permanent target = ((EntersTheBattlefieldEvent) event).getTarget(); if (target != null) { target.setTapped(true); } @@ -101,7 +102,7 @@ class LoxodonGatekeeperTapEffect extends ReplacementEffectImpl { @Override public boolean applies(GameEvent event, Ability source, Game game) { if (game.getOpponents(source.getControllerId()).contains(event.getPlayerId())) { - Permanent permanent = game.getPermanentEntering(event.getTargetId()); + Permanent permanent = ((EntersTheBattlefieldEvent) event).getTarget(); if (permanent != null && (permanent.getCardType().contains(CardType.CREATURE) || permanent.getCardType().contains(CardType.LAND) diff --git a/Mage.Sets/src/mage/sets/ravnica/SistersOfStoneDeath.java b/Mage.Sets/src/mage/sets/ravnica/SistersOfStoneDeath.java index 200188ec098..92302fb34a7 100644 --- a/Mage.Sets/src/mage/sets/ravnica/SistersOfStoneDeath.java +++ b/Mage.Sets/src/mage/sets/ravnica/SistersOfStoneDeath.java @@ -118,18 +118,18 @@ class SistersOfStoneDeathEffect extends OneShotEffect { public boolean apply(Game game, Ability source) { CardsImpl cardsInExile = new CardsImpl(); TargetCard target = new TargetCard(Zone.PICK, new FilterCard()); - Player you = game.getPlayer(source.getControllerId()); - if (you != null) { + Player controller = game.getPlayer(source.getControllerId()); + if (controller != null) { ExileZone exile = game.getExile().getExileZone(exileId); if (exile != null) { - LinkedList cards = new LinkedList(exile); + LinkedList cards = new LinkedList<>(exile); for (UUID cardId : cards) { Card card = game.getCard(cardId); cardsInExile.add(card); } - if (you.choose(Outcome.PutCreatureInPlay, cardsInExile, target, game)) { + if (controller.choose(Outcome.PutCreatureInPlay, cardsInExile, target, game)) { Card chosenCard = game.getCard(target.getFirstTarget()); - return you.putOntoBattlefieldWithInfo(chosenCard, game, Zone.EXILED, source.getSourceId()); + return controller.moveCards(chosenCard, Zone.EXILED, source, game); } } } diff --git a/Mage.Sets/src/mage/sets/returntoravnica/CorpsejackMenace.java b/Mage.Sets/src/mage/sets/returntoravnica/CorpsejackMenace.java index 10bf030e45a..a5d959857b3 100644 --- a/Mage.Sets/src/mage/sets/returntoravnica/CorpsejackMenace.java +++ b/Mage.Sets/src/mage/sets/returntoravnica/CorpsejackMenace.java @@ -40,6 +40,7 @@ import mage.constants.Rarity; import mage.constants.Zone; import mage.counters.CounterType; import mage.game.Game; +import mage.game.events.EntersTheBattlefieldEvent; import mage.game.events.GameEvent; import mage.game.permanent.Permanent; @@ -95,7 +96,7 @@ class CorpsejackMenaceReplacementEffect extends ReplacementEffectImpl { public boolean replaceEvent(GameEvent event, Ability source, Game game) { Permanent permanent = game.getPermanent(event.getTargetId()); if (permanent == null) { - permanent = game.getPermanentEntering(event.getTargetId()); + permanent = ((EntersTheBattlefieldEvent) event).getTarget(); } if (permanent != null) { permanent.addCounters(CounterType.P1P1.createInstance(event.getAmount() * 2), game, event.getAppliedEffects()); @@ -111,7 +112,7 @@ class CorpsejackMenaceReplacementEffect extends ReplacementEffectImpl { @Override public boolean applies(GameEvent event, Ability source, Game game) { if (event.getData().equals(CounterType.P1P1.getName())) { - Permanent permanent = game.getPermanent(event.getTargetId()); + Permanent permanent = ((EntersTheBattlefieldEvent) event).getTarget(); if (permanent == null) { permanent = game.getPermanentEntering(event.getTargetId()); } diff --git a/Mage.Sets/src/mage/sets/scarsofmirrodin/TunnelIgnus.java b/Mage.Sets/src/mage/sets/scarsofmirrodin/TunnelIgnus.java index 0b2216e27f9..806759e787d 100644 --- a/Mage.Sets/src/mage/sets/scarsofmirrodin/TunnelIgnus.java +++ b/Mage.Sets/src/mage/sets/scarsofmirrodin/TunnelIgnus.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.scarsofmirrodin; import java.util.HashMap; @@ -76,7 +75,8 @@ public class TunnelIgnus extends CardImpl { } class TunnelIgnusWatcher extends Watcher { - protected Map counts = new HashMap(); + + protected Map counts = new HashMap<>(); public TunnelIgnusWatcher() { super("LandPlayedCount", WatcherScope.PLAYER); @@ -84,7 +84,7 @@ class TunnelIgnusWatcher extends Watcher { public TunnelIgnusWatcher(final TunnelIgnusWatcher watcher) { super(watcher); - for (Entry entry: watcher.counts.entrySet()) { + for (Entry entry : watcher.counts.entrySet()) { counts.put(entry.getKey(), entry.getValue()); } } @@ -116,6 +116,7 @@ class TunnelIgnusWatcher extends Watcher { } class TunnelIgnusTriggeredAbility extends TriggeredAbilityImpl { + TunnelIgnusTriggeredAbility() { super(Zone.BATTLEFIELD, new DamageTargetEffect(3)); } @@ -153,4 +154,4 @@ class TunnelIgnusTriggeredAbility extends TriggeredAbilityImpl { public String getRule() { return "Whenever a land enters the battlefield under an opponent's control, if that player had another land enter the battlefield under his or her control this turn, {this} deals 3 damage to that player."; } -} \ No newline at end of file +} diff --git a/Mage.Sets/src/mage/sets/shadowmoor/FlourishingDefenses.java b/Mage.Sets/src/mage/sets/shadowmoor/FlourishingDefenses.java index 9e94853f483..c18b7e9d8e5 100644 --- a/Mage.Sets/src/mage/sets/shadowmoor/FlourishingDefenses.java +++ b/Mage.Sets/src/mage/sets/shadowmoor/FlourishingDefenses.java @@ -90,9 +90,6 @@ class FlourishingDefensesTriggeredAbility extends TriggeredAbilityImpl { public boolean checkTrigger(GameEvent event, Game game) { if (event.getData().equals(CounterType.M1M1.getName())) { Permanent permanent = game.getPermanentOrLKIBattlefield(event.getTargetId()); - if (permanent == null) { - permanent = game.getPermanentEntering(event.getTargetId()); - } if (permanent != null && permanent.getCardType().contains(CardType.CREATURE)) { return true; } diff --git a/Mage.Sets/src/mage/sets/speedvscunning/AquamorphEntity.java b/Mage.Sets/src/mage/sets/speedvscunning/AquamorphEntity.java index 3d57c2229d3..c286fd7ffbe 100644 --- a/Mage.Sets/src/mage/sets/speedvscunning/AquamorphEntity.java +++ b/Mage.Sets/src/mage/sets/speedvscunning/AquamorphEntity.java @@ -44,6 +44,7 @@ import mage.constants.Outcome; import mage.constants.Rarity; import mage.constants.Zone; import mage.game.Game; +import mage.game.events.EntersTheBattlefieldEvent; import mage.game.events.GameEvent; import mage.game.events.GameEvent.EventType; import mage.game.permanent.Permanent; @@ -112,7 +113,7 @@ class AquamorphEntityReplacementEffect extends ReplacementEffectImpl { public boolean applies(GameEvent event, Ability source, Game game) { if (event.getType() == EventType.ENTERS_THE_BATTLEFIELD) { if (event.getTargetId().equals(source.getSourceId())) { - Permanent sourcePermanent = game.getPermanentEntering(source.getSourceId()); + Permanent sourcePermanent = ((EntersTheBattlefieldEvent) event).getTarget();; if (sourcePermanent != null && !sourcePermanent.isFaceDown(game)) { return true; } @@ -133,7 +134,7 @@ class AquamorphEntityReplacementEffect extends ReplacementEffectImpl { @Override public boolean replaceEvent(GameEvent event, Ability source, Game game) { - Permanent permanent = game.getPermanentEntering(source.getSourceId()); + Permanent permanent = ((EntersTheBattlefieldEvent) event).getTarget(); if (permanent != null) { Choice choice = new ChoiceImpl(true); choice.setMessage("Choose what the creature becomes to"); diff --git a/Mage.Sets/src/mage/sets/tempest/Dracoplasm.java b/Mage.Sets/src/mage/sets/tempest/Dracoplasm.java index 33b9e60a024..8776797ba03 100644 --- a/Mage.Sets/src/mage/sets/tempest/Dracoplasm.java +++ b/Mage.Sets/src/mage/sets/tempest/Dracoplasm.java @@ -48,6 +48,7 @@ import mage.constants.Zone; import mage.filter.common.FilterControlledCreaturePermanent; import mage.filter.predicate.permanent.AnotherPredicate; import mage.game.Game; +import mage.game.events.EntersTheBattlefieldEvent; import mage.game.events.GameEvent; import mage.game.permanent.Permanent; import mage.players.Player; @@ -122,7 +123,7 @@ class DracoplasmEffect extends ReplacementEffectImpl { @Override public boolean replaceEvent(GameEvent event, Ability source, Game game) { - Permanent creature = game.getPermanentEntering(event.getTargetId()); + Permanent creature = ((EntersTheBattlefieldEvent) event).getTarget(); Player controller = game.getPlayer(source.getControllerId()); if (creature != null && controller != null) { Target target = new TargetControlledPermanent(0, Integer.MAX_VALUE, filter, true); diff --git a/Mage.Sets/src/mage/sets/tempest/LivingDeath.java b/Mage.Sets/src/mage/sets/tempest/LivingDeath.java index fd01450856a..f3c071223d2 100644 --- a/Mage.Sets/src/mage/sets/tempest/LivingDeath.java +++ b/Mage.Sets/src/mage/sets/tempest/LivingDeath.java @@ -43,6 +43,7 @@ import mage.game.ExileZone; import mage.game.Game; import mage.game.permanent.Permanent; import mage.players.Player; + /** * * @author Plopman @@ -53,7 +54,6 @@ public class LivingDeath extends CardImpl { super(ownerId, 36, "Living Death", Rarity.RARE, new CardType[]{CardType.SORCERY}, "{3}{B}{B}"); this.expansionSetCode = "TMP"; - // Each player exiles all creature cards from his or her graveyard, then sacrifices all creatures he or she controls, then puts all cards he or she exiled this way onto the battlefield. this.getSpellAbility().addEffect(new LivingDeathEffect()); } @@ -67,6 +67,7 @@ public class LivingDeath extends CardImpl { return new LivingDeath(this); } } + class LivingDeathEffect extends OneShotEffect { public LivingDeathEffect() { @@ -89,16 +90,16 @@ class LivingDeathEffect extends OneShotEffect { MageObject sourceObject = game.getObject(source.getSourceId()); if (controller != null && sourceObject != null) { // move creature cards from graveyard to exile - for (UUID playerId: controller.getInRange()){ + for (UUID playerId : controller.getInRange()) { Player player = game.getPlayer(playerId); if (player != null) { - for (Card card :player.getGraveyard().getCards(new FilterCreatureCard(), game)) { + for (Card card : player.getGraveyard().getCards(new FilterCreatureCard(), game)) { controller.moveCardToExileWithInfo(card, source.getSourceId(), sourceObject.getIdName(), source.getSourceId(), game, Zone.GRAVEYARD, true); } } } // sacrifice all creatures - for (Permanent permanent :game.getBattlefield().getActivePermanents(new FilterCreaturePermanent(), source.getControllerId(), game)) { + for (Permanent permanent : game.getBattlefield().getActivePermanents(new FilterCreaturePermanent(), source.getControllerId(), game)) { permanent.sacrifice(source.getSourceId(), game); } // put exiled cards to battlefield @@ -107,6 +108,7 @@ class LivingDeathEffect extends OneShotEffect { for (Card card : exileZone.getCards(game)) { Player player = game.getPlayer(card.getOwnerId()); if (player != null) { + player.moveCards(card, Zone.EXILED, source, game); player.putOntoBattlefieldWithInfo(card, game, Zone.EXILED, source.getSourceId()); } } diff --git a/Mage.Sets/src/mage/sets/tempest/RootMaze.java b/Mage.Sets/src/mage/sets/tempest/RootMaze.java index 26835f74da4..eb573226647 100644 --- a/Mage.Sets/src/mage/sets/tempest/RootMaze.java +++ b/Mage.Sets/src/mage/sets/tempest/RootMaze.java @@ -38,6 +38,7 @@ import mage.constants.Outcome; import mage.constants.Rarity; import mage.constants.Zone; import mage.game.Game; +import mage.game.events.EntersTheBattlefieldEvent; import mage.game.events.GameEvent; import mage.game.events.GameEvent.EventType; import mage.game.permanent.Permanent; @@ -79,7 +80,7 @@ class RootMazeEffect extends ReplacementEffectImpl { @Override public boolean replaceEvent(GameEvent event, Ability source, Game game) { - Permanent target = game.getPermanentEntering(event.getTargetId()); + Permanent target = ((EntersTheBattlefieldEvent) event).getTarget(); if (target != null) { target.setTapped(true); } @@ -93,7 +94,7 @@ class RootMazeEffect extends ReplacementEffectImpl { @Override public boolean applies(GameEvent event, Ability source, Game game) { - Permanent permanent = game.getPermanentEntering(event.getTargetId()); + Permanent permanent = ((EntersTheBattlefieldEvent) event).getTarget(); return permanent != null && (permanent.getCardType().contains(CardType.LAND) || permanent.getCardType().contains(CardType.ARTIFACT)); } diff --git a/Mage.Sets/src/mage/sets/theros/PyxisOfPandemonium.java b/Mage.Sets/src/mage/sets/theros/PyxisOfPandemonium.java index 62ce1a931bb..3b1e6e3e836 100644 --- a/Mage.Sets/src/mage/sets/theros/PyxisOfPandemonium.java +++ b/Mage.Sets/src/mage/sets/theros/PyxisOfPandemonium.java @@ -173,7 +173,7 @@ class PyxisOfPandemoniumPutOntoBattlefieldEffect extends OneShotEffect { for (Card card : exileZone.getCards(game)) { card.setFaceDown(false, game); if (CardUtil.isPermanentCard(card)) { - player.putOntoBattlefieldWithInfo(card, game, Zone.EXILED, source.getSourceId()); + player.moveCards(card, Zone.EXILED, source, game); } } } diff --git a/Mage.Sets/src/mage/sets/theros/XenagosTheReveler.java b/Mage.Sets/src/mage/sets/theros/XenagosTheReveler.java index b71a4b0cc07..cb9bcd6c965 100644 --- a/Mage.Sets/src/mage/sets/theros/XenagosTheReveler.java +++ b/Mage.Sets/src/mage/sets/theros/XenagosTheReveler.java @@ -198,7 +198,7 @@ class XenagosExileEffect extends OneShotEffect { for (UUID targetId : target1.getTargets()) { Card card = cards.get(targetId, game); if (card != null) { - player.putOntoBattlefieldWithInfo(card, game, Zone.EXILED, source.getSourceId()); + player.moveCards(card, Zone.EXILED, source, game); } } } diff --git a/Mage.Sets/src/mage/sets/timespiral/LivingEnd.java b/Mage.Sets/src/mage/sets/timespiral/LivingEnd.java index 398a3e28fc2..de93d360d5a 100644 --- a/Mage.Sets/src/mage/sets/timespiral/LivingEnd.java +++ b/Mage.Sets/src/mage/sets/timespiral/LivingEnd.java @@ -63,7 +63,7 @@ public class LivingEnd extends CardImpl { // Each player exiles all creature cards from his or her graveyard, then sacrifices all creatures // he or she controls, then puts all cards he or she exiled this way onto the battlefield. this.getSpellAbility().addEffect(new LivingEndEffect()); - + } public LivingEnd(final LivingEnd card) { @@ -98,16 +98,16 @@ class LivingEndEffect extends OneShotEffect { MageObject sourceObject = game.getObject(source.getSourceId()); if (controller != null && sourceObject != null) { // move creature cards from graveyard to exile - for (UUID playerId: controller.getInRange()){ + for (UUID playerId : controller.getInRange()) { Player player = game.getPlayer(playerId); if (player != null) { - for (Card card :player.getGraveyard().getCards(new FilterCreatureCard(), game)) { + for (Card card : player.getGraveyard().getCards(new FilterCreatureCard(), game)) { controller.moveCardToExileWithInfo(card, source.getSourceId(), sourceObject.getIdName(), source.getSourceId(), game, Zone.GRAVEYARD, true); } } } // sacrifice all creatures - for (Permanent permanent :game.getBattlefield().getActivePermanents(new FilterCreaturePermanent(), source.getControllerId(), game)) { + for (Permanent permanent : game.getBattlefield().getActivePermanents(new FilterCreaturePermanent(), source.getControllerId(), game)) { permanent.sacrifice(source.getSourceId(), game); } // put exiled cards to battlefield @@ -116,7 +116,7 @@ class LivingEndEffect extends OneShotEffect { for (Card card : exileZone.getCards(game)) { Player player = game.getPlayer(card.getOwnerId()); if (player != null) { - player.putOntoBattlefieldWithInfo(card, game, Zone.EXILED, source.getSourceId()); + player.moveCards(card, Zone.EXILED, source, game); } } } diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/triggers/FathomMageTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/triggers/FathomMageTest.java index 0d26c441ff4..145785ccc8b 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/triggers/FathomMageTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/triggers/FathomMageTest.java @@ -60,7 +60,7 @@ public class FathomMageTest extends CardTestPlayerBase { assertPowerToughness(playerA, "Fathom Mage", 3, 3); Permanent fathomMage = getPermanent("Fathom Mage", playerA); - Assert.assertEquals("Fathom Mage has to be a Mutant", fathomMage.getSubtype().contains("Mutant"), true); + Assert.assertEquals("Fathom Mage has to be a Mutant", true, fathomMage.getSubtype().contains("Mutant")); assertHandCount(playerA, 2); } diff --git a/Mage/src/mage/abilities/effects/common/AmplifyEffect.java b/Mage/src/mage/abilities/effects/common/AmplifyEffect.java index dcae2105843..b05ddd626c1 100644 --- a/Mage/src/mage/abilities/effects/common/AmplifyEffect.java +++ b/Mage/src/mage/abilities/effects/common/AmplifyEffect.java @@ -116,7 +116,7 @@ public class AmplifyEffect extends ReplacementEffectImpl { cards.addAll(target.getTargets()); int amountCounters = cards.size() * amplifyFactor.getFactor(); sourceCreature.addCounters(CounterType.P1P1.createInstance(amountCounters), game); - controller.revealCards(sourceCreature.getName(), cards, game); + controller.revealCards(sourceCreature.getIdName(), cards, game); } } } diff --git a/Mage/src/mage/abilities/effects/common/DevourEffect.java b/Mage/src/mage/abilities/effects/common/DevourEffect.java index b2baf9ef7c0..18432616aa8 100644 --- a/Mage/src/mage/abilities/effects/common/DevourEffect.java +++ b/Mage/src/mage/abilities/effects/common/DevourEffect.java @@ -39,6 +39,7 @@ import mage.counters.CounterType; import mage.filter.common.FilterControlledCreaturePermanent; import mage.filter.predicate.permanent.AnotherPredicate; import mage.game.Game; +import mage.game.events.EntersTheBattlefieldEvent; import mage.game.events.GameEvent; import mage.game.permanent.Permanent; import mage.players.Player; @@ -116,7 +117,7 @@ public class DevourEffect extends ReplacementEffectImpl { @Override public boolean applies(GameEvent event, Ability source, Game game) { if (event.getTargetId().equals(source.getSourceId())) { - Permanent sourcePermanent = game.getPermanentEntering(source.getSourceId()); + Permanent sourcePermanent = ((EntersTheBattlefieldEvent) event).getTarget(); game.getState().setValue(sourcePermanent.getId().toString() + "devoured", null); return true; } @@ -130,7 +131,7 @@ public class DevourEffect extends ReplacementEffectImpl { @Override public boolean replaceEvent(GameEvent event, Ability source, Game game) { - Permanent creature = game.getPermanentEntering(event.getTargetId()); + Permanent creature = ((EntersTheBattlefieldEvent) event).getTarget(); Player controller = game.getPlayer(source.getControllerId()); if (creature != null && controller != null) { Target target = new TargetControlledCreaturePermanent(1, Integer.MAX_VALUE, filter, true); diff --git a/Mage/src/mage/abilities/effects/common/continuous/AddCardSubTypeTargetEffect.java b/Mage/src/mage/abilities/effects/common/continuous/AddCardSubTypeTargetEffect.java index 475a7f8d6b6..e4ed2543d96 100644 --- a/Mage/src/mage/abilities/effects/common/continuous/AddCardSubTypeTargetEffect.java +++ b/Mage/src/mage/abilities/effects/common/continuous/AddCardSubTypeTargetEffect.java @@ -25,7 +25,6 @@ * authors and should not be interpreted as representing official policies, either expressed * or implied, of BetaSteward_at_googlemail.com. */ - package mage.abilities.effects.common.continuous; import mage.abilities.Ability; @@ -42,7 +41,7 @@ import mage.game.permanent.Permanent; * @author nantuko */ public class AddCardSubTypeTargetEffect extends ContinuousEffectImpl { - + private final String addedSubType; public AddCardSubTypeTargetEffect(String addedSubType, Duration duration) { diff --git a/Mage/src/mage/abilities/effects/common/continuous/SetPowerToughnessSourceEffect.java b/Mage/src/mage/abilities/effects/common/continuous/SetPowerToughnessSourceEffect.java index add455f4b14..d523a5cbd06 100644 --- a/Mage/src/mage/abilities/effects/common/continuous/SetPowerToughnessSourceEffect.java +++ b/Mage/src/mage/abilities/effects/common/continuous/SetPowerToughnessSourceEffect.java @@ -1,16 +1,16 @@ /* * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. - * + * * Redistribution and use in source and binary forms, with or without modification, are * permitted provided that the following conditions are met: - * + * * 1. Redistributions of source code must retain the above copyright notice, this list of * conditions and the following disclaimer. - * + * * 2. Redistributions in binary form must reproduce the above copyright notice, this list * of conditions and the following disclaimer in the documentation and/or other materials * provided with the distribution. - * + * * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR @@ -20,12 +20,11 @@ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * + * * The views and conclusions contained in the software and documentation are those of the * authors and should not be interpreted as representing official policies, either expressed * or implied, of BetaSteward_at_googlemail.com. */ - package mage.abilities.effects.common.continuous; import mage.MageObject; @@ -76,7 +75,10 @@ public class SetPowerToughnessSourceEffect extends ContinuousEffectImpl { @Override public boolean apply(Game game, Ability source) { - MageObject mageObject = game.getObject(source.getSourceId()); + MageObject mageObject = game.getObject(source.getSourceId()); + if (mageObject == null) { + game.getPermanentEntering(source.getSourceId()); + } if (mageObject == null) { if (duration.equals(Duration.Custom)) { discard(); diff --git a/Mage/src/mage/abilities/keyword/UnleashAbility.java b/Mage/src/mage/abilities/keyword/UnleashAbility.java index 07cccfe4880..953d482278f 100644 --- a/Mage/src/mage/abilities/keyword/UnleashAbility.java +++ b/Mage/src/mage/abilities/keyword/UnleashAbility.java @@ -37,6 +37,7 @@ import mage.constants.Outcome; import mage.constants.Zone; import mage.counters.CounterType; import mage.game.Game; +import mage.game.events.EntersTheBattlefieldEvent; import mage.game.events.GameEvent; import mage.game.events.GameEvent.EventType; import mage.game.permanent.Permanent; @@ -97,10 +98,10 @@ class UnleashReplacementEffect extends ReplacementEffectImpl { @Override public boolean replaceEvent(GameEvent event, Ability source, Game game) { - Permanent creature = game.getPermanentEntering(source.getSourceId()); + Permanent creature = ((EntersTheBattlefieldEvent) event).getTarget(); Player controller = game.getPlayer(source.getControllerId()); if (creature != null && controller != null) { - if (controller.chooseUse(outcome, "Unleash " + creature.getName() + "?", source, game)) { + if (controller.chooseUse(outcome, "Unleash " + creature.getLogName() + "?", source, game)) { if (!game.isSimulation()) { game.informPlayers(controller.getLogName() + " unleashes " + creature.getName()); } From 415700ccb2192ec2522797e37fa20f5e2ef30070 Mon Sep 17 00:00:00 2001 From: LevelX2 Date: Sun, 18 Oct 2015 23:33:23 +0200 Subject: [PATCH 171/268] * Some more changes for rework of ENTERS_THE_BATTLEFIELD event and card movement. --- Mage.Common/src/mage/utils/MageVersion.java | 2 +- .../src/mage/sets/alarareborn/Wargate.java | 13 +- .../sets/antiquities/TransmuteArtifact.java | 40 +++---- .../src/mage/sets/apocalypse/LifeDeath.java | 17 ++- .../sets/archenemy/MakeshiftMannequin.java | 17 +-- .../sets/avacynrestored/RestorationAngel.java | 16 +-- .../betrayersofkamigawa/GoryosVengeance.java | 4 +- .../IwamoriOfTheOpenFist.java | 19 +-- .../betrayersofkamigawa/PatronOfTheMoon.java | 11 +- .../sets/bornofthegods/Peregrination.java | 7 +- .../sets/championsofkamigawa/Reweave.java | 15 +-- .../championsofkamigawa/ThroughTheBreach.java | 2 +- .../src/mage/sets/coldsnap/ArcumDagsson.java | 16 +-- .../mage/sets/commander/KaaliaOfTheVast.java | 20 ++-- .../src/mage/sets/commander/KodamasReach.java | 6 +- .../sets/commander/TarielReckonerOfSouls.java | 2 +- .../commander2014/DarettiScrapSavant.java | 2 +- .../sets/commander2014/InfernalOffering.java | 14 +-- .../commander2014/NahiriTheLithomancer.java | 4 +- .../mage/sets/commander2014/ScrapMastery.java | 25 ++-- .../mage/sets/commander2014/WakeTheDead.java | 37 +++--- .../sets/commander2014/WaveOfVitriol.java | 33 +++-- .../src/mage/sets/conflux/PathToExile.java | 59 +++++---- .../mage/sets/conflux/SkywardEyeProphets.java | 4 +- .../sets/conspiracy/GrenzoDungeonWarden.java | 2 +- .../src/mage/sets/conspiracy/Victimize.java | 20 ++-- .../darkascension/MikaeusTheUnhallowed.java | 10 +- .../src/mage/sets/darksteel/Reshape.java | 20 ++-- .../mage/sets/dissension/CryptChampion.java | 16 +-- .../sets/dragonsmaze/BloodBaronOfVizkopa.java | 71 +++++------ .../sets/dragonsoftarkir/DeathmistRaptor.java | 6 +- .../sets/dragonsoftarkir/SwiftWarkite.java | 4 +- .../elvesvsgoblins/SkirkDrillSergeant.java | 18 ++- .../src/mage/sets/exodus/OathOfDruids.java | 17 ++- .../src/mage/sets/exodus/OathOfLieges.java | 2 +- .../fatereforged/GhastlyConscription.java | 18 +-- .../sets/fatereforged/JeskaiInfiltrator.java | 37 +++--- .../sets/fatereforged/RallyTheAncestors.java | 7 +- .../sets/fatereforged/TorrentElemental.java | 5 +- .../fatereforged/UginTheSpiritDragon.java | 9 +- .../mage/sets/fifthdawn/EndlessWhispers.java | 31 ++--- .../src/mage/sets/fifthdawn/MyrServitor.java | 22 ++-- .../src/mage/sets/fourthedition/TheRack.java | 4 +- .../mage/sets/futuresight/SwordOfTheMeek.java | 4 +- .../sets/gatecrash/ObzedatGhostCouncil.java | 2 +- .../src/mage/sets/iceage/DanceOfTheDead.java | 52 ++++---- .../src/mage/sets/innistrad/CaravanVigil.java | 7 +- .../src/mage/sets/innistrad/GhostQuarter.java | 14 +-- .../mage/sets/invasion/PhyrexianDelver.java | 2 +- .../mage/sets/invasion/ThicketElemental.java | 14 +-- .../mage/sets/judgment/WorldgorgerDragon.java | 22 ++-- .../sets/khansoftarkir/AshcloudPhoenix.java | 20 ++-- .../sets/khansoftarkir/KheruLichLord.java | 30 ++--- .../khansoftarkir/MeanderingTowershell.java | 26 ++-- .../sets/khansoftarkir/SeeTheUnwritten.java | 25 ++-- .../sets/lorwyn/IncandescentSoulstoke.java | 2 +- .../src/mage/sets/magic2010/HiveMind.java | 7 +- .../mage/sets/magic2010/OpenTheVaults.java | 42 +++---- .../mage/sets/magic2010/SphinxAmbassador.java | 12 +- .../src/mage/sets/magic2011/Cultivate.java | 6 +- .../mage/sets/magic2011/NecroticPlague.java | 19 ++- .../mage/sets/magic2015/BoonweaverGiant.java | 18 +-- .../magic2015/JaliraMasterPolymorphist.java | 4 +- .../mage/sets/magic2015/NissaWorldwaker.java | 23 ++-- .../sets/magic2015/YisanTheWandererBard.java | 25 ++-- .../sets/magicorigins/NissasPilgrimage.java | 4 +- .../sets/magicorigins/TheGreatAurora.java | 94 +++++++-------- .../sets/magicorigins/WoodlandBellower.java | 21 ++-- .../sets/mediainserts/MagisterOfWorth.java | 14 +-- .../mage/sets/mercadianmasques/Bribery.java | 10 +- .../src/mage/sets/mirage/ShallowGrave.java | 2 +- .../sets/mirrodin/ScytheOfTheWretched.java | 3 +- .../mirrodinbesieged/GreenSunsZenith.java | 25 ++-- .../mage/sets/modernmasters/ToothAndNail.java | 11 +- .../src/mage/sets/morningtide/Scapeshift.java | 42 +++---- .../sets/nemesis/LinSivviDefiantHero.java | 26 ++-- .../mage/sets/newphyrexia/BirthingPod.java | 23 ++-- .../sets/newphyrexia/MeliraSylvokOutcast.java | 26 ++-- .../src/mage/sets/odyssey/Zoologist.java | 22 ++-- .../sets/onslaught/PatriarchsBidding.java | 22 ++-- .../sets/onslaught/RiptideShapeshifter.java | 32 ++--- .../sets/ravnica/SistersOfStoneDeath.java | 8 +- .../returntoravnica/CorpsejackMenace.java | 5 +- .../sets/returntoravnica/VolatileRig.java | 2 +- .../sets/saviorsofkamigawa/EnduringIdeal.java | 23 ++-- .../saviorsofkamigawa/EternalDominion.java | 15 ++- .../FootstepsOfTheGoryo.java | 11 +- .../mage/sets/shadowmoor/ImpromptuRaid.java | 2 +- .../mage/sets/shadowmoor/PuppeteerClique.java | 10 +- .../sets/shardsofalara/TezzeretTheSeeker.java | 14 +-- .../src/mage/sets/tempest/CorpseDance.java | 35 +++--- .../src/mage/sets/tempest/LivingDeath.java | 28 +++-- .../mage/sets/tempest/StaunchDefenders.java | 6 +- .../sets/tenthedition/AcademyResearchers.java | 16 +-- .../sets/theros/AshiokNightmareWeaver.java | 12 +- .../mage/sets/theros/PyxisOfPandemonium.java | 9 +- .../src/mage/sets/theros/WhipOfErebos.java | 29 +++-- .../mage/sets/theros/XenagosTheReveler.java | 26 ++-- .../src/mage/sets/timespiral/LivingEnd.java | 25 ++-- .../mage/sets/urzasdestiny/Gamekeeper.java | 12 +- .../src/mage/sets/urzasdestiny/Replenish.java | 30 ++--- .../mage/sets/urzaslegacy/GoblinWelder.java | 8 +- .../src/mage/sets/urzassaga/CopperGnomes.java | 11 +- Mage.Sets/src/mage/sets/urzassaga/Exhume.java | 9 +- .../src/mage/sets/urzassaga/PlanarBirth.java | 19 +-- .../src/mage/sets/urzassaga/SneakAttack.java | 10 +- .../mage/sets/vintagemasters/ChaosWarp.java | 30 +++-- .../src/mage/sets/vintagemasters/Eureka.java | 3 +- .../sets/vintagemasters/MistmoonGriffin.java | 4 +- .../src/mage/sets/visions/Necromancy.java | 6 +- .../mage/sets/weatherlight/BoneDancer.java | 10 +- .../sets/worldwake/QuestForUlasTemple.java | 9 +- .../src/mage/sets/zendikar/SummoningTrap.java | 13 +- .../cards/abilities/keywords/PersistTest.java | 3 +- .../cards/abilities/keywords/UndyingTest.java | 4 +- .../cards/enchantments/OathOfLiegesTest.java | 1 + .../cards/triggers/WorldgorgerDragonTest.java | 113 +++++++++--------- .../java/org/mage/test/player/TestPlayer.java | 15 --- Mage/src/mage/abilities/AbilityImpl.java | 9 +- .../effects/common/CopyPermanentEffect.java | 2 +- .../PutLandFromHandOntoBattlefieldEffect.java | 14 +-- ...ourceFromGraveyardToBattlefieldEffect.java | 35 +++--- .../search/SearchLibraryPutInPlayEffect.java | 74 +++++------- ...rchLibraryPutInPlayTargetPlayerEffect.java | 35 +++--- .../effects/keyword/ManifestEffect.java | 6 +- .../keyword/ManifestTargetPlayerEffect.java | 4 +- .../mage/cards/repository/CardRepository.java | 2 +- Mage/src/mage/players/Player.java | 40 ------- Mage/src/mage/players/PlayerImpl.java | 30 +---- 129 files changed, 1029 insertions(+), 1265 deletions(-) diff --git a/Mage.Common/src/mage/utils/MageVersion.java b/Mage.Common/src/mage/utils/MageVersion.java index 5e79ba1e3ed..bc712e76d26 100644 --- a/Mage.Common/src/mage/utils/MageVersion.java +++ b/Mage.Common/src/mage/utils/MageVersion.java @@ -41,7 +41,7 @@ public class MageVersion implements Serializable, Comparable { public final static int MAGE_VERSION_MAJOR = 1; public final static int MAGE_VERSION_MINOR = 4; public final static int MAGE_VERSION_PATCH = 4; - public final static String MAGE_VERSION_MINOR_PATCH = "v8"; + public final static String MAGE_VERSION_MINOR_PATCH = "v9"; public final static String MAGE_VERSION_INFO = ""; private final int major; diff --git a/Mage.Sets/src/mage/sets/alarareborn/Wargate.java b/Mage.Sets/src/mage/sets/alarareborn/Wargate.java index db3728446e6..38654b08777 100644 --- a/Mage.Sets/src/mage/sets/alarareborn/Wargate.java +++ b/Mage.Sets/src/mage/sets/alarareborn/Wargate.java @@ -28,14 +28,13 @@ package mage.sets.alarareborn; import java.util.UUID; - -import mage.constants.CardType; -import mage.constants.Rarity; import mage.abilities.Ability; import mage.abilities.effects.OneShotEffect; import mage.cards.Card; import mage.cards.CardImpl; +import mage.constants.CardType; import mage.constants.Outcome; +import mage.constants.Rarity; import mage.constants.Zone; import mage.filter.Filter; import mage.filter.common.FilterPermanentCard; @@ -54,10 +53,6 @@ public class Wargate extends CardImpl { super(ownerId, 129, "Wargate", Rarity.RARE, new CardType[]{CardType.SORCERY}, "{X}{G}{W}{U}"); this.expansionSetCode = "ARB"; - - - - // Search your library for a permanent card with converted mana cost X or less, put it onto the battlefield, then shuffle your library. this.getSpellAbility().addEffect(new WargateEffect()); } @@ -72,8 +67,8 @@ public class Wargate extends CardImpl { } } - class WargateEffect extends OneShotEffect { + WargateEffect() { super(Outcome.PutCreatureInPlay); staticText = "Search your library for a permanent card with converted mana cost X or less, put it onto the battlefield, then shuffle your library"; @@ -97,7 +92,7 @@ class WargateEffect extends OneShotEffect { if (target.getTargets().size() > 0) { Card card = controller.getLibrary().getCard(target.getFirstTarget(), game); if (card != null) { - controller.putOntoBattlefieldWithInfo(card, game, Zone.LIBRARY, source.getSourceId()); + controller.moveCards(card, Zone.BATTLEFIELD, source, game); } } } diff --git a/Mage.Sets/src/mage/sets/antiquities/TransmuteArtifact.java b/Mage.Sets/src/mage/sets/antiquities/TransmuteArtifact.java index d0b6d85fde4..7a12056f9a8 100644 --- a/Mage.Sets/src/mage/sets/antiquities/TransmuteArtifact.java +++ b/Mage.Sets/src/mage/sets/antiquities/TransmuteArtifact.java @@ -27,7 +27,6 @@ */ package mage.sets.antiquities; -import java.util.List; import java.util.UUID; import mage.abilities.Ability; import mage.abilities.costs.mana.GenericManaCost; @@ -43,7 +42,6 @@ import mage.filter.common.FilterControlledArtifactPermanent; import mage.game.Game; import mage.game.permanent.Permanent; import mage.players.Player; -import mage.target.common.TargetArtifactPermanent; import mage.target.common.TargetCardInLibrary; import mage.target.common.TargetControlledPermanent; @@ -57,7 +55,6 @@ public class TransmuteArtifact extends CardImpl { super(ownerId, 58, "Transmute Artifact", Rarity.UNCOMMON, new CardType[]{CardType.SORCERY}, "{U}{U}"); this.expansionSetCode = "ATQ"; - // Sacrifice an artifact. If you do, search your library for an artifact card. If that card's converted mana cost is less than or equal to the sacrificed artifact's converted mana cost, put it onto the battlefield. If it's greater, you may pay {X}, where X is the difference. If you do, put it onto the battlefield. If you don't, put it into its owner's graveyard. Then shuffle your library. this.getSpellAbility().addEffect(new TransmuteArtifactEffect()); } @@ -74,7 +71,6 @@ public class TransmuteArtifact extends CardImpl { class TransmuteArtifactEffect extends SearchEffect { - public TransmuteArtifactEffect() { super(new TargetCardInLibrary(new FilterArtifactCard()), Outcome.PutCardInPlay); staticText = "Sacrifice an artifact. If you do, search your library for an artifact card. If that card's converted mana cost is less than or equal to the sacrificed artifact's converted mana cost, put it onto the battlefield. If it's greater, you may pay {X}, where X is the difference. If you do, put it onto the battlefield. If you don't, put it into its owner's graveyard. Then shuffle your library"; @@ -95,41 +91,36 @@ class TransmuteArtifactEffect extends SearchEffect { if (controller == null) { return false; } - //Sacrifice an artifact. + //Sacrifice an artifact. int convertedManaCost = 0; boolean sacrifice = false; TargetControlledPermanent targetArtifact = new TargetControlledPermanent(new FilterControlledArtifactPermanent()); - if(controller.chooseTarget(Outcome.Sacrifice, targetArtifact, source, game)){ + if (controller.chooseTarget(Outcome.Sacrifice, targetArtifact, source, game)) { Permanent permanent = game.getPermanent(targetArtifact.getFirstTarget()); - if(permanent != null){ + if (permanent != null) { convertedManaCost = permanent.getManaCost().convertedManaCost(); sacrifice = permanent.sacrifice(source.getSourceId(), game); } - } - else - { + } else { return true; } - //If you do, search your library for an artifact card. + //If you do, search your library for an artifact card. if (sacrifice && controller.searchLibrary(target, game)) { if (target.getTargets().size() > 0) { - for (UUID cardId: target.getTargets()) { + for (UUID cardId : target.getTargets()) { Card card = controller.getLibrary().getCard(cardId, game); if (card != null) { - //If that card's converted mana cost is less than or equal to the sacrificed artifact's converted mana cost, put it onto the battlefield. - if(card.getManaCost().convertedManaCost() <= convertedManaCost){ - controller.putOntoBattlefieldWithInfo(card, game, Zone.LIBRARY, source.getSourceId()); - } - else - { - //If it's greater, you may pay {X}, where X is the difference. If you do, put it onto the battlefield. + //If that card's converted mana cost is less than or equal to the sacrificed artifact's converted mana cost, put it onto the battlefield. + if (card.getManaCost().convertedManaCost() <= convertedManaCost) { + controller.moveCards(card, Zone.BATTLEFIELD, source, game); + } else { + //If it's greater, you may pay {X}, where X is the difference. If you do, put it onto the battlefield. GenericManaCost cost = new GenericManaCost(card.getManaCost().convertedManaCost() - convertedManaCost); - if(cost.pay(source, game, source.getSourceId(), source.getControllerId(), false)){ - controller.putOntoBattlefieldWithInfo(card, game, Zone.LIBRARY, source.getSourceId()); - } - else{ + if (cost.pay(source, game, source.getSourceId(), source.getControllerId(), false)) { + controller.moveCards(card, Zone.BATTLEFIELD, source, game); + } else { //If you don't, put it into its owner's graveyard. Then shuffle your library - controller.moveCards(card, Zone.LIBRARY, Zone.GRAVEYARD, source, game); + controller.moveCards(card, Zone.GRAVEYARD, source, game); } } } @@ -142,5 +133,4 @@ class TransmuteArtifactEffect extends SearchEffect { return false; } - } diff --git a/Mage.Sets/src/mage/sets/apocalypse/LifeDeath.java b/Mage.Sets/src/mage/sets/apocalypse/LifeDeath.java index 1db52a16d06..0cdede7a804 100644 --- a/Mage.Sets/src/mage/sets/apocalypse/LifeDeath.java +++ b/Mage.Sets/src/mage/sets/apocalypse/LifeDeath.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.apocalypse; import java.util.UUID; @@ -34,11 +33,11 @@ import mage.abilities.Ability; import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.continuous.BecomesCreatureAllEffect; import mage.cards.Card; -import mage.constants.CardType; -import mage.constants.Rarity; import mage.cards.SplitCard; +import mage.constants.CardType; import mage.constants.Duration; import mage.constants.Outcome; +import mage.constants.Rarity; import mage.constants.Zone; import mage.filter.common.FilterControlledLandPermanent; import mage.filter.common.FilterCreatureCard; @@ -52,7 +51,6 @@ import mage.target.common.TargetCardInYourGraveyard; * * @author LevelX2 */ - public class LifeDeath extends SplitCard { public LifeDeath(UUID ownerId) { @@ -61,8 +59,8 @@ public class LifeDeath extends SplitCard { // Life // All lands you control become 1/1 creatures until end of turn. They're still lands. - getLeftHalfCard().getSpellAbility().addEffect(new BecomesCreatureAllEffect(new LifeLandToken(), "lands", - new FilterControlledLandPermanent("lands you control"), Duration.EndOfTurn)); + getLeftHalfCard().getSpellAbility().addEffect(new BecomesCreatureAllEffect(new LifeLandToken(), "lands", + new FilterControlledLandPermanent("lands you control"), Duration.EndOfTurn)); // Death // Return target creature card from your graveyard to the battlefield. You lose life equal to its converted mana cost. @@ -83,6 +81,7 @@ public class LifeDeath extends SplitCard { } class LifeLandToken extends Token { + public LifeLandToken() { super("", "1/1 creatures"); cardType.add(CardType.CREATURE); @@ -115,10 +114,10 @@ class DeathEffect extends OneShotEffect { if (creatureCard != null && controller != null) { boolean result = false; if (game.getState().getZone(creatureCard.getId()).equals(Zone.GRAVEYARD)) { - result = controller.putOntoBattlefieldWithInfo(creatureCard, game, Zone.GRAVEYARD, source.getSourceId()); - } + controller.moveCards(creatureCard, Zone.BATTLEFIELD, source, game); + } controller.loseLife(creatureCard.getManaCost().convertedManaCost(), game); - return result; + return true; } return false; } diff --git a/Mage.Sets/src/mage/sets/archenemy/MakeshiftMannequin.java b/Mage.Sets/src/mage/sets/archenemy/MakeshiftMannequin.java index e6f6c9a72df..cf248de7b5d 100644 --- a/Mage.Sets/src/mage/sets/archenemy/MakeshiftMannequin.java +++ b/Mage.Sets/src/mage/sets/archenemy/MakeshiftMannequin.java @@ -44,6 +44,7 @@ import mage.constants.Rarity; import mage.constants.SubLayer; import mage.constants.Zone; import mage.counters.CounterType; +import mage.counters.Counters; import mage.filter.common.FilterCreatureCard; import mage.game.Game; import mage.game.permanent.Permanent; @@ -77,21 +78,21 @@ public class MakeshiftMannequin extends CardImpl { } class MakeshiftMannequinEffect extends OneShotEffect { - + MakeshiftMannequinEffect() { super(Outcome.PutCreatureInPlay); this.staticText = "Return target creature card from your graveyard to the battlefield with a mannequin counter on it. For as long as that creature has a mannequin counter on it, it has \"When this creature becomes the target of a spell or ability, sacrifice it.\""; } - + MakeshiftMannequinEffect(final MakeshiftMannequinEffect effect) { super(effect); } - + @Override public MakeshiftMannequinEffect copy() { return new MakeshiftMannequinEffect(this); } - + @Override public boolean apply(Game game, Ability source) { Player controller = game.getPlayer(source.getControllerId()); @@ -99,12 +100,14 @@ class MakeshiftMannequinEffect extends OneShotEffect { UUID cardId = this.getTargetPointer().getFirst(game, source); Card card = controller.getGraveyard().get(cardId, game); if (card != null) { - if (controller.putOntoBattlefieldWithInfo(card, game, Zone.GRAVEYARD, source.getSourceId())) { + Counters counters = new Counters(); + counters.addCounter(CounterType.MANNEQUIN.createInstance()); + game.setEnterWithCounters(cardId, counters); + if (controller.moveCards(card, Zone.BATTLEFIELD, source, game)) { Permanent permanent = game.getPermanent(cardId); if (permanent != null) { - permanent.addCounters(CounterType.MANNEQUIN.createInstance(), game); ContinuousEffect gainedEffect = new MakeshiftMannequinGainAbilityEffect(); - gainedEffect.setTargetPointer(new FixedTarget(cardId)); + gainedEffect.setTargetPointer(new FixedTarget(permanent, game)); game.addEffect(gainedEffect, source); } } diff --git a/Mage.Sets/src/mage/sets/avacynrestored/RestorationAngel.java b/Mage.Sets/src/mage/sets/avacynrestored/RestorationAngel.java index bd3043c6e72..65582db1bf7 100644 --- a/Mage.Sets/src/mage/sets/avacynrestored/RestorationAngel.java +++ b/Mage.Sets/src/mage/sets/avacynrestored/RestorationAngel.java @@ -51,7 +51,7 @@ import mage.target.common.TargetControlledCreaturePermanent; /** * * @author noxx - + * */ public class RestorationAngel extends CardImpl { @@ -71,7 +71,7 @@ public class RestorationAngel extends CardImpl { this.addAbility(FlashAbility.getInstance()); this.addAbility(FlyingAbility.getInstance()); - + // When Restoration Angel enters the battlefield, you may exile target non-Angel creature you control, then return that card to the battlefield under your control Ability ability = new EntersBattlefieldTriggeredAbility(new RestorationAngelEffect(), true); ability.addTarget(new TargetControlledCreaturePermanent(1, 1, filter, false)); @@ -111,11 +111,13 @@ class RestorationAngelEffect extends OneShotEffect { Permanent sourcePermanent = game.getPermanentOrLKIBattlefield(source.getSourceId()); Permanent permanent = game.getPermanent(targetPointer.getFirst(game, source)); if (permanent != null && sourcePermanent != null) { - controller.moveCardToExileWithInfo(permanent, source.getSourceId(), sourcePermanent.getIdName(), source.getSourceId(), game, Zone.BATTLEFIELD, true); - Card card = game.getCard(targetPointer.getFirst(game, source)); - if (card != null) { - Zone currentZone = game.getState().getZone(card.getId()); - return controller.putOntoBattlefieldWithInfo(card, game, currentZone, source.getSourceId()); + int zcc = permanent.getZoneChangeCounter(game); + controller.moveCards(permanent, Zone.EXILED, source, game); + Card card = game.getCard(permanent.getId()); + if (card != null + && card.getZoneChangeCounter(game) == zcc + 1 + && game.getState().getZone(card.getId()).equals(Zone.EXILED)) { + return controller.moveCards(card, Zone.BATTLEFIELD, source, game); } } } diff --git a/Mage.Sets/src/mage/sets/betrayersofkamigawa/GoryosVengeance.java b/Mage.Sets/src/mage/sets/betrayersofkamigawa/GoryosVengeance.java index c30dfb512fe..16bef199b09 100644 --- a/Mage.Sets/src/mage/sets/betrayersofkamigawa/GoryosVengeance.java +++ b/Mage.Sets/src/mage/sets/betrayersofkamigawa/GoryosVengeance.java @@ -110,12 +110,12 @@ class GoryosVengeanceEffect extends OneShotEffect { if (controller != null) { Card card = game.getCard(targetPointer.getFirst(game, source)); if (card != null) { - if (controller.putOntoBattlefieldWithInfo(card, game, Zone.GRAVEYARD, source.getSourceId())) { + if (controller.moveCards(card, Zone.BATTLEFIELD, source, game)) { Permanent permanent = game.getPermanent(card.getId()); if (permanent != null) { // Haste ContinuousEffect effect = new GainAbilityTargetEffect(HasteAbility.getInstance(), Duration.Custom); - effect.setTargetPointer(new FixedTarget(permanent.getId())); + effect.setTargetPointer(new FixedTarget(permanent, game)); game.addEffect(effect, source); // Exile it at end of turn Effect exileEffect = new ExileTargetEffect("Exile " + permanent.getName() + " at the beginning of the next end step"); diff --git a/Mage.Sets/src/mage/sets/betrayersofkamigawa/IwamoriOfTheOpenFist.java b/Mage.Sets/src/mage/sets/betrayersofkamigawa/IwamoriOfTheOpenFist.java index 98bc1dbe5f7..b37336ee341 100644 --- a/Mage.Sets/src/mage/sets/betrayersofkamigawa/IwamoriOfTheOpenFist.java +++ b/Mage.Sets/src/mage/sets/betrayersofkamigawa/IwamoriOfTheOpenFist.java @@ -84,26 +84,26 @@ public class IwamoriOfTheOpenFist extends CardImpl { class IwamoriOfTheOpenFistEffect extends OneShotEffect { private static final FilterCard filter = new FilterCard("legendary creature card"); - + static { filter.add(new SupertypePredicate("Legendary")); filter.add(new CardTypePredicate(CardType.CREATURE)); } - + public IwamoriOfTheOpenFistEffect() { super(Outcome.Detriment); this.staticText = "each opponent may put a legendary creature card from his or her hand onto the battlefield"; } - + public IwamoriOfTheOpenFistEffect(final IwamoriOfTheOpenFistEffect effect) { super(effect); } - + @Override public IwamoriOfTheOpenFistEffect copy() { return new IwamoriOfTheOpenFistEffect(this); } - + @Override public boolean apply(Game game, Ability source) { Player controller = game.getPlayer(source.getControllerId()); @@ -123,14 +123,7 @@ class IwamoriOfTheOpenFistEffect extends OneShotEffect { } } } - if (cards.size() > 0) { - for (Card card: cards.getCards(game)) { - Player player = game.getPlayer(card.getOwnerId()); - if (player != null) { - player.putOntoBattlefieldWithInfo(card, game, Zone.HAND, source.getSourceId()); - } - } - } + controller.moveCards(cards.getCards(game), Zone.BATTLEFIELD, source, game, false, false, true, null); return true; } diff --git a/Mage.Sets/src/mage/sets/betrayersofkamigawa/PatronOfTheMoon.java b/Mage.Sets/src/mage/sets/betrayersofkamigawa/PatronOfTheMoon.java index 826408a71be..f6d16875adc 100644 --- a/Mage.Sets/src/mage/sets/betrayersofkamigawa/PatronOfTheMoon.java +++ b/Mage.Sets/src/mage/sets/betrayersofkamigawa/PatronOfTheMoon.java @@ -35,8 +35,8 @@ import mage.abilities.costs.mana.ManaCostsImpl; import mage.abilities.effects.OneShotEffect; import mage.abilities.keyword.FlyingAbility; import mage.abilities.keyword.OfferingAbility; -import mage.cards.Card; import mage.cards.CardImpl; +import mage.cards.CardsImpl; import mage.constants.CardType; import mage.constants.Outcome; import mage.constants.Rarity; @@ -100,13 +100,8 @@ class PatronOfTheMoonEffect extends OneShotEffect { if (controller != null) { TargetCard target = new TargetCardInHand(0, 2, new FilterLandCard("up to two land cards to put onto the battlefield tapped")); controller.chooseTarget(outcome, controller.getHand(), target, source, game); - for (UUID cardId : target.getTargets()) { - Card card = game.getCard(cardId); - if (card != null) { - controller.putOntoBattlefieldWithInfo(card, game, Zone.HAND, source.getSourceId(), true); - } - } - return true; + return controller.moveCards(new CardsImpl(target.getTargets()).getCards(game), + Zone.BATTLEFIELD, source, game, true, false, false, null); } return false; } diff --git a/Mage.Sets/src/mage/sets/bornofthegods/Peregrination.java b/Mage.Sets/src/mage/sets/bornofthegods/Peregrination.java index d5fdc7aca32..688d96d8083 100644 --- a/Mage.Sets/src/mage/sets/bornofthegods/Peregrination.java +++ b/Mage.Sets/src/mage/sets/bornofthegods/Peregrination.java @@ -113,14 +113,13 @@ class PeregrinationEffect extends OneShotEffect { TargetCard target2 = new TargetCard(Zone.LIBRARY, filter); controller.choose(Outcome.Benefit, revealed, target2, game); Card card = revealed.get(target2.getFirstTarget(), game); - - controller.putOntoBattlefieldWithInfo(card, game, Zone.LIBRARY, source.getSourceId(), true); + controller.moveCards(card, Zone.BATTLEFIELD, source, game, true, false, false, null); revealed.remove(card); card = revealed.getCards(game).iterator().next(); - controller.moveCards(card, null, Zone.HAND, source, game); + controller.moveCards(card, Zone.HAND, source, game); } else if (target.getTargets().size() == 1) { Card card = revealed.getCards(game).iterator().next(); - controller.putOntoBattlefieldWithInfo(card, game, Zone.LIBRARY, source.getSourceId(), true); + controller.moveCards(card, Zone.BATTLEFIELD, source, game, true, false, false, null); } } diff --git a/Mage.Sets/src/mage/sets/championsofkamigawa/Reweave.java b/Mage.Sets/src/mage/sets/championsofkamigawa/Reweave.java index 665831faad9..6a82d96309c 100644 --- a/Mage.Sets/src/mage/sets/championsofkamigawa/Reweave.java +++ b/Mage.Sets/src/mage/sets/championsofkamigawa/Reweave.java @@ -28,6 +28,7 @@ package mage.sets.championsofkamigawa; import java.util.UUID; +import mage.MageObject; import mage.abilities.Ability; import mage.abilities.effects.OneShotEffect; import mage.abilities.keyword.SpliceOntoArcaneAbility; @@ -58,7 +59,6 @@ public class Reweave extends CardImpl { this.expansionSetCode = "CHK"; this.subtype.add("Arcane"); - // Target permanent's controller sacrifices it. If he or she does, that player reveals cards from the top of his or her library until he or she reveals a permanent card that shares a card type with the sacrificed permanent, puts that card onto the battlefield, then shuffles his or her library. this.getSpellAbility().addEffect(new ReweaveEffect()); Target target = new TargetPermanent(); @@ -97,9 +97,10 @@ class ReweaveEffect extends OneShotEffect { } @Override - public boolean apply(Game game, Ability source) { - Permanent permanent = game.getPermanent(source.getTargets().getFirstTarget()); - if (permanent != null) { + public boolean apply(Game game, Ability source) { + Permanent permanent = game.getPermanent(getTargetPointer().getFirst(game, source)); + MageObject sourceObject = source.getSourceObject(game); + if (permanent != null && sourceObject != null) { if (permanent.sacrifice(source.getSourceId(), game)) { Player permanentController = game.getPlayer(permanent.getControllerId()); if (permanentController != null) { @@ -122,11 +123,11 @@ class ReweaveEffect extends OneShotEffect { } } } while (!cardFound && library.size() > 0); - permanentController.putOntoBattlefieldWithInfo(card, game, Zone.LIBRARY, source.getSourceId()); + permanentController.moveCards(card, Zone.BATTLEFIELD, source, game); } if (cards.size() > 0) { - permanentController.revealCards("Reweave", cards, game); + permanentController.revealCards(sourceObject.getIdName(), cards, game); if (cardFound && card != null) { cards.remove(card); } @@ -137,7 +138,7 @@ class ReweaveEffect extends OneShotEffect { return true; } return false; - } + } } return true; } diff --git a/Mage.Sets/src/mage/sets/championsofkamigawa/ThroughTheBreach.java b/Mage.Sets/src/mage/sets/championsofkamigawa/ThroughTheBreach.java index bf4e4d5139b..f8510304312 100644 --- a/Mage.Sets/src/mage/sets/championsofkamigawa/ThroughTheBreach.java +++ b/Mage.Sets/src/mage/sets/championsofkamigawa/ThroughTheBreach.java @@ -106,7 +106,7 @@ class ThroughTheBreachEffect extends OneShotEffect { if (controller.choose(Outcome.PutCreatureInPlay, target, source.getSourceId(), game)) { Card card = game.getCard(target.getFirstTarget()); if (card != null) { - if (controller.putOntoBattlefieldWithInfo(card, game, Zone.HAND, source.getSourceId())) { + if (controller.moveCards(card, Zone.BATTLEFIELD, source, game)) { Permanent permanent = game.getPermanent(card.getId()); if (permanent != null) { ContinuousEffect effect = new GainAbilityTargetEffect(HasteAbility.getInstance(), Duration.Custom); diff --git a/Mage.Sets/src/mage/sets/coldsnap/ArcumDagsson.java b/Mage.Sets/src/mage/sets/coldsnap/ArcumDagsson.java index 653bb2a81d0..7205351a470 100644 --- a/Mage.Sets/src/mage/sets/coldsnap/ArcumDagsson.java +++ b/Mage.Sets/src/mage/sets/coldsnap/ArcumDagsson.java @@ -56,8 +56,9 @@ import mage.target.common.TargetCardInLibrary; * @author emerald000 */ public class ArcumDagsson extends CardImpl { - + private static final FilterPermanent filter = new FilterArtifactPermanent("artifact creature"); + static { filter.add(new CardTypePredicate(CardType.CREATURE)); } @@ -88,26 +89,27 @@ public class ArcumDagsson extends CardImpl { } class ArcumDagssonEffect extends OneShotEffect { - + private static final FilterCard filter = new FilterArtifactCard("noncreature artifact card"); + static { filter.add(Predicates.not(new CardTypePredicate(CardType.CREATURE))); } - + ArcumDagssonEffect() { super(Outcome.Removal); this.staticText = "Target artifact creature's controller sacrifices it. That player may search his or her library for a noncreature artifact card, put it onto the battlefield, then shuffle his or her library"; } - + ArcumDagssonEffect(final ArcumDagssonEffect effect) { super(effect); } - + @Override public ArcumDagssonEffect copy() { return new ArcumDagssonEffect(this); } - + @Override public boolean apply(Game game, Ability source) { Permanent artifactCreature = game.getPermanent(this.getTargetPointer().getFirst(game, source)); @@ -120,7 +122,7 @@ class ArcumDagssonEffect extends OneShotEffect { if (player.searchLibrary(target, game)) { Card card = game.getCard(target.getFirstTarget()); if (card != null) { - player.putOntoBattlefieldWithInfo(card, game, Zone.LIBRARY, source.getSourceId()); + player.moveCards(card, Zone.BATTLEFIELD, source, game); } } player.shuffleLibrary(game); diff --git a/Mage.Sets/src/mage/sets/commander/KaaliaOfTheVast.java b/Mage.Sets/src/mage/sets/commander/KaaliaOfTheVast.java index ae71daeb4db..bc05511f481 100644 --- a/Mage.Sets/src/mage/sets/commander/KaaliaOfTheVast.java +++ b/Mage.Sets/src/mage/sets/commander/KaaliaOfTheVast.java @@ -1,16 +1,16 @@ /* * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. - * + * * Redistribution and use in source and binary forms, with or without modification, are * permitted provided that the following conditions are met: - * + * * 1. Redistributions of source code must retain the above copyright notice, this list of * conditions and the following disclaimer. - * + * * 2. Redistributions in binary form must reproduce the above copyright notice, this list * of conditions and the following disclaimer in the documentation and/or other materials * provided with the distribution. - * + * * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR @@ -20,7 +20,7 @@ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * + * * The views and conclusions contained in the software and documentation are those of the * authors and should not be interpreted as representing official policies, either expressed * or implied, of BetaSteward_at_googlemail.com. @@ -148,20 +148,20 @@ class KaaliaOfTheVastEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { - Player player = game.getPlayer(source.getControllerId()); - if (player == null || !player.chooseUse(Outcome.PutCreatureInPlay, "Put an Angel, Demon, or Dragon creature card from your hand onto the battlefield tapped and attacking?", source, game)) { + Player controller = game.getPlayer(source.getControllerId()); + if (controller == null || !controller.chooseUse(Outcome.PutCreatureInPlay, "Put an Angel, Demon, or Dragon creature card from your hand onto the battlefield tapped and attacking?", source, game)) { return false; } TargetCardInHand target = new TargetCardInHand(filter); - if (target.canChoose(player.getId(), game) && target.choose(getOutcome(), player.getId(), source.getSourceId(), game)) { + if (target.canChoose(controller.getId(), game) && target.choose(getOutcome(), controller.getId(), source.getSourceId(), game)) { if (target.getTargets().size() > 0) { UUID cardId = target.getFirstTarget(); Card card = game.getCard(cardId); if (card != null && game.getCombat() != null) { UUID defenderId = game.getCombat().getDefendingPlayerId(source.getSourceId(), game); if (defenderId != null) { - player.getHand().remove(card); - player.putOntoBattlefieldWithInfo(card, game, Zone.HAND, source.getSourceId(), true); + controller.getHand().remove(card); + controller.moveCards(card, Zone.BATTLEFIELD, source, game, true, false, false, null); Permanent creature = game.getPermanent(cardId); if (creature != null) { game.getCombat().addAttackerToCombat(card.getId(), defenderId, game); diff --git a/Mage.Sets/src/mage/sets/commander/KodamasReach.java b/Mage.Sets/src/mage/sets/commander/KodamasReach.java index 6b7883e9e8b..103a617285c 100644 --- a/Mage.Sets/src/mage/sets/commander/KodamasReach.java +++ b/Mage.Sets/src/mage/sets/commander/KodamasReach.java @@ -110,17 +110,17 @@ class KodamasReachEffect extends OneShotEffect { controller.choose(Outcome.Benefit, revealed, target2, game); Card card = revealed.get(target2.getFirstTarget(), game); if (card != null) { - controller.putOntoBattlefieldWithInfo(card, game, Zone.LIBRARY, source.getSourceId(), true); + controller.moveCards(card, Zone.BATTLEFIELD, source, game, true, false, false, null); revealed.remove(card); } card = revealed.getCards(game).iterator().next(); if (card != null) { - controller.moveCards(card, null, Zone.HAND, source, game); + controller.moveCards(card, Zone.HAND, source, game); } } else if (target.getTargets().size() == 1) { Card card = revealed.getCards(game).iterator().next(); if (card != null) { - controller.putOntoBattlefieldWithInfo(card, game, Zone.LIBRARY, source.getSourceId(), true); + controller.moveCards(card, Zone.BATTLEFIELD, source, game, true, false, false, null); } } diff --git a/Mage.Sets/src/mage/sets/commander/TarielReckonerOfSouls.java b/Mage.Sets/src/mage/sets/commander/TarielReckonerOfSouls.java index 7cfe1e0b577..cb464431dbc 100644 --- a/Mage.Sets/src/mage/sets/commander/TarielReckonerOfSouls.java +++ b/Mage.Sets/src/mage/sets/commander/TarielReckonerOfSouls.java @@ -110,7 +110,7 @@ class TarielReckonerOfSoulsEffect extends OneShotEffect { } if (!creatureCards.isEmpty()) { Card card = creatureCards.getRandom(game); - controller.putOntoBattlefieldWithInfo(card, game, Zone.GRAVEYARD, source.getSourceId()); + controller.moveCards(card, Zone.BATTLEFIELD, source, game); } return true; } diff --git a/Mage.Sets/src/mage/sets/commander2014/DarettiScrapSavant.java b/Mage.Sets/src/mage/sets/commander2014/DarettiScrapSavant.java index a4d4ceab35c..0f07b4a61ab 100644 --- a/Mage.Sets/src/mage/sets/commander2014/DarettiScrapSavant.java +++ b/Mage.Sets/src/mage/sets/commander2014/DarettiScrapSavant.java @@ -164,7 +164,7 @@ class DarettiSacrificeEffect extends OneShotEffect { if (artifact != null && artifact.sacrifice(source.getSourceId(), game)) { Card card = game.getCard(getTargetPointer().getFirst(game, source)); if (card != null) { - return controller.putOntoBattlefieldWithInfo(card, game, Zone.GRAVEYARD, source.getSourceId()); + return controller.moveCards(card, Zone.BATTLEFIELD, source, game); } } } diff --git a/Mage.Sets/src/mage/sets/commander2014/InfernalOffering.java b/Mage.Sets/src/mage/sets/commander2014/InfernalOffering.java index 18a0fef42cb..07816fa09d4 100644 --- a/Mage.Sets/src/mage/sets/commander2014/InfernalOffering.java +++ b/Mage.Sets/src/mage/sets/commander2014/InfernalOffering.java @@ -104,7 +104,7 @@ class InfernalOfferingSacrificeEffect extends OneShotEffect { if (opponent != null) { //Choose creatures to sacrifice Map toSacrifice = new HashMap<>(2); - for (UUID playerId : player.getInRange()) { + for (UUID playerId : game.getState().getPlayersInRange(player.getId(), game)) { if (playerId.equals(player.getId()) || playerId.equals(opponent.getId())) { target = new TargetControlledCreaturePermanent(1, 1, new FilterControlledCreaturePermanent(), true); if (target.choose(Outcome.Sacrifice, playerId, source.getControllerId(), game)) { @@ -154,16 +154,16 @@ class InfernalOfferingReturnEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { - Player player = game.getPlayer(source.getControllerId()); - if (player != null) { + Player controller = game.getPlayer(source.getControllerId()); + if (controller != null) { Target target = new TargetOpponent(true); target.choose(Outcome.PutCreatureInPlay, source.getControllerId(), source.getSourceId(), game); Player opponent = game.getPlayer(target.getFirstTarget()); target = new TargetCardInYourGraveyard(new FilterCreatureCard("creature card in your graveyard")); - if (target.choose(Outcome.PutCreatureInPlay, player.getId(), source.getSourceId(), game)) { - Card card = player.getGraveyard().get(target.getFirstTarget(), game); + if (target.choose(Outcome.PutCreatureInPlay, controller.getId(), source.getSourceId(), game)) { + Card card = controller.getGraveyard().get(target.getFirstTarget(), game); if (card != null) { - player.putOntoBattlefieldWithInfo(card, game, Zone.GRAVEYARD, source.getSourceId()); + controller.moveCards(card, Zone.BATTLEFIELD, source, game); } } if (opponent != null) { @@ -171,7 +171,7 @@ class InfernalOfferingReturnEffect extends OneShotEffect { if (target.choose(Outcome.PutCreatureInPlay, opponent.getId(), source.getSourceId(), game)) { Card card = opponent.getGraveyard().get(target.getFirstTarget(), game); if (card != null) { - opponent.putOntoBattlefieldWithInfo(card, game, Zone.GRAVEYARD, source.getSourceId()); + opponent.moveCards(card, Zone.BATTLEFIELD, source, game); } } } diff --git a/Mage.Sets/src/mage/sets/commander2014/NahiriTheLithomancer.java b/Mage.Sets/src/mage/sets/commander2014/NahiriTheLithomancer.java index 890dd2eab04..eb480233616 100644 --- a/Mage.Sets/src/mage/sets/commander2014/NahiriTheLithomancer.java +++ b/Mage.Sets/src/mage/sets/commander2014/NahiriTheLithomancer.java @@ -186,14 +186,14 @@ class NahiriTheLithomancerSecondAbilityEffect extends OneShotEffect { controller.choose(outcome, target, source.getSourceId(), game); Card card = controller.getHand().get(target.getFirstTarget(), game); if (card != null) { - controller.putOntoBattlefieldWithInfo(card, game, Zone.HAND, source.getSourceId()); + controller.moveCards(card, Zone.BATTLEFIELD, source, game); } } else { Target target = new TargetCardInYourGraveyard(0, 1, filter); target.choose(Outcome.PutCardInPlay, source.getControllerId(), source.getSourceId(), game); Card card = controller.getGraveyard().get(target.getFirstTarget(), game); if (card != null) { - controller.putOntoBattlefieldWithInfo(card, game, Zone.GRAVEYARD, source.getSourceId()); + controller.moveCards(card, Zone.BATTLEFIELD, source, game); } } return true; diff --git a/Mage.Sets/src/mage/sets/commander2014/ScrapMastery.java b/Mage.Sets/src/mage/sets/commander2014/ScrapMastery.java index 280abdd9587..f2512b5b703 100644 --- a/Mage.Sets/src/mage/sets/commander2014/ScrapMastery.java +++ b/Mage.Sets/src/mage/sets/commander2014/ScrapMastery.java @@ -28,14 +28,14 @@ package mage.sets.commander2014; import java.util.HashMap; -import java.util.HashSet; import java.util.Map; import java.util.Set; import java.util.UUID; import mage.abilities.Ability; import mage.abilities.effects.OneShotEffect; -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; @@ -92,19 +92,16 @@ class ScrapMasteryEffect extends OneShotEffect { if (controller != null) { Map> exiledCards = new HashMap<>(); // exile artifacts from graveyard - for (UUID playerId : controller.getInRange()) { + for (UUID playerId : game.getState().getPlayersInRange(controller.getId(), game)) { Player player = game.getPlayer(playerId); if (player != null) { - Set cards = new HashSet<>(); - for (Card card : player.getGraveyard().getCards(new FilterArtifactCard(), game)) { - cards.add(card.getId()); - player.moveCardToExileWithInfo(card, null, "", source.getSourceId(), game, Zone.GRAVEYARD, true); - } + Set cards = player.getGraveyard().getCards(new FilterArtifactCard(), game); + controller.moveCards(cards, Zone.EXILED, source, game); exiledCards.put(player.getId(), cards); } } // sacrifice all artifacts - for (UUID playerId : controller.getInRange()) { + for (UUID playerId : game.getState().getPlayersInRange(controller.getId(), game)) { Player player = game.getPlayer(playerId); if (player != null) { for (Permanent permanent : game.getBattlefield().getAllActivePermanents(new FilterArtifactPermanent(), playerId, game)) { @@ -113,15 +110,11 @@ class ScrapMasteryEffect extends OneShotEffect { } } // puts all cards he or she exiled this way onto the battlefield - for (UUID playerId : controller.getInRange()) { + for (UUID playerId : game.getState().getPlayersInRange(controller.getId(), game)) { Player player = game.getPlayer(playerId); if (player != null) { - for (UUID cardId : exiledCards.get(playerId)) { - Card card = game.getCard(cardId); - if (card != null) { - controller.moveCards(card, Zone.EXILED, source, game); - } - } + Cards playersExiledCards = new CardsImpl(exiledCards.get(playerId)); + controller.moveCards(playersExiledCards, Zone.BATTLEFIELD, source, game); } } return true; diff --git a/Mage.Sets/src/mage/sets/commander2014/WakeTheDead.java b/Mage.Sets/src/mage/sets/commander2014/WakeTheDead.java index fc1c258ea11..eb7e9438ae7 100644 --- a/Mage.Sets/src/mage/sets/commander2014/WakeTheDead.java +++ b/Mage.Sets/src/mage/sets/commander2014/WakeTheDead.java @@ -37,8 +37,9 @@ import mage.abilities.effects.ContinuousRuleModifyingEffectImpl; import mage.abilities.effects.Effect; import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.SacrificeTargetEffect; -import mage.cards.Card; import mage.cards.CardImpl; +import mage.cards.Cards; +import mage.cards.CardsImpl; import mage.constants.CardType; import mage.constants.Duration; import mage.constants.Outcome; @@ -148,26 +149,22 @@ class WakeTheDeadReturnFromGraveyardToBattlefieldTargetEffect extends OneShotEff @Override public boolean apply(Game game, Ability source) { - Player player = game.getPlayer(source.getControllerId()); - if (player != null) { - for (UUID targetId : getTargetPointer().getTargets(game, source)) { - Card card = game.getCard(targetId); - if (card != null) { - if (player.putOntoBattlefieldWithInfo(card, game, Zone.GRAVEYARD, source.getSourceId(), false)) { - 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", source.getControllerId()); - effect.setTargetPointer(new FixedTarget(permanent, game)); - DelayedTriggeredAbility delayedAbility = new AtTheBeginOfNextEndStepDelayedTriggeredAbility(effect); - delayedAbility.setSourceId(source.getSourceId()); - delayedAbility.setControllerId(source.getControllerId()); - delayedAbility.setSourceObject(source.getSourceObject(game), game); - game.addDelayedTriggeredAbility(delayedAbility); - } - - } + Player controller = game.getPlayer(source.getControllerId()); + if (controller != null) { + Cards cards = new CardsImpl(getTargetPointer().getTargets(game, source)); + controller.moveCards(cards, Zone.BATTLEFIELD, source, game); + for (UUID targetId : cards) { + Permanent creature = game.getPermanent(targetId); + if (creature != null) { + Effect effect = new SacrificeTargetEffect("Sacrifice those creatures at the beginning of the next end step", source.getControllerId()); + effect.setTargetPointer(new FixedTarget(creature, game)); + DelayedTriggeredAbility delayedAbility = new AtTheBeginOfNextEndStepDelayedTriggeredAbility(effect); + 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/WaveOfVitriol.java b/Mage.Sets/src/mage/sets/commander2014/WaveOfVitriol.java index 19994d3145c..bb5bb951b94 100644 --- a/Mage.Sets/src/mage/sets/commander2014/WaveOfVitriol.java +++ b/Mage.Sets/src/mage/sets/commander2014/WaveOfVitriol.java @@ -28,12 +28,15 @@ package mage.sets.commander2014; import java.util.HashMap; +import java.util.LinkedHashSet; import java.util.Map; +import java.util.Set; import java.util.UUID; import mage.abilities.Ability; import mage.abilities.effects.OneShotEffect; -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; @@ -86,9 +89,9 @@ class WaveOfVitriolEffect extends OneShotEffect { new CardTypePredicate(CardType.LAND), Predicates.not(new SupertypePredicate("Basic")) ) - )); } + public WaveOfVitriolEffect() { super(Outcome.Benefit); this.staticText = "Each player sacrifices all artifacts, enchantments, and nonbasic lands he or she controls. For each land sacrificed this way, its controller may search his or her library for a basic land card and put it onto the battlefield tapped. Then each player who searched his or her library this way shuffles it"; @@ -108,11 +111,11 @@ class WaveOfVitriolEffect extends OneShotEffect { Player controller = game.getPlayer(source.getControllerId()); if (controller != null) { Map sacrificedLands = new HashMap<>(); - for(UUID playerId: controller.getInRange()) { + for (UUID playerId : controller.getInRange()) { Player player = game.getPlayer(playerId); if (player != null) { int count = 0; - for(Permanent permanent: game.getBattlefield().getAllActivePermanents(filter, playerId, game)) { + for (Permanent permanent : game.getBattlefield().getAllActivePermanents(filter, playerId, game)) { if (permanent.sacrifice(source.getSourceId(), game) && permanent.getCardType().contains(CardType.LAND)) { count++; } @@ -123,25 +126,19 @@ class WaveOfVitriolEffect extends OneShotEffect { } } game.getState().handleSimultaneousEvent(game); - for(Map.Entry entry: sacrificedLands.entrySet()) { + Cards toBattlefield = new CardsImpl(); + Set playersToShuffle = new LinkedHashSet<>(); + for (Map.Entry entry : sacrificedLands.entrySet()) { if (entry.getKey().chooseUse(Outcome.PutLandInPlay, "Search your library for up to " + entry.getValue() + " basic lands?", source, game)) { Target target = new TargetCardInLibrary(0, entry.getValue(), new FilterBasicLandCard()); entry.getKey().chooseTarget(outcome, target, source, game); - for(UUID targetId: target.getTargets()) { - Card card = game.getCard(targetId); - if (card != null) { - entry.getKey().putOntoBattlefieldWithInfo(card, game, Zone.LIBRARY, source.getSourceId(), true); - } - } - entry.getKey().shuffleLibrary(game); - } else { - entry.setValue(0); + toBattlefield.addAll(target.getTargets()); + playersToShuffle.add(entry.getKey()); } } - for(Map.Entry entry: sacrificedLands.entrySet()) { - if (entry.getValue() > 0) { - entry.getKey().shuffleLibrary(game); - } + controller.moveCards(toBattlefield.getCards(game), Zone.BATTLEFIELD, source, game, true, false, true, null); + for (Player player : playersToShuffle) { + player.shuffleLibrary(game); } return true; diff --git a/Mage.Sets/src/mage/sets/conflux/PathToExile.java b/Mage.Sets/src/mage/sets/conflux/PathToExile.java index bc78ddb72ef..63f6a0c889a 100644 --- a/Mage.Sets/src/mage/sets/conflux/PathToExile.java +++ b/Mage.Sets/src/mage/sets/conflux/PathToExile.java @@ -1,31 +1,30 @@ /* -* Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. -* -* Redistribution and use in source and binary forms, with or without modification, are -* permitted provided that the following conditions are met: -* -* 1. Redistributions of source code must retain the above copyright notice, this list of -* conditions and the following disclaimer. -* -* 2. Redistributions in binary form must reproduce the above copyright notice, this list -* of conditions and the following disclaimer in the documentation and/or other materials -* provided with the distribution. -* -* THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED -* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND -* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR -* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR -* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON -* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING -* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF -* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -* -* The views and conclusions contained in the software and documentation are those of the -* authors and should not be interpreted as representing official policies, either expressed -* or implied, of BetaSteward_at_googlemail.com. -*/ - + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ package mage.sets.conflux; import java.util.UUID; @@ -52,7 +51,7 @@ public class PathToExile extends CardImpl { public PathToExile(UUID ownerId) { super(ownerId, 15, "Path to Exile", Rarity.UNCOMMON, new CardType[]{CardType.INSTANT}, "{W}"); - this.expansionSetCode = "CON"; + this.expansionSetCode = "CON"; // Exile target creature. Its controller may search his or her library for a basic land card, // put that card onto the battlefield tapped, then shuffle his or her library. @@ -93,13 +92,13 @@ class PathToExileEffect extends OneShotEffect { if (controller != null && permanent != null) { Player player = game.getPlayer(permanent.getControllerId()); // if the zone change to exile gets replaced does not prevent the target controller to be able to search - controller.moveCardToExileWithInfo(permanent, null, "", source.getSourceId(), game, Zone.BATTLEFIELD, true); + controller.moveCardToExileWithInfo(permanent, null, "", source.getSourceId(), game, Zone.BATTLEFIELD, true); if (player.chooseUse(Outcome.PutCardInPlay, "Search your library for a basic land card?", source, game)) { TargetCardInLibrary target = new TargetCardInLibrary(new FilterBasicLandCard()); if (player.searchLibrary(target, game)) { Card card = player.getLibrary().getCard(target.getFirstTarget(), game); if (card != null) { - player.putOntoBattlefieldWithInfo(card, game, Zone.LIBRARY, source.getSourceId(), true); + controller.moveCards(card, Zone.BATTLEFIELD, source, game, true, false, false, null); } } player.shuffleLibrary(game); diff --git a/Mage.Sets/src/mage/sets/conflux/SkywardEyeProphets.java b/Mage.Sets/src/mage/sets/conflux/SkywardEyeProphets.java index 09778edade8..e70912fe986 100644 --- a/Mage.Sets/src/mage/sets/conflux/SkywardEyeProphets.java +++ b/Mage.Sets/src/mage/sets/conflux/SkywardEyeProphets.java @@ -106,9 +106,9 @@ public class SkywardEyeProphets extends CardImpl { cards.add(card); controller.revealCards(sourceObject.getName(), cards, game); if (card.getCardType().contains(CardType.LAND)) { - return controller.putOntoBattlefieldWithInfo(card, game, Zone.LIBRARY, source.getSourceId()); + return controller.moveCards(card, Zone.BATTLEFIELD, source, game); } else { - controller.moveCards(card, null, Zone.HAND, source, game); + controller.moveCards(card, Zone.HAND, source, game); } } return true; diff --git a/Mage.Sets/src/mage/sets/conspiracy/GrenzoDungeonWarden.java b/Mage.Sets/src/mage/sets/conspiracy/GrenzoDungeonWarden.java index 2a152f5c5d6..855d62758c7 100644 --- a/Mage.Sets/src/mage/sets/conspiracy/GrenzoDungeonWarden.java +++ b/Mage.Sets/src/mage/sets/conspiracy/GrenzoDungeonWarden.java @@ -106,7 +106,7 @@ class GrenzoDungeonWardenEffect extends OneShotEffect { if (card.getCardType().contains(CardType.CREATURE)) { Permanent sourcePermanent = game.getPermanentOrLKIBattlefield(source.getSourceId()); if (sourcePermanent != null && card.getPower().getValue() <= sourcePermanent.getPower().getValue()) { - controller.putOntoBattlefieldWithInfo(card, game, Zone.GRAVEYARD, source.getSourceId()); + controller.moveCards(card, Zone.BATTLEFIELD, source, game); } } } diff --git a/Mage.Sets/src/mage/sets/conspiracy/Victimize.java b/Mage.Sets/src/mage/sets/conspiracy/Victimize.java index 5f8a7bf3fc4..a49a512c2d3 100644 --- a/Mage.Sets/src/mage/sets/conspiracy/Victimize.java +++ b/Mage.Sets/src/mage/sets/conspiracy/Victimize.java @@ -31,8 +31,8 @@ import java.util.UUID; import mage.abilities.Ability; import mage.abilities.costs.common.SacrificeTargetCost; import mage.abilities.effects.OneShotEffect; -import mage.cards.Card; import mage.cards.CardImpl; +import mage.cards.CardsImpl; import mage.constants.CardType; import mage.constants.Outcome; import mage.constants.Rarity; @@ -70,36 +70,32 @@ public class Victimize extends CardImpl { } class VictimizeEffect extends OneShotEffect { - + VictimizeEffect() { super(Outcome.PutCreatureInPlay); this.staticText = "Choose two target creature cards in your graveyard. Sacrifice a creature. If you do, return the chosen cards to the battlefield tapped"; } - + VictimizeEffect(final VictimizeEffect effect) { super(effect); } - + @Override public VictimizeEffect copy() { return new VictimizeEffect(this); } - + @Override public boolean apply(Game game, Ability source) { Player controller = game.getPlayer(source.getControllerId()); if (controller != null) { SacrificeTargetCost cost = new SacrificeTargetCost(new TargetControlledCreaturePermanent(new FilterControlledCreaturePermanent("a creature"))); if (cost.pay(source, game, source.getSourceId(), source.getControllerId(), false)) { - for (UUID targetId: getTargetPointer().getTargets(game, source)) { - Card card = game.getCard(targetId); - if (card != null) { - controller.putOntoBattlefieldWithInfo(card, game, Zone.GRAVEYARD, source.getSourceId(), true); - } - } + controller.moveCards(new CardsImpl(getTargetPointer().getTargets(game, source)).getCards(game), + Zone.BATTLEFIELD, source, game, true, false, false, null); } return true; } return false; - } + } } diff --git a/Mage.Sets/src/mage/sets/darkascension/MikaeusTheUnhallowed.java b/Mage.Sets/src/mage/sets/darkascension/MikaeusTheUnhallowed.java index 99831fe3acc..6b0ca36525a 100644 --- a/Mage.Sets/src/mage/sets/darkascension/MikaeusTheUnhallowed.java +++ b/Mage.Sets/src/mage/sets/darkascension/MikaeusTheUnhallowed.java @@ -28,10 +28,6 @@ package mage.sets.darkascension; import java.util.UUID; -import mage.constants.CardType; -import mage.constants.Duration; -import mage.constants.Rarity; -import mage.constants.Zone; import mage.MageInt; import mage.abilities.TriggeredAbilityImpl; import mage.abilities.common.SimpleStaticAbility; @@ -41,6 +37,10 @@ import mage.abilities.effects.common.continuous.GainAbilityControlledEffect; import mage.abilities.keyword.IntimidateAbility; import mage.abilities.keyword.UndyingAbility; 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; @@ -74,6 +74,7 @@ public class MikaeusTheUnhallowed extends CardImpl { this.addAbility(IntimidateAbility.getInstance()); // Whenever a Human deals damage to you, destroy it. this.addAbility(new MikaeusTheUnhallowedAbility()); + // Other non-Human creatures you control get +1/+1 and have undying. this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new BoostControlledEffect(1, 1, Duration.WhileOnBattlefield, filter, true))); this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new GainAbilityControlledEffect(new UndyingAbility(), Duration.WhileOnBattlefield, filter, true))); @@ -109,7 +110,6 @@ class MikaeusTheUnhallowedAbility extends TriggeredAbilityImpl { return event.getType() == GameEvent.EventType.DAMAGED_PLAYER; } - @Override public boolean checkTrigger(GameEvent event, Game game) { if (event.getTargetId().equals(this.controllerId)) { diff --git a/Mage.Sets/src/mage/sets/darksteel/Reshape.java b/Mage.Sets/src/mage/sets/darksteel/Reshape.java index 28303ac7d8d..c1472d3c268 100644 --- a/Mage.Sets/src/mage/sets/darksteel/Reshape.java +++ b/Mage.Sets/src/mage/sets/darksteel/Reshape.java @@ -28,15 +28,14 @@ package mage.sets.darksteel; import java.util.UUID; - -import mage.constants.CardType; -import mage.constants.Rarity; import mage.abilities.Ability; import mage.abilities.costs.common.SacrificeTargetCost; import mage.abilities.effects.OneShotEffect; import mage.cards.Card; import mage.cards.CardImpl; +import mage.constants.CardType; import mage.constants.Outcome; +import mage.constants.Rarity; import mage.constants.Zone; import mage.filter.Filter; import mage.filter.FilterCard; @@ -64,7 +63,6 @@ public class Reshape extends CardImpl { super(ownerId, 31, "Reshape", Rarity.RARE, new CardType[]{CardType.SORCERY}, "{X}{U}{U}"); this.expansionSetCode = "DST"; - // As an additional cost to cast Reshape, sacrifice an artifact. this.getSpellAbility().addCost(new SacrificeTargetCost(new TargetControlledPermanent(1, 1, filter, false))); // Search your library for an artifact card with converted mana cost X or less and put it onto the battlefield. Then shuffle your library. @@ -94,8 +92,8 @@ class ReshapeSearchEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { - Player player = game.getPlayer(source.getControllerId()); - if (player == null) { + Player controller = game.getPlayer(source.getControllerId()); + if (controller == null) { return false; } //Set the mana cost one higher to 'emulate' a less than or equal to comparison. @@ -104,17 +102,17 @@ class ReshapeSearchEffect extends OneShotEffect { filter.add(new CardTypePredicate(CardType.ARTIFACT)); filter.add(new ConvertedManaCostPredicate(Filter.ComparisonType.LessThan, xValue)); TargetCardInLibrary target = new TargetCardInLibrary(filter); - if (player.searchLibrary(target, game)) { + if (controller.searchLibrary(target, game)) { if (target.getTargets().size() > 0) { - Card card = player.getLibrary().getCard(target.getFirstTarget(), game); + Card card = controller.getLibrary().getCard(target.getFirstTarget(), game); if (card != null) { - player.putOntoBattlefieldWithInfo(card, game, Zone.LIBRARY, source.getSourceId()); + controller.moveCards(card, Zone.BATTLEFIELD, source, game); } } - player.shuffleLibrary(game); + controller.shuffleLibrary(game); return true; } - player.shuffleLibrary(game); + controller.shuffleLibrary(game); return false; } diff --git a/Mage.Sets/src/mage/sets/dissension/CryptChampion.java b/Mage.Sets/src/mage/sets/dissension/CryptChampion.java index 894a5fdff35..7d29bfdf552 100644 --- a/Mage.Sets/src/mage/sets/dissension/CryptChampion.java +++ b/Mage.Sets/src/mage/sets/dissension/CryptChampion.java @@ -69,10 +69,10 @@ public class CryptChampion extends CardImpl { // Double strike this.addAbility(DoubleStrikeAbility.getInstance()); - + // When Crypt Champion enters the battlefield, each player puts a creature card with converted mana cost 3 or less from his or her graveyard onto the battlefield. this.addAbility(new EntersBattlefieldTriggeredAbility(new CryptChampionEffect())); - + // When Crypt Champion enters the battlefield, sacrifice it unless {R} was spent to cast it. this.addAbility(new EntersBattlefieldTriggeredAbility(new SacrificeSourceUnlessConditionEffect(new ManaWasSpentCondition(ColoredManaSymbol.R)), false), new ManaSpentToCastWatcher()); } @@ -88,26 +88,26 @@ public class CryptChampion extends CardImpl { } class CryptChampionEffect extends OneShotEffect { - + CryptChampionEffect() { super(Outcome.PutCreatureInPlay); this.staticText = "each player puts a creature card with converted mana cost 3 or less from his or her graveyard onto the battlefield"; } - + CryptChampionEffect(final CryptChampionEffect effect) { super(effect); } - + @Override public CryptChampionEffect copy() { return new CryptChampionEffect(this); } - + @Override public boolean apply(Game game, Ability source) { Player controller = game.getPlayer(source.getControllerId()); if (controller != null) { - for (UUID playerId : controller.getInRange()) { + for (UUID playerId : game.getState().getPlayersInRange(controller.getId(), game)) { Player player = game.getPlayer(playerId); if (player != null) { FilterCard filter = new FilterCreatureCard("creature card with converted mana cost 3 or less from your graveyard"); @@ -117,7 +117,7 @@ class CryptChampionEffect extends OneShotEffect { if (target.canChoose(playerId, game) && player.chooseTarget(outcome, target, source, game)) { Card card = game.getCard(target.getFirstTarget()); if (card != null) { - player.putOntoBattlefieldWithInfo(card, game, Zone.GRAVEYARD, source.getSourceId()); + player.moveCards(card, Zone.BATTLEFIELD, source, game); } } } diff --git a/Mage.Sets/src/mage/sets/dragonsmaze/BloodBaronOfVizkopa.java b/Mage.Sets/src/mage/sets/dragonsmaze/BloodBaronOfVizkopa.java index 24af9bc9355..d675c36e768 100644 --- a/Mage.Sets/src/mage/sets/dragonsmaze/BloodBaronOfVizkopa.java +++ b/Mage.Sets/src/mage/sets/dragonsmaze/BloodBaronOfVizkopa.java @@ -25,17 +25,9 @@ * 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.Duration; -import mage.constants.Layer; -import mage.constants.Outcome; -import mage.constants.Rarity; -import mage.constants.SubLayer; -import mage.constants.Zone; import mage.MageInt; import mage.ObjectColor; import mage.abilities.Ability; @@ -45,6 +37,13 @@ import mage.abilities.keyword.FlyingAbility; import mage.abilities.keyword.LifelinkAbility; import mage.abilities.keyword.ProtectionAbility; import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.Layer; +import mage.constants.Outcome; +import mage.constants.Rarity; +import mage.constants.SubLayer; +import mage.constants.Zone; import mage.filter.FilterCard; import mage.filter.predicate.Predicates; import mage.filter.predicate.mageobject.ColorPredicate; @@ -52,27 +51,21 @@ import mage.game.Game; import mage.game.permanent.Permanent; import mage.players.Player; -/** - * - * @author LevelX2 - */ - - public class BloodBaronOfVizkopa extends CardImpl { private static final FilterCard filter = new FilterCard("white and from black"); + static { filter.add(Predicates.or( new ColorPredicate(ObjectColor.WHITE), new ColorPredicate(ObjectColor.BLACK))); } - public BloodBaronOfVizkopa (UUID ownerId) { + public BloodBaronOfVizkopa(UUID ownerId) { super(ownerId, 57, "Blood Baron of Vizkopa", Rarity.MYTHIC, new CardType[]{CardType.CREATURE}, "{3}{W}{B}"); this.expansionSetCode = "DGM"; this.subtype.add("Vampire"); - this.power = new MageInt(4); this.toughness = new MageInt(4); @@ -85,7 +78,7 @@ public class BloodBaronOfVizkopa extends CardImpl { } - public BloodBaronOfVizkopa (final BloodBaronOfVizkopa card) { + public BloodBaronOfVizkopa(final BloodBaronOfVizkopa card) { super(card); } @@ -97,7 +90,7 @@ public class BloodBaronOfVizkopa extends CardImpl { } class BloodBaronOfVizkopaEffect extends ContinuousEffectImpl { - + public BloodBaronOfVizkopaEffect() { super(Duration.WhileOnBattlefield, Outcome.BoostCreature); staticText = "As long as you have 30 or more life and an opponent has 10 or less life, {this} gets +6/+6 and has flying"; @@ -117,21 +110,21 @@ class BloodBaronOfVizkopaEffect extends ContinuousEffectImpl { if (conditionState(source, game)) { Permanent creature = game.getPermanent(source.getSourceId()); if (creature != null) { - switch (layer) { - case PTChangingEffects_7: - if (sublayer == SubLayer.ModifyPT_7c) { - creature.addPower(6); - creature.addToughness(6); - } - break; - case AbilityAddingRemovingEffects_6: - if (sublayer == SubLayer.NA) { - creature.addAbility(FlyingAbility.getInstance(), source.getSourceId(), game); - } - break; - default: - } - return true; + switch (layer) { + case PTChangingEffects_7: + if (sublayer == SubLayer.ModifyPT_7c) { + creature.addPower(6); + creature.addToughness(6); + } + break; + case AbilityAddingRemovingEffects_6: + if (sublayer == SubLayer.NA) { + creature.addAbility(FlyingAbility.getInstance(), source.getSourceId(), game); + } + break; + default: + } + return true; } } return false; @@ -140,10 +133,12 @@ class BloodBaronOfVizkopaEffect extends ContinuousEffectImpl { protected boolean conditionState(Ability source, Game game) { Player player = game.getPlayer(source.getControllerId()); if (player != null && player.getLife() >= 30) { - for (UUID opponentId :player.getInRange()) { - Player opponent = game.getPlayer(opponentId); - if (opponent != null && opponent.getLife() < 11) { - return true; + for (UUID opponentId : player.getInRange()) { + if (player.hasOpponent(opponentId, game)) { + Player opponent = game.getPlayer(opponentId); + if (opponent != null && opponent.getLife() < 11) { + return true; + } } } } @@ -159,6 +154,6 @@ class BloodBaronOfVizkopaEffect extends ContinuousEffectImpl { public boolean hasLayer(Layer layer) { return (layer.equals(Layer.AbilityAddingRemovingEffects_6) || layer.equals(layer.PTChangingEffects_7)); - } + } } diff --git a/Mage.Sets/src/mage/sets/dragonsoftarkir/DeathmistRaptor.java b/Mage.Sets/src/mage/sets/dragonsoftarkir/DeathmistRaptor.java index 098a319ff68..629a1e35e6a 100644 --- a/Mage.Sets/src/mage/sets/dragonsoftarkir/DeathmistRaptor.java +++ b/Mage.Sets/src/mage/sets/dragonsoftarkir/DeathmistRaptor.java @@ -101,9 +101,9 @@ class DeathmistRaptorEffect extends OneShotEffect { Player controller = game.getPlayer(source.getControllerId()); MageObject sourceObject = source.getSourceObjectIfItStillExists(game); if (controller != null && (sourceObject instanceof Card)) { - controller.putOntoBattlefieldWithInfo((Card) sourceObject, game, Zone.GRAVEYARD, source.getSourceId(), false, - controller.chooseUse(Outcome.Detriment, "Return " + sourceObject.getLogName() + " face down to battlefield (otherwise face up)?", source, game)); - return true; + return controller.moveCards((Card) sourceObject, Zone.BATTLEFIELD, source, game, false, + controller.chooseUse(Outcome.Detriment, "Return " + sourceObject.getLogName() + " face down to battlefield (otherwise face up)?", source, game), + false, null); } return false; } diff --git a/Mage.Sets/src/mage/sets/dragonsoftarkir/SwiftWarkite.java b/Mage.Sets/src/mage/sets/dragonsoftarkir/SwiftWarkite.java index 7cf4b87280b..bfd5b48ff0d 100644 --- a/Mage.Sets/src/mage/sets/dragonsoftarkir/SwiftWarkite.java +++ b/Mage.Sets/src/mage/sets/dragonsoftarkir/SwiftWarkite.java @@ -122,7 +122,7 @@ class SwiftWarkiteEffect extends OneShotEffect { controller.choose(outcome, target, source.getSourceId(), game); Card card = controller.getHand().get(target.getFirstTarget(), game); if (card != null) { - if (controller.putOntoBattlefieldWithInfo(card, game, Zone.HAND, source.getSourceId())) { + if (controller.moveCards(card, Zone.BATTLEFIELD, source, game)) { Permanent creature = game.getPermanent(card.getId()); if (creature != null) { ContinuousEffect effect = new GainAbilityTargetEffect(HasteAbility.getInstance(), Duration.Custom); @@ -143,7 +143,7 @@ class SwiftWarkiteEffect extends OneShotEffect { target.choose(Outcome.PutCardInPlay, source.getControllerId(), source.getSourceId(), game); Card card = controller.getGraveyard().get(target.getFirstTarget(), game); if (card != null) { - controller.putOntoBattlefieldWithInfo(card, game, Zone.GRAVEYARD, source.getSourceId()); + controller.moveCards(card, Zone.BATTLEFIELD, source, game); Permanent creature = game.getPermanent(card.getId()); if (creature != null) { ContinuousEffect effect = new GainAbilityTargetEffect(HasteAbility.getInstance(), Duration.Custom); diff --git a/Mage.Sets/src/mage/sets/elvesvsgoblins/SkirkDrillSergeant.java b/Mage.Sets/src/mage/sets/elvesvsgoblins/SkirkDrillSergeant.java index 55756cd3dbf..c5abcd76b27 100644 --- a/Mage.Sets/src/mage/sets/elvesvsgoblins/SkirkDrillSergeant.java +++ b/Mage.Sets/src/mage/sets/elvesvsgoblins/SkirkDrillSergeant.java @@ -37,7 +37,6 @@ import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.DoIfCostPaid; import mage.cards.Card; import mage.cards.CardImpl; -import mage.cards.Cards; import mage.cards.CardsImpl; import mage.constants.CardType; import mage.constants.Outcome; @@ -108,23 +107,20 @@ class SkirkDrillSergeantEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { - Player player = game.getPlayer(source.getControllerId()); + Player controller = game.getPlayer(source.getControllerId()); MageObject sourceObject = game.getObject(source.getSourceId()); - if (player == null || sourceObject == null) { + if (controller == null || sourceObject == null) { return false; } - if (player.getLibrary().size() > 0) { - Card card = player.getLibrary().getFromTop(game); - Cards cards = new CardsImpl(); - cards.add(card); - player.revealCards(sourceObject.getName(), cards, game); - + if (controller.getLibrary().size() > 0) { + Card card = controller.getLibrary().getFromTop(game); + controller.revealCards(sourceObject.getIdName(), new CardsImpl(card), game); if (card != null) { if (filter.match(card, game)) { - player.putOntoBattlefieldWithInfo(card, game, Zone.LIBRARY, source.getSourceId()); + controller.moveCards(card, Zone.BATTLEFIELD, source, game); } else { - player.moveCards(card, Zone.LIBRARY, Zone.GRAVEYARD, source, game); + controller.moveCards(card, Zone.GRAVEYARD, source, game); } } } diff --git a/Mage.Sets/src/mage/sets/exodus/OathOfDruids.java b/Mage.Sets/src/mage/sets/exodus/OathOfDruids.java index e08f682393c..e613109d666 100644 --- a/Mage.Sets/src/mage/sets/exodus/OathOfDruids.java +++ b/Mage.Sets/src/mage/sets/exodus/OathOfDruids.java @@ -65,7 +65,6 @@ public class OathOfDruids extends CardImpl { super(ownerId, 115, "Oath of Druids", Rarity.RARE, new CardType[]{CardType.ENCHANTMENT}, "{1}{G}"); this.expansionSetCode = "EXO"; - // At the beginning of each player's upkeep, that player chooses target player who controls more creatures than he or she does and is his or her opponent. The first player may reveal cards from the top of his or her library until he or she reveals a creature card. If he or she does, that player puts that card onto the battlefield and all other cards revealed this way into his or her graveyard. Ability ability = new BeginningOfUpkeepTriggeredAbility(new OathOfDruidsEffect(), TargetController.ANY, true); ability.addTarget(new TargetPlayer(1, 1, false, filter)); @@ -136,32 +135,32 @@ class OathOfDruidsEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { MageObject sourceObject = game.getObject(source.getSourceId()); - Player player = game.getPlayer(source.getControllerId()); - if (player == null || sourceObject == null) { + Player controller = game.getPlayer(source.getControllerId()); + if (controller == null || sourceObject == null) { return false; } Cards revealed = new CardsImpl(); Card creatureCard = null; Cards nonCreatureCards = new CardsImpl(); //The first player may reveal cards from the top of his or her library - while (creatureCard == null && player.getLibrary().size() > 0) { - Card card = player.getLibrary().removeFromTop(game); + while (creatureCard == null && controller.getLibrary().size() > 0) { + Card card = controller.getLibrary().removeFromTop(game); revealed.add(card); - // until he or she reveals a creature card. + // until he or she reveals a creature card. if (card.getCardType().contains(CardType.CREATURE)) { creatureCard = card; } else { nonCreatureCards.add(card); } } - player.revealCards(sourceObject.getName(), revealed, game); + controller.revealCards(sourceObject.getIdName(), revealed, game); //If he or she does, that player puts that card onto the battlefield if (creatureCard != null) { - player.putOntoBattlefieldWithInfo(creatureCard, game, Zone.LIBRARY, source.getSourceId()); + controller.moveCards(creatureCard, Zone.BATTLEFIELD, source, game); } // and all other cards revealed this way into his or her graveyard - player.moveCards(nonCreatureCards, Zone.LIBRARY, Zone.GRAVEYARD, source, game); + controller.moveCards(nonCreatureCards, Zone.GRAVEYARD, source, game); return true; } diff --git a/Mage.Sets/src/mage/sets/exodus/OathOfLieges.java b/Mage.Sets/src/mage/sets/exodus/OathOfLieges.java index f11e6b7823e..ad31783661b 100644 --- a/Mage.Sets/src/mage/sets/exodus/OathOfLieges.java +++ b/Mage.Sets/src/mage/sets/exodus/OathOfLieges.java @@ -65,7 +65,7 @@ public class OathOfLieges extends CardImpl { this.expansionSetCode = "EXO"; // At the beginning of each player's upkeep, that player chooses target player who controls more lands than he or she does and is his or her opponent. The first player may search his or her library for a basic land card, put that card onto the battlefield, then shuffle his or her library. - Effect effect = new SearchLibraryPutInPlayTargetPlayerEffect(new TargetCardInLibrary(new FilterBasicLandCard()), false, Outcome.PutLandInPlay); + Effect effect = new SearchLibraryPutInPlayTargetPlayerEffect(new TargetCardInLibrary(new FilterBasicLandCard()), false, true, Outcome.PutLandInPlay, true); effect.setText("that player chooses target player who controls more lands than he or she does and is his or her opponent. The first player may search his or her library for a basic land card, put that card onto the battlefield, then shuffle his or her library"); Ability ability = new BeginningOfUpkeepTriggeredAbility(effect, TargetController.ANY, true); ability.addTarget(new TargetPlayer(1, 1, false, filter)); diff --git a/Mage.Sets/src/mage/sets/fatereforged/GhastlyConscription.java b/Mage.Sets/src/mage/sets/fatereforged/GhastlyConscription.java index 333415da47a..746d4f6fe9f 100644 --- a/Mage.Sets/src/mage/sets/fatereforged/GhastlyConscription.java +++ b/Mage.Sets/src/mage/sets/fatereforged/GhastlyConscription.java @@ -29,6 +29,8 @@ package mage.sets.fatereforged; import java.util.ArrayList; import java.util.Collections; +import java.util.LinkedHashSet; +import java.util.Set; import java.util.UUID; import mage.MageObjectReference; import mage.abilities.Ability; @@ -96,15 +98,18 @@ class GhastlyConscriptionEffect extends OneShotEffect { Player targetPlayer = game.getPlayer(getTargetPointer().getFirst(game, source)); if (controller != null && targetPlayer != null) { ArrayList cardsToManifest = new ArrayList<>(); - for(Card card: targetPlayer.getGraveyard().getCards(new FilterCreatureCard(), game)) { + for (Card card : targetPlayer.getGraveyard().getCards(new FilterCreatureCard(), game)) { cardsToManifest.add(card); controller.moveCardToExileWithInfo(card, null, "", source.getSourceId(), game, Zone.GRAVEYARD, true); } + if (cardsToManifest.isEmpty()) { + return true; + } Collections.shuffle(cardsToManifest); game.informPlayers(controller.getLogName() + " shuffles the face-down pile"); Ability newSource = source.copy(); newSource.setWorksFaceDown(true); - for (Card card: cardsToManifest) { + for (Card card : cardsToManifest) { ManaCosts manaCosts = null; if (card.getCardType().contains(CardType.CREATURE)) { manaCosts = card.getSpellAbility().getManaCosts(); @@ -112,13 +117,12 @@ class GhastlyConscriptionEffect extends OneShotEffect { manaCosts = new ManaCostsImpl("{0}"); } } - MageObjectReference objectReference= new MageObjectReference(card.getId(), card.getZoneChangeCounter(game) +1, game); + MageObjectReference objectReference = new MageObjectReference(card.getId(), card.getZoneChangeCounter(game) + 1, game); game.addEffect(new BecomesFaceDownCreatureEffect(manaCosts, objectReference, Duration.Custom, FaceDownType.MANIFESTED), newSource); - if (controller.putOntoBattlefieldWithInfo(card, game, Zone.EXILED, source.getSourceId(), false, true)) { - game.informPlayers(new StringBuilder(controller.getLogName()) - .append(" puts facedown card from exile onto the battlefield").toString()); - } } + Set toBattlefield = new LinkedHashSet(); + toBattlefield.addAll(cardsToManifest); + controller.moveCards(toBattlefield, Zone.BATTLEFIELD, source, game, false, true, false, null); return true; } return false; diff --git a/Mage.Sets/src/mage/sets/fatereforged/JeskaiInfiltrator.java b/Mage.Sets/src/mage/sets/fatereforged/JeskaiInfiltrator.java index 2b64b4db950..30fc48f26c6 100644 --- a/Mage.Sets/src/mage/sets/fatereforged/JeskaiInfiltrator.java +++ b/Mage.Sets/src/mage/sets/fatereforged/JeskaiInfiltrator.java @@ -29,7 +29,9 @@ package mage.sets.fatereforged; import java.util.ArrayList; import java.util.Collections; +import java.util.LinkedHashSet; import java.util.List; +import java.util.Set; import java.util.UUID; import mage.MageInt; import mage.MageObjectReference; @@ -74,7 +76,7 @@ public class JeskaiInfiltrator extends CardImpl { Effect effect = new ConditionalRestrictionEffect(new CantBeBlockedSourceEffect(), new OneControlledCreatureCondition()); effect.setText("{this} can't be blocked as long as you control no other creatures"); this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, effect)); - + // Whenever Jeskai Infiltrator deals combat damage to a player, exile it and the top card of your library in a face-down pile, shuffle that pile, then manifest those cards. this.addAbility(new DealsCombatDamageToAPlayerTriggeredAbility(new JeskaiInfiltratorEffect(), false)); } @@ -90,35 +92,35 @@ public class JeskaiInfiltrator extends CardImpl { } class JeskaiInfiltratorEffect extends OneShotEffect { - + JeskaiInfiltratorEffect() { super(Outcome.PutCreatureInPlay); this.staticText = "exile it and the top card of your library in a face-down pile, shuffle that pile, then manifest those cards"; } - + JeskaiInfiltratorEffect(final JeskaiInfiltratorEffect effect) { super(effect); } - + @Override public JeskaiInfiltratorEffect copy() { return new JeskaiInfiltratorEffect(this); } - + @Override public boolean apply(Game game, Ability source) { - Player player = game.getPlayer(source.getControllerId()); - if (player != null) { + Player controller = game.getPlayer(source.getControllerId()); + if (controller != null) { List cardsToManifest = new ArrayList<>(2); Permanent sourcePermanent = game.getPermanent(source.getSourceId()); Card sourceCard = game.getCard(source.getSourceId()); - if (sourcePermanent != null && sourceCard != null) { - player.moveCardToExileWithInfo(sourcePermanent, sourcePermanent.getId(), sourcePermanent.getIdName(), source.getSourceId(), game, Zone.BATTLEFIELD, true); + if (sourcePermanent != null && sourceCard != null) { + controller.moveCardToExileWithInfo(sourcePermanent, sourcePermanent.getId(), sourcePermanent.getIdName(), source.getSourceId(), game, Zone.BATTLEFIELD, true); cardsToManifest.add(sourceCard); } - if (sourcePermanent!= null && player.getLibrary().size() > 0) { - Card cardFromLibrary = player.getLibrary().removeFromTop(game); - player.moveCardToExileWithInfo(cardFromLibrary, sourcePermanent.getId(), sourcePermanent.getIdName(), source.getSourceId(), game, Zone.LIBRARY, true); + if (sourcePermanent != null && controller.getLibrary().size() > 0) { + Card cardFromLibrary = controller.getLibrary().removeFromTop(game); + controller.moveCardToExileWithInfo(cardFromLibrary, sourcePermanent.getId(), sourcePermanent.getIdName(), source.getSourceId(), game, Zone.LIBRARY, true); cardsToManifest.add(cardFromLibrary); } Collections.shuffle(cardsToManifest); @@ -133,13 +135,12 @@ class JeskaiInfiltratorEffect extends OneShotEffect { manaCosts = new ManaCostsImpl("{0}"); } } - MageObjectReference objectReference= new MageObjectReference(card.getId(), card.getZoneChangeCounter(game) +1, game); - game.addEffect(new BecomesFaceDownCreatureEffect(manaCosts, objectReference, Duration.Custom, FaceDownType.MANIFESTED), newSource); - if (player.putOntoBattlefieldWithInfo(card, game, Zone.EXILED, source.getSourceId(), false, true)) { - game.informPlayers(new StringBuilder(player.getLogName()) - .append(" puts facedown card from exile onto the battlefield").toString()); - } + MageObjectReference objectReference = new MageObjectReference(card.getId(), card.getZoneChangeCounter(game) + 1, game); + game.addEffect(new BecomesFaceDownCreatureEffect(manaCosts, objectReference, Duration.Custom, FaceDownType.MANIFESTED), newSource); } + Set toBattlefield = new LinkedHashSet(); + toBattlefield.addAll(cardsToManifest); + controller.moveCards(toBattlefield, Zone.BATTLEFIELD, source, game, false, true, false, null); return true; } return false; diff --git a/Mage.Sets/src/mage/sets/fatereforged/RallyTheAncestors.java b/Mage.Sets/src/mage/sets/fatereforged/RallyTheAncestors.java index 100549a277a..564996f1e27 100644 --- a/Mage.Sets/src/mage/sets/fatereforged/RallyTheAncestors.java +++ b/Mage.Sets/src/mage/sets/fatereforged/RallyTheAncestors.java @@ -46,6 +46,7 @@ import mage.filter.Filter.ComparisonType; import mage.filter.common.FilterCreatureCard; import mage.filter.predicate.mageobject.ConvertedManaCostPredicate; import mage.game.Game; +import mage.game.permanent.Permanent; import mage.players.Player; import mage.target.targetpointer.FixedTarget; @@ -99,11 +100,13 @@ class RallyTheAncestorsEffect extends OneShotEffect { FilterCreatureCard filter = new FilterCreatureCard(); filter.add(new ConvertedManaCostPredicate(ComparisonType.LessThan, xValue + 1)); Set cards = player.getGraveyard().getCards(filter, game); + player.moveCards(cards, Zone.BATTLEFIELD, source, game); for (Card card : cards) { if (card != null) { - if (player.putOntoBattlefieldWithInfo(card, game, Zone.GRAVEYARD, source.getSourceId())) { + Permanent permanent = game.getPermanent(card.getId()); + if (permanent != null) { Effect exileEffect = new ExileTargetEffect("Exile those creatures at the beginning of your next upkeep"); - exileEffect.setTargetPointer(new FixedTarget(card.getId(), card.getZoneChangeCounter(game))); + exileEffect.setTargetPointer(new FixedTarget(permanent, game)); DelayedTriggeredAbility delayedAbility = new AtTheBeginOfYourNextUpkeepDelayedTriggeredAbility(exileEffect); delayedAbility.setSourceId(source.getSourceId()); delayedAbility.setControllerId(source.getControllerId()); diff --git a/Mage.Sets/src/mage/sets/fatereforged/TorrentElemental.java b/Mage.Sets/src/mage/sets/fatereforged/TorrentElemental.java index d9590de8ffa..662d434e6df 100644 --- a/Mage.Sets/src/mage/sets/fatereforged/TorrentElemental.java +++ b/Mage.Sets/src/mage/sets/fatereforged/TorrentElemental.java @@ -97,6 +97,7 @@ class ReturnSourceFromExileToBattlefieldEffect extends OneShotEffect { this.tapped = tapped; setText(); } + public ReturnSourceFromExileToBattlefieldEffect(boolean tapped, boolean ownerControl) { super(Outcome.PutCreatureInPlay); this.tapped = tapped; @@ -135,7 +136,7 @@ class ReturnSourceFromExileToBattlefieldEffect extends OneShotEffect { return false; } - return player.putOntoBattlefieldWithInfo(card, game, Zone.EXILED, source.getSourceId(), tapped); + return player.moveCards(card, Zone.BATTLEFIELD, source, game, true, false, false, null); } private void setText() { @@ -144,7 +145,7 @@ class ReturnSourceFromExileToBattlefieldEffect extends OneShotEffect { sb.append(" tapped"); } if (ownerControl) { - sb.append(" under its owner's control"); + sb.append(" under its owner's control"); } staticText = sb.toString(); } diff --git a/Mage.Sets/src/mage/sets/fatereforged/UginTheSpiritDragon.java b/Mage.Sets/src/mage/sets/fatereforged/UginTheSpiritDragon.java index 2ebf0e1caa3..a7cbbf6bc0b 100644 --- a/Mage.Sets/src/mage/sets/fatereforged/UginTheSpiritDragon.java +++ b/Mage.Sets/src/mage/sets/fatereforged/UginTheSpiritDragon.java @@ -35,8 +35,8 @@ import mage.abilities.costs.Cost; import mage.abilities.costs.common.PayVariableLoyaltyCost; import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.DamageTargetEffect; -import mage.cards.Card; import mage.cards.CardImpl; +import mage.cards.CardsImpl; import mage.constants.CardType; import mage.constants.Outcome; import mage.constants.Rarity; @@ -154,12 +154,7 @@ class UginTheSpiritDragonEffect3 extends OneShotEffect { controller.drawCards(7, game); TargetCardInHand target = new TargetCardInHand(0, 7, new FilterPermanentCard("permanent cards")); if (controller.choose(Outcome.PutCardInPlay, target, source.getSourceId(), game)) { - for (UUID targetId : target.getTargets()) { - Card card = game.getCard(targetId); - if (card != null) { - controller.putOntoBattlefieldWithInfo(card, game, Zone.HAND, source.getControllerId()); - } - } + controller.moveCards(new CardsImpl(target.getTargets()), Zone.BATTLEFIELD, source, game); } return true; } diff --git a/Mage.Sets/src/mage/sets/fifthdawn/EndlessWhispers.java b/Mage.Sets/src/mage/sets/fifthdawn/EndlessWhispers.java index df557686aee..2e772173bb2 100644 --- a/Mage.Sets/src/mage/sets/fifthdawn/EndlessWhispers.java +++ b/Mage.Sets/src/mage/sets/fifthdawn/EndlessWhispers.java @@ -59,18 +59,17 @@ public class EndlessWhispers extends CardImpl { super(ownerId, 49, "Endless Whispers", Rarity.RARE, new CardType[]{CardType.ENCHANTMENT}, "{2}{B}{B}"); this.expansionSetCode = "5DN"; - // Each creature has "When this creature dies, choose target opponent. That player puts this card from its owner's graveyard onto the battlefield under his or her control at the beginning of the next end step." DelayedTriggeredAbility delayedAbility = new AtTheBeginOfNextEndStepDelayedTriggeredAbility(new ReturnSourceToBattlefieldEffect()); Effect effect = new CreateDelayedTriggeredAbilityEffect(delayedAbility, true); effect.setText("choose target opponent. That player puts this card from its owner's graveyard onto the battlefield under his or her control at the beginning of the next end step"); Ability gainAbility = new DiesTriggeredAbility(effect); gainAbility.addTarget(new TargetOpponent()); - + effect = new GainAbilityAllEffect(gainAbility, Duration.WhileOnBattlefield, new FilterCreaturePermanent("Each creature")); effect.setText("Each creature has \"When this creature dies, choose target opponent. That player puts this card from its owner's graveyard onto the battlefield under his or her control at the beginning of the next end step.\""); this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, effect)); - + } public EndlessWhispers(final EndlessWhispers card) { @@ -85,18 +84,17 @@ public class EndlessWhispers extends CardImpl { class ReturnSourceToBattlefieldEffect extends OneShotEffect { - public ReturnSourceToBattlefieldEffect() { this(false); } public ReturnSourceToBattlefieldEffect(boolean tapped) { super(Outcome.PutCreatureInPlay); - setText(); + staticText = "That player puts this card from its owner's graveyard onto the battlefield under his or her control"; } + public ReturnSourceToBattlefieldEffect(boolean tapped, boolean ownerControl) { super(Outcome.PutCreatureInPlay); - setText(); } public ReturnSourceToBattlefieldEffect(final ReturnSourceToBattlefieldEffect effect) { @@ -112,24 +110,19 @@ class ReturnSourceToBattlefieldEffect extends OneShotEffect { public boolean apply(Game game, Ability source) { if (!game.getState().getZone(source.getSourceId()).equals(Zone.GRAVEYARD)) { return false; - } + } Card card = game.getCard(source.getSourceId()); if (card == null) { return false; } - + Player player = game.getPlayer(source.getFirstTarget()); - - if (player == null) { + + if (player == null) { return false; - } - - return player.putOntoBattlefieldWithInfo(card, game, Zone.GRAVEYARD, source.getSourceId(), false); + } + + return player.moveCards(card, Zone.BATTLEFIELD, source, game, true, false, false, null); } - private void setText() { - StringBuilder sb = new StringBuilder("That player puts this card from its owner's graveyard onto the battlefield under his or her control"); - - } - -} \ No newline at end of file +} diff --git a/Mage.Sets/src/mage/sets/fifthdawn/MyrServitor.java b/Mage.Sets/src/mage/sets/fifthdawn/MyrServitor.java index f284a356e4c..33c27d2d941 100644 --- a/Mage.Sets/src/mage/sets/fifthdawn/MyrServitor.java +++ b/Mage.Sets/src/mage/sets/fifthdawn/MyrServitor.java @@ -34,7 +34,6 @@ import mage.abilities.common.BeginningOfUpkeepTriggeredAbility; import mage.abilities.condition.common.SourceOnBattlefieldCondition; import mage.abilities.decorator.ConditionalTriggeredAbility; import mage.abilities.effects.OneShotEffect; -import mage.cards.Card; import mage.cards.CardImpl; import mage.constants.CardType; import mage.constants.Outcome; @@ -66,7 +65,7 @@ public class MyrServitor extends CardImpl { SourceOnBattlefieldCondition.getInstance(), "At the beginning of your upkeep, if {this} is on the battlefield, each player returns all cards named Myr Servitor from his or her graveyard to the battlefield" )); - + } public MyrServitor(final MyrServitor card) { @@ -80,39 +79,38 @@ public class MyrServitor extends CardImpl { } class MyrServitorReturnEffect extends OneShotEffect { - + private static final FilterCard filter = new FilterCard("cards named Myr Servitor"); - + static { filter.add(new NamePredicate("Myr Servitor")); } - + public MyrServitorReturnEffect() { super(Outcome.PutCardInPlay); this.staticText = "if {this} is on the battlefield, each player returns all cards named Myr Servitor from his or her graveyard to the battlefield"; } - + public MyrServitorReturnEffect(final MyrServitorReturnEffect effect) { super(effect); } - + @Override public MyrServitorReturnEffect copy() { return new MyrServitorReturnEffect(this); } - + @Override public boolean apply(Game game, Ability source) { Player controller = game.getPlayer(source.getControllerId()); if (controller != null) { - for (UUID playerId: controller.getInRange()) { + for (UUID playerId : game.getState().getPlayersInRange(controller.getId(), game)) { Player player = game.getPlayer(playerId); if (player != null) { - for (Card card: player.getGraveyard().getCards(filter, game)) { - player.putOntoBattlefieldWithInfo(card, game, Zone.GRAVEYARD, source.getSourceId()); - } + controller.moveCards(player.getGraveyard().getCards(filter, game), Zone.BATTLEFIELD, source, game); } } + return true; } return false; } diff --git a/Mage.Sets/src/mage/sets/fourthedition/TheRack.java b/Mage.Sets/src/mage/sets/fourthedition/TheRack.java index a99f13634fa..bbbed87b4d3 100644 --- a/Mage.Sets/src/mage/sets/fourthedition/TheRack.java +++ b/Mage.Sets/src/mage/sets/fourthedition/TheRack.java @@ -96,7 +96,7 @@ class TheRackTriggeredAbility extends TriggeredAbilityImpl { @Override public String getRule() { - return new StringBuilder("At the beginning of the chosen player's upkeep, ").append(super.getRule()).toString(); + return "At the beginning of the chosen player's upkeep, " + super.getRule(); } } @@ -119,7 +119,7 @@ class TheRackEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { - UUID playerId = (UUID) game.getState().getValue(new StringBuilder(source.getSourceId().toString()).append("_player").toString()); + UUID playerId = (UUID) game.getState().getValue(source.getSourceId().toString() + "_player"); Player chosenPlayer = game.getPlayer(playerId); if (chosenPlayer != null) { int damage = 3 - chosenPlayer.getHand().size(); diff --git a/Mage.Sets/src/mage/sets/futuresight/SwordOfTheMeek.java b/Mage.Sets/src/mage/sets/futuresight/SwordOfTheMeek.java index eaaf39e852f..737dfd0139d 100644 --- a/Mage.Sets/src/mage/sets/futuresight/SwordOfTheMeek.java +++ b/Mage.Sets/src/mage/sets/futuresight/SwordOfTheMeek.java @@ -70,7 +70,7 @@ public class SwordOfTheMeek extends CardImpl { this.subtype.add("Equipment"); // Equipped creature gets +1/+2. - this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new BoostEquippedEffect(1,2,Duration.WhileOnBattlefield))); + this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new BoostEquippedEffect(1, 2, Duration.WhileOnBattlefield))); // Equip {2} this.addAbility(new EquipAbility(Outcome.BoostCreature, new GenericManaCost(2))); // Whenever a 1/1 creature enters the battlefield under your control, you may return Sword of the Meek from your graveyard to the battlefield, then attach it to that creature. @@ -108,7 +108,7 @@ class SwordOfTheMeekEffect extends OneShotEffect { Card equipment = game.getCard(source.getSourceId()); Player controller = game.getPlayer(source.getControllerId()); if (equipment != null && controller != null && game.getState().getZone(source.getSourceId()).equals(Zone.GRAVEYARD)) { - controller.putOntoBattlefieldWithInfo(equipment, game, Zone.GRAVEYARD, source.getSourceId()); + controller.moveCards(equipment, Zone.BATTLEFIELD, source, game); Permanent permanent = game.getPermanent(getTargetPointer().getFirst(game, source)); if (permanent != null) { return permanent.addAttachment(equipment.getId(), game); diff --git a/Mage.Sets/src/mage/sets/gatecrash/ObzedatGhostCouncil.java b/Mage.Sets/src/mage/sets/gatecrash/ObzedatGhostCouncil.java index 4435598c20d..4ebfb6bdee6 100644 --- a/Mage.Sets/src/mage/sets/gatecrash/ObzedatGhostCouncil.java +++ b/Mage.Sets/src/mage/sets/gatecrash/ObzedatGhostCouncil.java @@ -180,7 +180,7 @@ class ObzedatGhostCouncilReturnEffect extends OneShotEffect { // return it only from the own exile zone if (currentZone != null && currentZone.size() > 0) { Player owner = game.getPlayer(card.getOwnerId()); - if (owner != null && owner.putOntoBattlefieldWithInfo(card, game, Zone.EXILED, source.getSourceId())) { + if (owner != null && owner.moveCards(card, Zone.BATTLEFIELD, source, game)) { return true; } } diff --git a/Mage.Sets/src/mage/sets/iceage/DanceOfTheDead.java b/Mage.Sets/src/mage/sets/iceage/DanceOfTheDead.java index 5f308525d87..126046c1d68 100644 --- a/Mage.Sets/src/mage/sets/iceage/DanceOfTheDead.java +++ b/Mage.Sets/src/mage/sets/iceage/DanceOfTheDead.java @@ -78,13 +78,12 @@ public class DanceOfTheDead extends CardImpl { this.expansionSetCode = "ICE"; this.subtype.add("Aura"); - // Enchant creature card in a graveyard TargetCardInGraveyard auraTarget = new TargetCardInGraveyard(new FilterCreatureCard("creature card in a graveyard")); this.getSpellAbility().addTarget(auraTarget); this.getSpellAbility().addEffect(new DanceOfTheDeadAttachEffect(Outcome.PutCreatureInPlay)); Ability enchantAbility = new EnchantAbility(auraTarget.getTargetName()); - this.addAbility(enchantAbility); + this.addAbility(enchantAbility); // When Dance of the Dead enters the battlefield, if it's on the battlefield, it loses "enchant creature card in a graveyard" and gains "enchant creature put onto the battlefield with Dance of the Dead." Put enchanted creature card to the battlefield tapped under your control and attach Dance of the Dead to it. When Dance of the Dead leaves the battlefield, that creature's controller sacrifices it. Ability ability = new ConditionalTriggeredAbility( new EntersBattlefieldTriggeredAbility(new DanceOfTheDeadReAttachEffect(), false), @@ -92,18 +91,18 @@ public class DanceOfTheDead extends CardImpl { "When {this} enters the battlefield, if it's on the battlefield, it loses \"enchant creature card in a graveyard\" and gains \"enchant creature put onto the battlefield with {this}.\" Return enchanted creature card to the battlefield under your control and attach {this} to it."); ability.addEffect(new DanceOfTheDeadChangeAbilityEffect()); this.addAbility(ability); - this.addAbility(new LeavesBattlefieldTriggeredAbility(new DanceOfTheDeadLeavesBattlefieldTriggeredEffect(), false)); - + this.addAbility(new LeavesBattlefieldTriggeredAbility(new DanceOfTheDeadLeavesBattlefieldTriggeredEffect(), false)); + // Enchanted creature gets +1/+1 and doesn't untap during its controller's untap step. ability = new SimpleStaticAbility(Zone.BATTLEFIELD, new BoostEnchantedEffect(1, 1, Duration.WhileOnBattlefield)); Effect effect = new DontUntapInControllersUntapStepEnchantedEffect(); effect.setText("and doesn't untap during its controller's untap step"); ability.addEffect(effect); this.addAbility(ability); - + // At the beginning of the upkeep of enchanted creature's controller, that player may pay {1}{B}. If he or she does, untap that creature. this.addAbility(new BeginningOfUpkeepTriggeredAbility(Zone.BATTLEFIELD, new DanceOfTheDeadDoIfCostPaidEffect(), TargetController.CONTROLLER_ATTACHED_TO, false)); - + } public DanceOfTheDead(final DanceOfTheDead card) { @@ -117,36 +116,36 @@ public class DanceOfTheDead extends CardImpl { } class DanceOfTheDeadReAttachEffect extends OneShotEffect { - + public DanceOfTheDeadReAttachEffect() { super(Outcome.Benefit); this.staticText = "Return enchanted creature card to the battlefield under your control and attach {this} to it"; } - + public DanceOfTheDeadReAttachEffect(final DanceOfTheDeadReAttachEffect effect) { super(effect); } - + @Override public DanceOfTheDeadReAttachEffect copy() { return new DanceOfTheDeadReAttachEffect(this); } - + @Override public boolean apply(Game game, Ability source) { Player controller = game.getPlayer(source.getControllerId()); Permanent enchantment = game.getPermanent(source.getSourceId()); - + if (controller != null && enchantment != null) { Card cardInGraveyard = game.getCard(enchantment.getAttachedTo()); if (cardInGraveyard == null) { return true; } - + // put card into play - controller.putOntoBattlefieldWithInfo(cardInGraveyard, game, Zone.GRAVEYARD, source.getSourceId(), true); + controller.moveCards(cardInGraveyard, Zone.BATTLEFIELD, source, game, true, false, false, null); Permanent enchantedCreature = game.getPermanent(cardInGraveyard.getId()); - + FilterCreaturePermanent filter = new FilterCreaturePermanent("enchant creature put onto the battlefield with Dance of the Dead"); filter.add(new PermanentIdPredicate(cardInGraveyard.getId())); Target target = new TargetCreaturePermanent(filter); @@ -159,27 +158,27 @@ class DanceOfTheDeadReAttachEffect extends OneShotEffect { } return true; } - + return false; } } - + class DanceOfTheDeadLeavesBattlefieldTriggeredEffect extends OneShotEffect { - + public DanceOfTheDeadLeavesBattlefieldTriggeredEffect() { super(Outcome.Benefit); this.staticText = "enchanted creature's controller sacrifices it"; } - + public DanceOfTheDeadLeavesBattlefieldTriggeredEffect(final DanceOfTheDeadLeavesBattlefieldTriggeredEffect effect) { super(effect); } - + @Override public DanceOfTheDeadLeavesBattlefieldTriggeredEffect copy() { return new DanceOfTheDeadLeavesBattlefieldTriggeredEffect(this); } - + @Override public boolean apply(Game game, Ability source) { Player controller = game.getPlayer(source.getControllerId()); @@ -236,17 +235,16 @@ class DanceOfTheDeadAttachEffect extends OneShotEffect { class DanceOfTheDeadChangeAbilityEffect extends ContinuousEffectImpl implements SourceEffect { private final static Ability newAbility = new EnchantAbility("creature put onto the battlefield with Dance of the Dead"); - + static { newAbility.setRuleAtTheTop(true); } - + public DanceOfTheDeadChangeAbilityEffect() { super(Duration.WhileOnBattlefield, Layer.AbilityAddingRemovingEffects_6, SubLayer.NA, Outcome.AddAbility); staticText = "it loses \"enchant creature card in a graveyard\" and gains \"enchant creature put onto the battlefield with Dance of the Dead\""; } - public DanceOfTheDeadChangeAbilityEffect(final DanceOfTheDeadChangeAbilityEffect effect) { super(effect); } @@ -255,7 +253,7 @@ class DanceOfTheDeadChangeAbilityEffect extends ContinuousEffectImpl implements public DanceOfTheDeadChangeAbilityEffect copy() { return new DanceOfTheDeadChangeAbilityEffect(this); } - + @Override public void init(Ability source, Game game) { super.init(source, game); @@ -267,7 +265,7 @@ class DanceOfTheDeadChangeAbilityEffect extends ContinuousEffectImpl implements Permanent permanent = affectedObjectList.get(0).getPermanent(game);; if (permanent != null) { Ability abilityToRemove = null; - for (Ability ability: permanent.getAbilities()) { + for (Ability ability : permanent.getAbilities()) { if (ability instanceof EnchantAbility) { abilityToRemove = ability; } @@ -277,7 +275,7 @@ class DanceOfTheDeadChangeAbilityEffect extends ContinuousEffectImpl implements } permanent.addAbility(newAbility, source.getSourceId(), game); return true; - } + } return false; } } @@ -309,4 +307,4 @@ class DanceOfTheDeadDoIfCostPaidEffect extends DoIfCostPaid { return new StringBuilder("that player may ").append(getCostText()) .append(". If he or she does, ").append(executingEffects.getText(mode)).toString(); } -} \ No newline at end of file +} diff --git a/Mage.Sets/src/mage/sets/innistrad/CaravanVigil.java b/Mage.Sets/src/mage/sets/innistrad/CaravanVigil.java index 4dc4e3bd417..7bbd95e03b1 100644 --- a/Mage.Sets/src/mage/sets/innistrad/CaravanVigil.java +++ b/Mage.Sets/src/mage/sets/innistrad/CaravanVigil.java @@ -96,13 +96,12 @@ class CaravanVigilEffect extends OneShotEffect { if (controller.searchLibrary(target, game)) { Card card = controller.getLibrary().getCard(target.getFirstTarget(), game); if (card != null) { - Cards cards = new CardsImpl(); - cards.add(card); + Cards cards = new CardsImpl(card); if (MorbidCondition.getInstance().apply(game, source) && controller.chooseUse(Outcome.PutLandInPlay, "Do you wish to put the card onto the battlefield instead?", source, game)) { - controller.putOntoBattlefieldWithInfo(card, game, Zone.LIBRARY, source.getSourceId()); + controller.moveCards(card, Zone.BATTLEFIELD, source, game); } else { - controller.moveCards(card, null, Zone.HAND, source, game); + controller.moveCards(card, Zone.HAND, source, game); } controller.revealCards(sourceObject.getIdName(), cards, game); } diff --git a/Mage.Sets/src/mage/sets/innistrad/GhostQuarter.java b/Mage.Sets/src/mage/sets/innistrad/GhostQuarter.java index aeba8786b36..5d05bc28c57 100644 --- a/Mage.Sets/src/mage/sets/innistrad/GhostQuarter.java +++ b/Mage.Sets/src/mage/sets/innistrad/GhostQuarter.java @@ -98,16 +98,16 @@ class GhostQuarterEffect extends OneShotEffect { public boolean apply(Game game, Ability source) { Permanent permanent = (Permanent) game.getPermanentOrLKIBattlefield(source.getFirstTarget()); // if indestructible effect should work also if (permanent != null) { - Player player = game.getPlayer(permanent.getControllerId()); - if (player.chooseUse(Outcome.PutLandInPlay, "Do you wish to search for a basic land, put it onto the battlefield and then shuffle your library?", source, game)) { + Player controller = game.getPlayer(permanent.getControllerId()); + if (controller.chooseUse(Outcome.PutLandInPlay, "Do you wish to search for a basic land, put it onto the battlefield and then shuffle your library?", source, game)) { TargetCardInLibrary target = new TargetCardInLibrary(new FilterBasicLandCard()); - if (player.searchLibrary(target, game)) { - Card card = player.getLibrary().getCard(target.getFirstTarget(), game); - if (card != null) { - player.putOntoBattlefieldWithInfo(card, game, Zone.LIBRARY, source.getSourceId()); + if (controller.searchLibrary(target, game)) { + Card card = controller.getLibrary().getCard(target.getFirstTarget(), game); + if (card != null) { + controller.moveCards(card, Zone.BATTLEFIELD, source, game); } } - player.shuffleLibrary(game); + controller.shuffleLibrary(game); } return true; } diff --git a/Mage.Sets/src/mage/sets/invasion/PhyrexianDelver.java b/Mage.Sets/src/mage/sets/invasion/PhyrexianDelver.java index eb4c4a5174d..1178f5af64c 100644 --- a/Mage.Sets/src/mage/sets/invasion/PhyrexianDelver.java +++ b/Mage.Sets/src/mage/sets/invasion/PhyrexianDelver.java @@ -98,7 +98,7 @@ class PhyrexianDelverEffect extends OneShotEffect { if (creatureCard != null && controller != null) { boolean result = false; if (game.getState().getZone(creatureCard.getId()).equals(Zone.GRAVEYARD)) { - result = controller.putOntoBattlefieldWithInfo(creatureCard, game, Zone.GRAVEYARD, source.getSourceId()); + result = controller.moveCards(creatureCard, Zone.BATTLEFIELD, source, game);; } controller.loseLife(creatureCard.getManaCost().convertedManaCost(), game); return result; diff --git a/Mage.Sets/src/mage/sets/invasion/ThicketElemental.java b/Mage.Sets/src/mage/sets/invasion/ThicketElemental.java index 142a7b4fc14..e669ddd5ade 100644 --- a/Mage.Sets/src/mage/sets/invasion/ThicketElemental.java +++ b/Mage.Sets/src/mage/sets/invasion/ThicketElemental.java @@ -67,7 +67,7 @@ public class ThicketElemental extends CardImpl { // When Thicket Elemental enters the battlefield, if it was kicked, you may reveal cards from the top of your library until you reveal a creature card. If you do, put that card onto the battlefield and shuffle all other cards revealed this way into your library. TriggeredAbility ability = new EntersBattlefieldTriggeredAbility(new ThicketElementalEffect()); this.addAbility(new ConditionalTriggeredAbility(ability, KickedCondition.getInstance(), - "When {this} enters the battlefield, if it was kicked, you may reveal cards from the top of your library until you reveal a creature card. If you do, put that card onto the battlefield and shuffle all other cards revealed this way into your library.")); + "When {this} enters the battlefield, if it was kicked, you may reveal cards from the top of your library until you reveal a creature card. If you do, put that card onto the battlefield and shuffle all other cards revealed this way into your library.")); } public ThicketElemental(final ThicketElemental card) { @@ -82,8 +82,6 @@ public class ThicketElemental extends CardImpl { class ThicketElementalEffect extends OneShotEffect { - - public ThicketElementalEffect() { super(Outcome.Benefit); staticText = "if {this} was kicked, reveal cards from the top of your library until you reveal a creature card. Put that card onto the battlefield and shuffle all other cards revealed this way into your library"; @@ -102,15 +100,13 @@ class ThicketElementalEffect extends OneShotEffect { while (controller.getLibrary().size() > 0) { Card card = controller.getLibrary().removeFromTop(game); if (card.getCardType().contains(CardType.CREATURE)) { - controller.putOntoBattlefieldWithInfo(card, game, Zone.LIBRARY, source.getSourceId()); + controller.moveCards(card, Zone.BATTLEFIELD, source, game); break; } revealedCards.add(card); } - controller.revealCards("ThicketElemental", revealedCards, game); - for (Card card: revealedCards.getCards(game)) { - card.moveToZone(Zone.LIBRARY, source.getSourceId(), game, true); - } + controller.revealCards(sourceObject.getIdName(), revealedCards, game); + controller.moveCards(revealedCards, Zone.LIBRARY, source, game); controller.shuffleLibrary(game); return true; } @@ -121,4 +117,4 @@ class ThicketElementalEffect extends OneShotEffect { public ThicketElementalEffect copy() { return new ThicketElementalEffect(this); } -} \ No newline at end of file +} diff --git a/Mage.Sets/src/mage/sets/judgment/WorldgorgerDragon.java b/Mage.Sets/src/mage/sets/judgment/WorldgorgerDragon.java index 0256568c9cd..692fc29a17e 100644 --- a/Mage.Sets/src/mage/sets/judgment/WorldgorgerDragon.java +++ b/Mage.Sets/src/mage/sets/judgment/WorldgorgerDragon.java @@ -27,6 +27,8 @@ */ package mage.sets.judgment; +import java.util.LinkedHashSet; +import java.util.Set; import java.util.UUID; import mage.MageInt; import mage.MageObject; @@ -44,10 +46,10 @@ import mage.constants.Rarity; import mage.constants.TargetController; import mage.constants.Zone; import mage.filter.FilterPermanent; +import mage.filter.predicate.permanent.AnotherPredicate; import mage.filter.predicate.permanent.ControllerPredicate; import mage.game.ExileZone; import mage.game.Game; -import mage.game.permanent.Permanent; import mage.game.permanent.PermanentToken; import mage.players.Player; import mage.util.CardUtil; @@ -94,6 +96,7 @@ class WorldgorgerDragonEntersEffect extends OneShotEffect { static { filter.add(new ControllerPredicate(TargetController.YOU)); + filter.add(new AnotherPredicate()); } public WorldgorgerDragonEntersEffect() { @@ -112,11 +115,9 @@ class WorldgorgerDragonEntersEffect extends OneShotEffect { if (controller != null) { UUID exileId = CardUtil.getExileZoneId(game, source.getSourceId(), source.getSourceObjectZoneChangeCounter()); if (exileId != null) { - for (Permanent permanent : game.getBattlefield().getAllActivePermanents(filter, source.getControllerId(), game)) { - if (!permanent.getId().equals(source.getSourceId())) { // Another - controller.moveCardToExileWithInfo(permanent, exileId, sourceObject.getIdName(), source.getSourceId(), game, Zone.BATTLEFIELD, true); - } - } + Set cardsToExile = new LinkedHashSet<>(); + cardsToExile.addAll(game.getBattlefield().getActivePermanents(filter, source.getControllerId(), source.getSourceId(), game)); + controller.moveCardsToExile(cardsToExile, source, game, true, exileId, sourceObject.getIdName()); return true; } } @@ -148,14 +149,7 @@ class WorldgorgerDragonLeavesEffect extends OneShotEffect { int zoneChangeCounter = (sourceObject instanceof PermanentToken) ? source.getSourceObjectZoneChangeCounter() : source.getSourceObjectZoneChangeCounter() - 1; ExileZone exile = game.getExile().getExileZone(CardUtil.getExileZoneId(game, source.getSourceId(), zoneChangeCounter)); if (exile != null) { - exile = exile.copy(); - for (UUID cardId : exile) { - Card card = game.getCard(cardId); - if (card != null) { - controller.moveCards(card, Zone.EXILED, source, game); - } - } - return true; + return controller.moveCards(exile.getCards(game), Zone.BATTLEFIELD, source, game, false, false, true, null); } } return false; diff --git a/Mage.Sets/src/mage/sets/khansoftarkir/AshcloudPhoenix.java b/Mage.Sets/src/mage/sets/khansoftarkir/AshcloudPhoenix.java index 115370c7f92..4a11b9fbfdc 100644 --- a/Mage.Sets/src/mage/sets/khansoftarkir/AshcloudPhoenix.java +++ b/Mage.Sets/src/mage/sets/khansoftarkir/AshcloudPhoenix.java @@ -64,13 +64,13 @@ public class AshcloudPhoenix extends CardImpl { // Flying this.addAbility(FlyingAbility.getInstance()); - + // When Ashcloud Phoenix dies, return it to the battlefield face down under your control. this.addAbility(new DiesTriggeredAbility(new AshcloudPhoenixEffect())); - + // Morph {4}{R}{R} this.addAbility(new MorphAbility(this, new ManaCostsImpl<>("{4}{R}{R}"))); - + // When Ashcloud Phoenix is turned face up, it deals 2 damage to each player. Effect effect = new DamagePlayersEffect(2, TargetController.ANY); effect.setText("it deals 2 damage to each player"); @@ -88,30 +88,30 @@ public class AshcloudPhoenix extends CardImpl { } class AshcloudPhoenixEffect extends OneShotEffect { - + AshcloudPhoenixEffect() { super(Outcome.PutCreatureInPlay); this.staticText = "return it to the battlefield face down under your control"; } - + AshcloudPhoenixEffect(final AshcloudPhoenixEffect effect) { super(effect); } - + @Override public AshcloudPhoenixEffect copy() { return new AshcloudPhoenixEffect(this); } - + @Override public boolean apply(Game game, Ability source) { - Player player = game.getPlayer(source.getControllerId()); - if (player != null) { + Player controller = game.getPlayer(source.getControllerId()); + if (controller != null) { Card card = game.getCard(source.getSourceId()); if (card != null) { Player owner = game.getPlayer(card.getOwnerId()); if (owner != null && owner.getGraveyard().contains(card.getId())) { - player.putOntoBattlefieldWithInfo(card, game, Zone.GRAVEYARD, source.getSourceId(), false, true); + controller.moveCards(card, Zone.BATTLEFIELD, source, game, false, true, false, null); } } return true; diff --git a/Mage.Sets/src/mage/sets/khansoftarkir/KheruLichLord.java b/Mage.Sets/src/mage/sets/khansoftarkir/KheruLichLord.java index fa93f72f934..048f1d84fc0 100644 --- a/Mage.Sets/src/mage/sets/khansoftarkir/KheruLichLord.java +++ b/Mage.Sets/src/mage/sets/khansoftarkir/KheruLichLord.java @@ -112,45 +112,41 @@ class KheruLichLordEffect extends OneShotEffect { Player controller = game.getPlayer(source.getControllerId()); if (controller != null) { Cards cards = new CardsImpl(); - for (Card card : controller.getGraveyard().getCards(new FilterCreatureCard(), source.getSourceId(), source.getControllerId(), game)) { - cards.add(card.getId()); - } - - if (cards.size() > 0) { - Card card = cards.getRandom(game); - controller.putOntoBattlefieldWithInfo(card, game, Zone.GRAVEYARD, source.getSourceId()); + cards.addAll(controller.getGraveyard().getCards(new FilterCreatureCard(), source.getSourceId(), source.getControllerId(), game)); + Card card = cards.getRandom(game); + if (card != null) { + controller.moveCards(card, Zone.BATTLEFIELD, source, game); Permanent permanent = game.getPermanent(card.getId()); if (permanent != null) { + FixedTarget fixedTarget = new FixedTarget(permanent, game); ContinuousEffect effect = new GainAbilityTargetEffect(FlyingAbility.getInstance(), Duration.EndOfTurn); - effect.setTargetPointer(new FixedTarget(permanent.getId())); + effect.setTargetPointer(fixedTarget); game.addEffect(effect, source); effect = new GainAbilityTargetEffect(TrampleAbility.getInstance(), Duration.EndOfTurn); - effect.setTargetPointer(new FixedTarget(permanent.getId())); + effect.setTargetPointer(fixedTarget); game.addEffect(effect, source); effect = new GainAbilityTargetEffect(HasteAbility.getInstance(), Duration.EndOfTurn); - effect.setTargetPointer(new FixedTarget(permanent.getId())); + effect.setTargetPointer(fixedTarget); game.addEffect(effect, source); ExileTargetEffect exileEffect = new ExileTargetEffect(); - exileEffect.setTargetPointer(new FixedTarget(permanent.getId())); + exileEffect.setTargetPointer(fixedTarget); DelayedTriggeredAbility delayedAbility = new AtTheBeginOfNextEndStepDelayedTriggeredAbility(exileEffect); delayedAbility.setSourceId(source.getSourceId()); delayedAbility.setControllerId(source.getControllerId()); delayedAbility.setSourceObject(source.getSourceObject(game), game); game.addDelayedTriggeredAbility(delayedAbility); - KheruLichLordReplacementEffect replacementEffect = new KheruLichLordReplacementEffect(); - replacementEffect.setTargetPointer(new FixedTarget(permanent.getId())); + KheruLichLordReplacementEffect replacementEffect = new KheruLichLordReplacementEffect(); + replacementEffect.setTargetPointer(fixedTarget); game.addEffect(replacementEffect, source); - } } return true; } - return false; } } @@ -183,11 +179,11 @@ class KheruLichLordReplacementEffect extends ReplacementEffectImpl { return true; } - @Override + @Override public boolean checksEventType(GameEvent event, Game game) { return event.getType() == GameEvent.EventType.ZONE_CHANGE; } - + @Override public boolean applies(GameEvent event, Ability source, Game game) { if (event.getType() == GameEvent.EventType.ZONE_CHANGE diff --git a/Mage.Sets/src/mage/sets/khansoftarkir/MeanderingTowershell.java b/Mage.Sets/src/mage/sets/khansoftarkir/MeanderingTowershell.java index 87bcfe85461..a51b22e36a8 100644 --- a/Mage.Sets/src/mage/sets/khansoftarkir/MeanderingTowershell.java +++ b/Mage.Sets/src/mage/sets/khansoftarkir/MeanderingTowershell.java @@ -46,19 +46,21 @@ import mage.game.permanent.Permanent; import mage.players.Player; /** - * As Meandering Towershell returns to the battlefield because of the delayed triggered ability, - * you choose which opponent or opposing planeswalker it’s attacking. It doesn’t have to attack - * the same opponent or opposing planeswalker that it was when it was exiled. + * As Meandering Towershell returns to the battlefield because of the delayed + * triggered ability, you choose which opponent or opposing planeswalker it’s + * attacking. It doesn’t have to attack the same opponent or opposing + * planeswalker that it was when it was exiled. * - * If Meandering Towershell enters the battlefield attacking, it wasn’t declared as an attacking - * creature that turn. Abilities that trigger when a creature attacks, including its own triggered - * ability, won’t trigger. + * If Meandering Towershell enters the battlefield attacking, it wasn’t declared + * as an attacking creature that turn. Abilities that trigger when a creature + * attacks, including its own triggered ability, won’t trigger. * - * On the turn Meandering Towershell attacks and is exiled, raid abilities will see it as a creature - * that attacked. Conversely, on the turn Meandering Towershell enters the battlefield attacking, - * raid abilities will not. + * On the turn Meandering Towershell attacks and is exiled, raid abilities will + * see it as a creature that attacked. Conversely, on the turn Meandering + * Towershell enters the battlefield attacking, raid abilities will not. * - * If you attack with a Meandering Towershell that you don’t own, you’ll control it when it returns to the battlefield. + * If you attack with a Meandering Towershell that you don’t own, you’ll control + * it when it returns to the battlefield. * * @author LevelX2 */ @@ -75,7 +77,7 @@ public class MeanderingTowershell extends CardImpl { // Islandwalk this.addAbility(new IslandwalkAbility()); - // Whenever Meandering Towershell attacks, exile it. + // Whenever Meandering Towershell attacks, exile it. // Return it to the battlefield under your control tapped and attacking // at the beginning of the next declare attackers step on your next turn. this.addAbility(new AttacksTriggeredAbility(new MeanderingTowershellEffect(), false)); @@ -191,7 +193,7 @@ class MeanderingTowershellReturnEffect extends OneShotEffect { if (controller != null) { Card card = game.getCard(source.getSourceId()); if (card != null && game.getState().getZone(source.getSourceId()).equals(Zone.EXILED)) { - controller.putOntoBattlefieldWithInfo(card, game, Zone.EXILED, source.getSourceId(), true); + controller.moveCards(card, Zone.BATTLEFIELD, source, game, true, false, false, null); game.getCombat().addAttackingCreature(card.getId(), game); return true; } diff --git a/Mage.Sets/src/mage/sets/khansoftarkir/SeeTheUnwritten.java b/Mage.Sets/src/mage/sets/khansoftarkir/SeeTheUnwritten.java index bf66ae2db31..75c2c3dc55b 100644 --- a/Mage.Sets/src/mage/sets/khansoftarkir/SeeTheUnwritten.java +++ b/Mage.Sets/src/mage/sets/khansoftarkir/SeeTheUnwritten.java @@ -47,8 +47,6 @@ import mage.game.Game; import mage.players.Player; import mage.target.TargetCard; - - /** * * @author LevelX2 @@ -59,15 +57,14 @@ public class SeeTheUnwritten extends CardImpl { super(ownerId, 149, "See the Unwritten", Rarity.MYTHIC, new CardType[]{CardType.SORCERY}, "{4}{G}{G}"); this.expansionSetCode = "KTK"; - // Reveal the top eight cards of your library. You may put a creature card from among them onto the battlefield. Put the rest into your graveyard. // Ferocious - If you control a creature with power 4 or greater, you may put two creature cards onto the battlefield instead of one. this.getSpellAbility().addEffect(new ConditionalOneShotEffect( new SeeTheUnwrittenEffect(1), - new SeeTheUnwrittenEffect(2), + new SeeTheUnwrittenEffect(2), new InvertCondition(FerociousCondition.getInstance()), - "Reveal the top eight cards of your library. You may put a creature card from among them onto the battlefield. Put the rest into your graveyard." + - "
Ferocious — If you control a creature with power 4 or greater, you may put two creature cards onto the battlefield instead of one" )); + "Reveal the top eight cards of your library. You may put a creature card from among them onto the battlefield. Put the rest into your graveyard." + + "
Ferocious — If you control a creature with power 4 or greater, you may put two creature cards onto the battlefield instead of one")); } public SeeTheUnwritten(final SeeTheUnwritten card) { @@ -89,9 +86,9 @@ class SeeTheUnwrittenEffect extends OneShotEffect { public SeeTheUnwrittenEffect(int numberOfCardsToPutIntoPlay) { super(Outcome.DrawCard); this.numberOfCardsToPutIntoPlay = numberOfCardsToPutIntoPlay; - this.staticText = "Reveal the top eight cards of your library. You may put " + - (numberOfCardsToPutIntoPlay == 1 ? "a creature card":"two creature cards") + - " from among them onto the battlefield. Put the rest into your graveyard"; + this.staticText = "Reveal the top eight cards of your library. You may put " + + (numberOfCardsToPutIntoPlay == 1 ? "a creature card" : "two creature cards") + + " from among them onto the battlefield. Put the rest into your graveyard"; } public SeeTheUnwrittenEffect(final SeeTheUnwrittenEffect effect) { @@ -126,24 +123,24 @@ class SeeTheUnwrittenEffect extends OneShotEffect { if (!cards.isEmpty()) { controller.revealCards(sourceObject.getName(), cards, game); if (creatureCardsFound > 0 && controller.chooseUse(outcome, "Put creature(s) into play?", source, game)) { - int cardsToChoose = Math.min(numberOfCardsToPutIntoPlay, creatureCardsFound); + int cardsToChoose = Math.min(numberOfCardsToPutIntoPlay, creatureCardsFound); TargetCard target = new TargetCard(cardsToChoose, cardsToChoose, Zone.LIBRARY, filter); if (controller.choose(Outcome.PutCreatureInPlay, cards, target, game)) { - for(UUID creatureId: target.getTargets()) { + for (UUID creatureId : target.getTargets()) { Card card = game.getCard(creatureId); if (card != null) { cards.remove(card); - controller.putOntoBattlefieldWithInfo(card, game, Zone.LIBRARY, source.getSourceId()); + controller.moveCards(card, Zone.BATTLEFIELD, source, game); } } } } - controller.moveCards(cards, Zone.LIBRARY, Zone.GRAVEYARD, source, game); + controller.moveCards(cards, Zone.GRAVEYARD, source, game); } return true; } return false; } - + } diff --git a/Mage.Sets/src/mage/sets/lorwyn/IncandescentSoulstoke.java b/Mage.Sets/src/mage/sets/lorwyn/IncandescentSoulstoke.java index f3ceefded0e..719016c9804 100644 --- a/Mage.Sets/src/mage/sets/lorwyn/IncandescentSoulstoke.java +++ b/Mage.Sets/src/mage/sets/lorwyn/IncandescentSoulstoke.java @@ -128,7 +128,7 @@ class IncandescentSoulstokeEffect extends OneShotEffect { if (controller.choose(Outcome.PutCreatureInPlay, target, source.getSourceId(), game)) { Card card = game.getCard(target.getFirstTarget()); if (card != null) { - if (controller.putOntoBattlefieldWithInfo(card, game, Zone.HAND, source.getSourceId())) { + if (controller.moveCards(card, Zone.BATTLEFIELD, source, game)) { Permanent permanent = game.getPermanent(card.getId()); if (permanent != null) { ContinuousEffect effect = new GainAbilityTargetEffect(HasteAbility.getInstance(), Duration.Custom); diff --git a/Mage.Sets/src/mage/sets/magic2010/HiveMind.java b/Mage.Sets/src/mage/sets/magic2010/HiveMind.java index b33a3c8e8a2..36d56343ed8 100644 --- a/Mage.Sets/src/mage/sets/magic2010/HiveMind.java +++ b/Mage.Sets/src/mage/sets/magic2010/HiveMind.java @@ -27,9 +27,7 @@ */ package mage.sets.magic2010; -import java.util.Set; import java.util.UUID; - import mage.abilities.Ability; import mage.abilities.TriggeredAbilityImpl; import mage.abilities.effects.Effect; @@ -130,13 +128,12 @@ class HiveMindEffect extends OneShotEffect { public boolean apply(Game game, Ability source) { Spell spell; spell = game.getStack().getSpell(((FixedTarget) getTargetPointer()).getTarget()); - if (spell == null) { // if spell e.g. was countered + if (spell == null) { // if spell e.g. was countered spell = (Spell) game.getLastKnownInformation(((FixedTarget) getTargetPointer()).getTarget(), Zone.STACK); } Player player = game.getPlayer(source.getControllerId()); if (spell != null && player != null) { - Set players = player.getInRange(); - for (UUID playerId : players) { + for (UUID playerId : game.getState().getPlayersInRange(player.getId(), game)) { if (!playerId.equals(spell.getControllerId())) { Spell copy = spell.copySpell(); copy.setControllerId(playerId); diff --git a/Mage.Sets/src/mage/sets/magic2010/OpenTheVaults.java b/Mage.Sets/src/mage/sets/magic2010/OpenTheVaults.java index 7b44f6e0f01..192c5d22db8 100644 --- a/Mage.Sets/src/mage/sets/magic2010/OpenTheVaults.java +++ b/Mage.Sets/src/mage/sets/magic2010/OpenTheVaults.java @@ -27,18 +27,17 @@ */ package mage.sets.magic2010; -import java.util.LinkedList; -import java.util.Set; +import java.util.LinkedHashSet; import java.util.UUID; -import mage.constants.CardType; -import mage.constants.Outcome; -import mage.constants.Rarity; -import mage.constants.Zone; import mage.abilities.Ability; import mage.abilities.effects.OneShotEffect; import mage.cards.Card; import mage.cards.CardImpl; import mage.cards.Cards; +import mage.constants.CardType; +import mage.constants.Outcome; +import mage.constants.Rarity; +import mage.constants.Zone; import mage.game.Game; import mage.players.Player; @@ -52,7 +51,6 @@ public class OpenTheVaults extends CardImpl { super(ownerId, 21, "Open the Vaults", Rarity.RARE, new CardType[]{CardType.SORCERY}, "{4}{W}{W}"); this.expansionSetCode = "M10"; - // Return all artifact and enchantment cards from all graveyards to the battlefield under their owners' control. this.getSpellAbility().addEffect(new OpenTheVaultsEffect()); } @@ -85,33 +83,21 @@ class OpenTheVaultsEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { - Player player = game.getPlayer(source.getControllerId()); - if (player != null) { - LinkedList enchantments = new LinkedList(); - LinkedList artifacts = new LinkedList(); - - Set playerIds = player.getInRange(); - playerIds.add(player.getId()); - - for (UUID playerId : playerIds) { + Player controller = game.getPlayer(source.getControllerId()); + if (controller != null) { + LinkedHashSet cardsToReturn = new LinkedHashSet<>(); + for (UUID playerId : game.getState().getPlayersInRange(controller.getId(), game)) { Cards graveyard = game.getPlayer(playerId).getGraveyard(); for (UUID cardId : graveyard) { Card card = game.getCard(cardId); - if (card != null && card.getCardType().contains(CardType.ENCHANTMENT)) { - enchantments.add(card); - } - if (card != null && card.getCardType().contains(CardType.ARTIFACT)) { - artifacts.add(card); + if (card != null + && (card.getCardType().contains(CardType.ENCHANTMENT) || card.getCardType().contains(CardType.ARTIFACT))) { + cardsToReturn.add(card); } } } - - for (Card card : enchantments) { - card.putOntoBattlefield(game, Zone.GRAVEYARD, source.getSourceId(), card.getOwnerId()); - } - for (Card card : artifacts) { - card.putOntoBattlefield(game, Zone.GRAVEYARD, source.getSourceId(), card.getOwnerId()); - } + controller.moveCards(cardsToReturn, Zone.BATTLEFIELD, source, game, false, false, true, null); + return true; } return false; } diff --git a/Mage.Sets/src/mage/sets/magic2010/SphinxAmbassador.java b/Mage.Sets/src/mage/sets/magic2010/SphinxAmbassador.java index 595a34013f8..c76befa295f 100644 --- a/Mage.Sets/src/mage/sets/magic2010/SphinxAmbassador.java +++ b/Mage.Sets/src/mage/sets/magic2010/SphinxAmbassador.java @@ -95,16 +95,16 @@ class SphinxAmbassadorEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { - Player player = game.getPlayer(source.getControllerId()); + Player controller = game.getPlayer(source.getControllerId()); Player targetPlayer = game.getPlayer(targetPointer.getFirst(game, source)); Permanent sourcePermanent = game.getPermanentOrLKIBattlefield(source.getSourceId()); - if (player != null && targetPlayer != null && sourcePermanent != null) { + if (controller != null && targetPlayer != null && sourcePermanent != null) { TargetCardInLibrary target = new TargetCardInLibrary(); - player.searchLibrary(target, game, targetPlayer.getId()); + controller.searchLibrary(target, game, targetPlayer.getId()); Card card = game.getCard(target.getFirstTarget()); if (card != null) { - TreeSet choices = new TreeSet(); + TreeSet choices = new TreeSet<>(); Collection cards = game.getCards(); for (Card gameCard : cards) { if (gameCard.getOwnerId().equals(targetPlayer.getId())) { @@ -124,8 +124,8 @@ class SphinxAmbassadorEffect extends OneShotEffect { game.informPlayers(new StringBuilder(sourcePermanent.getName()).append(", named card: [").append(cardName).append("]").toString()); if (!card.getName().equals(cardName) && card.getCardType().contains(CardType.CREATURE)) { - if (player.chooseUse(outcome, new StringBuilder("Put ").append(card.getName()).append(" onto the battlefield?").toString(), source, game)) { - player.putOntoBattlefieldWithInfo(card, game, Zone.LIBRARY, source.getSourceId()); + if (controller.chooseUse(outcome, new StringBuilder("Put ").append(card.getName()).append(" onto the battlefield?").toString(), source, game)) { + controller.moveCards(card, Zone.BATTLEFIELD, source, game); } } } diff --git a/Mage.Sets/src/mage/sets/magic2011/Cultivate.java b/Mage.Sets/src/mage/sets/magic2011/Cultivate.java index b68d4a6bdeb..d8b36c43345 100644 --- a/Mage.Sets/src/mage/sets/magic2011/Cultivate.java +++ b/Mage.Sets/src/mage/sets/magic2011/Cultivate.java @@ -111,17 +111,17 @@ class CultivateEffect extends OneShotEffect { controller.choose(Outcome.Benefit, revealed, target2, game); Card card = revealed.get(target2.getFirstTarget(), game); if (card != null) { - controller.putOntoBattlefieldWithInfo(card, game, Zone.LIBRARY, source.getSourceId(), true); + controller.moveCards(card, Zone.BATTLEFIELD, source, game, true, false, false, null); revealed.remove(card); } card = revealed.getCards(game).iterator().next(); if (card != null) { - controller.moveCards(card, null, Zone.HAND, source, game); + controller.moveCards(card, Zone.HAND, source, game); } } else if (target.getTargets().size() == 1) { Card card = revealed.getCards(game).iterator().next(); if (card != null) { - controller.putOntoBattlefieldWithInfo(card, game, Zone.LIBRARY, source.getSourceId(), true); + controller.moveCards(card, Zone.BATTLEFIELD, source, game, true, false, false, null); } } diff --git a/Mage.Sets/src/mage/sets/magic2011/NecroticPlague.java b/Mage.Sets/src/mage/sets/magic2011/NecroticPlague.java index 58a741397a3..d9cdc57cb98 100644 --- a/Mage.Sets/src/mage/sets/magic2011/NecroticPlague.java +++ b/Mage.Sets/src/mage/sets/magic2011/NecroticPlague.java @@ -1,16 +1,16 @@ /* * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. - * + * * Redistribution and use in source and binary forms, with or without modification, are * permitted provided that the following conditions are met: - * + * * 1. Redistributions of source code must retain the above copyright notice, this list of * conditions and the following disclaimer. - * + * * 2. Redistributions in binary form must reproduce the above copyright notice, this list * of conditions and the following disclaimer in the documentation and/or other materials * provided with the distribution. - * + * * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR @@ -20,12 +20,11 @@ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * + * * The views and conclusions contained in the software and documentation are those of the * authors and should not be interpreted as representing official policies, either expressed * or implied, of BetaSteward_at_googlemail.com. */ - package mage.sets.magic2011; import java.util.UUID; @@ -86,7 +85,7 @@ public class NecroticPlague extends CardImpl { Effect effect = new GainAbilityAttachedEffect(gainedAbility, AttachmentType.AURA, Duration.WhileOnBattlefield); effect.setText("Enchanted creature has \"At the beginning of your upkeep, sacrifice this creature.\""); this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, effect)); - this.addAbility(new DiesAttachedTriggeredAbility(new NecroticPlagueEffect(),"enchanted creature", false)); + this.addAbility(new DiesAttachedTriggeredAbility(new NecroticPlagueEffect(), "enchanted creature", false)); } @@ -94,7 +93,7 @@ public class NecroticPlague extends CardImpl { public void adjustTargets(Ability ability, Game game) { if (ability instanceof DiesAttachedTriggeredAbility) { Permanent attachedTo = null; - for (Effect effect :ability.getEffects()) { + for (Effect effect : ability.getEffects()) { attachedTo = (Permanent) effect.getValue("attachedTo"); } if (attachedTo != null) { @@ -122,8 +121,6 @@ public class NecroticPlague extends CardImpl { class NecroticPlagueEffect extends OneShotEffect { - - public NecroticPlagueEffect() { super(Outcome.PutCardInPlay); staticText = "its controller chooses target creature one of his or her opponents controls. Return {this} from its owner's graveyard to the battlefield attached to that creature"; @@ -143,7 +140,7 @@ class NecroticPlagueEffect extends OneShotEffect { Permanent creature = game.getPermanent(this.getTargetPointer().getFirst(game, source)); if (sourceEnchantmentCard != null && creature != null) { game.getState().setValue("attachTo:" + sourceEnchantmentCard.getId(), creature); - creatureController.putOntoBattlefieldWithInfo(sourceEnchantmentCard, game, Zone.GRAVEYARD, source.getSourceId()); + creatureController.moveCards(sourceEnchantmentCard, Zone.BATTLEFIELD, source, game); return creature.addAttachment(sourceEnchantmentCard.getId(), game); } } diff --git a/Mage.Sets/src/mage/sets/magic2015/BoonweaverGiant.java b/Mage.Sets/src/mage/sets/magic2015/BoonweaverGiant.java index 12075176452..d5f432ff10e 100644 --- a/Mage.Sets/src/mage/sets/magic2015/BoonweaverGiant.java +++ b/Mage.Sets/src/mage/sets/magic2015/BoonweaverGiant.java @@ -97,8 +97,8 @@ class BoonweaverGiantEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { - Player player = game.getPlayer(source.getControllerId()); - if (player == null) { + Player controller = game.getPlayer(source.getControllerId()); + if (controller == null) { return false; } @@ -108,18 +108,18 @@ class BoonweaverGiantEffect extends OneShotEffect { Card card = null; Zone zone = null; - if (player.chooseUse(Outcome.Neutral, "Search your graveyard for an Aura card?", source, game)) { + if (controller.chooseUse(Outcome.Neutral, "Search your graveyard for an Aura card?", source, game)) { TargetCardInYourGraveyard target = new TargetCardInYourGraveyard(filter); - if (player.choose(Outcome.PutCardInPlay, player.getGraveyard(), target, game)) { + if (controller.choose(Outcome.PutCardInPlay, controller.getGraveyard(), target, game)) { card = game.getCard(target.getFirstTarget()); if (card != null) { zone = Zone.GRAVEYARD; } } } - if (card == null && player.chooseUse(Outcome.Neutral, "Search your Hand for an Aura card?", source, game)) { + if (card == null && controller.chooseUse(Outcome.Neutral, "Search your Hand for an Aura card?", source, game)) { TargetCardInHand target = new TargetCardInHand(filter); - if (player.choose(Outcome.PutCardInPlay, player.getHand(), target, game)) { + if (controller.choose(Outcome.PutCardInPlay, controller.getHand(), target, game)) { card = game.getCard(target.getFirstTarget()); if (card != null) { zone = Zone.HAND; @@ -128,13 +128,13 @@ class BoonweaverGiantEffect extends OneShotEffect { } if (card == null) { TargetCardInLibrary target = new TargetCardInLibrary(filter); - if (player.searchLibrary(target, game)) { + if (controller.searchLibrary(target, game)) { card = game.getCard(target.getFirstTarget()); if (card != null) { zone = Zone.LIBRARY; } } - player.shuffleLibrary(game); + controller.shuffleLibrary(game); } // aura card found - attach it if (card != null) { @@ -142,7 +142,7 @@ class BoonweaverGiantEffect extends OneShotEffect { if (permanent != null) { game.getState().setValue("attachTo:" + card.getId(), permanent); } - player.putOntoBattlefieldWithInfo(card, game, zone, source.getSourceId()); + controller.moveCards(card, Zone.BATTLEFIELD, source, game); if (permanent != null) { return permanent.addAttachment(card.getId(), game); } diff --git a/Mage.Sets/src/mage/sets/magic2015/JaliraMasterPolymorphist.java b/Mage.Sets/src/mage/sets/magic2015/JaliraMasterPolymorphist.java index a9cd3d3260d..cc21944e5c5 100644 --- a/Mage.Sets/src/mage/sets/magic2015/JaliraMasterPolymorphist.java +++ b/Mage.Sets/src/mage/sets/magic2015/JaliraMasterPolymorphist.java @@ -132,10 +132,10 @@ class JaliraMasterPolymorphistEffect extends OneShotEffect { } while (library.size() > 0 && card != null && !filter.match(card, game)); // reveal cards if (!cards.isEmpty()) { - controller.revealCards(sourceObject.getName(), cards, game); + controller.revealCards(sourceObject.getIdName(), cards, game); } // put nonlegendary creature card to battlefield - controller.putOntoBattlefieldWithInfo(card, game, Zone.LIBRARY, source.getSourceId()); + controller.moveCards(card, Zone.BATTLEFIELD, source, game); // remove it from revealed card list cards.remove(card); // Put the rest on the bottom of your library in a random order diff --git a/Mage.Sets/src/mage/sets/magic2015/NissaWorldwaker.java b/Mage.Sets/src/mage/sets/magic2015/NissaWorldwaker.java index 00f8de29bc3..c1fc0b51a84 100644 --- a/Mage.Sets/src/mage/sets/magic2015/NissaWorldwaker.java +++ b/Mage.Sets/src/mage/sets/magic2015/NissaWorldwaker.java @@ -51,6 +51,7 @@ import mage.filter.common.FilterLandPermanent; import mage.filter.predicate.mageobject.SubtypePredicate; import mage.filter.predicate.permanent.ControllerPredicate; import mage.game.Game; +import mage.game.permanent.Permanent; import mage.game.permanent.token.Token; import mage.players.Player; import mage.target.TargetPermanent; @@ -121,26 +122,30 @@ class NissaWorldwakerSearchEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { - Player player = game.getPlayer(source.getControllerId()); - if (player == null) { + Player controller = game.getPlayer(source.getControllerId()); + if (controller == null) { return false; } TargetCardInLibrary target = new TargetCardInLibrary(0, Integer.MAX_VALUE, new FilterBasicLandCard()); - if (player.searchLibrary(target, game)) { + if (controller.searchLibrary(target, game)) { if (target.getTargets().size() > 0) { for (UUID cardId : target.getTargets()) { - Card card = player.getLibrary().getCard(cardId, game); + Card card = controller.getLibrary().getCard(cardId, game); if (card != null) { - if (player.putOntoBattlefieldWithInfo(card, game, Zone.LIBRARY, source.getSourceId())) { - ContinuousEffect effect = new BecomesCreatureTargetEffect(new NissaWorldwakerToken(), false, true, Duration.Custom); - effect.setTargetPointer(new FixedTarget(card.getId())); - game.addEffect(effect, source); + if (controller.moveCards(card, Zone.BATTLEFIELD, source, game)) { + Permanent land = game.getPermanent(card.getId()); + if (land != null) { + ContinuousEffect effect = new BecomesCreatureTargetEffect(new NissaWorldwakerToken(), false, true, Duration.Custom); + effect.setTargetPointer(new FixedTarget(land, game)); + game.addEffect(effect, source); + + } } } } } } - player.shuffleLibrary(game); + controller.shuffleLibrary(game); return true; } } diff --git a/Mage.Sets/src/mage/sets/magic2015/YisanTheWandererBard.java b/Mage.Sets/src/mage/sets/magic2015/YisanTheWandererBard.java index c5c6d4568e9..978e17f81dd 100644 --- a/Mage.Sets/src/mage/sets/magic2015/YisanTheWandererBard.java +++ b/Mage.Sets/src/mage/sets/magic2015/YisanTheWandererBard.java @@ -35,7 +35,6 @@ import mage.abilities.costs.common.PutCountersSourceCost; import mage.abilities.costs.common.TapSourceCost; import mage.abilities.costs.mana.ManaCostsImpl; import mage.abilities.effects.OneShotEffect; -import mage.abilities.effects.common.search.SearchLibraryPutInPlayEffect; import mage.cards.Card; import mage.cards.CardImpl; import mage.constants.CardType; @@ -86,40 +85,36 @@ public class YisanTheWandererBard extends CardImpl { } class YisanTheWandererBardEffect extends OneShotEffect { - + public YisanTheWandererBardEffect() { super(Outcome.Benefit); this.staticText = "Search your library for a creature card with converted mana cost equal to the number of verse counters on {this}, put it onto the battlefield, then shuffle your library"; } - + public YisanTheWandererBardEffect(final YisanTheWandererBardEffect effect) { super(effect); } - + @Override public YisanTheWandererBardEffect copy() { return new YisanTheWandererBardEffect(this); } - + @Override public boolean apply(Game game, Ability source) { - Player player = game.getPlayer(source.getControllerId()); + Player controller = game.getPlayer(source.getControllerId()); Permanent sourcePermanent = game.getPermanentOrLKIBattlefield(source.getSourceId()); - if (sourcePermanent != null && player != null) { + if (sourcePermanent != null && controller != null) { int newConvertedCost = sourcePermanent.getCounters().getCount("verse"); FilterCard filter = new FilterCard("creature card with converted mana cost " + newConvertedCost); filter.add(new ConvertedManaCostPredicate(Filter.ComparisonType.Equal, newConvertedCost)); filter.add(new CardTypePredicate(CardType.CREATURE)); TargetCardInLibrary target = new TargetCardInLibrary(filter); - if (player.searchLibrary(target, game)) { - for (UUID cardId : target.getTargets()) { - Card card = player.getLibrary().getCard(cardId, game); - if (card != null) { - player.putOntoBattlefieldWithInfo(card, game, Zone.LIBRARY, source.getSourceId()); - } - } + if (controller.searchLibrary(target, game)) { + Card card = controller.getLibrary().getCard(target.getFirstTarget(), game); + controller.moveCards(card, Zone.BATTLEFIELD, source, game); } - player.shuffleLibrary(game); + controller.shuffleLibrary(game); return true; } return false; diff --git a/Mage.Sets/src/mage/sets/magicorigins/NissasPilgrimage.java b/Mage.Sets/src/mage/sets/magicorigins/NissasPilgrimage.java index 442643c5ffc..d6023fed3fa 100644 --- a/Mage.Sets/src/mage/sets/magicorigins/NissasPilgrimage.java +++ b/Mage.Sets/src/mage/sets/magicorigins/NissasPilgrimage.java @@ -113,8 +113,8 @@ class NissasPilgrimageEffect extends OneShotEffect { Card card = cards.getRandom(game); if (card != null) { cards.remove(card); - controller.putOntoBattlefieldWithInfo(card, game, Zone.LIBRARY, source.getSourceId(), true); - controller.moveCards(cards, Zone.LIBRARY, Zone.HAND, source, game); + controller.moveCards(card, Zone.BATTLEFIELD, source, game, true, false, false, null); + controller.moveCards(cards, Zone.HAND, source, game); } } } diff --git a/Mage.Sets/src/mage/sets/magicorigins/TheGreatAurora.java b/Mage.Sets/src/mage/sets/magicorigins/TheGreatAurora.java index c6fc391ddf2..2fcfe39ffe4 100644 --- a/Mage.Sets/src/mage/sets/magicorigins/TheGreatAurora.java +++ b/Mage.Sets/src/mage/sets/magicorigins/TheGreatAurora.java @@ -36,8 +36,9 @@ import java.util.UUID; import mage.abilities.Ability; import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.ExileSpellEffect; -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; @@ -92,63 +93,62 @@ class TheGreatAuroraEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { + Player controller = game.getPlayer(source.getControllerId()); + if (controller != null) { - Map> permanentsOwned = new HashMap<>(); - Collection permanents = game.getBattlefield().getActivePermanents(source.getControllerId(), game); - for (Permanent permanent : permanents) { - List list = permanentsOwned.get(permanent.getOwnerId()); - if (list == null) { - list = new ArrayList<>(); - permanentsOwned.put(permanent.getOwnerId(), list); - } - list.add(permanent); - } - - // shuffle permanents and hand cards into owner's library - Map permanentsCount = new HashMap<>(); - - for (UUID playerId : game.getState().getPlayersInRange(source.getControllerId(), game)) { - Player player = game.getPlayer(playerId); - if (player != null) { - int handCards = player.getHand().size(); - player.moveCards(player.getHand(), Zone.HAND, Zone.LIBRARY, source, game); - List list = permanentsOwned.remove(player.getId()); - permanentsCount.put(playerId, handCards + (list != null ? list.size() : 0)); - for (Permanent permanent : list) { - player.moveCardToLibraryWithInfo(permanent, source.getSourceId(), game, Zone.BATTLEFIELD, true, true); + Map> permanentsOwned = new HashMap<>(); + Collection permanents = game.getBattlefield().getActivePermanents(source.getControllerId(), game); + for (Permanent permanent : permanents) { + List list = permanentsOwned.get(permanent.getOwnerId()); + if (list == null) { + list = new ArrayList<>(); + permanentsOwned.put(permanent.getOwnerId(), list); } - player.shuffleLibrary(game); + list.add(permanent); } - } - game.applyEffects(); // so effects from creatures that were on the battlefield won't trigger from draw or put into play + // shuffle permanents and hand cards into owner's library + Map permanentsCount = new HashMap<>(); - // Draw cards - for (UUID playerId : game.getState().getPlayersInRange(source.getControllerId(), game)) { - Player player = game.getPlayer(playerId); - if (player != null) { - int count = permanentsCount.get(playerId); - if (count > 0) { - player.drawCards(count, game); + for (UUID playerId : game.getState().getPlayersInRange(source.getControllerId(), game)) { + Player player = game.getPlayer(playerId); + if (player != null) { + int handCards = player.getHand().size(); + player.moveCards(player.getHand(), Zone.HAND, Zone.LIBRARY, source, game); + List list = permanentsOwned.remove(player.getId()); + permanentsCount.put(playerId, handCards + (list != null ? list.size() : 0)); + for (Permanent permanent : list) { + player.moveCardToLibraryWithInfo(permanent, source.getSourceId(), game, Zone.BATTLEFIELD, true, true); + } + player.shuffleLibrary(game); } } - } - // put lands onto the battlefield - for (UUID playerId : game.getState().getPlayersInRange(source.getControllerId(), game)) { - Player player = game.getPlayer(playerId); - if (player != null) { - TargetCard target = new TargetCardInHand(0, Integer.MAX_VALUE, new FilterLandCard("put any number of land cards from your hand onto the battlefield")); - player.chooseTarget(Outcome.PutLandInPlay, player.getHand(), target, source, game); - for (UUID cardId : target.getTargets()) { - Card card = game.getCard(cardId); - if (card != null) { - player.putOntoBattlefieldWithInfo(card, game, Zone.HAND, source.getSourceId(), false); + game.applyEffects(); // so effects from creatures that were on the battlefield won't trigger from draw or put into play + + // Draw cards + for (UUID playerId : game.getState().getPlayersInRange(source.getControllerId(), game)) { + Player player = game.getPlayer(playerId); + if (player != null) { + int count = permanentsCount.get(playerId); + if (count > 0) { + player.drawCards(count, game); } } - } + + // put lands onto the battlefield + Cards toBattlefield = new CardsImpl(); + for (UUID playerId : game.getState().getPlayersInRange(source.getControllerId(), game)) { + Player player = game.getPlayer(playerId); + if (player != null) { + TargetCard target = new TargetCardInHand(0, Integer.MAX_VALUE, new FilterLandCard("put any number of land cards from your hand onto the battlefield")); + player.chooseTarget(Outcome.PutLandInPlay, player.getHand(), target, source, game); + toBattlefield.addAll(target.getTargets()); + } + } + return controller.moveCards(toBattlefield.getCards(game), Zone.BATTLEFIELD, source, game, true, false, true, null); } - return true; + return false; } } diff --git a/Mage.Sets/src/mage/sets/magicorigins/WoodlandBellower.java b/Mage.Sets/src/mage/sets/magicorigins/WoodlandBellower.java index adfa437ce62..3df2f8848c2 100644 --- a/Mage.Sets/src/mage/sets/magicorigins/WoodlandBellower.java +++ b/Mage.Sets/src/mage/sets/magicorigins/WoodlandBellower.java @@ -78,6 +78,7 @@ public class WoodlandBellower extends CardImpl { } class WoodlandBellowerEffect extends OneShotEffect { + WoodlandBellowerEffect() { super(Outcome.PutCreatureInPlay); staticText = "Search your library for a nonlegendary green creature card with converted mana cost 3 or less, put it onto the battlefield, then shuffle your library"; @@ -89,27 +90,25 @@ class WoodlandBellowerEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { - Player player = game.getPlayer(source.getControllerId()); - if (player == null) { + Player controller = game.getPlayer(source.getControllerId()); + if (controller == null) { return false; } FilterCard filter = new FilterCard("nonlegendary green creature card with converted mana cost 3 or less"); filter.add(new ColorPredicate(ObjectColor.GREEN)); - filter.add(new CardTypePredicate(CardType.CREATURE)); + filter.add(new CardTypePredicate(CardType.CREATURE)); filter.add(Predicates.not(new SupertypePredicate("Legendary"))); filter.add(new ConvertedManaCostPredicate(Filter.ComparisonType.LessThan, 4)); TargetCardInLibrary target = new TargetCardInLibrary(filter); - if (player.searchLibrary(target, game)) { + if (controller.searchLibrary(target, game)) { if (target.getTargets().size() > 0) { - Card card = player.getLibrary().getCard(target.getFirstTarget(), game); - if (card != null) { - player.putOntoBattlefieldWithInfo(card, game, Zone.LIBRARY, source.getSourceId()); - } + Card card = controller.getLibrary().getCard(target.getFirstTarget(), game); + controller.moveCards(card, Zone.BATTLEFIELD, source, game); } - player.shuffleLibrary(game); + controller.shuffleLibrary(game); return true; } - player.shuffleLibrary(game); + controller.shuffleLibrary(game); return false; } @@ -118,4 +117,4 @@ class WoodlandBellowerEffect extends OneShotEffect { return new WoodlandBellowerEffect(this); } -} \ No newline at end of file +} diff --git a/Mage.Sets/src/mage/sets/mediainserts/MagisterOfWorth.java b/Mage.Sets/src/mage/sets/mediainserts/MagisterOfWorth.java index 8730131d3ba..0c293502e33 100644 --- a/Mage.Sets/src/mage/sets/mediainserts/MagisterOfWorth.java +++ b/Mage.Sets/src/mage/sets/mediainserts/MagisterOfWorth.java @@ -35,7 +35,6 @@ import mage.abilities.common.EntersBattlefieldTriggeredAbility; import mage.abilities.effects.Effect; import mage.abilities.effects.OneShotEffect; import mage.abilities.keyword.FlyingAbility; -import mage.cards.Card; import mage.cards.CardImpl; import mage.constants.CardType; import mage.constants.Outcome; @@ -109,8 +108,7 @@ class MagisterOfWorthVoteEffect extends OneShotEffect { if (player.chooseUse(Outcome.DestroyPermanent, "Choose grace?", source, game)) { graceCount++; game.informPlayers(player.getLogName() + " has chosen: grace"); - } - else { + } else { condemnationCount++; game.informPlayers(player.getLogName() + " has chosen: condemnation"); } @@ -130,7 +128,7 @@ class MagisterOfWorthVoteEffect extends OneShotEffect { class MagisterOfWorthDestroyEffect extends OneShotEffect { private static final FilterPermanent filter = new FilterCreaturePermanent("creatures other than {this}"); - + static { filter.add(new AnotherPredicate()); } @@ -175,12 +173,10 @@ class MagisterOfWorthReturnFromGraveyardEffect extends OneShotEffect { Player controller = game.getPlayer(source.getControllerId()); MageObject sourceObject = game.getObject(source.getSourceId()); if (controller != null && sourceObject != null) { - for (UUID playerId: controller.getInRange()) { + for (UUID playerId : controller.getInRange()) { Player player = game.getPlayer(playerId); if (player != null) { - for (Card card :player.getGraveyard().getCards(new FilterCreatureCard(), game)) { - player.putOntoBattlefieldWithInfo(card, game, Zone.GRAVEYARD, source.getSourceId()); - } + player.moveCards(player.getGraveyard().getCards(new FilterCreatureCard(), game), Zone.BATTLEFIELD, source, game); } } return true; @@ -193,4 +189,4 @@ class MagisterOfWorthReturnFromGraveyardEffect extends OneShotEffect { return new MagisterOfWorthReturnFromGraveyardEffect(this); } -} \ No newline at end of file +} diff --git a/Mage.Sets/src/mage/sets/mercadianmasques/Bribery.java b/Mage.Sets/src/mage/sets/mercadianmasques/Bribery.java index 199c4f5e1bc..c7aec373447 100644 --- a/Mage.Sets/src/mage/sets/mercadianmasques/Bribery.java +++ b/Mage.Sets/src/mage/sets/mercadianmasques/Bribery.java @@ -27,7 +27,6 @@ */ package mage.sets.mercadianmasques; -import java.util.List; import java.util.UUID; import mage.abilities.Ability; import mage.abilities.effects.OneShotEffect; @@ -91,13 +90,8 @@ class BriberyEffect extends OneShotEffect { if (controller != null && opponent != null) { TargetCardInLibrary target = new TargetCardInLibrary(0, 1, new FilterCreatureCard("creature card")); if (controller.searchLibrary(target, game, opponent.getId())) { - List targets = target.getTargets(); - for (UUID targetId : targets) { - Card card = opponent.getLibrary().getCard(targetId, game); - if (card != null) { - controller.putOntoBattlefieldWithInfo(card, game, Zone.LIBRARY, source.getSourceId()); - } - } + Card card = opponent.getLibrary().getCard(target.getFirstTarget(), game); + controller.moveCards(card, Zone.BATTLEFIELD, source, game); } opponent.shuffleLibrary(game); return true; diff --git a/Mage.Sets/src/mage/sets/mirage/ShallowGrave.java b/Mage.Sets/src/mage/sets/mirage/ShallowGrave.java index 67ef2954399..9ee5675fccf 100644 --- a/Mage.Sets/src/mage/sets/mirage/ShallowGrave.java +++ b/Mage.Sets/src/mage/sets/mirage/ShallowGrave.java @@ -100,7 +100,7 @@ class ShallowGraveEffect extends OneShotEffect { } } if (lastCreatureCard != null) { - if (controller.putOntoBattlefieldWithInfo(lastCreatureCard, game, Zone.GRAVEYARD, source.getSourceId())) { + if (controller.moveCards(lastCreatureCard, Zone.BATTLEFIELD, source, game)) { Permanent returnedCreature = game.getPermanent(lastCreatureCard.getId()); if (returnedCreature != null) { FixedTarget fixedTarget = new FixedTarget(returnedCreature, game); diff --git a/Mage.Sets/src/mage/sets/mirrodin/ScytheOfTheWretched.java b/Mage.Sets/src/mage/sets/mirrodin/ScytheOfTheWretched.java index a0b0f53927a..67e45f89c1a 100644 --- a/Mage.Sets/src/mage/sets/mirrodin/ScytheOfTheWretched.java +++ b/Mage.Sets/src/mage/sets/mirrodin/ScytheOfTheWretched.java @@ -158,8 +158,7 @@ class ScytheOfTheWretchedReanimateEffect extends OneShotEffect { Card card = game.getCard(getTargetPointer().getFirst(game, source)); Player controller = game.getPlayer(source.getControllerId()); if (card != null && controller != null) { - Zone currentZone = game.getState().getZone(card.getId()); - controller.putOntoBattlefieldWithInfo(card, game, currentZone, source.getSourceId()); + controller.moveCards(card, Zone.BATTLEFIELD, source, game); Effect effect = new AttachEffect(Outcome.AddAbility); effect.setTargetPointer(new FixedTarget(card.getId())); effect.apply(game, source); diff --git a/Mage.Sets/src/mage/sets/mirrodinbesieged/GreenSunsZenith.java b/Mage.Sets/src/mage/sets/mirrodinbesieged/GreenSunsZenith.java index eb95700b42a..03cb3e2fbf8 100644 --- a/Mage.Sets/src/mage/sets/mirrodinbesieged/GreenSunsZenith.java +++ b/Mage.Sets/src/mage/sets/mirrodinbesieged/GreenSunsZenith.java @@ -25,18 +25,18 @@ * authors and should not be interpreted as representing official policies, either expressed * or implied, of BetaSteward_at_googlemail.com. */ - package mage.sets.mirrodinbesieged; -import mage.constants.CardType; -import mage.constants.Rarity; +import java.util.UUID; import mage.ObjectColor; import mage.abilities.Ability; import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.ShuffleSpellEffect; import mage.cards.Card; import mage.cards.CardImpl; +import mage.constants.CardType; import mage.constants.Outcome; +import mage.constants.Rarity; import mage.constants.Zone; import mage.filter.Filter; import mage.filter.FilterCard; @@ -47,8 +47,6 @@ import mage.game.Game; import mage.players.Player; import mage.target.common.TargetCardInLibrary; -import java.util.UUID; - /** * @author Loki */ @@ -77,6 +75,7 @@ public class GreenSunsZenith extends CardImpl { } class GreenSunsZenithSearchEffect extends OneShotEffect { + GreenSunsZenithSearchEffect() { super(Outcome.PutCreatureInPlay); staticText = "Search your library for a green creature card with converted mana cost X or less, put it onto the battlefield, then shuffle your library"; @@ -88,28 +87,28 @@ class GreenSunsZenithSearchEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { - Player player = game.getPlayer(source.getControllerId()); - if (player == null) { + Player controller = game.getPlayer(source.getControllerId()); + if (controller == null) { return false; } //Set the mana cost one higher to 'emulate' a less than or equal to comparison. int xValue = source.getManaCostsToPay().getX() + 1; FilterCard filter = new FilterCard("green creature card with converted mana cost " + xValue + " or less"); filter.add(new ColorPredicate(ObjectColor.GREEN)); - filter.add(new CardTypePredicate(CardType.CREATURE)); + filter.add(new CardTypePredicate(CardType.CREATURE)); filter.add(new ConvertedManaCostPredicate(Filter.ComparisonType.LessThan, xValue)); TargetCardInLibrary target = new TargetCardInLibrary(filter); - if (player.searchLibrary(target, game)) { + if (controller.searchLibrary(target, game)) { if (target.getTargets().size() > 0) { - Card card = player.getLibrary().getCard(target.getFirstTarget(), game); + Card card = controller.getLibrary().getCard(target.getFirstTarget(), game); if (card != null) { - player.putOntoBattlefieldWithInfo(card, game, Zone.LIBRARY, source.getSourceId()); + controller.moveCards(card, Zone.BATTLEFIELD, source, game); } } - player.shuffleLibrary(game); + controller.shuffleLibrary(game); return true; } - player.shuffleLibrary(game); + controller.shuffleLibrary(game); return false; } diff --git a/Mage.Sets/src/mage/sets/modernmasters/ToothAndNail.java b/Mage.Sets/src/mage/sets/modernmasters/ToothAndNail.java index 86f2e6936b8..30762aeb3d7 100644 --- a/Mage.Sets/src/mage/sets/modernmasters/ToothAndNail.java +++ b/Mage.Sets/src/mage/sets/modernmasters/ToothAndNail.java @@ -33,8 +33,8 @@ import mage.abilities.Mode; import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.search.SearchLibraryPutInHandEffect; import mage.abilities.keyword.EntwineAbility; -import mage.cards.Card; import mage.cards.CardImpl; +import mage.cards.CardsImpl; import mage.constants.CardType; import mage.constants.Outcome; import mage.constants.Rarity; @@ -102,13 +102,8 @@ class ToothAndNailPutCreatureOnBattlefieldEffect extends OneShotEffect { TargetCardInHand target = new TargetCardInHand(0, 2, new FilterCreatureCard("creature cards")); if (controller.choose(Outcome.PutCreatureInPlay, target, source.getSourceId(), game)) { - for (UUID targetId : target.getTargets()) { - Card card = game.getCard(targetId); - if (card != null) { - controller.putOntoBattlefieldWithInfo(card, game, Zone.HAND, source.getSourceId(), false); - } - } - return true; + return controller.moveCards(new CardsImpl(getTargetPointer().getTargets(game, source)).getCards(game), + Zone.BATTLEFIELD, source, game, true, false, false, null); } return false; } diff --git a/Mage.Sets/src/mage/sets/morningtide/Scapeshift.java b/Mage.Sets/src/mage/sets/morningtide/Scapeshift.java index f1c69c592e4..5e7f57e6dd5 100644 --- a/Mage.Sets/src/mage/sets/morningtide/Scapeshift.java +++ b/Mage.Sets/src/mage/sets/morningtide/Scapeshift.java @@ -27,16 +27,14 @@ */ package mage.sets.morningtide; -import java.util.List; import java.util.UUID; - +import mage.abilities.Ability; +import mage.abilities.effects.OneShotEffect; +import mage.cards.CardImpl; +import mage.cards.CardsImpl; import mage.constants.CardType; import mage.constants.Outcome; import mage.constants.Rarity; -import mage.abilities.Ability; -import mage.abilities.effects.OneShotEffect; -import mage.cards.Card; -import mage.cards.CardImpl; import mage.constants.Zone; import mage.filter.common.FilterControlledLandPermanent; import mage.filter.common.FilterLandCard; @@ -56,7 +54,6 @@ public class Scapeshift extends CardImpl { super(ownerId, 136, "Scapeshift", Rarity.RARE, new CardType[]{CardType.SORCERY}, "{2}{G}{G}"); this.expansionSetCode = "MOR"; - // Sacrifice any number of lands. Search your library for that many land cards, put them onto the battlefield tapped, then shuffle your library. this.getSpellAbility().addEffect(new ScapeshiftEffect()); } @@ -71,12 +68,11 @@ public class Scapeshift extends CardImpl { } } - class ScapeshiftEffect extends OneShotEffect { public ScapeshiftEffect() { super(Outcome.Neutral); - staticText = "Sacrifice any number of lands. Search your library for that many land cards, put them onto the battlefield tapped, then shuffle your library"; + staticText = "Sacrifice any number of lands. Search your library for that many land cards, put them onto the battlefield tapped, then shuffle your library"; } public ScapeshiftEffect(final ScapeshiftEffect effect) { @@ -90,35 +86,29 @@ class ScapeshiftEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { - Player player = game.getPlayer(source.getControllerId()); - if (player == null){ + Player controller = game.getPlayer(source.getControllerId()); + if (controller == null) { return false; } int amount = 0; TargetControlledPermanent sacrificeLand = new TargetControlledPermanent(0, Integer.MAX_VALUE, new FilterControlledLandPermanent("lands you control"), true); - if(player.chooseTarget(Outcome.Sacrifice, sacrificeLand, source, game)){ - for(Object uuid : sacrificeLand.getTargets()){ - Permanent land = game.getPermanent((UUID)uuid); - if(land != null){ + if (controller.chooseTarget(Outcome.Sacrifice, sacrificeLand, source, game)) { + for (Object uuid : sacrificeLand.getTargets()) { + Permanent land = game.getPermanent((UUID) uuid); + if (land != null) { land.sacrifice(source.getSourceId(), game); amount++; } } } TargetCardInLibrary target = new TargetCardInLibrary(amount, new FilterLandCard("lands")); - if (player.searchLibrary(target, game)) { - if (target.getTargets().size() > 0) { - for (UUID cardId: (List)target.getTargets()) { - Card card = player.getLibrary().getCard(cardId, game); - if (card != null) { - player.putOntoBattlefieldWithInfo(card, game, Zone.LIBRARY, source.getControllerId(), true); - } - } - } - player.shuffleLibrary(game); + if (controller.searchLibrary(target, game)) { + controller.moveCards(new CardsImpl(target.getTargets()).getCards(game), + Zone.BATTLEFIELD, source, game, true, false, false, null); + controller.shuffleLibrary(game); return true; } - player.shuffleLibrary(game); + controller.shuffleLibrary(game); return false; } diff --git a/Mage.Sets/src/mage/sets/nemesis/LinSivviDefiantHero.java b/Mage.Sets/src/mage/sets/nemesis/LinSivviDefiantHero.java index efc9dcd7c22..3748ad54259 100644 --- a/Mage.Sets/src/mage/sets/nemesis/LinSivviDefiantHero.java +++ b/Mage.Sets/src/mage/sets/nemesis/LinSivviDefiantHero.java @@ -59,16 +59,16 @@ import mage.target.common.TargetCardInYourGraveyard; * @author fireshoes */ public class LinSivviDefiantHero extends CardImpl { - + private static final FilterCard filter = new FilterCard("Rebel card from your graveyard"); - + static { filter.add(new OwnerPredicate(TargetController.YOU)); filter.add(new SubtypePredicate("Rebel")); } - + static final String rule = "Put target Rebel card from your graveyard on the bottom of your library"; - + public LinSivviDefiantHero(UUID ownerId) { super(ownerId, 12, "Lin Sivvi, Defiant Hero", Rarity.RARE, new CardType[]{CardType.CREATURE}, "{1}{W}{W}"); this.expansionSetCode = "NMS"; @@ -84,7 +84,7 @@ public class LinSivviDefiantHero extends CardImpl { new ManaCostsImpl("{X}")); ability.addCost(new TapSourceCost()); this.addAbility(ability); - + // {3}: Put target Rebel card from your graveyard on the bottom of your library. ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new PutOnLibraryTargetEffect(false, rule), new GenericManaCost(3)); ability.addTarget(new TargetCardInYourGraveyard(1, filter)); @@ -119,8 +119,8 @@ class LinSivviDefiantHeroEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { - Player player = game.getPlayer(source.getControllerId()); - if (player == null) { + Player controller = game.getPlayer(source.getControllerId()); + if (controller == null) { return false; } @@ -131,15 +131,15 @@ class LinSivviDefiantHeroEffect extends OneShotEffect { filter.add(new SubtypePredicate("Rebel")); TargetCardInLibrary target = new TargetCardInLibrary(filter); - if (player.searchLibrary(target, game)) { - Card card = player.getLibrary().getCard(target.getFirstTarget(), game); + if (controller.searchLibrary(target, game)) { + Card card = controller.getLibrary().getCard(target.getFirstTarget(), game); if (card != null) { - player.putOntoBattlefieldWithInfo(card, game, Zone.LIBRARY, source.getSourceId()); + controller.moveCards(card, Zone.BATTLEFIELD, source, game); } - player.shuffleLibrary(game); + controller.shuffleLibrary(game); return true; } - player.shuffleLibrary(game); + controller.shuffleLibrary(game); return false; } -} \ No newline at end of file +} diff --git a/Mage.Sets/src/mage/sets/newphyrexia/BirthingPod.java b/Mage.Sets/src/mage/sets/newphyrexia/BirthingPod.java index 03790814187..8109def52a8 100644 --- a/Mage.Sets/src/mage/sets/newphyrexia/BirthingPod.java +++ b/Mage.Sets/src/mage/sets/newphyrexia/BirthingPod.java @@ -28,9 +28,6 @@ package mage.sets.newphyrexia; import java.util.UUID; - -import mage.constants.CardType; -import mage.constants.Rarity; import mage.abilities.Ability; import mage.abilities.common.ActivateAsSorceryActivatedAbility; import mage.abilities.costs.Cost; @@ -40,7 +37,9 @@ import mage.abilities.costs.mana.ManaCostsImpl; import mage.abilities.effects.OneShotEffect; import mage.cards.Card; import mage.cards.CardImpl; +import mage.constants.CardType; import mage.constants.Outcome; +import mage.constants.Rarity; import mage.constants.Zone; import mage.filter.Filter; import mage.filter.FilterCard; @@ -61,7 +60,6 @@ public class BirthingPod extends CardImpl { super(ownerId, 104, "Birthing Pod", Rarity.RARE, new CardType[]{CardType.ARTIFACT}, "{3}{GP}"); this.expansionSetCode = "NPH"; - // {1}{GP}, {tap}, Sacrifice a creature: Search your library for a creature card with converted mana cost equal to 1 plus the sacrificed creature's converted mana cost, put that card onto the battlefield, then shuffle your library. Activate this ability only any time you could cast a sorcery. Ability ability = new ActivateAsSorceryActivatedAbility(Zone.BATTLEFIELD, new BirthingPodEffect(), new ManaCostsImpl("{1}{GP}")); ability.addCost(new TapSourceCost()); @@ -80,6 +78,7 @@ public class BirthingPod extends CardImpl { } class BirthingPodEffect extends OneShotEffect { + BirthingPodEffect() { super(Outcome.Benefit); staticText = "Search your library for a creature card with converted mana cost equal to 1 plus the sacrificed creature's converted mana cost, put that card onto the battlefield, then shuffle your library"; @@ -101,22 +100,18 @@ class BirthingPodEffect extends OneShotEffect { break; } } - Player player = game.getPlayer(source.getControllerId()); - if (sacrificedPermanent != null && player != null) { + Player controller = game.getPlayer(source.getControllerId()); + if (sacrificedPermanent != null && controller != null) { int newConvertedCost = sacrificedPermanent.getManaCost().convertedManaCost() + 1; FilterCard filter = new FilterCard("creature card with converted mana cost " + newConvertedCost); filter.add(new ConvertedManaCostPredicate(Filter.ComparisonType.Equal, newConvertedCost)); filter.add(new CardTypePredicate(CardType.CREATURE)); TargetCardInLibrary target = new TargetCardInLibrary(filter); - if (player.searchLibrary(target, game)) { - for (UUID cardId : target.getTargets()) { - Card card = player.getLibrary().getCard(cardId, game); - if (card != null) { - player.putOntoBattlefieldWithInfo(card, game, Zone.LIBRARY, source.getSourceId()); - } - } + if (controller.searchLibrary(target, game)) { + Card card = controller.getLibrary().getCard(target.getFirstTarget(), game); + controller.moveCards(card, Zone.BATTLEFIELD, source, game); } - player.shuffleLibrary(game); + controller.shuffleLibrary(game); return true; } return false; diff --git a/Mage.Sets/src/mage/sets/newphyrexia/MeliraSylvokOutcast.java b/Mage.Sets/src/mage/sets/newphyrexia/MeliraSylvokOutcast.java index b43ddb45473..0e370f97e18 100644 --- a/Mage.Sets/src/mage/sets/newphyrexia/MeliraSylvokOutcast.java +++ b/Mage.Sets/src/mage/sets/newphyrexia/MeliraSylvokOutcast.java @@ -29,13 +29,6 @@ package mage.sets.newphyrexia; import java.util.Set; import java.util.UUID; -import mage.constants.CardType; -import mage.constants.Duration; -import mage.constants.Layer; -import mage.constants.Outcome; -import mage.constants.Rarity; -import mage.constants.SubLayer; -import mage.constants.Zone; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.SimpleStaticAbility; @@ -43,6 +36,13 @@ import mage.abilities.effects.ContinuousEffectImpl; import mage.abilities.effects.ReplacementEffectImpl; import mage.abilities.keyword.InfectAbility; import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.Layer; +import mage.constants.Outcome; +import mage.constants.Rarity; +import mage.constants.SubLayer; +import mage.constants.Zone; import mage.counters.CounterType; import mage.filter.common.FilterCreaturePermanent; import mage.game.Game; @@ -63,7 +63,6 @@ public class MeliraSylvokOutcast extends CardImpl { this.subtype.add("Human"); this.subtype.add("Scout"); - this.power = new MageInt(2); this.toughness = new MageInt(2); @@ -113,7 +112,7 @@ class MeliraSylvokOutcastEffect extends ReplacementEffectImpl { public boolean checksEventType(GameEvent event, Game game) { return event.getType() == EventType.ADD_COUNTER; } - + @Override public boolean applies(GameEvent event, Ability source, Game game) { return event.getData().equals(CounterType.POISON.getName()) && event.getTargetId().equals(source.getControllerId()); @@ -141,16 +140,19 @@ class MeliraSylvokOutcastEffect2 extends ReplacementEffectImpl { public boolean replaceEvent(GameEvent event, Ability source, Game game) { return true; } - + @Override public boolean checksEventType(GameEvent event, Game game) { return event.getType() == EventType.ADD_COUNTER; } - + @Override public boolean applies(GameEvent event, Ability source, Game game) { if (event.getData().equals(CounterType.M1M1.getName())) { Permanent perm = game.getPermanent(event.getTargetId()); + if (perm == null) { + perm = game.getPermanentEntering(event.getTargetId()); + } if (perm != null && perm.getCardType().contains(CardType.CREATURE) && perm.getControllerId().equals(source.getControllerId())) { return true; } @@ -181,7 +183,7 @@ class MeliraSylvokOutcastEffect3 extends ContinuousEffectImpl { @Override public boolean apply(Game game, Ability source) { Set opponents = game.getOpponents(source.getControllerId()); - for (Permanent perm: game.getBattlefield().getActivePermanents(filter, source.getControllerId(), game)) { + for (Permanent perm : game.getBattlefield().getActivePermanents(filter, source.getControllerId(), game)) { if (opponents.contains(perm.getControllerId())) { perm.getAbilities().remove(InfectAbility.getInstance()); } diff --git a/Mage.Sets/src/mage/sets/odyssey/Zoologist.java b/Mage.Sets/src/mage/sets/odyssey/Zoologist.java index 5780599cfe9..cc7330b0491 100644 --- a/Mage.Sets/src/mage/sets/odyssey/Zoologist.java +++ b/Mage.Sets/src/mage/sets/odyssey/Zoologist.java @@ -29,6 +29,7 @@ package mage.sets.odyssey; import java.util.UUID; import mage.MageInt; +import mage.MageObject; import mage.abilities.Ability; import mage.abilities.common.SimpleActivatedAbility; import mage.abilities.costs.common.TapSourceCost; @@ -36,7 +37,6 @@ import mage.abilities.costs.mana.ManaCostsImpl; import mage.abilities.effects.OneShotEffect; import mage.cards.Card; import mage.cards.CardImpl; -import mage.cards.Cards; import mage.cards.CardsImpl; import mage.constants.CardType; import mage.constants.Outcome; @@ -94,25 +94,23 @@ class ZoologistEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { - Player player = game.getPlayer(source.getControllerId()); - if (player == null) { + Player controller = game.getPlayer(source.getControllerId()); + MageObject sourceObject = source.getSourceObject(game); + if (controller == null || sourceObject == null) { return false; } - if (player.getLibrary().size() > 0) { - Card card = player.getLibrary().getFromTop(game); - Cards cards = new CardsImpl(); - cards.add(card); - player.revealCards("Zoologist", cards, game); - + if (controller.getLibrary().size() > 0) { + Card card = controller.getLibrary().getFromTop(game); + controller.revealCards(sourceObject.getIdName(), new CardsImpl(card), game); if (card != null) { if (card.getCardType().contains(CardType.CREATURE)) { - player.putOntoBattlefieldWithInfo(card, game, Zone.LIBRARY, source.getSourceId()); + controller.moveCards(card, Zone.BATTLEFIELD, source, game); } else { - player.moveCards(card, Zone.LIBRARY, Zone.GRAVEYARD, source, game); + controller.moveCards(card, Zone.GRAVEYARD, source, game); } } } - return false; + return true; } } diff --git a/Mage.Sets/src/mage/sets/onslaught/PatriarchsBidding.java b/Mage.Sets/src/mage/sets/onslaught/PatriarchsBidding.java index 42b4dfd2de0..61d54f0c357 100644 --- a/Mage.Sets/src/mage/sets/onslaught/PatriarchsBidding.java +++ b/Mage.Sets/src/mage/sets/onslaught/PatriarchsBidding.java @@ -35,7 +35,6 @@ import java.util.UUID; import mage.MageObject; import mage.abilities.Ability; import mage.abilities.effects.OneShotEffect; -import mage.cards.Card; import mage.cards.CardImpl; import mage.cards.repository.CardRepository; import mage.choices.Choice; @@ -78,7 +77,7 @@ class PatriarchsBiddingEffect extends OneShotEffect { public PatriarchsBiddingEffect() { super(Outcome.PutCreatureInPlay); - this.staticText = "Each player chooses a creature type. Each player returns all creature cards of a type chosen this way from his or her graveyard to the battlefield."; + this.staticText = "each player chooses a creature type. Each player returns all creature cards of a type chosen this way from his or her graveyard to the battlefield"; } public PatriarchsBiddingEffect(final PatriarchsBiddingEffect effect) { @@ -91,12 +90,12 @@ class PatriarchsBiddingEffect extends OneShotEffect { } @Override - public boolean apply(Game game, Ability ability) { - Player controller = game.getPlayer(ability.getControllerId()); - MageObject sourceObject = game.getObject(ability.getSourceId()); + public boolean apply(Game game, Ability source) { + Player controller = game.getPlayer(source.getControllerId()); + MageObject sourceObject = game.getObject(source.getSourceId()); if (controller != null) { Set chosenTypes = new HashSet<>(); - for (UUID playerId : controller.getInRange()) { + for (UUID playerId : game.getState().getPlayersInRange(controller.getId(), game)) { Player player = game.getPlayer(playerId); Choice typeChoice = new ChoiceImpl(true); typeChoice.setMessage("Choose a creature type"); @@ -108,24 +107,21 @@ class PatriarchsBiddingEffect extends OneShotEffect { } String chosenType = typeChoice.getChoice(); if (chosenType != null) { - game.informPlayers(sourceObject.getName() + ": " + player.getLogName() + " has chosen " + chosenType); + game.informPlayers(sourceObject.getLogName() + ": " + player.getLogName() + " has chosen " + chosenType); chosenTypes.add(chosenType); } } - + List predicates = new ArrayList<>(); for (String type : chosenTypes) { predicates.add(new SubtypePredicate(type)); } FilterCard filter = new FilterCreatureCard(); filter.add(Predicates.or(predicates)); - - for (UUID playerId : controller.getInRange()) { + for (UUID playerId : game.getState().getPlayersInRange(controller.getId(), game)) { Player player = game.getPlayer(playerId); if (player != null) { - for (Card card : player.getGraveyard().getCards(filter, game)) { - player.putOntoBattlefieldWithInfo(card, game, Zone.GRAVEYARD, ability.getSourceId()); - } + player.moveCards(player.getGraveyard().getCards(filter, game), Zone.BATTLEFIELD, source, game); } } return true; diff --git a/Mage.Sets/src/mage/sets/onslaught/RiptideShapeshifter.java b/Mage.Sets/src/mage/sets/onslaught/RiptideShapeshifter.java index 0f4b766a2cd..72ff1eb3c97 100644 --- a/Mage.Sets/src/mage/sets/onslaught/RiptideShapeshifter.java +++ b/Mage.Sets/src/mage/sets/onslaught/RiptideShapeshifter.java @@ -29,6 +29,7 @@ package mage.sets.onslaught; import java.util.UUID; import mage.MageInt; +import mage.MageObject; import mage.abilities.Ability; import mage.abilities.common.SimpleActivatedAbility; import mage.abilities.costs.common.SacrificeSourceCost; @@ -79,47 +80,46 @@ public class RiptideShapeshifter extends CardImpl { } class RiptideShapeshifterEffect extends OneShotEffect { - + RiptideShapeshifterEffect() { super(Outcome.PutCreatureInPlay); this.staticText = "Choose a creature type. Reveal cards from the top of your library until you reveal a creature card of that type. Put that card onto the battlefield and shuffle the rest into your library"; } - + RiptideShapeshifterEffect(final RiptideShapeshifterEffect effect) { super(effect); } - + @Override public RiptideShapeshifterEffect copy() { return new RiptideShapeshifterEffect(this); } - + @Override public boolean apply(Game game, Ability source) { - Player player = game.getPlayer(source.getControllerId()); - if (player != null) { + Player controller = game.getPlayer(source.getControllerId()); + MageObject sourceObject = source.getSourceObject(game); + if (controller != null && sourceObject != null) { Choice choice = new ChoiceImpl(true); choice.setMessage("Choose a creature type:"); choice.setChoices(CardRepository.instance.getCreatureTypes()); - while (!player.choose(Outcome.BoostCreature, choice, game)) { - if (!player.canRespond()) { + while (!controller.choose(Outcome.BoostCreature, choice, game)) { + if (!controller.canRespond()) { return false; } } Cards revealedCards = new CardsImpl(); - while (player.getLibrary().size() > 0) { - Card card = player.getLibrary().removeFromTop(game); + while (controller.getLibrary().size() > 0) { + Card card = controller.getLibrary().removeFromTop(game); if (card.getCardType().contains(CardType.CREATURE) && card.getSubtype().contains(choice.getChoice())) { - player.putOntoBattlefieldWithInfo(card, game, Zone.LIBRARY, source.getSourceId()); + controller.moveCards(card, Zone.BATTLEFIELD, source, game); break; } revealedCards.add(card); } - player.revealCards("Riptide Shapeshifter", revealedCards, game); - for (Card card: revealedCards.getCards(game)) { - card.moveToZone(Zone.LIBRARY, source.getSourceId(), game, true); - } - player.shuffleLibrary(game); + controller.revealCards(sourceObject.getIdName(), revealedCards, game); + controller.moveCards(revealedCards, Zone.LIBRARY, source, game); + controller.shuffleLibrary(game); return true; } return false; diff --git a/Mage.Sets/src/mage/sets/ravnica/SistersOfStoneDeath.java b/Mage.Sets/src/mage/sets/ravnica/SistersOfStoneDeath.java index 92302fb34a7..13fa2e682d0 100644 --- a/Mage.Sets/src/mage/sets/ravnica/SistersOfStoneDeath.java +++ b/Mage.Sets/src/mage/sets/ravnica/SistersOfStoneDeath.java @@ -43,7 +43,7 @@ import mage.constants.CardType; import mage.constants.Outcome; import mage.constants.Rarity; import mage.constants.Zone; -import mage.filter.FilterCard; +import mage.filter.common.FilterCreatureCard; import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.Predicates; import mage.filter.predicate.permanent.BlockedByIdPredicate; @@ -101,7 +101,7 @@ public class SistersOfStoneDeath extends CardImpl { class SistersOfStoneDeathEffect extends OneShotEffect { - private UUID exileId; + private final UUID exileId; public SistersOfStoneDeathEffect(UUID exileId) { super(Outcome.PutCreatureInPlay); @@ -117,7 +117,7 @@ class SistersOfStoneDeathEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { CardsImpl cardsInExile = new CardsImpl(); - TargetCard target = new TargetCard(Zone.PICK, new FilterCard()); + TargetCard target = new TargetCard(Zone.EXILED, new FilterCreatureCard()); Player controller = game.getPlayer(source.getControllerId()); if (controller != null) { ExileZone exile = game.getExile().getExileZone(exileId); @@ -129,7 +129,7 @@ class SistersOfStoneDeathEffect extends OneShotEffect { } if (controller.choose(Outcome.PutCreatureInPlay, cardsInExile, target, game)) { Card chosenCard = game.getCard(target.getFirstTarget()); - return controller.moveCards(chosenCard, Zone.EXILED, source, game); + return controller.moveCards(chosenCard, Zone.BATTLEFIELD, source, game); } } } diff --git a/Mage.Sets/src/mage/sets/returntoravnica/CorpsejackMenace.java b/Mage.Sets/src/mage/sets/returntoravnica/CorpsejackMenace.java index a5d959857b3..10bf030e45a 100644 --- a/Mage.Sets/src/mage/sets/returntoravnica/CorpsejackMenace.java +++ b/Mage.Sets/src/mage/sets/returntoravnica/CorpsejackMenace.java @@ -40,7 +40,6 @@ import mage.constants.Rarity; import mage.constants.Zone; import mage.counters.CounterType; import mage.game.Game; -import mage.game.events.EntersTheBattlefieldEvent; import mage.game.events.GameEvent; import mage.game.permanent.Permanent; @@ -96,7 +95,7 @@ class CorpsejackMenaceReplacementEffect extends ReplacementEffectImpl { public boolean replaceEvent(GameEvent event, Ability source, Game game) { Permanent permanent = game.getPermanent(event.getTargetId()); if (permanent == null) { - permanent = ((EntersTheBattlefieldEvent) event).getTarget(); + permanent = game.getPermanentEntering(event.getTargetId()); } if (permanent != null) { permanent.addCounters(CounterType.P1P1.createInstance(event.getAmount() * 2), game, event.getAppliedEffects()); @@ -112,7 +111,7 @@ class CorpsejackMenaceReplacementEffect extends ReplacementEffectImpl { @Override public boolean applies(GameEvent event, Ability source, Game game) { if (event.getData().equals(CounterType.P1P1.getName())) { - Permanent permanent = ((EntersTheBattlefieldEvent) event).getTarget(); + Permanent permanent = game.getPermanent(event.getTargetId()); if (permanent == null) { permanent = game.getPermanentEntering(event.getTargetId()); } diff --git a/Mage.Sets/src/mage/sets/returntoravnica/VolatileRig.java b/Mage.Sets/src/mage/sets/returntoravnica/VolatileRig.java index cc804adcfad..8a43a92c249 100644 --- a/Mage.Sets/src/mage/sets/returntoravnica/VolatileRig.java +++ b/Mage.Sets/src/mage/sets/returntoravnica/VolatileRig.java @@ -195,7 +195,7 @@ class VolatileRigEffect2 extends OneShotEffect { for (Permanent permanent: permanents) { permanent.damage(4, source.getSourceId(), game, false, true); } - for (UUID playerId: player.getInRange()) { + for (UUID playerId: game.getState().getPlayersInRange(player.getId(), game)) { Player damageToPlayer = game.getPlayer(playerId); if (damageToPlayer != null) { damageToPlayer.damage(4, source.getSourceId(), game, false, true); diff --git a/Mage.Sets/src/mage/sets/saviorsofkamigawa/EnduringIdeal.java b/Mage.Sets/src/mage/sets/saviorsofkamigawa/EnduringIdeal.java index b3483485a0a..02c4cf52ea5 100644 --- a/Mage.Sets/src/mage/sets/saviorsofkamigawa/EnduringIdeal.java +++ b/Mage.Sets/src/mage/sets/saviorsofkamigawa/EnduringIdeal.java @@ -46,7 +46,7 @@ import mage.target.common.TargetCardInLibrary; /** * * @author jeffwadsworth - + * */ public class EnduringIdeal extends CardImpl { @@ -54,13 +54,12 @@ public class EnduringIdeal extends CardImpl { super(ownerId, 9, "Enduring Ideal", Rarity.RARE, new CardType[]{CardType.SORCERY}, "{5}{W}{W}"); this.expansionSetCode = "SOK"; - // Search your library for an enchantment card and put it onto the battlefield. Then shuffle your library. this.getSpellAbility().addEffect(new EnduringIdealEffect()); - + // Epic this.getSpellAbility().addEffect(new EpicEffect()); - + } public EnduringIdeal(final EnduringIdeal card) { @@ -74,9 +73,9 @@ public class EnduringIdeal extends CardImpl { } class EnduringIdealEffect extends OneShotEffect { - + private static final FilterCard filter = new FilterCard(); - + static { filter.add(new CardTypePredicate(CardType.ENCHANTMENT)); } @@ -93,16 +92,16 @@ class EnduringIdealEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { boolean applied = false; - Player you = game.getPlayer(source.getControllerId()); - if (you != null) { + Player controller = game.getPlayer(source.getControllerId()); + if (controller != null) { TargetCardInLibrary target = new TargetCardInLibrary(filter); - you.searchLibrary(target, game); + controller.searchLibrary(target, game); Card targetCard = game.getCard(target.getFirstTarget()); if (targetCard == null) { applied = false; - } else{ - applied = you.putOntoBattlefieldWithInfo(targetCard, game, Zone.LIBRARY, source.getSourceId()); - you.shuffleLibrary(game); + } else { + applied = controller.moveCards(targetCard, Zone.BATTLEFIELD, source, game); + controller.shuffleLibrary(game); } } return applied; diff --git a/Mage.Sets/src/mage/sets/saviorsofkamigawa/EternalDominion.java b/Mage.Sets/src/mage/sets/saviorsofkamigawa/EternalDominion.java index cd5d754421b..7b63cd400fe 100644 --- a/Mage.Sets/src/mage/sets/saviorsofkamigawa/EternalDominion.java +++ b/Mage.Sets/src/mage/sets/saviorsofkamigawa/EternalDominion.java @@ -56,12 +56,11 @@ public class EternalDominion extends CardImpl { super(ownerId, 36, "Eternal Dominion", Rarity.RARE, new CardType[]{CardType.SORCERY}, "{7}{U}{U}{U}"); this.expansionSetCode = "SOK"; - // Search target opponent's library for an artifact, creature, enchantment, or land card. // Put that card onto the battlefield under your control. Then that player shuffles his or her library. this.getSpellAbility().addEffect(new EternalDominionEffect()); this.getSpellAbility().addTarget(new TargetOpponent()); - + // Epic this.getSpellAbility().addEffect(new EpicEffect()); @@ -78,9 +77,9 @@ public class EternalDominion extends CardImpl { } class EternalDominionEffect extends OneShotEffect { - + private static final FilterCard filter = new FilterCard("an artifact, creature, enchantment, or land card"); - + static { filter.add(Predicates.or(new CardTypePredicate(CardType.ARTIFACT), new CardTypePredicate(CardType.CREATURE), @@ -101,13 +100,13 @@ class EternalDominionEffect extends OneShotEffect { public boolean apply(Game game, Ability source) { boolean applied = false; Player opponent = game.getPlayer(source.getFirstTarget()); - Player you = game.getPlayer(source.getControllerId()); - if (opponent != null && you != null) { + Player controller = game.getPlayer(source.getControllerId()); + if (opponent != null && controller != null) { TargetCardInLibrary target = new TargetCardInLibrary(filter); - you.searchLibrary(target, game, opponent.getId()); + controller.searchLibrary(target, game, opponent.getId()); Card targetCard = game.getCard(target.getFirstTarget()); if (targetCard != null) { - applied = you.putOntoBattlefieldWithInfo(targetCard, game, Zone.LIBRARY, source.getSourceId()); + applied = controller.moveCards(targetCard, Zone.BATTLEFIELD, source, game); } opponent.shuffleLibrary(game); } diff --git a/Mage.Sets/src/mage/sets/saviorsofkamigawa/FootstepsOfTheGoryo.java b/Mage.Sets/src/mage/sets/saviorsofkamigawa/FootstepsOfTheGoryo.java index 1e3be38179f..1fe60da5cad 100644 --- a/Mage.Sets/src/mage/sets/saviorsofkamigawa/FootstepsOfTheGoryo.java +++ b/Mage.Sets/src/mage/sets/saviorsofkamigawa/FootstepsOfTheGoryo.java @@ -28,7 +28,6 @@ package mage.sets.saviorsofkamigawa; import java.util.UUID; - import mage.abilities.Ability; import mage.abilities.DelayedTriggeredAbility; import mage.abilities.common.delayed.AtTheBeginOfNextEndStepDelayedTriggeredAbility; @@ -37,7 +36,10 @@ import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.SacrificeTargetEffect; import mage.cards.Card; import mage.cards.CardImpl; -import mage.constants.*; +import mage.constants.CardType; +import mage.constants.Outcome; +import mage.constants.Rarity; +import mage.constants.Zone; import mage.filter.common.FilterCreatureCard; import mage.game.Game; import mage.game.permanent.Permanent; @@ -93,7 +95,7 @@ class FootstepsOfTheGoryoEffect extends OneShotEffect { if (controller != null) { Card card = game.getCard(getTargetPointer().getFirst(game, source)); if (card != null) { - if (controller.putOntoBattlefieldWithInfo(card, game, Zone.GRAVEYARD, source.getSourceId())) { + if (controller.moveCards(card, Zone.BATTLEFIELD, source, game)) { Permanent permanent = game.getPermanent(card.getId()); if (permanent != null) { // Sacrifice it at end of turn @@ -104,11 +106,10 @@ class FootstepsOfTheGoryoEffect extends OneShotEffect { delayedAbility.setControllerId(source.getControllerId()); delayedAbility.setSourceObject(source.getSourceObject(game), game); game.addDelayedTriggeredAbility(delayedAbility); - return true; - } } } + return true; } return false; } diff --git a/Mage.Sets/src/mage/sets/shadowmoor/ImpromptuRaid.java b/Mage.Sets/src/mage/sets/shadowmoor/ImpromptuRaid.java index 690b42690dd..de9ede0bc2d 100644 --- a/Mage.Sets/src/mage/sets/shadowmoor/ImpromptuRaid.java +++ b/Mage.Sets/src/mage/sets/shadowmoor/ImpromptuRaid.java @@ -117,7 +117,7 @@ class ImpromptuRaidEffect extends OneShotEffect { controller.moveCards(card, Zone.LIBRARY, Zone.GRAVEYARD, source, game); return true; } - if (controller.putOntoBattlefieldWithInfo(card, game, Zone.LIBRARY, source.getSourceId())) { + if (controller.moveCards(card, Zone.BATTLEFIELD, source, game)) { Permanent permanent = game.getPermanent(card.getId()); if (permanent != null) { ContinuousEffect effect = new GainAbilityTargetEffect(HasteAbility.getInstance(), Duration.EndOfTurn); diff --git a/Mage.Sets/src/mage/sets/shadowmoor/PuppeteerClique.java b/Mage.Sets/src/mage/sets/shadowmoor/PuppeteerClique.java index 3fb47b66b54..c0568cfaf3a 100644 --- a/Mage.Sets/src/mage/sets/shadowmoor/PuppeteerClique.java +++ b/Mage.Sets/src/mage/sets/shadowmoor/PuppeteerClique.java @@ -116,16 +116,16 @@ class PuppeteerCliqueEffect extends OneShotEffect { boolean result = false; Card card = game.getCard(getTargetPointer().getFirst(game, source)); if (card != null) { - Player you = game.getPlayer(source.getControllerId()); - if (you != null) { - if (you.putOntoBattlefieldWithInfo(card, game, Zone.GRAVEYARD, source.getSourceId())) { + Player controller = game.getPlayer(source.getControllerId()); + if (controller != null) { + if (controller.moveCards(card, Zone.BATTLEFIELD, source, game)) { Permanent permanent = game.getPermanent(card.getId()); if (permanent != null) { ContinuousEffect hasteEffect = new GainAbilityTargetEffect(HasteAbility.getInstance(), Duration.Custom); - hasteEffect.setTargetPointer(new FixedTarget(permanent.getId())); + hasteEffect.setTargetPointer(new FixedTarget(permanent, game)); game.addEffect(hasteEffect, source); ExileTargetEffect exileEffect = new ExileTargetEffect("exile " + permanent.getLogName()); - exileEffect.setTargetPointer(new FixedTarget(card.getId())); + exileEffect.setTargetPointer(new FixedTarget(permanent, game)); DelayedTriggeredAbility delayedAbility = new AtTheBeginOfNextEndStepDelayedTriggeredAbility(exileEffect, TargetController.YOU); delayedAbility.setSourceId(source.getSourceId()); delayedAbility.setControllerId(source.getControllerId()); diff --git a/Mage.Sets/src/mage/sets/shardsofalara/TezzeretTheSeeker.java b/Mage.Sets/src/mage/sets/shardsofalara/TezzeretTheSeeker.java index af865ed4cee..d4a44c46efb 100644 --- a/Mage.Sets/src/mage/sets/shardsofalara/TezzeretTheSeeker.java +++ b/Mage.Sets/src/mage/sets/shardsofalara/TezzeretTheSeeker.java @@ -107,8 +107,8 @@ class TezzeretTheSeekerEffect2 extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { - Player player = game.getPlayer(source.getControllerId()); - if (player == null) { + Player controller = game.getPlayer(source.getControllerId()); + if (controller == null) { return false; } @@ -123,15 +123,15 @@ class TezzeretTheSeekerEffect2 extends OneShotEffect { filter.add(new ConvertedManaCostPredicate(ComparisonType.LessThan, cmc + 1)); TargetCardInLibrary target = new TargetCardInLibrary(filter); - if (player.searchLibrary(target, game)) { - Card card = player.getLibrary().getCard(target.getFirstTarget(), game); + if (controller.searchLibrary(target, game)) { + Card card = controller.getLibrary().getCard(target.getFirstTarget(), game); if (card != null) { - player.putOntoBattlefieldWithInfo(card, game, Zone.LIBRARY, source.getSourceId()); + controller.moveCards(card, Zone.BATTLEFIELD, source, game); } - player.shuffleLibrary(game); + controller.shuffleLibrary(game); return true; } - player.shuffleLibrary(game); + controller.shuffleLibrary(game); return false; } } diff --git a/Mage.Sets/src/mage/sets/tempest/CorpseDance.java b/Mage.Sets/src/mage/sets/tempest/CorpseDance.java index a7589fdc5c7..0087bb59d0c 100644 --- a/Mage.Sets/src/mage/sets/tempest/CorpseDance.java +++ b/Mage.Sets/src/mage/sets/tempest/CorpseDance.java @@ -45,6 +45,7 @@ import mage.constants.Outcome; import mage.constants.Rarity; import mage.constants.Zone; import mage.game.Game; +import mage.game.permanent.Permanent; import mage.players.Player; import mage.target.targetpointer.FixedTarget; @@ -58,7 +59,6 @@ public class CorpseDance extends CardImpl { super(ownerId, 10, "Corpse Dance", Rarity.RARE, new CardType[]{CardType.INSTANT}, "{2}{B}"); this.expansionSetCode = "TMP"; - // Buyback {2} this.addAbility(new BuybackAbility("{2}")); @@ -97,26 +97,29 @@ class CorpseDanceEffect extends OneShotEffect { Player controller = game.getPlayer(source.getControllerId()); if (controller != null) { Card lastCreatureCard = null; - for (Card card :controller.getGraveyard().getCards(game)) { + for (Card card : controller.getGraveyard().getCards(game)) { if (card.getCardType().contains(CardType.CREATURE)) { lastCreatureCard = card; } } if (lastCreatureCard != null) { - if (controller.putOntoBattlefieldWithInfo(lastCreatureCard, game, Zone.GRAVEYARD, source.getSourceId())) { - FixedTarget fixedTarget = new FixedTarget(lastCreatureCard.getId()); - // Gains Haste - ContinuousEffect hasteEffect = new GainAbilityTargetEffect(HasteAbility.getInstance(), Duration.EndOfTurn); - hasteEffect.setTargetPointer(fixedTarget); - game.addEffect(hasteEffect, source); - // Exile it at end of turn - ExileTargetEffect exileEffect = new ExileTargetEffect(null,"",Zone.BATTLEFIELD); - exileEffect.setTargetPointer(fixedTarget); - DelayedTriggeredAbility delayedAbility = new AtTheBeginOfNextEndStepDelayedTriggeredAbility(exileEffect); - delayedAbility.setSourceId(source.getSourceId()); - delayedAbility.setControllerId(source.getControllerId()); - delayedAbility.setSourceObject(source.getSourceObject(game), game); - game.addDelayedTriggeredAbility(delayedAbility); + if (controller.moveCards(lastCreatureCard, Zone.BATTLEFIELD, source, game)) { + Permanent creature = game.getPermanent(lastCreatureCard.getId()); + if (creature != null) { + FixedTarget fixedTarget = new FixedTarget(creature, game); + // Gains Haste + ContinuousEffect hasteEffect = new GainAbilityTargetEffect(HasteAbility.getInstance(), Duration.EndOfTurn); + hasteEffect.setTargetPointer(fixedTarget); + game.addEffect(hasteEffect, source); + // Exile it at end of turn + ExileTargetEffect exileEffect = new ExileTargetEffect(null, "", Zone.BATTLEFIELD); + exileEffect.setTargetPointer(fixedTarget); + DelayedTriggeredAbility delayedAbility = new AtTheBeginOfNextEndStepDelayedTriggeredAbility(exileEffect); + 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/LivingDeath.java b/Mage.Sets/src/mage/sets/tempest/LivingDeath.java index f3c071223d2..1980018d64a 100644 --- a/Mage.Sets/src/mage/sets/tempest/LivingDeath.java +++ b/Mage.Sets/src/mage/sets/tempest/LivingDeath.java @@ -27,6 +27,9 @@ */ package mage.sets.tempest; +import java.util.HashMap; +import java.util.Map; +import java.util.Set; import java.util.UUID; import mage.MageObject; import mage.abilities.Ability; @@ -39,7 +42,6 @@ import mage.constants.Rarity; import mage.constants.Zone; import mage.filter.common.FilterCreatureCard; import mage.filter.common.FilterCreaturePermanent; -import mage.game.ExileZone; import mage.game.Game; import mage.game.permanent.Permanent; import mage.players.Player; @@ -89,27 +91,31 @@ class LivingDeathEffect extends OneShotEffect { Player controller = game.getPlayer(source.getControllerId()); MageObject sourceObject = game.getObject(source.getSourceId()); if (controller != null && sourceObject != null) { + Map> exiledCards = new HashMap<>(); // move creature cards from graveyard to exile - for (UUID playerId : controller.getInRange()) { + for (UUID playerId : game.getState().getPlayersInRange(source.getControllerId(), game)) { Player player = game.getPlayer(playerId); if (player != null) { - for (Card card : player.getGraveyard().getCards(new FilterCreatureCard(), game)) { - controller.moveCardToExileWithInfo(card, source.getSourceId(), sourceObject.getIdName(), source.getSourceId(), game, Zone.GRAVEYARD, true); + Set cardsPlayer = player.getGraveyard().getCards(new FilterCreatureCard(), game); + if (!cardsPlayer.isEmpty()) { + exiledCards.put(player.getId(), cardsPlayer); + player.moveCards(cardsPlayer, Zone.EXILED, source, game); } } } + game.applyEffects(); // sacrifice all creatures for (Permanent permanent : game.getBattlefield().getActivePermanents(new FilterCreaturePermanent(), source.getControllerId(), game)) { permanent.sacrifice(source.getSourceId(), game); } + game.applyEffects(); // put exiled cards to battlefield - ExileZone exileZone = game.getState().getExile().getExileZone(source.getSourceId()); - if (exileZone != null) { - for (Card card : exileZone.getCards(game)) { - Player player = game.getPlayer(card.getOwnerId()); - if (player != null) { - player.moveCards(card, Zone.EXILED, source, game); - player.putOntoBattlefieldWithInfo(card, game, Zone.EXILED, source.getSourceId()); + for (UUID playerId : game.getState().getPlayersInRange(source.getControllerId(), game)) { + Player player = game.getPlayer(playerId); + if (player != null) { + Set cardsPlayer = exiledCards.get(playerId); + if (cardsPlayer != null && !cardsPlayer.isEmpty()) { + player.moveCards(cardsPlayer, Zone.BATTLEFIELD, source, game, false, false, false, null); } } } diff --git a/Mage.Sets/src/mage/sets/tempest/StaunchDefenders.java b/Mage.Sets/src/mage/sets/tempest/StaunchDefenders.java index 39fe7dbece7..cfaeaa21ead 100644 --- a/Mage.Sets/src/mage/sets/tempest/StaunchDefenders.java +++ b/Mage.Sets/src/mage/sets/tempest/StaunchDefenders.java @@ -28,12 +28,12 @@ package mage.sets.tempest; import java.util.UUID; -import mage.constants.CardType; -import mage.constants.Rarity; import mage.MageInt; import mage.abilities.common.EntersBattlefieldTriggeredAbility; import mage.abilities.effects.common.GainLifeEffect; import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.Rarity; /** * @@ -49,6 +49,8 @@ public class StaunchDefenders extends CardImpl { this.power = new MageInt(3); this.toughness = new MageInt(4); + + // When Staunch Defenders enters the battlefield, you gain 4 life. this.addAbility(new EntersBattlefieldTriggeredAbility(new GainLifeEffect(4), false)); } diff --git a/Mage.Sets/src/mage/sets/tenthedition/AcademyResearchers.java b/Mage.Sets/src/mage/sets/tenthedition/AcademyResearchers.java index febe7582f76..f3d2fec5dd3 100644 --- a/Mage.Sets/src/mage/sets/tenthedition/AcademyResearchers.java +++ b/Mage.Sets/src/mage/sets/tenthedition/AcademyResearchers.java @@ -76,35 +76,35 @@ public class AcademyResearchers extends CardImpl { } class AcademyResearchersEffect extends OneShotEffect { - + AcademyResearchersEffect() { super(Outcome.PutCardInPlay); this.staticText = "you may put an Aura card from your hand onto the battlefield attached to {this}."; } - + AcademyResearchersEffect(final AcademyResearchersEffect effect) { super(effect); } - + @Override public AcademyResearchersEffect copy() { return new AcademyResearchersEffect(this); } - + @Override public boolean apply(Game game, Ability source) { - Player player = game.getPlayer(source.getControllerId()); + Player controller = game.getPlayer(source.getControllerId()); Permanent permanent = game.getPermanent(source.getSourceId()); - if (player != null && permanent != null){ + if (controller != null && permanent != null) { FilterCard filter = new FilterCard(); filter.add(new SubtypePredicate("Aura")); filter.add(new AuraCardCanAttachToPermanentId(permanent.getId())); TargetCardInHand target = new TargetCardInHand(0, 1, filter); - if (player.choose(Outcome.PutCardInPlay, target, source.getSourceId(), game)) { + if (controller.choose(Outcome.PutCardInPlay, target, source.getSourceId(), game)) { Card auraInHand = game.getCard(target.getFirstTarget()); if (auraInHand != null) { game.getState().setValue("attachTo:" + auraInHand.getId(), permanent); - if (player.putOntoBattlefieldWithInfo(auraInHand, game, Zone.HAND, source.getSourceId())) { + if (controller.moveCards(auraInHand, Zone.BATTLEFIELD, source, game)) { permanent.addAttachment(auraInHand.getId(), game); } } diff --git a/Mage.Sets/src/mage/sets/theros/AshiokNightmareWeaver.java b/Mage.Sets/src/mage/sets/theros/AshiokNightmareWeaver.java index 18d2eaee092..f9749475e70 100644 --- a/Mage.Sets/src/mage/sets/theros/AshiokNightmareWeaver.java +++ b/Mage.Sets/src/mage/sets/theros/AshiokNightmareWeaver.java @@ -167,16 +167,14 @@ class AshiokNightmareWeaverPutIntoPlayEffect extends OneShotEffect { if (target.canChoose(source.getSourceId(), controller.getId(), game)) { if (controller.chooseTarget(Outcome.PutCreatureInPlay, target, source, game)) { Card card = game.getCard(target.getFirstTarget()); - if (card != null && controller.putOntoBattlefieldWithInfo(card, game, Zone.EXILED, source.getSourceId())) { - // why is this change of controller neccessary? + if (card != null + && controller.moveCards(card, Zone.BATTLEFIELD, source, game)) { Permanent permanent = game.getPermanent(card.getId()); if (permanent != null) { - permanent.changeControllerId(source.getControllerId(), game); + ContinuousEffectImpl effect = new AshiokNightmareWeaverAddTypeEffect(); + effect.setTargetPointer(new FixedTarget(permanent, game)); + game.addEffect(effect, source); } - - ContinuousEffectImpl effect = new AshiokNightmareWeaverAddTypeEffect(); - effect.setTargetPointer(new FixedTarget(card.getId())); - game.addEffect(effect, source); return true; } } diff --git a/Mage.Sets/src/mage/sets/theros/PyxisOfPandemonium.java b/Mage.Sets/src/mage/sets/theros/PyxisOfPandemonium.java index 3b1e6e3e836..ae89cc24db2 100644 --- a/Mage.Sets/src/mage/sets/theros/PyxisOfPandemonium.java +++ b/Mage.Sets/src/mage/sets/theros/PyxisOfPandemonium.java @@ -39,6 +39,8 @@ import mage.abilities.costs.mana.GenericManaCost; import mage.abilities.effects.OneShotEffect; 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; @@ -161,8 +163,8 @@ class PyxisOfPandemoniumPutOntoBattlefieldEffect extends OneShotEffect { } else { return true; } - - for (UUID playerId : controller.getInRange()) { + Cards cardsToBringIntoPlay = new CardsImpl(); + for (UUID playerId : game.getState().getPlayersInRange(controller.getId(), game)) { Player player = game.getPlayer(playerId); if (player != null) { String exileKey = playerId.toString() + CardUtil.getExileZoneId(game, source.getSourceId(), source.getSourceObjectZoneChangeCounter()).toString(); @@ -173,13 +175,14 @@ class PyxisOfPandemoniumPutOntoBattlefieldEffect extends OneShotEffect { for (Card card : exileZone.getCards(game)) { card.setFaceDown(false, game); if (CardUtil.isPermanentCard(card)) { - player.moveCards(card, Zone.EXILED, source, game); + cardsToBringIntoPlay.add(card); } } } } } } + controller.moveCards(cardsToBringIntoPlay.getCards(game), Zone.BATTLEFIELD, source, game, false, false, true, null); return true; } return false; diff --git a/Mage.Sets/src/mage/sets/theros/WhipOfErebos.java b/Mage.Sets/src/mage/sets/theros/WhipOfErebos.java index 6b345fdd021..8d9dd84c469 100644 --- a/Mage.Sets/src/mage/sets/theros/WhipOfErebos.java +++ b/Mage.Sets/src/mage/sets/theros/WhipOfErebos.java @@ -115,19 +115,22 @@ class WhipOfErebosEffect extends OneShotEffect { Card card = game.getCard(this.getTargetPointer().getFirst(game, source)); Player controller = game.getPlayer(source.getControllerId()); if (controller != null && card != null) { - if (controller.putOntoBattlefieldWithInfo(card, game, Zone.GRAVEYARD, source.getSourceId())) { - // gains haste - ContinuousEffect effect = new GainAbilityTargetEffect(HasteAbility.getInstance(), Duration.Custom); - effect.setTargetPointer(new FixedTarget(card.getId())); - game.addEffect(effect, source); - // Exile at begin of next end step - ExileTargetEffect exileEffect = new ExileTargetEffect(null, null, Zone.BATTLEFIELD); - exileEffect.setTargetPointer(new FixedTarget(card.getId(), card.getZoneChangeCounter(game))); - DelayedTriggeredAbility delayedAbility = new AtTheBeginOfNextEndStepDelayedTriggeredAbility(exileEffect); - delayedAbility.setSourceId(source.getSourceId()); - delayedAbility.setControllerId(source.getControllerId()); - delayedAbility.setSourceObject(source.getSourceObject(game), game); - game.addDelayedTriggeredAbility(delayedAbility); + if (controller.moveCards(card, Zone.BATTLEFIELD, source, game)) { + Permanent creature = game.getPermanent(card.getId()); + if (creature != null) { + // gains haste + ContinuousEffect effect = new GainAbilityTargetEffect(HasteAbility.getInstance(), Duration.Custom); + effect.setTargetPointer(new FixedTarget(creature, game)); + game.addEffect(effect, source); + // Exile at begin of next end step + ExileTargetEffect exileEffect = new ExileTargetEffect(null, null, Zone.BATTLEFIELD); + exileEffect.setTargetPointer(new FixedTarget(creature, game)); + DelayedTriggeredAbility delayedAbility = new AtTheBeginOfNextEndStepDelayedTriggeredAbility(exileEffect); + 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/theros/XenagosTheReveler.java b/Mage.Sets/src/mage/sets/theros/XenagosTheReveler.java index cb9bcd6c965..8dca6413956 100644 --- a/Mage.Sets/src/mage/sets/theros/XenagosTheReveler.java +++ b/Mage.Sets/src/mage/sets/theros/XenagosTheReveler.java @@ -38,7 +38,6 @@ import mage.abilities.common.PlanswalkerEntersWithLoyalityCountersAbility; import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.CreateTokenEffect; import mage.abilities.keyword.HasteAbility; -import mage.cards.Card; import mage.cards.CardImpl; import mage.cards.Cards; import mage.cards.CardsImpl; @@ -179,28 +178,19 @@ class XenagosExileEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { - Player player = game.getPlayer(source.getControllerId()); - if (player != null) { - Cards cards = new CardsImpl(Zone.EXILED); - int count = Math.min(player.getLibrary().size(), 7); - for (int i = 0; i < count; i++) { - Card card = player.getLibrary().getFromTop(game); - cards.add(card); - card.moveToExile(null, null, source.getSourceId(), game); - } + Player controller = game.getPlayer(source.getControllerId()); + if (controller != null) { + Cards exiledCards = new CardsImpl(); + exiledCards.addAll(controller.getLibrary().getTopCards(game, 7)); + controller.moveCards(exiledCards, Zone.EXILED, source, game); FilterCard filter = new FilterCard("creature and/or land cards to put onto the battlefield"); filter.add(Predicates.or(new CardTypePredicate(CardType.CREATURE), new CardTypePredicate(CardType.LAND))); TargetCard target1 = new TargetCard(0, Integer.MAX_VALUE, Zone.EXILED, filter); - if (cards.size() > 0 + if (exiledCards.size() > 0 && target1.canChoose(source.getSourceId(), source.getControllerId(), game) - && player.choose(Outcome.PutCardInPlay, cards, target1, game)) { - for (UUID targetId : target1.getTargets()) { - Card card = cards.get(targetId, game); - if (card != null) { - player.moveCards(card, Zone.EXILED, source, game); - } - } + && controller.choose(Outcome.PutCardInPlay, exiledCards, target1, game)) { + controller.moveCards(new CardsImpl(target1.getTargets()), Zone.BATTLEFIELD, source, game); } return true; } diff --git a/Mage.Sets/src/mage/sets/timespiral/LivingEnd.java b/Mage.Sets/src/mage/sets/timespiral/LivingEnd.java index de93d360d5a..cf26eed618f 100644 --- a/Mage.Sets/src/mage/sets/timespiral/LivingEnd.java +++ b/Mage.Sets/src/mage/sets/timespiral/LivingEnd.java @@ -27,6 +27,9 @@ */ package mage.sets.timespiral; +import java.util.HashMap; +import java.util.Map; +import java.util.Set; import java.util.UUID; import mage.MageObject; import mage.abilities.Ability; @@ -41,7 +44,6 @@ import mage.constants.Rarity; import mage.constants.Zone; import mage.filter.common.FilterCreatureCard; import mage.filter.common.FilterCreaturePermanent; -import mage.game.ExileZone; import mage.game.Game; import mage.game.permanent.Permanent; import mage.players.Player; @@ -97,12 +99,15 @@ class LivingEndEffect extends OneShotEffect { Player controller = game.getPlayer(source.getControllerId()); MageObject sourceObject = game.getObject(source.getSourceId()); if (controller != null && sourceObject != null) { + Map> exiledCards = new HashMap<>(); // move creature cards from graveyard to exile - for (UUID playerId : controller.getInRange()) { + for (UUID playerId : game.getState().getPlayersInRange(source.getControllerId(), game)) { Player player = game.getPlayer(playerId); if (player != null) { - for (Card card : player.getGraveyard().getCards(new FilterCreatureCard(), game)) { - controller.moveCardToExileWithInfo(card, source.getSourceId(), sourceObject.getIdName(), source.getSourceId(), game, Zone.GRAVEYARD, true); + Set cardsPlayer = player.getGraveyard().getCards(new FilterCreatureCard(), game); + if (!cardsPlayer.isEmpty()) { + exiledCards.put(player.getId(), cardsPlayer); + player.moveCards(cardsPlayer, Zone.EXILED, source, game); } } } @@ -111,12 +116,12 @@ class LivingEndEffect extends OneShotEffect { permanent.sacrifice(source.getSourceId(), game); } // put exiled cards to battlefield - ExileZone exileZone = game.getState().getExile().getExileZone(source.getSourceId()); - if (exileZone != null) { - for (Card card : exileZone.getCards(game)) { - Player player = game.getPlayer(card.getOwnerId()); - if (player != null) { - player.moveCards(card, Zone.EXILED, source, game); + for (UUID playerId : game.getState().getPlayersInRange(source.getControllerId(), game)) { + Player player = game.getPlayer(playerId); + if (player != null) { + Set cardsPlayer = exiledCards.get(playerId); + if (cardsPlayer != null && !cardsPlayer.isEmpty()) { + player.moveCards(cardsPlayer, Zone.BATTLEFIELD, source, game, false, false, false, null); } } } diff --git a/Mage.Sets/src/mage/sets/urzasdestiny/Gamekeeper.java b/Mage.Sets/src/mage/sets/urzasdestiny/Gamekeeper.java index 71b6e21e76b..060dd763312 100644 --- a/Mage.Sets/src/mage/sets/urzasdestiny/Gamekeeper.java +++ b/Mage.Sets/src/mage/sets/urzasdestiny/Gamekeeper.java @@ -77,8 +77,6 @@ public class Gamekeeper extends CardImpl { class GamekeeperEffect extends OneShotEffect { - - public GamekeeperEffect() { super(Outcome.Benefit); staticText = "reveal cards from the top of your library until you reveal a creature card. Put that card onto the battlefield and put all other cards revealed this way into your graveyard"; @@ -98,15 +96,13 @@ class GamekeeperEffect extends OneShotEffect { while (controller.getLibrary().size() > 0) { Card card = controller.getLibrary().removeFromTop(game); if (card.getCardType().contains(CardType.CREATURE)) { - controller.putOntoBattlefieldWithInfo(card, game, Zone.LIBRARY, source.getSourceId()); + controller.moveCards(card, Zone.BATTLEFIELD, source, game); break; } revealedCards.add(card); } - controller.revealCards("Gamekeeper", revealedCards, game); - for (Card card: revealedCards.getCards(game)) { - card.moveToZone(Zone.GRAVEYARD, source.getSourceId(), game, true); - } + controller.revealCards(sourceObject.getIdName(), revealedCards, game); + controller.moveCards(revealedCards, Zone.GRAVEYARD, source, game); return true; } return false; @@ -116,4 +112,4 @@ class GamekeeperEffect extends OneShotEffect { public GamekeeperEffect copy() { return new GamekeeperEffect(this); } -} \ No newline at end of file +} diff --git a/Mage.Sets/src/mage/sets/urzasdestiny/Replenish.java b/Mage.Sets/src/mage/sets/urzasdestiny/Replenish.java index ec46d722ec8..217f77fb07c 100644 --- a/Mage.Sets/src/mage/sets/urzasdestiny/Replenish.java +++ b/Mage.Sets/src/mage/sets/urzasdestiny/Replenish.java @@ -27,17 +27,15 @@ */ package mage.sets.urzasdestiny; -import java.util.ArrayList; -import java.util.List; import java.util.UUID; import mage.abilities.Ability; import mage.abilities.effects.OneShotEffect; -import mage.cards.Card; import mage.cards.CardImpl; import mage.constants.CardType; import mage.constants.Outcome; import mage.constants.Rarity; import mage.constants.Zone; +import mage.filter.common.FilterEnchantmentCard; import mage.game.Game; import mage.players.Player; @@ -51,7 +49,6 @@ public class Replenish extends CardImpl { super(ownerId, 15, "Replenish", Rarity.RARE, new CardType[]{CardType.SORCERY}, "{3}{W}"); this.expansionSetCode = "UDS"; - // Return all enchantment cards from your graveyard to the battlefield. this.getSpellAbility().addEffect(new ReplenishEffect()); } @@ -67,36 +64,27 @@ public class Replenish extends CardImpl { } class ReplenishEffect extends OneShotEffect { - + ReplenishEffect() { super(Outcome.PutCardInPlay); this.staticText = "Return all enchantment cards from your graveyard to the battlefield"; } - + ReplenishEffect(final ReplenishEffect effect) { super(effect); } - + @Override public ReplenishEffect copy() { return new ReplenishEffect(this); } - + @Override public boolean apply(Game game, Ability source) { - Player player = game.getPlayer(source.getControllerId()); - if (player != null) { - List cards = new ArrayList<>(0); - for (UUID cardId : player.getGraveyard()) { - Card card = game.getCard(cardId); - if (card != null && card.getCardType().contains(CardType.ENCHANTMENT)) { - cards.add(card); - } - } - for (Card card : cards) { - player.putOntoBattlefieldWithInfo(card, game, Zone.GRAVEYARD, source.getSourceId()); - } - return true; + Player controller = game.getPlayer(source.getControllerId()); + if (controller != null) { + return controller.moveCards(controller.getGraveyard().getCards(new FilterEnchantmentCard(), source.getSourceId(), + source.getControllerId(), game), Zone.BATTLEFIELD, source, game); } return false; } diff --git a/Mage.Sets/src/mage/sets/urzaslegacy/GoblinWelder.java b/Mage.Sets/src/mage/sets/urzaslegacy/GoblinWelder.java index d9ccd3e001c..a34a97f95e3 100644 --- a/Mage.Sets/src/mage/sets/urzaslegacy/GoblinWelder.java +++ b/Mage.Sets/src/mage/sets/urzaslegacy/GoblinWelder.java @@ -30,7 +30,6 @@ package mage.sets.urzaslegacy; import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; -import mage.abilities.Mode; import mage.abilities.common.SimpleActivatedAbility; import mage.abilities.costs.common.TapSourceCost; import mage.abilities.effects.OneShotEffect; @@ -78,7 +77,6 @@ public class GoblinWelder extends CardImpl { public GoblinWelder copy() { return new GoblinWelder(this); } - public class GoblinWelderEffect extends OneShotEffect { @@ -87,7 +85,6 @@ public class GoblinWelder extends CardImpl { staticText = "Choose target artifact a player controls and target artifact card in that player's graveyard. If both targets are still legal as this ability resolves, that player simultaneously sacrifices the artifact and returns the artifact card to the battlefield"; } - public GoblinWelderEffect(final GoblinWelderEffect effect) { super(effect); } @@ -106,7 +103,7 @@ public class GoblinWelder extends CardImpl { && currentZone == Zone.GRAVEYARD && card.getOwnerId().equals(artifact.getControllerId())) { boolean sacrifice = artifact.sacrifice(source.getSourceId(), game); - boolean putOnBF = owner.putOntoBattlefieldWithInfo(card, game, Zone.GRAVEYARD, source.getSourceId()); + boolean putOnBF = owner.moveCards(card, Zone.BATTLEFIELD, source, game); if (sacrifice || putOnBF) { return true; } @@ -121,7 +118,7 @@ public class GoblinWelder extends CardImpl { } } - + class GoblinWelderTarget extends TargetCardInGraveyard { public GoblinWelderTarget() { @@ -146,7 +143,6 @@ public class GoblinWelder extends CardImpl { } return false; } - @Override public GoblinWelderTarget copy() { diff --git a/Mage.Sets/src/mage/sets/urzassaga/CopperGnomes.java b/Mage.Sets/src/mage/sets/urzassaga/CopperGnomes.java index 2971de2eda7..145b521c5cb 100644 --- a/Mage.Sets/src/mage/sets/urzassaga/CopperGnomes.java +++ b/Mage.Sets/src/mage/sets/urzassaga/CopperGnomes.java @@ -94,19 +94,18 @@ class PutArtifactOnBattlefieldEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { - Player player = game.getPlayer(source.getControllerId()); - if (player == null || !player.chooseUse(Outcome.PutCardInPlay, choiceText, source, game)) { + Player controller = game.getPlayer(source.getControllerId()); + if (controller == null || !controller.chooseUse(Outcome.PutCardInPlay, choiceText, source, game)) { return false; } TargetCardInHand target = new TargetCardInHand(new FilterArtifactCard()); - if (player.choose(Outcome.PutCardInPlay, target, source.getSourceId(), game)) { + if (controller.choose(Outcome.PutCardInPlay, target, source.getSourceId(), game)) { Card card = game.getCard(target.getFirstTarget()); if (card != null) { - player.putOntoBattlefieldWithInfo(card, game, Zone.HAND, source.getSourceId()); - return true; + return controller.moveCards(card, Zone.BATTLEFIELD, source, game); } } return false; } -} \ No newline at end of file +} diff --git a/Mage.Sets/src/mage/sets/urzassaga/Exhume.java b/Mage.Sets/src/mage/sets/urzassaga/Exhume.java index 4b853980dd8..6350318c19f 100644 --- a/Mage.Sets/src/mage/sets/urzassaga/Exhume.java +++ b/Mage.Sets/src/mage/sets/urzassaga/Exhume.java @@ -52,7 +52,6 @@ public class Exhume extends CardImpl { super(ownerId, 134, "Exhume", Rarity.COMMON, new CardType[]{CardType.SORCERY}, "{1}{B}"); this.expansionSetCode = "USG"; - // Each player puts a creature card from his or her graveyard onto the battlefield. this.getSpellAbility().addEffect(new ExhumeEffect()); } @@ -90,17 +89,17 @@ class ExhumeEffect extends OneShotEffect { return false; } - for (UUID playerId : controller.getInRange()) { + for (UUID playerId : game.getState().getPlayersInRange(controller.getId(), game)) { Player player = game.getPlayer(playerId); if (player != null) { FilterCreatureCard filterCreatureCard = new FilterCreatureCard("creature card from your graveyard"); filterCreatureCard.add(new OwnerIdPredicate(playerId)); TargetCardInGraveyard target = new TargetCardInGraveyard(filterCreatureCard); - if (target.canChoose(playerId, game) && - player.chooseTarget(outcome, target, source, game)) { + if (target.canChoose(playerId, game) + && player.chooseTarget(outcome, target, source, game)) { Card card = game.getCard(target.getFirstTarget()); if (card != null) { - player.putOntoBattlefieldWithInfo(card, game, Zone.GRAVEYARD, source.getSourceId()); + player.moveCards(card, Zone.BATTLEFIELD, source, game); } } } diff --git a/Mage.Sets/src/mage/sets/urzassaga/PlanarBirth.java b/Mage.Sets/src/mage/sets/urzassaga/PlanarBirth.java index fdd6644437e..7b298acc3d7 100644 --- a/Mage.Sets/src/mage/sets/urzassaga/PlanarBirth.java +++ b/Mage.Sets/src/mage/sets/urzassaga/PlanarBirth.java @@ -30,8 +30,9 @@ package mage.sets.urzassaga; import java.util.UUID; import mage.abilities.Ability; import mage.abilities.effects.OneShotEffect; -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; @@ -65,33 +66,33 @@ public class PlanarBirth extends CardImpl { } class PlanarBirthEffect extends OneShotEffect { - + PlanarBirthEffect() { super(Outcome.PutLandInPlay); this.staticText = "Return all basic land cards from all graveyards to the battlefield tapped under their owners' control"; } - + PlanarBirthEffect(final PlanarBirthEffect effect) { super(effect); } - + @Override public PlanarBirthEffect copy() { return new PlanarBirthEffect(this); } - + @Override public boolean apply(Game game, Ability source) { Player controller = game.getPlayer(source.getControllerId()); if (controller != null) { - for (UUID playerId : controller.getInRange()) { + Cards toBattlefield = new CardsImpl(); + for (UUID playerId : game.getState().getPlayersInRange(controller.getId(), game)) { Player player = game.getPlayer(playerId); if (player != null) { - for (Card card : player.getGraveyard().getCards(new FilterBasicLandCard(), source.getSourceId(), controller.getId(), game)) { - player.putOntoBattlefieldWithInfo(card, game, Zone.GRAVEYARD, source.getSourceId(), true); - } + toBattlefield.addAll(player.getGraveyard().getCards(new FilterBasicLandCard(), source.getSourceId(), controller.getId(), game)); } } + controller.moveCards(toBattlefield.getCards(game), Zone.BATTLEFIELD, source, game, true, false, true, null); return true; } return false; diff --git a/Mage.Sets/src/mage/sets/urzassaga/SneakAttack.java b/Mage.Sets/src/mage/sets/urzassaga/SneakAttack.java index 3720511de42..4cb45d7a1fc 100644 --- a/Mage.Sets/src/mage/sets/urzassaga/SneakAttack.java +++ b/Mage.Sets/src/mage/sets/urzassaga/SneakAttack.java @@ -96,14 +96,14 @@ class SneakAttackEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { - Player player = game.getPlayer(source.getControllerId()); - if (player != null) { - if (player.chooseUse(Outcome.PutCreatureInPlay, choiceText, source, game)) { + Player controller = game.getPlayer(source.getControllerId()); + if (controller != null) { + if (controller.chooseUse(Outcome.PutCreatureInPlay, choiceText, source, game)) { TargetCardInHand target = new TargetCardInHand(new FilterCreatureCard()); - if (player.choose(Outcome.PutCreatureInPlay, target, source.getSourceId(), game)) { + if (controller.choose(Outcome.PutCreatureInPlay, target, source.getSourceId(), game)) { Card card = game.getCard(target.getFirstTarget()); if (card != null) { - if (player.putOntoBattlefieldWithInfo(card, game, Zone.HAND, source.getSourceId())) { + if (controller.moveCards(card, Zone.BATTLEFIELD, source, game)) { Permanent permanent = game.getPermanent(card.getId()); if (permanent != null) { ContinuousEffect effect = new GainAbilityTargetEffect(HasteAbility.getInstance(), Duration.Custom); diff --git a/Mage.Sets/src/mage/sets/vintagemasters/ChaosWarp.java b/Mage.Sets/src/mage/sets/vintagemasters/ChaosWarp.java index 96230a129e5..d4e09af0c93 100644 --- a/Mage.Sets/src/mage/sets/vintagemasters/ChaosWarp.java +++ b/Mage.Sets/src/mage/sets/vintagemasters/ChaosWarp.java @@ -35,20 +35,20 @@ import mage.cards.Card; import mage.cards.CardImpl; import mage.cards.Cards; import mage.cards.CardsImpl; -import mage.players.Player; import mage.constants.CardType; import mage.constants.Outcome; import mage.constants.Rarity; import mage.constants.Zone; +import mage.filter.common.FilterPermanentCard; import mage.game.Game; import mage.game.permanent.Permanent; +import mage.players.Player; import mage.target.TargetPermanent; -import mage.filter.common.FilterPermanentCard; /** * * @author Mitchel Stein - * + * */ public class ChaosWarp extends CardImpl { @@ -56,14 +56,13 @@ public class ChaosWarp extends CardImpl { super(ownerId, 154, "Chaos Warp", Rarity.RARE, new CardType[]{CardType.INSTANT}, "{2}{R}"); this.expansionSetCode = "VMA"; - // The owner of target permanent shuffles it into his or her library, this.getSpellAbility().addEffect(new ChaosWarpShuffleIntoLibraryEffect()); this.getSpellAbility().addTarget(new TargetPermanent()); - //then reveals the top card of his or her library. + //then reveals the top card of his or her library. //If it's a permanent card, he or she puts it onto the battlefield. this.getSpellAbility().addEffect(new ChaosWarpRevealEffect()); - + } public ChaosWarp(final ChaosWarp card) { @@ -94,9 +93,9 @@ class ChaosWarpShuffleIntoLibraryEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { - Permanent permanent = game.getPermanent(targetPointer.getFirst(game, source)); + Permanent permanent = game.getPermanent(targetPointer.getFirst(game, source)); if (permanent != null) { - Player owner = game.getPlayer(permanent.getOwnerId()); + Player owner = game.getPlayer(permanent.getOwnerId()); if (owner != null) { owner.moveCardToLibraryWithInfo(permanent, source.getSourceId(), game, Zone.BATTLEFIELD, true, true); owner.shuffleLibrary(game); @@ -108,10 +107,10 @@ class ChaosWarpShuffleIntoLibraryEffect extends OneShotEffect { } class ChaosWarpRevealEffect extends OneShotEffect { - -public ChaosWarpRevealEffect() { + + public ChaosWarpRevealEffect() { super(Outcome.PutCardInPlay); - this.staticText = "then reveals the top card of his or her library. If it's a permanent card, he or she puts it onto the battlefield."; + this.staticText = "then reveals the top card of his or her library. If it's a permanent card, he or she puts it onto the battlefield"; } public ChaosWarpRevealEffect(final ChaosWarpRevealEffect effect) { @@ -138,11 +137,10 @@ public ChaosWarpRevealEffect() { if (owner.getLibrary().size() > 0) { Card card = owner.getLibrary().getFromTop(game); if (card != null) { - Cards cards = new CardsImpl(); - cards.add(card); - owner.revealCards(sourceObject.getName(), cards, game); - if (new FilterPermanentCard().match(card, game)) { - owner.putOntoBattlefieldWithInfo(card, game, Zone.LIBRARY, source.getSourceId()); + Cards cards = new CardsImpl(card); + owner.revealCards(sourceObject.getIdName(), cards, game); + if (new FilterPermanentCard().match(card, game)) { + owner.moveCards(card, Zone.BATTLEFIELD, source, game); } } } diff --git a/Mage.Sets/src/mage/sets/vintagemasters/Eureka.java b/Mage.Sets/src/mage/sets/vintagemasters/Eureka.java index c47f7887e12..d5dbfa28e5e 100644 --- a/Mage.Sets/src/mage/sets/vintagemasters/Eureka.java +++ b/Mage.Sets/src/mage/sets/vintagemasters/Eureka.java @@ -53,7 +53,6 @@ public class Eureka extends CardImpl { super(ownerId, 208, "Eureka", Rarity.MYTHIC, new CardType[]{CardType.SORCERY}, "{2}{G}{G}"); this.expansionSetCode = "VMA"; - // Starting with you, each player may put a permanent card from his or her hand onto the battlefield. Repeat this process until no one puts a card onto the battlefield. this.getSpellAbility().addEffect(new EurekaEffect()); } @@ -108,7 +107,7 @@ class EurekaEffect extends OneShotEffect { if (target.chooseTarget(outcome, currentPlayer.getId(), source, game)) { Card card = game.getCard(target.getFirstTarget()); if (card != null) { - currentPlayer.putOntoBattlefieldWithInfo(card, game, Zone.HAND, source.getSourceId()); + currentPlayer.moveCards(card, Zone.BATTLEFIELD, source, game); firstInactivePlayer = null; } } diff --git a/Mage.Sets/src/mage/sets/vintagemasters/MistmoonGriffin.java b/Mage.Sets/src/mage/sets/vintagemasters/MistmoonGriffin.java index d6f979dca39..290f1681191 100644 --- a/Mage.Sets/src/mage/sets/vintagemasters/MistmoonGriffin.java +++ b/Mage.Sets/src/mage/sets/vintagemasters/MistmoonGriffin.java @@ -97,13 +97,13 @@ class MistmoonGriffinEffect extends OneShotEffect { Player controller = game.getPlayer(source.getControllerId()); if (controller != null) { Card lastCreatureCard = null; - for (Card card :controller.getGraveyard().getCards(game)) { + for (Card card : controller.getGraveyard().getCards(game)) { if (card.getCardType().contains(CardType.CREATURE)) { lastCreatureCard = card; } } if (lastCreatureCard != null) { - return controller.putOntoBattlefieldWithInfo(lastCreatureCard, game, Zone.GRAVEYARD, source.getSourceId()); + return controller.moveCards(lastCreatureCard, Zone.BATTLEFIELD, source, game); } return true; } diff --git a/Mage.Sets/src/mage/sets/visions/Necromancy.java b/Mage.Sets/src/mage/sets/visions/Necromancy.java index f109d320e53..89910cb3ab9 100644 --- a/Mage.Sets/src/mage/sets/visions/Necromancy.java +++ b/Mage.Sets/src/mage/sets/visions/Necromancy.java @@ -196,13 +196,11 @@ class NecromancyReAttachEffect extends OneShotEffect { Permanent enchantment = game.getPermanent(source.getSourceId()); Card cardInGraveyard = game.getCard(getTargetPointer().getFirst(game, source)); if (controller != null && enchantment != null && cardInGraveyard != null) { - // put card into play - controller.putOntoBattlefieldWithInfo(cardInGraveyard, game, Zone.GRAVEYARD, source.getSourceId()); + controller.moveCards(cardInGraveyard, Zone.BATTLEFIELD, source, game); Permanent enchantedCreature = game.getPermanent(cardInGraveyard.getId()); - if (enchantedCreature != null) { enchantedCreature.addAttachment(enchantment.getId(), game); - FilterCreaturePermanent filter = new FilterCreaturePermanent("enchant creature put onto the battlefield with Necromancy"); + FilterCreaturePermanent filter = new FilterCreaturePermanent("enchant creature put onto the battlefield with " + enchantment.getIdName()); filter.add(new PermanentIdPredicate(cardInGraveyard.getId())); Target target = new TargetCreaturePermanent(filter); target.addTarget(enchantedCreature.getId(), source, game); diff --git a/Mage.Sets/src/mage/sets/weatherlight/BoneDancer.java b/Mage.Sets/src/mage/sets/weatherlight/BoneDancer.java index 85d29071310..45c623b43b8 100644 --- a/Mage.Sets/src/mage/sets/weatherlight/BoneDancer.java +++ b/Mage.Sets/src/mage/sets/weatherlight/BoneDancer.java @@ -92,15 +92,15 @@ class BoneDancerEffect extends OneShotEffect { public boolean apply(Game game, Ability source) { Player controller = game.getPlayer(source.getControllerId()); Player defendingPlayer = game.getPlayer(targetPointer.getFirst(game, source)); - if(controller != null && defendingPlayer != null) { + if (controller != null && defendingPlayer != null) { Card lastCreatureCard = null; - for(Card card : defendingPlayer.getGraveyard().getCards(game)) { - if(card.getCardType().contains(CardType.CREATURE)) { + for (Card card : defendingPlayer.getGraveyard().getCards(game)) { + if (card.getCardType().contains(CardType.CREATURE)) { lastCreatureCard = card; } } - if(lastCreatureCard != null) { - return controller.putOntoBattlefieldWithInfo(lastCreatureCard, game, Zone.GRAVEYARD, source.getSourceId()); + if (lastCreatureCard != null) { + controller.moveCards(lastCreatureCard, Zone.BATTLEFIELD, source, game); } return true; } diff --git a/Mage.Sets/src/mage/sets/worldwake/QuestForUlasTemple.java b/Mage.Sets/src/mage/sets/worldwake/QuestForUlasTemple.java index d4ae627af11..95eaa8a0b70 100644 --- a/Mage.Sets/src/mage/sets/worldwake/QuestForUlasTemple.java +++ b/Mage.Sets/src/mage/sets/worldwake/QuestForUlasTemple.java @@ -62,7 +62,6 @@ public class QuestForUlasTemple extends CardImpl { super(ownerId, 35, "Quest for Ula's Temple", Rarity.RARE, new CardType[]{CardType.ENCHANTMENT}, "{U}"); this.expansionSetCode = "WWK"; - // At the beginning of your upkeep, you may look at the top card of your library. If it's a creature card, you may reveal it and put a quest counter on Quest for Ula's Temple. this.addAbility(new BeginningOfUpkeepTriggeredAbility(Zone.BATTLEFIELD, new QuestForUlasTempleEffect(), TargetController.YOU, true)); @@ -140,7 +139,7 @@ class QuestForUlasTempleTriggeredAbility extends TriggeredAbilityImpl { } @Override -public boolean checkTrigger(GameEvent event, Game game) { + public boolean checkTrigger(GameEvent event, Game game) { Permanent quest = game.getPermanent(super.getSourceId()); return quest != null && quest.getCounters().getCount(CounterType.QUEST) >= 3; } @@ -178,12 +177,10 @@ class QuestForUlasTempleEffect2 extends OneShotEffect { if (controller != null) { TargetCardInHand target = new TargetCardInHand(filter); if (target.canChoose(source.getSourceId(), controller.getId(), game) - &&controller.chooseUse(Outcome.PutCreatureInPlay, query, source, game)) { + && controller.chooseUse(Outcome.PutCreatureInPlay, query, source, game)) { if (controller.choose(Outcome.PutCreatureInPlay, target, source.getSourceId(), game)) { Card card = game.getCard(target.getFirstTarget()); - if (card != null) { - controller.putOntoBattlefieldWithInfo(card, game, Zone.HAND, source.getSourceId()); - } + controller.moveCards(card, Zone.BATTLEFIELD, source, game); } } return true; diff --git a/Mage.Sets/src/mage/sets/zendikar/SummoningTrap.java b/Mage.Sets/src/mage/sets/zendikar/SummoningTrap.java index e2fd1b88a42..61aa2805786 100644 --- a/Mage.Sets/src/mage/sets/zendikar/SummoningTrap.java +++ b/Mage.Sets/src/mage/sets/zendikar/SummoningTrap.java @@ -28,12 +28,6 @@ package mage.sets.zendikar; import java.util.UUID; - -import mage.constants.CardType; -import mage.constants.Outcome; -import mage.constants.Rarity; -import mage.constants.WatcherScope; -import mage.constants.Zone; import mage.abilities.Ability; import mage.abilities.costs.AlternativeCostImpl; import mage.abilities.costs.Cost; @@ -43,6 +37,11 @@ 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.WatcherScope; +import mage.constants.Zone; import mage.filter.common.FilterCreatureCard; import mage.game.Game; import mage.game.events.GameEvent; @@ -179,7 +178,7 @@ class SummoningTrapEffect extends OneShotEffect { Card card = cards.get(target.getFirstTarget(), game); if (card != null) { cards.remove(card); - controller.putOntoBattlefieldWithInfo(card, game, Zone.LIBRARY, source.getSourceId()); + controller.moveCards(card, Zone.BATTLEFIELD, source, game); } } if (cards.size() > 0) { diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/abilities/keywords/PersistTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/abilities/keywords/PersistTest.java index e8fcc2a4487..85a451e4298 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/abilities/keywords/PersistTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/abilities/keywords/PersistTest.java @@ -195,8 +195,7 @@ public class PersistTest extends CardTestPlayerBase { assertPermanentCount(playerB, "Glen Elendra Archmage", 1); assertPowerToughness(playerB, "Glen Elendra Archmage", 1, 1); - assertPermanentCount(playerA, "Glen Elendra Archmage", 1); - assertPowerToughness(playerA, "Glen Elendra Archmage", 1, 1); + assertGraveyardCount(playerA, "Clever Impersonator", 1); } @Test diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/abilities/keywords/UndyingTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/abilities/keywords/UndyingTest.java index 31fc57868bf..058b5e5bed1 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/abilities/keywords/UndyingTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/abilities/keywords/UndyingTest.java @@ -2,6 +2,7 @@ package org.mage.test.cards.abilities.keywords; import mage.constants.PhaseStep; import mage.constants.Zone; +import mage.counters.CounterType; import org.junit.Test; import org.mage.test.serverside.base.CardTestPlayerBase; @@ -238,7 +239,8 @@ public class UndyingTest extends CardTestPlayerBase { assertPermanentCount(playerA, "Tatterkite", 1); assertPermanentCount(playerA, "Mikaeus, the Unhallowed", 1); - assertPowerToughness(playerA, "Tatterkite", 3, 2); + assertCounterCount("Tatterkite", CounterType.P1P1, 1); + assertPowerToughness(playerA, "Tatterkite", 4, 3); } diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/enchantments/OathOfLiegesTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/enchantments/OathOfLiegesTest.java index 2ad4dc07a44..df0c508f1e2 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/enchantments/OathOfLiegesTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/enchantments/OathOfLiegesTest.java @@ -78,6 +78,7 @@ public class OathOfLiegesTest extends CardTestPlayerBase { execute(); assertPermanentCount(playerA, "Oath of Lieges", 1); + assertPermanentCount(playerA, "Plains", 2); assertPermanentCount(playerB, "Plains", 2); } diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/triggers/WorldgorgerDragonTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/triggers/WorldgorgerDragonTest.java index db1557a3bd4..f21dade9e3c 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/triggers/WorldgorgerDragonTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/triggers/WorldgorgerDragonTest.java @@ -5,7 +5,6 @@ */ package org.mage.test.cards.triggers; - import mage.constants.PhaseStep; import mage.constants.Zone; import org.junit.Assert; @@ -16,7 +15,6 @@ import org.mage.test.serverside.base.CardTestPlayerBase; * * @author LevelX2 */ - public class WorldgorgerDragonTest extends CardTestPlayerBase { /** @@ -25,20 +23,23 @@ public class WorldgorgerDragonTest extends CardTestPlayerBase { @Test public void testDisabledEffectOnChangeZone() { addCard(Zone.BATTLEFIELD, playerA, "Mountain", 6); + // Flying + // Trample + // When Worldgorger Dragon enters the battlefield, exile all other permanents you control. + // When Worldgorger Dragon leaves the battlefield, return the exiled cards to the battlefield under their owners' control. addCard(Zone.HAND, playerA, "Worldgorger Dragon"); - + addCard(Zone.BATTLEFIELD, playerA, "Silvercoat Lion", 1); addCard(Zone.BATTLEFIELD, playerA, "Gerrard's Battle Cry", 1); - + addCard(Zone.BATTLEFIELD, playerB, "Swamp", 2); // Destroy target nonartifact, nonblack creature. It can't be regenerated. addCard(Zone.HAND, playerB, "Terror", 1); - castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Worldgorger Dragon"); - + castSpell(2, PhaseStep.PRECOMBAT_MAIN, playerB, "Terror", "Worldgorger Dragon"); - + setStopAt(2, PhaseStep.BEGIN_COMBAT); execute(); @@ -47,30 +48,35 @@ public class WorldgorgerDragonTest extends CardTestPlayerBase { assertGraveyardCount(playerA, "Worldgorger Dragon", 1); assertGraveyardCount(playerB, "Terror", 1); - + assertPermanentCount(playerA, "Silvercoat Lion", 1); assertPermanentCount(playerA, "Gerrard's Battle Cry", 1); - + } - /** - 1. Cast Animate Dead, targeting the Dragon - 2. Dragon comes into play, it's ability goes on the stack. - 3. The ability resolves, and all my other permanents leave play - 4. Since Animate Dead left play, Dragon goes to the graveyard - 5. Since the Dragon left play, the land and Animate Dead return to play. Animate Dead triggers, targeting the Dragon. - 6. In response to Animate Dead's ability going on the stack, tap the lands for mana. - 7. Animate Dead resolves, Dragon comes into play, everything else leaves play. - 8. Steps 4-7 repeat endlessly. Your mana pool fills. - 9. You can interrupt the sequence to play an instant. + /* + * 1. Cast Animate Dead, targeting the Dragon + * 2. Dragon comes into play, it's ability goes on the stack. + * 3. The ability resolves, and all my other permanents leave play + * 4. Since Animate Dead left play, Dragon goes to the graveyard + * 5. Since the Dragon left play, the land and Animate Dead return to play. Animate Dead triggers, targeting the Dragon. + * 6. In response to Animate Dead's ability going on the stack, tap the lands for mana. + * 7. Animate Dead resolves, Dragon comes into play, everything else leaves play. + * 8. Steps 4-7 repeat endlessly. Your mana pool fills. + * 9. You can interrupt the sequence to play an instant. */ @Test public void testWithAnimateDead() { addCard(Zone.BATTLEFIELD, playerA, "Swamp", 2); - + // When Worldgorger Dragon enters the battlefield, exile all other permanents you control. // When Worldgorger Dragon leaves the battlefield, return the exiled cards to the battlefield under their owners' control. addCard(Zone.GRAVEYARD, playerA, "Worldgorger Dragon", 1); + // Enchant creature card in a graveyard + // When Animate Dead enters the battlefield, if it's on the battlefield, it loses "enchant creature card in a graveyard" + // and gains "enchant creature put onto the battlefield with Animate Dead." Return enchanted creature card to the battlefield + // under your control and attach Animate Dead to it. When Animate Dead leaves the battlefield, that creature's controller sacrifices it. + // Enchanted creature gets -1/-0. addCard(Zone.HAND, playerA, "Animate Dead"); addCard(Zone.BATTLEFIELD, playerA, "Mountain", 3); // Instant {X}{R}{R} @@ -78,10 +84,9 @@ public class WorldgorgerDragonTest extends CardTestPlayerBase { addCard(Zone.HAND, playerA, "Volcanic Geyser", 1); // When Staunch Defenders enters the battlefield, you gain 4 life. addCard(Zone.BATTLEFIELD, playerA, "Staunch Defenders", 1); - castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Animate Dead", "Worldgorger Dragon"); - + activateManaAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "{T}: Add {R}"); activateManaAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "{T}: Add {R}"); activateManaAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "{T}: Add {R}"); @@ -107,43 +112,44 @@ public class WorldgorgerDragonTest extends CardTestPlayerBase { castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Volcanic Geyser", playerB, 22); setChoice(playerA, "X=20"); - + setStopAt(1, PhaseStep.BEGIN_COMBAT); execute(); - assertLife(playerA, 20); + assertLife(playerA, 44); assertLife(playerB, 0); assertGraveyardCount(playerA, "Volcanic Geyser", 1); - + } - + /** - * v9: Worldgorger Dragon + Animate Dead is still acting up (yey complex rules interactions!). - * The first time you return Animate Dead from Worldgorger's exile, it works like it's supposed - * to. You have to pick a creature, and it brings it back. But if you pick Worldgorger Dragon - * again, it allows you to not pick a creature, and regardless of whether you choose to skip or pick - * a different creature, it always returns the first creature you picked. Kind of hard to explain, - * but here's how to reproduce: - * - * 1) Cast Animate Dead, targeting Worldgorger Dragon - * 2) Worldgorger Dragon will exile Animate Dead, killing the dragon and returning the permanents - * 3) Select Worldgorger again - * 4) Step 2 repeats - * 5) Attempt to select a different creature. Worldgorger Dragon is returned instead. - * + * v9: Worldgorger Dragon + Animate Dead is still acting up (yey complex + * rules interactions!). The first time you return Animate Dead from + * Worldgorger's exile, it works like it's supposed to. You have to pick a + * creature, and it brings it back. But if you pick Worldgorger Dragon + * again, it allows you to not pick a creature, and regardless of whether + * you choose to skip or pick a different creature, it always returns the + * first creature you picked. Kind of hard to explain, but here's how to + * reproduce: + * + * 1) Cast Animate Dead, targeting Worldgorger Dragon 2) Worldgorger Dragon + * will exile Animate Dead, killing the dragon and returning the permanents + * 3) Select Worldgorger again 4) Step 2 repeats 5) Attempt to select a + * different creature. Worldgorger Dragon is returned instead. + * */ @Test public void testWithAnimateDeadDifferentTargets() { addCard(Zone.BATTLEFIELD, playerA, "Swamp", 2); - + // When Worldgorger Dragon enters the battlefield, exile all other permanents you control. // When Worldgorger Dragon leaves the battlefield, return the exiled cards to the battlefield under their owners' control. addCard(Zone.GRAVEYARD, playerA, "Worldgorger Dragon", 1); addCard(Zone.GRAVEYARD, playerA, "Silvercoat Lion", 1); - // When Animate Dead enters the battlefield, if it's on the battlefield, it loses "enchant creature card in a graveyard" - // and gains "enchant creature put onto the battlefield with Animate Dead." Return enchanted creature card to the battlefield + // When Animate Dead enters the battlefield, if it's on the battlefield, it loses "enchant creature card in a graveyard" + // and gains "enchant creature put onto the battlefield with Animate Dead." Return enchanted creature card to the battlefield // under your control and attach Animate Dead to it. When Animate Dead leaves the battlefield, that creature's controller sacrifices it. addCard(Zone.HAND, playerA, "Animate Dead"); addCard(Zone.BATTLEFIELD, playerA, "Mountain", 3); @@ -152,43 +158,42 @@ public class WorldgorgerDragonTest extends CardTestPlayerBase { addCard(Zone.HAND, playerA, "Volcanic Geyser", 1); // When Staunch Defenders enters the battlefield, you gain 4 life. addCard(Zone.BATTLEFIELD, playerA, "Staunch Defenders", 1); - + activateManaAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "{T}: Add {B}"); activateManaAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "{T}: Add {B}"); castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Animate Dead", "Worldgorger Dragon"); - activateManaAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "{T}: Add {R}"); + activateManaAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "{T}: Add {R}"); activateManaAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "{T}: Add {R}"); activateManaAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "{T}: Add {R}"); setChoice(playerA, "Worldgorger Dragon"); - activateManaAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "{T}: Add {R}"); + activateManaAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "{T}: Add {R}"); activateManaAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "{T}: Add {R}"); activateManaAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "{T}: Add {R}"); setChoice(playerA, "Silvercoat Lion"); - activateManaAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "{T}: Add {R}"); activateManaAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "{T}: Add {R}"); activateManaAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "{T}: Add {R}"); - - castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Volcanic Geyser", playerB, 9); + activateManaAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "{T}: Add {R}"); + + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Volcanic Geyser", playerB, 9); setChoice(playerA, "X=9"); - + setStopAt(1, PhaseStep.BEGIN_COMBAT); execute(); assertGraveyardCount(playerA, "Volcanic Geyser", 1); - assertGraveyardCount(playerA, "Worldgorger Dragon", 1); + assertGraveyardCount(playerA, "Worldgorger Dragon", 1); assertPermanentCount(playerA, "Silvercoat Lion", 1); - + assertLife(playerA, 28); assertLife(playerB, 11); Assert.assertEquals("Mana pool", "[]", playerA.getManaAvailable(currentGame).toString()); - } - -} \ No newline at end of file + +} diff --git a/Mage.Tests/src/test/java/org/mage/test/player/TestPlayer.java b/Mage.Tests/src/test/java/org/mage/test/player/TestPlayer.java index 702e99ba355..2f80da8fa0d 100644 --- a/Mage.Tests/src/test/java/org/mage/test/player/TestPlayer.java +++ b/Mage.Tests/src/test/java/org/mage/test/player/TestPlayer.java @@ -1799,21 +1799,6 @@ public class TestPlayer implements Player { return computerPlayer.moveCardToExileWithInfo(card, exileId, exileName, sourceId, game, fromZone, withName); } - @Override - public boolean putOntoBattlefieldWithInfo(Card card, Game game, Zone fromZone, UUID sourceId) { - return computerPlayer.putOntoBattlefieldWithInfo(card, game, fromZone, sourceId); - } - - @Override - public boolean putOntoBattlefieldWithInfo(Card card, Game game, Zone fromZone, UUID sourceId, boolean tapped) { - return computerPlayer.putOntoBattlefieldWithInfo(card, game, fromZone, sourceId, tapped); - } - - @Override - public boolean putOntoBattlefieldWithInfo(Card card, Game game, Zone fromZone, UUID sourceId, boolean tapped, boolean facedown) { - return computerPlayer.putOntoBattlefieldWithInfo(card, game, fromZone, sourceId, tapped, facedown); - } - @Override public boolean hasOpponent(UUID playerToCheckId, Game game) { return computerPlayer.hasOpponent(playerToCheckId, game); diff --git a/Mage/src/mage/abilities/AbilityImpl.java b/Mage/src/mage/abilities/AbilityImpl.java index 619a400685d..d7b581515ba 100644 --- a/Mage/src/mage/abilities/AbilityImpl.java +++ b/Mage/src/mage/abilities/AbilityImpl.java @@ -952,16 +952,15 @@ public abstract class AbilityImpl implements Ability { // for singleton abilities like Flying we can't rely on abilities' source because it's only once in continuous effects // so will use the sourceId of the object itself that came as a parameter if it is not null if (object == null) { - object = game.getObject(getSourceId()); + object = game.getPermanentEntering(getSourceId()); + if (object == null) { + object = game.getObject(getSourceId()); + } } if (object != null && !object.getAbilities().contains(this)) { if (object instanceof Permanent) { return false; } else { - Permanent permanent = game.getPermanentEntering(getSourceId()); - if (permanent != null && permanent.getAbilities().contains(this)) { - return true; - } // check if it's an ability that is temporary gained to a card Abilities otherAbilities = game.getState().getAllOtherAbilities(this.getSourceId()); if (otherAbilities == null || !otherAbilities.contains(this)) { diff --git a/Mage/src/mage/abilities/effects/common/CopyPermanentEffect.java b/Mage/src/mage/abilities/effects/common/CopyPermanentEffect.java index bf1ef297244..865adb292e8 100644 --- a/Mage/src/mage/abilities/effects/common/CopyPermanentEffect.java +++ b/Mage/src/mage/abilities/effects/common/CopyPermanentEffect.java @@ -98,7 +98,7 @@ public class CopyPermanentEffect extends OneShotEffect { } else { Target target = new TargetPermanent(filter); target.setNotTarget(true); - if (target.canChoose(source.getControllerId(), game)) { + if (target.canChoose(source.getSourceId(), player.getId(), game)) { player.choose(Outcome.Copy, target, source.getSourceId(), game); copyFromPermanent = game.getPermanent(target.getFirstTarget()); } diff --git a/Mage/src/mage/abilities/effects/common/PutLandFromHandOntoBattlefieldEffect.java b/Mage/src/mage/abilities/effects/common/PutLandFromHandOntoBattlefieldEffect.java index 8d819291cc3..c08da1ba5b3 100644 --- a/Mage/src/mage/abilities/effects/common/PutLandFromHandOntoBattlefieldEffect.java +++ b/Mage/src/mage/abilities/effects/common/PutLandFromHandOntoBattlefieldEffect.java @@ -25,7 +25,6 @@ * authors and should not be interpreted as representing official policies, either expressed * or implied, of BetaSteward_at_googlemail.com. */ - package mage.abilities.effects.common; import mage.abilities.Ability; @@ -50,10 +49,11 @@ public class PutLandFromHandOntoBattlefieldEffect extends OneShotEffect { public PutLandFromHandOntoBattlefieldEffect() { this(false); } + public PutLandFromHandOntoBattlefieldEffect(boolean tapped) { super(Outcome.PutLandInPlay); this.tapped = tapped; - staticText = "you may put a land card from your hand onto the battlefield" + (tapped ? " tapped":""); + staticText = "you may put a land card from your hand onto the battlefield" + (tapped ? " tapped" : ""); } public PutLandFromHandOntoBattlefieldEffect(final PutLandFromHandOntoBattlefieldEffect effect) { @@ -66,12 +66,12 @@ public class PutLandFromHandOntoBattlefieldEffect extends OneShotEffect { Player controller = game.getPlayer(source.getControllerId()); if (controller != null) { Target target = new TargetCardInHand(new FilterLandCard("land card")); - if (target.canChoose(source.getSourceId(), source.getControllerId(), game) && - controller.chooseUse(outcome, "Put land onto battlefield?", source, game) && - controller.choose(outcome, target, source.getSourceId(), game)) { + if (target.canChoose(source.getSourceId(), source.getControllerId(), game) + && controller.chooseUse(outcome, "Put land onto battlefield?", source, game) + && controller.choose(outcome, target, source.getSourceId(), game)) { Card card = game.getCard(target.getFirstTarget()); if (card != null) { - controller.putOntoBattlefieldWithInfo(card, game, Zone.HAND, source.getSourceId(), tapped); + controller.moveCards(card, Zone.BATTLEFIELD, source, game, tapped, false, false, null); } } return true; @@ -85,4 +85,4 @@ public class PutLandFromHandOntoBattlefieldEffect extends OneShotEffect { return new PutLandFromHandOntoBattlefieldEffect(this); } - } +} diff --git a/Mage/src/mage/abilities/effects/common/ReturnSourceFromGraveyardToBattlefieldEffect.java b/Mage/src/mage/abilities/effects/common/ReturnSourceFromGraveyardToBattlefieldEffect.java index a87f0360ff8..a1c3ebe28ab 100644 --- a/Mage/src/mage/abilities/effects/common/ReturnSourceFromGraveyardToBattlefieldEffect.java +++ b/Mage/src/mage/abilities/effects/common/ReturnSourceFromGraveyardToBattlefieldEffect.java @@ -1,16 +1,16 @@ /* * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. - * + * * Redistribution and use in source and binary forms, with or without modification, are * permitted provided that the following conditions are met: - * + * * 1. Redistributions of source code must retain the above copyright notice, this list of * conditions and the following disclaimer. - * + * * 2. Redistributions in binary form must reproduce the above copyright notice, this list * of conditions and the following disclaimer in the documentation and/or other materials * provided with the distribution. - * + * * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR @@ -20,19 +20,18 @@ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * + * * The views and conclusions contained in the software and documentation are those of the * authors and should not be interpreted as representing official policies, either expressed * or implied, of BetaSteward_at_googlemail.com. */ - package mage.abilities.effects.common; -import mage.constants.Outcome; -import mage.constants.Zone; import mage.abilities.Ability; import mage.abilities.effects.OneShotEffect; import mage.cards.Card; +import mage.constants.Outcome; +import mage.constants.Zone; import mage.game.Game; import mage.players.Player; @@ -54,6 +53,7 @@ public class ReturnSourceFromGraveyardToBattlefieldEffect extends OneShotEffect this.tapped = tapped; setText(); } + public ReturnSourceFromGraveyardToBattlefieldEffect(boolean tapped, boolean ownerControl) { super(Outcome.PutCreatureInPlay); this.tapped = tapped; @@ -76,32 +76,31 @@ public class ReturnSourceFromGraveyardToBattlefieldEffect extends OneShotEffect public boolean apply(Game game, Ability source) { if (!game.getState().getZone(source.getSourceId()).equals(Zone.GRAVEYARD)) { return false; - } + } Card card = game.getCard(source.getSourceId()); if (card == null) { return false; } - - Player player; + + Player player; if (ownerControl) { player = game.getPlayer(card.getOwnerId()); } else { player = game.getPlayer(source.getControllerId()); - } - if (player == null) { + } + if (player == null) { return false; - } - - return player.putOntoBattlefieldWithInfo(card, game, Zone.GRAVEYARD, source.getSourceId(), tapped); + } + return player.moveCards(card, Zone.BATTLEFIELD, source, game, tapped, false, true, null); } private void setText() { StringBuilder sb = new StringBuilder("return {this} from your graveyard to the battlefield"); if (tapped) { sb.append(" tapped"); - } + } if (ownerControl) { - sb.append(" under its owner's control"); + sb.append(" under its owner's control"); } staticText = sb.toString(); } diff --git a/Mage/src/mage/abilities/effects/common/search/SearchLibraryPutInPlayEffect.java b/Mage/src/mage/abilities/effects/common/search/SearchLibraryPutInPlayEffect.java index 6776adcc8ea..c92cbb7540e 100644 --- a/Mage/src/mage/abilities/effects/common/search/SearchLibraryPutInPlayEffect.java +++ b/Mage/src/mage/abilities/effects/common/search/SearchLibraryPutInPlayEffect.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.search; import java.util.List; import java.util.UUID; import mage.abilities.Ability; import mage.abilities.effects.SearchEffect; -import mage.cards.Card; +import mage.cards.CardsImpl; import mage.constants.Outcome; import mage.constants.Zone; import mage.game.Game; @@ -90,12 +89,8 @@ public class SearchLibraryPutInPlayEffect extends SearchEffect { } if (player.searchLibrary(target, game)) { if (target.getTargets().size() > 0) { - for (UUID cardId: target.getTargets()) { - Card card = player.getLibrary().getCard(cardId, game); - if (card != null) { - player.putOntoBattlefieldWithInfo(card, game, Zone.LIBRARY, source.getSourceId(), tapped); - } - } + player.moveCards(new CardsImpl(target.getTargets()).getCards(game), + Zone.BATTLEFIELD, source, game, true, false, false, null); } player.shuffleLibrary(game); return true; @@ -110,15 +105,13 @@ public class SearchLibraryPutInPlayEffect extends SearchEffect { StringBuilder sb = new StringBuilder(); sb.append("search your library for "); if (target.getNumberOfTargets() == 0 && target.getMaxNumberOfTargets() > 0) { - if ( target.getMaxNumberOfTargets() == Integer.MAX_VALUE ) { + if (target.getMaxNumberOfTargets() == Integer.MAX_VALUE) { sb.append("any number of ").append(" "); - } - else { + } else { sb.append("up to ").append(target.getMaxNumberOfTargets()).append(" "); } sb.append(target.getTargetName()).append(" and put them onto the battlefield"); - } - else { + } else { sb.append("a ").append(target.getTargetName()).append(" and put it onto the battlefield"); } if (tapped) { @@ -126,8 +119,7 @@ public class SearchLibraryPutInPlayEffect extends SearchEffect { } if (forceShuffle) { sb.append(". Then shuffle your library"); - } - else { + } else { sb.append(". If you do, shuffle your library"); } staticText = sb.toString(); diff --git a/Mage/src/mage/abilities/effects/common/search/SearchLibraryPutInPlayTargetPlayerEffect.java b/Mage/src/mage/abilities/effects/common/search/SearchLibraryPutInPlayTargetPlayerEffect.java index 74cf05fbe9f..8c68601cb38 100644 --- a/Mage/src/mage/abilities/effects/common/search/SearchLibraryPutInPlayTargetPlayerEffect.java +++ b/Mage/src/mage/abilities/effects/common/search/SearchLibraryPutInPlayTargetPlayerEffect.java @@ -9,7 +9,7 @@ import java.util.List; import java.util.UUID; import mage.abilities.Ability; import mage.abilities.effects.SearchEffect; -import mage.cards.Card; +import mage.cards.CardsImpl; import mage.constants.Outcome; import mage.constants.Zone; import mage.game.Game; @@ -20,11 +20,11 @@ import mage.target.common.TargetCardInLibrary; * * @author LevelX2 */ - public class SearchLibraryPutInPlayTargetPlayerEffect extends SearchEffect { protected boolean tapped; protected boolean forceShuffle; + protected boolean ownerIsController; public SearchLibraryPutInPlayTargetPlayerEffect(TargetCardInLibrary target) { this(target, false, true, Outcome.PutCardInPlay); @@ -43,9 +43,14 @@ public class SearchLibraryPutInPlayTargetPlayerEffect extends SearchEffect { } public SearchLibraryPutInPlayTargetPlayerEffect(TargetCardInLibrary target, boolean tapped, boolean forceShuffle, Outcome outcome) { + this(target, tapped, forceShuffle, outcome, false); + } + + public SearchLibraryPutInPlayTargetPlayerEffect(TargetCardInLibrary target, boolean tapped, boolean forceShuffle, Outcome outcome, boolean ownerIsController) { super(target, outcome); this.tapped = tapped; this.forceShuffle = forceShuffle; + this.ownerIsController = ownerIsController; setText(); } @@ -53,6 +58,7 @@ public class SearchLibraryPutInPlayTargetPlayerEffect extends SearchEffect { super(effect); this.tapped = effect.tapped; this.forceShuffle = effect.forceShuffle; + this.ownerIsController = effect.ownerIsController; } @Override @@ -62,26 +68,22 @@ public class SearchLibraryPutInPlayTargetPlayerEffect extends SearchEffect { @Override public boolean apply(Game game, Ability source) { - Player player = game.getPlayer(getTargetPointer().getFirst(game, source)); + Player player = game.getPlayer(getTargetPointer().getFirst(game, source)); if (player != null) { if (player.searchLibrary(target, game)) { if (target.getTargets().size() > 0) { - for (UUID cardId: target.getTargets()) { - Card card = player.getLibrary().getCard(cardId, game); - if (card != null) { - player.putOntoBattlefieldWithInfo(card, game, Zone.LIBRARY, source.getSourceId(), tapped); - } - } + player.moveCards(new CardsImpl(target.getTargets()).getCards(game), + Zone.BATTLEFIELD, source, game, tapped, false, ownerIsController, null); } player.shuffleLibrary(game); return true; } - + if (forceShuffle) { player.shuffleLibrary(game); } } - + return false; } @@ -89,15 +91,13 @@ public class SearchLibraryPutInPlayTargetPlayerEffect extends SearchEffect { StringBuilder sb = new StringBuilder(); sb.append("target player searches his or her library for "); if (target.getNumberOfTargets() == 0 && target.getMaxNumberOfTargets() > 0) { - if ( target.getMaxNumberOfTargets() == Integer.MAX_VALUE ) { + if (target.getMaxNumberOfTargets() == Integer.MAX_VALUE) { sb.append("any number of ").append(" "); - } - else { + } else { sb.append("up to ").append(target.getMaxNumberOfTargets()).append(" "); } sb.append(target.getTargetName()).append(" and put them onto the battlefield"); - } - else { + } else { sb.append("a ").append(target.getTargetName()).append(" and put it onto the battlefield"); } if (tapped) { @@ -105,8 +105,7 @@ public class SearchLibraryPutInPlayTargetPlayerEffect extends SearchEffect { } if (forceShuffle) { sb.append(". Then that player shuffles his or her library"); - } - else { + } else { sb.append(". If that player does, he or she shuffles his or her library"); } staticText = sb.toString(); diff --git a/Mage/src/mage/abilities/effects/keyword/ManifestEffect.java b/Mage/src/mage/abilities/effects/keyword/ManifestEffect.java index 71e6293628d..0640fc8ed85 100644 --- a/Mage/src/mage/abilities/effects/keyword/ManifestEffect.java +++ b/Mage/src/mage/abilities/effects/keyword/ManifestEffect.java @@ -86,13 +86,15 @@ public class ManifestEffect extends OneShotEffect { } MageObjectReference objectReference = new MageObjectReference(card.getId(), card.getZoneChangeCounter(game) + 1, game); game.addEffect(new BecomesFaceDownCreatureEffect(manaCosts, objectReference, Duration.Custom, FaceDownType.MANIFESTED), newSource); - controller.putOntoBattlefieldWithInfo(card, game, Zone.LIBRARY, newSource.getSourceId(), false, true); + + } + controller.moveCards(cards, Zone.BATTLEFIELD, source, game, false, true, false, null); + for (Card card : cards) { Permanent permanent = game.getPermanent(card.getId()); if (permanent != null) { permanent.setManifested(true); } } - game.applyEffects(); // to apply before ETB triggered or replace Effects are executed return true; } return false; diff --git a/Mage/src/mage/abilities/effects/keyword/ManifestTargetPlayerEffect.java b/Mage/src/mage/abilities/effects/keyword/ManifestTargetPlayerEffect.java index 897ff83f235..2e904878769 100644 --- a/Mage/src/mage/abilities/effects/keyword/ManifestTargetPlayerEffect.java +++ b/Mage/src/mage/abilities/effects/keyword/ManifestTargetPlayerEffect.java @@ -89,7 +89,9 @@ public class ManifestTargetPlayerEffect extends OneShotEffect { } MageObjectReference objectReference = new MageObjectReference(card.getId(), card.getZoneChangeCounter(game) + 1, game); game.addEffect(new BecomesFaceDownCreatureEffect(manaCosts, objectReference, Duration.Custom, FaceDownType.MANIFESTED), newSource); - targetPlayer.putOntoBattlefieldWithInfo(card, game, Zone.LIBRARY, newSource.getSourceId(), false, true); + } + targetPlayer.moveCards(cards, Zone.BATTLEFIELD, source, game, false, true, false, null); + for (Card card : cards) { Permanent permanent = game.getPermanent(card.getId()); if (permanent != null) { permanent.setManifested(true); diff --git a/Mage/src/mage/cards/repository/CardRepository.java b/Mage/src/mage/cards/repository/CardRepository.java index 0605160f496..ab5ff527376 100644 --- a/Mage/src/mage/cards/repository/CardRepository.java +++ b/Mage/src/mage/cards/repository/CardRepository.java @@ -61,7 +61,7 @@ public enum CardRepository { private static final String JDBC_URL = "jdbc:h2:file:./db/cards.h2;AUTO_SERVER=TRUE"; private static final String VERSION_ENTITY_NAME = "card"; // raise this if db structure was changed - private static final long CARD_DB_VERSION = 41; + private static final long CARD_DB_VERSION = 42; // raise this if new cards were added to the server private static final long CARD_CONTENT_VERSION = 40; diff --git a/Mage/src/mage/players/Player.java b/Mage/src/mage/players/Player.java index 60edef58aba..7cfa4444370 100644 --- a/Mage/src/mage/players/Player.java +++ b/Mage/src/mage/players/Player.java @@ -741,46 +741,6 @@ public interface Player extends MageItem, Copyable { */ boolean moveCardToLibraryWithInfo(Card card, UUID sourceId, Game game, Zone fromZone, boolean toTop, boolean withName); - /** - * Uses putOntoBattlefield and posts also a info message about in the game - * log - * - * @param card - * @param game - * @param fromZone - * @param sourceId - * @return - */ - @Deprecated - boolean putOntoBattlefieldWithInfo(Card card, Game game, Zone fromZone, UUID sourceId); - - /** - * Uses putOntoBattlefield and posts also a info message about in the game - * log - * - * @param card - * @param game - * @param fromZone - * @param sourceId - * @param tapped the card enters the battlefield tapped - * @return - */ - boolean putOntoBattlefieldWithInfo(Card card, Game game, Zone fromZone, UUID sourceId, boolean tapped); - - /** - * Uses putOntoBattlefield and posts also a info message about in the game - * log - * - * @param card - * @param game - * @param fromZone - * @param sourceId - * @param tapped the card enters the battlefield tapped - * @param facedown the card enters the battlefield facedown - * @return - */ - boolean putOntoBattlefieldWithInfo(Card card, Game game, Zone fromZone, UUID sourceId, boolean tapped, boolean facedown); - /** * Checks if the playerToCheckId is from an opponent in range * diff --git a/Mage/src/mage/players/PlayerImpl.java b/Mage/src/mage/players/PlayerImpl.java index 2330bd54541..80129822440 100644 --- a/Mage/src/mage/players/PlayerImpl.java +++ b/Mage/src/mage/players/PlayerImpl.java @@ -3025,7 +3025,7 @@ public abstract class PlayerImpl implements Player, Serializable { List permanents = new ArrayList<>(); List permanentsEntered = new ArrayList<>(); for (Card card : cards) { - UUID controllingPlayerId = byOwner ? card.getOwnerId() : source.getControllerId(); + UUID controllingPlayerId = byOwner ? card.getOwnerId() : getId(); fromZone = game.getState().getZone(card.getId()); if (faceDown) { card.setFaceDown(true, game); @@ -3307,34 +3307,6 @@ public abstract class PlayerImpl implements Player, Serializable { return result; } - @Deprecated - @Override - public boolean putOntoBattlefieldWithInfo(Card card, Game game, Zone fromZone, UUID sourceId) { - return this.putOntoBattlefieldWithInfo(card, game, fromZone, sourceId, false, false); - } - - @Deprecated - @Override - public boolean putOntoBattlefieldWithInfo(Card card, Game game, Zone fromZone, UUID sourceId, boolean tapped) { - return this.putOntoBattlefieldWithInfo(card, game, fromZone, sourceId, tapped, false); - } - - @Deprecated - @Override - public boolean putOntoBattlefieldWithInfo(Card card, Game game, Zone fromZone, UUID sourceId, boolean tapped, boolean facedown) { - boolean result = false; - if (card.putOntoBattlefield(game, fromZone, sourceId, this.getId(), tapped, facedown)) { - if (!game.isSimulation()) { - game.informPlayers(new StringBuilder(this.getLogName()) - .append(" puts ").append(facedown ? "a card face down " : card.getLogName()) - .append(" from ").append(fromZone.toString().toLowerCase(Locale.ENGLISH)).append(" ") - .append("onto the Battlefield").toString()); - } - result = true; - } - return result; - } - @Override public boolean hasOpponent(UUID playerToCheckId, Game game) { return !this.getId().equals(playerToCheckId) && game.isOpponent(this, playerToCheckId); From fef34b65f6cf932e7ca5c051fc2c9fb293d6705c Mon Sep 17 00:00:00 2001 From: LevelX2 Date: Sun, 18 Oct 2015 23:47:51 +0200 Subject: [PATCH 172/268] * Some more changes for rework of ENTERS_THE_BATTLEFIELD event and card movement. --- .../src/mage/sets/commander2013/PrimalVigor.java | 10 ++++++---- .../mage/sets/khansoftarkir/HardenedScales.java | 15 +++++++++------ .../mage/sets/modernmasters/DoublingSeason.java | 12 ++++++++---- .../sets/returntoravnica/CorpsejackMenace.java | 10 ++-------- 4 files changed, 25 insertions(+), 22 deletions(-) diff --git a/Mage.Sets/src/mage/sets/commander2013/PrimalVigor.java b/Mage.Sets/src/mage/sets/commander2013/PrimalVigor.java index ee069e6b007..468b0b9fae7 100644 --- a/Mage.Sets/src/mage/sets/commander2013/PrimalVigor.java +++ b/Mage.Sets/src/mage/sets/commander2013/PrimalVigor.java @@ -51,7 +51,6 @@ public class PrimalVigor extends CardImpl { super(ownerId, 162, "Primal Vigor", Rarity.RARE, new CardType[]{CardType.ENCHANTMENT}, "{4}{G}"); this.expansionSetCode = "C13"; - // If one or more tokens would be put onto the battlefield, twice that many of those tokens are put onto the battlefield instead. this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new PrimalVigorTokenEffect())); // If one or more +1/+1 counters would be placed on a creature, twice that many +1/+1 counters are placed on that creature instead. @@ -121,7 +120,7 @@ class PrimalVigorCounterEffect extends ReplacementEffectImpl { @Override public boolean replaceEvent(GameEvent event, Ability source, Game game) { - event.setAmount(event.getAmount() *2); + event.setAmount(event.getAmount() * 2); return false; } @@ -132,8 +131,11 @@ class PrimalVigorCounterEffect extends ReplacementEffectImpl { @Override public boolean applies(GameEvent event, Ability source, Game game) { - Permanent target = game.getPermanent(event.getTargetId()); - if (target != null && target.getCardType().contains(CardType.CREATURE) + Permanent permanent = game.getPermanent(event.getTargetId()); + if (permanent == null) { + permanent = game.getPermanentEntering(event.getTargetId()); + } + if (permanent != null && permanent.getCardType().contains(CardType.CREATURE) && event.getData() != null && event.getData().equals("+1/+1")) { return true; } diff --git a/Mage.Sets/src/mage/sets/khansoftarkir/HardenedScales.java b/Mage.Sets/src/mage/sets/khansoftarkir/HardenedScales.java index 3ecbf0b73e9..a83fa7b78be 100644 --- a/Mage.Sets/src/mage/sets/khansoftarkir/HardenedScales.java +++ b/Mage.Sets/src/mage/sets/khansoftarkir/HardenedScales.java @@ -53,7 +53,6 @@ public class HardenedScales extends CardImpl { super(ownerId, 133, "Hardened Scales", Rarity.RARE, new CardType[]{CardType.ENCHANTMENT}, "{G}"); this.expansionSetCode = "KTK"; - // If one or more +1/+1 counters would be placed on a creature you control, that many plus one +1/+1 counters are placed on it instead. this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new HardenedScalesEffect())); @@ -70,6 +69,7 @@ public class HardenedScales extends CardImpl { } class HardenedScalesEffect extends ReplacementEffectImpl { + HardenedScalesEffect() { super(Duration.WhileOnBattlefield, Outcome.BoostCreature, false); staticText = "If one or more +1/+1 counters would be placed on a creature you control, that many plus one +1/+1 counters are placed on it instead"; @@ -86,17 +86,20 @@ class HardenedScalesEffect extends ReplacementEffectImpl { return false; } - @Override + @Override public boolean checksEventType(GameEvent event, Game game) { return event.getType() == EventType.ADD_COUNTERS; } - + @Override public boolean applies(GameEvent event, Ability source, Game game) { if (event.getData().equals(CounterType.P1P1.getName())) { - Permanent target = game.getPermanent(event.getTargetId()); - if (target != null && target.getControllerId().equals(source.getControllerId()) - && target.getCardType().contains(CardType.CREATURE)) { + Permanent permanent = game.getPermanent(event.getTargetId()); + if (permanent == null) { + permanent = game.getPermanentEntering(event.getTargetId()); + } + if (permanent != null && permanent.getControllerId().equals(source.getControllerId()) + && permanent.getCardType().contains(CardType.CREATURE)) { return true; } } diff --git a/Mage.Sets/src/mage/sets/modernmasters/DoublingSeason.java b/Mage.Sets/src/mage/sets/modernmasters/DoublingSeason.java index 4c42462e1fe..1067cb393f1 100644 --- a/Mage.Sets/src/mage/sets/modernmasters/DoublingSeason.java +++ b/Mage.Sets/src/mage/sets/modernmasters/DoublingSeason.java @@ -113,6 +113,7 @@ class DoublingSeasonTokenEffect extends ReplacementEffectImpl { } class DoublingSeasonCounterEffect extends ReplacementEffectImpl { + DoublingSeasonCounterEffect() { super(Duration.WhileOnBattlefield, Outcome.BoostCreature, false); staticText = "If an effect would place one or more counters on a permanent you control, it places twice that many of those counters on that permanent instead"; @@ -128,15 +129,18 @@ class DoublingSeasonCounterEffect extends ReplacementEffectImpl { return false; } - @Override + @Override public boolean checksEventType(GameEvent event, Game game) { return event.getType() == GameEvent.EventType.ADD_COUNTERS; } - + @Override public boolean applies(GameEvent event, Ability source, Game game) { - Permanent target = game.getPermanent(event.getTargetId()); - if (target != null && target.getControllerId().equals(source.getControllerId())) { + Permanent permanent = game.getPermanent(event.getTargetId()); + if (permanent == null) { + permanent = game.getPermanentEntering(event.getTargetId()); + } + if (permanent != null && permanent.getControllerId().equals(source.getControllerId())) { return true; } return false; diff --git a/Mage.Sets/src/mage/sets/returntoravnica/CorpsejackMenace.java b/Mage.Sets/src/mage/sets/returntoravnica/CorpsejackMenace.java index 10bf030e45a..58085795567 100644 --- a/Mage.Sets/src/mage/sets/returntoravnica/CorpsejackMenace.java +++ b/Mage.Sets/src/mage/sets/returntoravnica/CorpsejackMenace.java @@ -93,14 +93,8 @@ class CorpsejackMenaceReplacementEffect extends ReplacementEffectImpl { @Override public boolean replaceEvent(GameEvent event, Ability source, Game game) { - Permanent permanent = game.getPermanent(event.getTargetId()); - if (permanent == null) { - permanent = game.getPermanentEntering(event.getTargetId()); - } - if (permanent != null) { - permanent.addCounters(CounterType.P1P1.createInstance(event.getAmount() * 2), game, event.getAppliedEffects()); - } - return true; + event.setAmount(event.getAmount() * 2); + return false; } @Override From 53af114105aaaac98306034cb3a65f9cda399f72 Mon Sep 17 00:00:00 2001 From: LevelX2 Date: Mon, 19 Oct 2015 08:32:55 +0200 Subject: [PATCH 173/268] * Skeleton Ship - Fixed wrong casting cost ({B} was missing). --- Mage.Sets/src/mage/sets/iceage/SkeletonShip.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Mage.Sets/src/mage/sets/iceage/SkeletonShip.java b/Mage.Sets/src/mage/sets/iceage/SkeletonShip.java index 38a31f5b63c..78053e99136 100644 --- a/Mage.Sets/src/mage/sets/iceage/SkeletonShip.java +++ b/Mage.Sets/src/mage/sets/iceage/SkeletonShip.java @@ -51,7 +51,7 @@ import mage.target.common.TargetCreaturePermanent; public class SkeletonShip extends CardImpl { public SkeletonShip(UUID ownerId) { - super(ownerId, 379, "Skeleton Ship", Rarity.RARE, new CardType[]{CardType.CREATURE}, "{3}{U}"); + super(ownerId, 379, "Skeleton Ship", Rarity.RARE, new CardType[]{CardType.CREATURE}, "{3}{U}{B}"); this.expansionSetCode = "ICE"; this.supertype.add("Legendary"); this.subtype.add("Skeleton"); @@ -62,7 +62,7 @@ public class SkeletonShip extends CardImpl { this.addAbility(new ControlsPermanentsControllerTriggeredAbility( new FilterLandPermanent("Island", "no Islands"), Filter.ComparisonType.Equal, 0, new SacrificeSourceEffect())); - + // {tap}: Put a -1/-1 counter on target creature. Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new AddCountersTargetEffect(CounterType.M1M1.createInstance()), new TapSourceCost()); ability.addTarget(new TargetCreaturePermanent()); From 6c438580464f25bb456a0ddaf16061b3ea0be7dc Mon Sep 17 00:00:00 2001 From: Neil Gentleman Date: Sun, 18 Oct 2015 21:42:38 -0700 Subject: [PATCH 174/268] Deck Editor: Fix redraw after missing image --- Mage.Client/src/main/java/mage/client/cards/BigCard.java | 1 + 1 file changed, 1 insertion(+) diff --git a/Mage.Client/src/main/java/mage/client/cards/BigCard.java b/Mage.Client/src/main/java/mage/client/cards/BigCard.java index 6265dc288a9..75fa5508789 100644 --- a/Mage.Client/src/main/java/mage/client/cards/BigCard.java +++ b/Mage.Client/src/main/java/mage/client/cards/BigCard.java @@ -161,6 +161,7 @@ public class BigCard extends JComponent { } public void addJXPanel(UUID cardId, JXPanel jxPanel) { + this.cardId = cardId; bigImage = null; synchronized (this) { if (this.panel != null) { remove(this.panel); } From 3817118bc0ed8eab56934a51f4dfbd9c2bbd768e Mon Sep 17 00:00:00 2001 From: Neil Gentleman Date: Sun, 18 Oct 2015 22:26:40 -0700 Subject: [PATCH 175/268] Fix 'Of', 'By' and 'The' in card names --- .../src/mage/deck/ShardsOfAlaraBlock.java | 2 +- .../mage/sets/championsofkamigawa/MyojinOfInfiniteRage.java | 2 +- .../mage/sets/championsofkamigawa/RyuseiTheFallingStar.java | 2 +- Mage.Sets/src/mage/sets/dragonsmaze/VoiceOfResurgence.java | 2 +- Mage.Sets/src/mage/sets/legends/ArenaOfTheAncients.java | 2 +- Mage.Sets/src/mage/sets/magic2010/DjinnOfWishes.java | 2 +- Mage.Sets/src/mage/sets/magicorigins/ConsecratedByBlood.java | 2 +- Mage.Sets/src/mage/sets/urzassaga/DiscipleOfGrace.java | 2 +- Mage.Sets/src/mage/sets/urzassaga/DiscipleOfLaw.java | 2 +- Mage.Sets/src/mage/sets/urzassaga/VoiceOfGrace.java | 2 +- Mage.Sets/src/mage/sets/urzassaga/VoiceOfLaw.java | 2 +- .../org/mage/test/cards/abilities/keywords/CyclingTest.java | 4 ++-- 12 files changed, 13 insertions(+), 13 deletions(-) diff --git a/Mage.Server.Plugins/Mage.Deck.Constructed/src/mage/deck/ShardsOfAlaraBlock.java b/Mage.Server.Plugins/Mage.Deck.Constructed/src/mage/deck/ShardsOfAlaraBlock.java index 44fc5e3e6b3..c8915b5a8b1 100644 --- a/Mage.Server.Plugins/Mage.Deck.Constructed/src/mage/deck/ShardsOfAlaraBlock.java +++ b/Mage.Server.Plugins/Mage.Deck.Constructed/src/mage/deck/ShardsOfAlaraBlock.java @@ -37,7 +37,7 @@ import mage.cards.decks.Constructed; public class ShardsOfAlaraBlock extends Constructed { public ShardsOfAlaraBlock() { - super("Constructed - Shards Of Alara Block"); + super("Constructed - Shards of Alara Block"); setCodes.add("ALA"); setCodes.add("CON"); setCodes.add("ARB"); diff --git a/Mage.Sets/src/mage/sets/championsofkamigawa/MyojinOfInfiniteRage.java b/Mage.Sets/src/mage/sets/championsofkamigawa/MyojinOfInfiniteRage.java index bc9ef137476..ac250e6c060 100644 --- a/Mage.Sets/src/mage/sets/championsofkamigawa/MyojinOfInfiniteRage.java +++ b/Mage.Sets/src/mage/sets/championsofkamigawa/MyojinOfInfiniteRage.java @@ -59,7 +59,7 @@ public class MyojinOfInfiniteRage extends CardImpl { private static final FilterLandPermanent filter = new FilterLandPermanent("lands"); public MyojinOfInfiniteRage(UUID ownerId) { - super(ownerId, 181, "Myojin Of Infinite Rage", Rarity.RARE, new CardType[]{CardType.CREATURE}, "{7}{R}{R}{R}"); + super(ownerId, 181, "Myojin of Infinite Rage", Rarity.RARE, new CardType[]{CardType.CREATURE}, "{7}{R}{R}{R}"); this.expansionSetCode = "CHK"; this.supertype.add("Legendary"); this.subtype.add("Spirit"); diff --git a/Mage.Sets/src/mage/sets/championsofkamigawa/RyuseiTheFallingStar.java b/Mage.Sets/src/mage/sets/championsofkamigawa/RyuseiTheFallingStar.java index 22072830492..db772aa455f 100644 --- a/Mage.Sets/src/mage/sets/championsofkamigawa/RyuseiTheFallingStar.java +++ b/Mage.Sets/src/mage/sets/championsofkamigawa/RyuseiTheFallingStar.java @@ -53,7 +53,7 @@ public class RyuseiTheFallingStar extends CardImpl { } public RyuseiTheFallingStar(UUID ownerID) { - super(ownerID, 185, "Ryusei, The Falling Star", Rarity.RARE, new CardType[]{CardType.CREATURE}, "{5}{R}"); + super(ownerID, 185, "Ryusei, the Falling Star", Rarity.RARE, new CardType[]{CardType.CREATURE}, "{5}{R}"); this.expansionSetCode = "CHK"; this.supertype.add("Legendary"); this.subtype.add("Dragon"); diff --git a/Mage.Sets/src/mage/sets/dragonsmaze/VoiceOfResurgence.java b/Mage.Sets/src/mage/sets/dragonsmaze/VoiceOfResurgence.java index 8bebbae8f2e..6e76865f938 100644 --- a/Mage.Sets/src/mage/sets/dragonsmaze/VoiceOfResurgence.java +++ b/Mage.Sets/src/mage/sets/dragonsmaze/VoiceOfResurgence.java @@ -104,7 +104,7 @@ class VoiceOfResurgenceTriggeredAbility extends TriggeredAbilityImpl { return true; } } - // Voice Of Resurgence Dies + // Voice of Resurgence Dies if (event.getType() == GameEvent.EventType.ZONE_CHANGE && getSourceId().equals(event.getTargetId())) { ZoneChangeEvent zce = (ZoneChangeEvent) event; return zce.getFromZone().equals(Zone.BATTLEFIELD) && zce.getToZone().equals(Zone.GRAVEYARD); diff --git a/Mage.Sets/src/mage/sets/legends/ArenaOfTheAncients.java b/Mage.Sets/src/mage/sets/legends/ArenaOfTheAncients.java index c5564f03ead..c8d98544ed1 100644 --- a/Mage.Sets/src/mage/sets/legends/ArenaOfTheAncients.java +++ b/Mage.Sets/src/mage/sets/legends/ArenaOfTheAncients.java @@ -32,7 +32,7 @@ public class ArenaOfTheAncients extends CardImpl { } public ArenaOfTheAncients(UUID ownerId) { - super(ownerId, 215, "Arena Of The Ancients", Rarity.RARE, new CardType[]{CardType.ARTIFACT}, "{3}"); + super(ownerId, 215, "Arena of the Ancients", Rarity.RARE, new CardType[]{CardType.ARTIFACT}, "{3}"); this.expansionSetCode = "LEG"; // When Arena of the Ancients enters the battlefield, tap all Legendary creatures diff --git a/Mage.Sets/src/mage/sets/magic2010/DjinnOfWishes.java b/Mage.Sets/src/mage/sets/magic2010/DjinnOfWishes.java index 1ad585e45f5..ea454dc5cdb 100644 --- a/Mage.Sets/src/mage/sets/magic2010/DjinnOfWishes.java +++ b/Mage.Sets/src/mage/sets/magic2010/DjinnOfWishes.java @@ -105,7 +105,7 @@ class DjinnOfWishesEffect extends OneShotEffect { Card card = player.getLibrary().getFromTop(game); Cards cards = new CardsImpl(); cards.add(card); - player.revealCards("Djinn Of Wishes", cards, game); + player.revealCards("Djinn of Wishes", cards, game); player.getLibrary().removeFromTop(game); diff --git a/Mage.Sets/src/mage/sets/magicorigins/ConsecratedByBlood.java b/Mage.Sets/src/mage/sets/magicorigins/ConsecratedByBlood.java index db3331a17ff..48fed631acf 100644 --- a/Mage.Sets/src/mage/sets/magicorigins/ConsecratedByBlood.java +++ b/Mage.Sets/src/mage/sets/magicorigins/ConsecratedByBlood.java @@ -66,7 +66,7 @@ public class ConsecratedByBlood extends CardImpl { } public ConsecratedByBlood(UUID ownerId) { - super(ownerId, 87, "Consecrated By Blood", Rarity.UNCOMMON, new CardType[]{CardType.ENCHANTMENT}, "{2}{B}{B}"); + super(ownerId, 87, "Consecrated by Blood", Rarity.UNCOMMON, new CardType[]{CardType.ENCHANTMENT}, "{2}{B}{B}"); this.expansionSetCode = "ORI"; this.subtype.add("Aura"); diff --git a/Mage.Sets/src/mage/sets/urzassaga/DiscipleOfGrace.java b/Mage.Sets/src/mage/sets/urzassaga/DiscipleOfGrace.java index b271ba24413..e34548dbd8b 100644 --- a/Mage.Sets/src/mage/sets/urzassaga/DiscipleOfGrace.java +++ b/Mage.Sets/src/mage/sets/urzassaga/DiscipleOfGrace.java @@ -53,7 +53,7 @@ public class DiscipleOfGrace extends CardImpl { } public DiscipleOfGrace(UUID ownerId) { - super(ownerId, 10, "Disciple Of Grace", Rarity.COMMON, new CardType[]{CardType.CREATURE}, "{1}{W}"); + super(ownerId, 10, "Disciple of Grace", Rarity.COMMON, new CardType[]{CardType.CREATURE}, "{1}{W}"); this.expansionSetCode = "USG"; this.subtype.add("Human"); this.subtype.add("Cleric"); diff --git a/Mage.Sets/src/mage/sets/urzassaga/DiscipleOfLaw.java b/Mage.Sets/src/mage/sets/urzassaga/DiscipleOfLaw.java index 8edffd89acc..b639fb3aaf9 100644 --- a/Mage.Sets/src/mage/sets/urzassaga/DiscipleOfLaw.java +++ b/Mage.Sets/src/mage/sets/urzassaga/DiscipleOfLaw.java @@ -53,7 +53,7 @@ public class DiscipleOfLaw extends CardImpl { } public DiscipleOfLaw(UUID ownerId) { - super(ownerId, 11, "Disciple Of Law", Rarity.COMMON, new CardType[]{CardType.CREATURE}, "{1}{W}"); + super(ownerId, 11, "Disciple of Law", Rarity.COMMON, new CardType[]{CardType.CREATURE}, "{1}{W}"); this.expansionSetCode = "USG"; this.subtype.add("Human"); this.subtype.add("Cleric"); diff --git a/Mage.Sets/src/mage/sets/urzassaga/VoiceOfGrace.java b/Mage.Sets/src/mage/sets/urzassaga/VoiceOfGrace.java index fa51e7b9e59..2fa195c2d3b 100644 --- a/Mage.Sets/src/mage/sets/urzassaga/VoiceOfGrace.java +++ b/Mage.Sets/src/mage/sets/urzassaga/VoiceOfGrace.java @@ -53,7 +53,7 @@ public class VoiceOfGrace extends CardImpl { } public VoiceOfGrace(UUID ownerId) { - super(ownerId, 54, "Voice Of Grace", Rarity.UNCOMMON, new CardType[]{CardType.CREATURE}, "{3}{W}"); + super(ownerId, 54, "Voice of Grace", Rarity.UNCOMMON, new CardType[]{CardType.CREATURE}, "{3}{W}"); this.expansionSetCode = "USG"; this.subtype.add("Angel"); diff --git a/Mage.Sets/src/mage/sets/urzassaga/VoiceOfLaw.java b/Mage.Sets/src/mage/sets/urzassaga/VoiceOfLaw.java index 898152c6247..51fcaf8fcba 100644 --- a/Mage.Sets/src/mage/sets/urzassaga/VoiceOfLaw.java +++ b/Mage.Sets/src/mage/sets/urzassaga/VoiceOfLaw.java @@ -52,7 +52,7 @@ public class VoiceOfLaw extends CardImpl { } public VoiceOfLaw(UUID ownerId) { - super(ownerId, 55, "Voice Of Law", Rarity.UNCOMMON, new CardType[]{CardType.CREATURE}, "{3}{W}"); + super(ownerId, 55, "Voice of Law", Rarity.UNCOMMON, new CardType[]{CardType.CREATURE}, "{3}{W}"); this.expansionSetCode = "USG"; this.subtype.add("Angel"); diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/abilities/keywords/CyclingTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/abilities/keywords/CyclingTest.java index e50598c40b4..472fada8fb9 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/abilities/keywords/CyclingTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/abilities/keywords/CyclingTest.java @@ -96,7 +96,7 @@ public class CyclingTest extends CardTestPlayerBase { addCard(Zone.GRAVEYARD, playerA, "Decree of Pain"); // Protection from black // Cycling {2} ({2}, Discard this card: Draw a card.) - addCard(Zone.BATTLEFIELD, playerB, "Disciple Of Grace"); + addCard(Zone.BATTLEFIELD, playerB, "Disciple of Grace"); activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Cycling {3}{B}{B}"); activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerB, "Cycling {2}"); @@ -108,7 +108,7 @@ public class CyclingTest extends CardTestPlayerBase { assertHandCount(playerB, 0); assertGraveyardCount(playerA, "Decree of Pain", 1); - assertPermanentCount(playerB, "Disciple Of Grace", 1); + assertPermanentCount(playerB, "Disciple of Grace", 1); } From ae969b1797f30489db04359e603cd2e645007a18 Mon Sep 17 00:00:00 2001 From: Neil Gentleman Date: Mon, 19 Oct 2015 02:21:33 -0700 Subject: [PATCH 176/268] Fix incorrect casting costs why is 3UU so unpopular? --- Mage.Sets/src/mage/sets/magic2011/AjanisPridemate.java | 2 +- Mage.Sets/src/mage/sets/odyssey/BalshanGriffin.java | 2 +- Mage.Sets/src/mage/sets/odyssey/FerventDenial.java | 2 +- Mage.Sets/src/mage/sets/onslaught/RiptideShapeshifter.java | 2 +- Mage.Sets/src/mage/sets/urzassaga/Sunder.java | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/Mage.Sets/src/mage/sets/magic2011/AjanisPridemate.java b/Mage.Sets/src/mage/sets/magic2011/AjanisPridemate.java index 57e2e4dd192..4272c6c4093 100644 --- a/Mage.Sets/src/mage/sets/magic2011/AjanisPridemate.java +++ b/Mage.Sets/src/mage/sets/magic2011/AjanisPridemate.java @@ -48,7 +48,7 @@ import mage.game.events.GameEvent.EventType; public class AjanisPridemate extends CardImpl { public AjanisPridemate(UUID ownerId) { - super(ownerId, 3, "Ajani's Pridemate", Rarity.UNCOMMON, new CardType[]{CardType.CREATURE}, "1}{W}"); + super(ownerId, 3, "Ajani's Pridemate", Rarity.UNCOMMON, new CardType[]{CardType.CREATURE}, "{1}{W}"); this.expansionSetCode = "M11"; this.subtype.add("Cat"); this.subtype.add("Soldier"); diff --git a/Mage.Sets/src/mage/sets/odyssey/BalshanGriffin.java b/Mage.Sets/src/mage/sets/odyssey/BalshanGriffin.java index 02662a1d3bc..fe4767b9919 100644 --- a/Mage.Sets/src/mage/sets/odyssey/BalshanGriffin.java +++ b/Mage.Sets/src/mage/sets/odyssey/BalshanGriffin.java @@ -49,7 +49,7 @@ import mage.target.common.TargetCardInHand; public class BalshanGriffin extends CardImpl { public BalshanGriffin(UUID ownerId) { - super(ownerId, 67, "Balshan Griffin", Rarity.UNCOMMON, new CardType[]{CardType.CREATURE}, "{3}{U}"); + super(ownerId, 67, "Balshan Griffin", Rarity.UNCOMMON, new CardType[]{CardType.CREATURE}, "{3}{U}{U}"); this.expansionSetCode = "ODY"; this.subtype.add("Griffin"); diff --git a/Mage.Sets/src/mage/sets/odyssey/FerventDenial.java b/Mage.Sets/src/mage/sets/odyssey/FerventDenial.java index 990232bc94e..24cb2a3e330 100644 --- a/Mage.Sets/src/mage/sets/odyssey/FerventDenial.java +++ b/Mage.Sets/src/mage/sets/odyssey/FerventDenial.java @@ -44,7 +44,7 @@ import mage.target.TargetSpell; public class FerventDenial extends CardImpl { public FerventDenial(UUID ownerId) { - super(ownerId, 86, "Fervent Denial", Rarity.UNCOMMON, new CardType[]{CardType.INSTANT}, "{3}{U}"); + super(ownerId, 86, "Fervent Denial", Rarity.UNCOMMON, new CardType[]{CardType.INSTANT}, "{3}{U}{U}"); this.expansionSetCode = "ODY"; diff --git a/Mage.Sets/src/mage/sets/onslaught/RiptideShapeshifter.java b/Mage.Sets/src/mage/sets/onslaught/RiptideShapeshifter.java index 72ff1eb3c97..615d8f2ee16 100644 --- a/Mage.Sets/src/mage/sets/onslaught/RiptideShapeshifter.java +++ b/Mage.Sets/src/mage/sets/onslaught/RiptideShapeshifter.java @@ -56,7 +56,7 @@ import mage.players.Player; public class RiptideShapeshifter extends CardImpl { public RiptideShapeshifter(UUID ownerId) { - super(ownerId, 109, "Riptide Shapeshifter", Rarity.UNCOMMON, new CardType[]{CardType.CREATURE}, "{3}{U}"); + super(ownerId, 109, "Riptide Shapeshifter", Rarity.UNCOMMON, new CardType[]{CardType.CREATURE}, "{3}{U}{U}"); this.expansionSetCode = "ONS"; this.subtype.add("Shapeshifter"); diff --git a/Mage.Sets/src/mage/sets/urzassaga/Sunder.java b/Mage.Sets/src/mage/sets/urzassaga/Sunder.java index ee8ff761003..fee91fcee5e 100644 --- a/Mage.Sets/src/mage/sets/urzassaga/Sunder.java +++ b/Mage.Sets/src/mage/sets/urzassaga/Sunder.java @@ -46,7 +46,7 @@ import mage.game.permanent.Permanent; public class Sunder extends CardImpl { public Sunder(UUID ownerId) { - super(ownerId, 101, "Sunder", Rarity.RARE, new CardType[]{CardType.INSTANT}, "{3}{U}"); + super(ownerId, 101, "Sunder", Rarity.RARE, new CardType[]{CardType.INSTANT}, "{3}{U}{U}"); this.expansionSetCode = "USG"; // Return all lands to their owners' hands. From e3d83c3545f66ed79df22b7e2d037e01f9f17b2c Mon Sep 17 00:00:00 2001 From: Neil Gentleman Date: Mon, 19 Oct 2015 02:32:58 -0700 Subject: [PATCH 177/268] Fix Minamo Sightbender toughness --- .../src/mage/sets/betrayersofkamigawa/MinamoSightbender.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Mage.Sets/src/mage/sets/betrayersofkamigawa/MinamoSightbender.java b/Mage.Sets/src/mage/sets/betrayersofkamigawa/MinamoSightbender.java index 10062690021..e10d7262166 100644 --- a/Mage.Sets/src/mage/sets/betrayersofkamigawa/MinamoSightbender.java +++ b/Mage.Sets/src/mage/sets/betrayersofkamigawa/MinamoSightbender.java @@ -62,7 +62,7 @@ public class MinamoSightbender extends CardImpl { this.subtype.add("Wizard"); this.power = new MageInt(1); - this.toughness = new MageInt(1); + this.toughness = new MageInt(2); // {X}, {T}: Target creature with power X or less can't be blocked this turn. Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new CantBeBlockedTargetEffect(), new ManaCostsImpl("{X}")); From 77c1b827bd10e1426e17186c82045a267aa39452 Mon Sep 17 00:00:00 2001 From: Neil Gentleman Date: Mon, 19 Oct 2015 02:58:15 -0700 Subject: [PATCH 178/268] Fix misc. creature types and missing Legendary & Arcane --- Mage.Sets/src/mage/sets/archenemy/SkirkCommando.java | 1 - Mage.Sets/src/mage/sets/battleforzendikar/DustStalker.java | 3 +-- .../src/mage/sets/betrayersofkamigawa/GenjuOfTheRealm.java | 1 + .../src/mage/sets/championsofkamigawa/CrushingPain.java | 2 +- .../src/mage/sets/championsofkamigawa/EtherealHaze.java | 2 +- Mage.Sets/src/mage/sets/conflux/EtherswornAdjudicator.java | 2 ++ .../src/mage/sets/dragonsmaze/SmeltWardGatekeepers.java | 2 +- Mage.Sets/src/mage/sets/fifthedition/ShanodinDryads.java | 1 + Mage.Sets/src/mage/sets/gatecrash/UrbanEvolution.java | 4 ---- Mage.Sets/src/mage/sets/journeyintonyx/PensiveMinotaur.java | 1 + Mage.Sets/src/mage/sets/magic2010/Lifelink.java | 4 ---- Mage.Sets/src/mage/sets/planechase/SilverMyr.java | 1 - .../src/mage/sets/returntoravnica/SphinxOfTheChimes.java | 2 +- .../mage/sets/saviorsofkamigawa/MatsuTribeBirdstalker.java | 1 + Mage.Sets/src/mage/sets/scarsofmirrodin/OxiddaDaredevil.java | 5 ++++- Mage.Sets/src/mage/sets/scourge/GoblinWarchief.java | 1 + Mage.Sets/src/mage/sets/tenthedition/HighwayRobber.java | 1 - Mage.Sets/src/mage/sets/urzassaga/GorillaWarrior.java | 1 + Mage.Sets/src/mage/sets/zendikar/ArrowVolleyTrap.java | 1 + 19 files changed, 18 insertions(+), 18 deletions(-) diff --git a/Mage.Sets/src/mage/sets/archenemy/SkirkCommando.java b/Mage.Sets/src/mage/sets/archenemy/SkirkCommando.java index 3dd3c0fc6d5..c364916e666 100644 --- a/Mage.Sets/src/mage/sets/archenemy/SkirkCommando.java +++ b/Mage.Sets/src/mage/sets/archenemy/SkirkCommando.java @@ -52,7 +52,6 @@ public class SkirkCommando extends CardImpl { super(ownerId, 47, "Skirk Commando", Rarity.COMMON, new CardType[]{CardType.CREATURE}, "{1}{R}{R}"); this.expansionSetCode = "ARC"; this.subtype.add("Goblin"); - this.subtype.add("Shaman"); this.power = new MageInt(2); this.toughness = new MageInt(1); diff --git a/Mage.Sets/src/mage/sets/battleforzendikar/DustStalker.java b/Mage.Sets/src/mage/sets/battleforzendikar/DustStalker.java index cd751056f6b..15b94094f9c 100644 --- a/Mage.Sets/src/mage/sets/battleforzendikar/DustStalker.java +++ b/Mage.Sets/src/mage/sets/battleforzendikar/DustStalker.java @@ -59,8 +59,7 @@ public class DustStalker extends CardImpl { public DustStalker(UUID ownerId) { super(ownerId, 202, "Dust Stalker", Rarity.RARE, new CardType[]{CardType.CREATURE}, "{2}{B}{R}"); this.expansionSetCode = "BFZ"; - this.supertype.add("Creautre"); - this.supertype.add("Eldrazi"); + this.subtype.add("Eldrazi"); this.power = new MageInt(5); this.toughness = new MageInt(3); diff --git a/Mage.Sets/src/mage/sets/betrayersofkamigawa/GenjuOfTheRealm.java b/Mage.Sets/src/mage/sets/betrayersofkamigawa/GenjuOfTheRealm.java index d973dc72a98..6afd9f2b81a 100644 --- a/Mage.Sets/src/mage/sets/betrayersofkamigawa/GenjuOfTheRealm.java +++ b/Mage.Sets/src/mage/sets/betrayersofkamigawa/GenjuOfTheRealm.java @@ -62,6 +62,7 @@ public class GenjuOfTheRealm extends CardImpl { super(ownerId, 151, "Genju of the Realm", Rarity.RARE, new CardType[]{CardType.ENCHANTMENT}, "{W}{U}{B}{R}{G}"); this.expansionSetCode = "BOK"; this.subtype.add("Aura"); + this.supertype.add("Legendary"); // Enchant Land diff --git a/Mage.Sets/src/mage/sets/championsofkamigawa/CrushingPain.java b/Mage.Sets/src/mage/sets/championsofkamigawa/CrushingPain.java index 048fa176252..8d797e53819 100644 --- a/Mage.Sets/src/mage/sets/championsofkamigawa/CrushingPain.java +++ b/Mage.Sets/src/mage/sets/championsofkamigawa/CrushingPain.java @@ -54,7 +54,7 @@ public class CrushingPain extends CardImpl { public CrushingPain (UUID ownerId) { super(ownerId, 162, "Crushing Pain", Rarity.COMMON, new CardType[]{CardType.INSTANT}, "{1}{R}"); this.expansionSetCode = "CHK"; - + this.subtype.add("Arcane"); // Crushing Pain deals 6 damage to target creature that was dealt damage this turn. this.getSpellAbility().addEffect(new DamageTargetEffect(6)); diff --git a/Mage.Sets/src/mage/sets/championsofkamigawa/EtherealHaze.java b/Mage.Sets/src/mage/sets/championsofkamigawa/EtherealHaze.java index 8c6eb77fe52..308de9cef81 100644 --- a/Mage.Sets/src/mage/sets/championsofkamigawa/EtherealHaze.java +++ b/Mage.Sets/src/mage/sets/championsofkamigawa/EtherealHaze.java @@ -45,7 +45,7 @@ public class EtherealHaze extends CardImpl { public EtherealHaze (UUID ownerId) { super(ownerId, 9, "Ethereal Haze", Rarity.COMMON, new CardType[]{CardType.INSTANT}, "{W}"); this.expansionSetCode = "CHK"; - + this.subtype.add("Arcane"); // Prevent all damage that would be dealt by creatures this turn. this.getSpellAbility().addEffect(new PreventAllDamageByAllEffect(new FilterCreaturePermanent("creatures"), Duration.EndOfTurn, false)); diff --git a/Mage.Sets/src/mage/sets/conflux/EtherswornAdjudicator.java b/Mage.Sets/src/mage/sets/conflux/EtherswornAdjudicator.java index 96d9df3d93d..6b5c29dcde7 100644 --- a/Mage.Sets/src/mage/sets/conflux/EtherswornAdjudicator.java +++ b/Mage.Sets/src/mage/sets/conflux/EtherswornAdjudicator.java @@ -63,6 +63,8 @@ public class EtherswornAdjudicator extends CardImpl { public EtherswornAdjudicator(UUID ownerId) { super(ownerId, 26, "Ethersworn Adjudicator", Rarity.MYTHIC, new CardType[]{CardType.ARTIFACT, CardType.CREATURE}, "{4}{U}"); this.expansionSetCode = "CON"; + this.subtype.add("Vedalken"); + this.subtype.add("Knight"); this.power = new MageInt(4); this.toughness = new MageInt(4); diff --git a/Mage.Sets/src/mage/sets/dragonsmaze/SmeltWardGatekeepers.java b/Mage.Sets/src/mage/sets/dragonsmaze/SmeltWardGatekeepers.java index 95f3582d94d..e79e5ae9797 100644 --- a/Mage.Sets/src/mage/sets/dragonsmaze/SmeltWardGatekeepers.java +++ b/Mage.Sets/src/mage/sets/dragonsmaze/SmeltWardGatekeepers.java @@ -70,7 +70,7 @@ public class SmeltWardGatekeepers extends CardImpl { super(ownerId, 39, "Smelt-Ward Gatekeepers", Rarity.COMMON, new CardType[]{CardType.CREATURE}, "{3}{R}"); this.expansionSetCode = "DGM"; this.subtype.add("Human"); - this.subtype.add("Soldier"); + this.subtype.add("Warrior"); this.power = new MageInt(2); this.toughness = new MageInt(4); diff --git a/Mage.Sets/src/mage/sets/fifthedition/ShanodinDryads.java b/Mage.Sets/src/mage/sets/fifthedition/ShanodinDryads.java index 9d7ff24671b..7d077635084 100644 --- a/Mage.Sets/src/mage/sets/fifthedition/ShanodinDryads.java +++ b/Mage.Sets/src/mage/sets/fifthedition/ShanodinDryads.java @@ -43,6 +43,7 @@ public class ShanodinDryads extends CardImpl { public ShanodinDryads(UUID ownerId) { super(ownerId, 187, "Shanodin Dryads", Rarity.COMMON, new CardType[]{CardType.CREATURE}, "{G}"); this.expansionSetCode = "5ED"; + this.subtype.add("Nymph"); this.subtype.add("Dryad"); this.power = new MageInt(1); diff --git a/Mage.Sets/src/mage/sets/gatecrash/UrbanEvolution.java b/Mage.Sets/src/mage/sets/gatecrash/UrbanEvolution.java index 626a9642465..53128276399 100644 --- a/Mage.Sets/src/mage/sets/gatecrash/UrbanEvolution.java +++ b/Mage.Sets/src/mage/sets/gatecrash/UrbanEvolution.java @@ -46,16 +46,12 @@ public class UrbanEvolution extends CardImpl { public UrbanEvolution(UUID ownerId) { super(ownerId, 204, "Urban Evolution", Rarity.UNCOMMON, new CardType[]{CardType.SORCERY}, "{3}{U}{G}"); this.expansionSetCode = "GTC"; - this.subtype.add("Wizard"); - //Draw three cards. this.getSpellAbility().addEffect(new DrawCardSourceControllerEffect(3)); //You may play an additional land this turn. this.getSpellAbility().addEffect(new PlayAdditionalLandsControllerEffect(1, Duration.EndOfTurn)); - - } public UrbanEvolution(final UrbanEvolution card) { diff --git a/Mage.Sets/src/mage/sets/journeyintonyx/PensiveMinotaur.java b/Mage.Sets/src/mage/sets/journeyintonyx/PensiveMinotaur.java index 81c49ed6e25..6fcac8eda9a 100644 --- a/Mage.Sets/src/mage/sets/journeyintonyx/PensiveMinotaur.java +++ b/Mage.Sets/src/mage/sets/journeyintonyx/PensiveMinotaur.java @@ -43,6 +43,7 @@ public class PensiveMinotaur extends CardImpl { super(ownerId, 105, "Pensive Minotaur", Rarity.COMMON, new CardType[]{CardType.CREATURE}, "{2}{R}"); this.expansionSetCode = "JOU"; this.subtype.add("Minotaur"); + this.subtype.add("Warrior"); this.power = new MageInt(2); this.toughness = new MageInt(3); diff --git a/Mage.Sets/src/mage/sets/magic2010/Lifelink.java b/Mage.Sets/src/mage/sets/magic2010/Lifelink.java index b74e6c36ab6..b46a46d7013 100644 --- a/Mage.Sets/src/mage/sets/magic2010/Lifelink.java +++ b/Mage.Sets/src/mage/sets/magic2010/Lifelink.java @@ -40,10 +40,6 @@ public class Lifelink extends mage.sets.magic2012.Lifelink { super(ownerId); this.cardNumber = 18; this.expansionSetCode = "M10"; - this.subtype.add("Aura"); - - this.color.setWhite(true); - } public Lifelink (final Lifelink card) { diff --git a/Mage.Sets/src/mage/sets/planechase/SilverMyr.java b/Mage.Sets/src/mage/sets/planechase/SilverMyr.java index 97f6440f77c..84d30675695 100644 --- a/Mage.Sets/src/mage/sets/planechase/SilverMyr.java +++ b/Mage.Sets/src/mage/sets/planechase/SilverMyr.java @@ -40,7 +40,6 @@ public class SilverMyr extends mage.sets.mirrodin.SilverMyr { super(ownerId); this.cardNumber = 126; this.expansionSetCode = "HOP"; - this.subtype.add("Myr"); } public SilverMyr (final SilverMyr card) { diff --git a/Mage.Sets/src/mage/sets/returntoravnica/SphinxOfTheChimes.java b/Mage.Sets/src/mage/sets/returntoravnica/SphinxOfTheChimes.java index aba60a810f2..21055514d8d 100644 --- a/Mage.Sets/src/mage/sets/returntoravnica/SphinxOfTheChimes.java +++ b/Mage.Sets/src/mage/sets/returntoravnica/SphinxOfTheChimes.java @@ -61,7 +61,7 @@ public class SphinxOfTheChimes extends CardImpl { public SphinxOfTheChimes(UUID ownerId) { super(ownerId, 52, "Sphinx of the Chimes", Rarity.RARE, new CardType[]{CardType.CREATURE}, "{4}{U}{U}"); this.expansionSetCode = "RTR"; - this.subtype.add("Bird"); + this.subtype.add("Sphinx"); this.power = new MageInt(5); this.toughness = new MageInt(6); diff --git a/Mage.Sets/src/mage/sets/saviorsofkamigawa/MatsuTribeBirdstalker.java b/Mage.Sets/src/mage/sets/saviorsofkamigawa/MatsuTribeBirdstalker.java index 34fed8bc030..0ba6ed34b44 100644 --- a/Mage.Sets/src/mage/sets/saviorsofkamigawa/MatsuTribeBirdstalker.java +++ b/Mage.Sets/src/mage/sets/saviorsofkamigawa/MatsuTribeBirdstalker.java @@ -55,6 +55,7 @@ public class MatsuTribeBirdstalker extends CardImpl { this.expansionSetCode = "SOK"; this.subtype.add("Snake"); this.subtype.add("Warrior"); + this.subtype.add("Archer"); this.power = new MageInt(2); this.toughness = new MageInt(2); diff --git a/Mage.Sets/src/mage/sets/scarsofmirrodin/OxiddaDaredevil.java b/Mage.Sets/src/mage/sets/scarsofmirrodin/OxiddaDaredevil.java index 834ecd9a51d..65a8259d5bd 100644 --- a/Mage.Sets/src/mage/sets/scarsofmirrodin/OxiddaDaredevil.java +++ b/Mage.Sets/src/mage/sets/scarsofmirrodin/OxiddaDaredevil.java @@ -58,9 +58,12 @@ public class OxiddaDaredevil extends CardImpl { public OxiddaDaredevil (UUID ownerId) { super(ownerId, 100, "Oxidda Daredevil", Rarity.COMMON, new CardType[]{CardType.CREATURE}, "{1}{R}"); this.expansionSetCode = "SOM"; - this.color.setRed(true); + this.subtype.add("Goblin"); + this.subtype.add("Artificer"); + this.power = new MageInt(2); this.toughness = new MageInt(1); + this.addAbility(new SimpleActivatedAbility(Zone.BATTLEFIELD, new GainAbilitySourceEffect(HasteAbility.getInstance(), Duration.EndOfTurn), new SacrificeTargetCost(new TargetControlledPermanent(filter)))); diff --git a/Mage.Sets/src/mage/sets/scourge/GoblinWarchief.java b/Mage.Sets/src/mage/sets/scourge/GoblinWarchief.java index 0d62d55ccd7..298f2be5c4a 100644 --- a/Mage.Sets/src/mage/sets/scourge/GoblinWarchief.java +++ b/Mage.Sets/src/mage/sets/scourge/GoblinWarchief.java @@ -60,6 +60,7 @@ public class GoblinWarchief extends CardImpl { super(ownerId, 97, "Goblin Warchief", Rarity.UNCOMMON, new CardType[]{CardType.CREATURE}, "{1}{R}{R}"); this.expansionSetCode = "SCG"; this.subtype.add("Goblin"); + this.subtype.add("Warrior"); this.power = new MageInt(2); this.toughness = new MageInt(2); diff --git a/Mage.Sets/src/mage/sets/tenthedition/HighwayRobber.java b/Mage.Sets/src/mage/sets/tenthedition/HighwayRobber.java index 6937d8e1ef0..6b55da06104 100644 --- a/Mage.Sets/src/mage/sets/tenthedition/HighwayRobber.java +++ b/Mage.Sets/src/mage/sets/tenthedition/HighwayRobber.java @@ -48,7 +48,6 @@ public class HighwayRobber extends CardImpl { super(ownerId, 150, "Highway Robber", Rarity.COMMON, new CardType[]{CardType.CREATURE}, "{2}{B}{B}"); this.expansionSetCode = "10E"; this.subtype.add("Human"); - this.subtype.add("Rogue"); this.subtype.add("Mercenary"); this.power = new MageInt(2); diff --git a/Mage.Sets/src/mage/sets/urzassaga/GorillaWarrior.java b/Mage.Sets/src/mage/sets/urzassaga/GorillaWarrior.java index 5c20c56b30c..3149b5f07a4 100644 --- a/Mage.Sets/src/mage/sets/urzassaga/GorillaWarrior.java +++ b/Mage.Sets/src/mage/sets/urzassaga/GorillaWarrior.java @@ -44,6 +44,7 @@ public class GorillaWarrior extends CardImpl { super(ownerId, 256, "Gorilla Warrior", Rarity.COMMON, new CardType[]{CardType.CREATURE}, "{2}{G}"); this.expansionSetCode = "USG"; this.subtype.add("Ape"); + this.subtype.add("Warrior"); this.power = new MageInt(3); this.toughness = new MageInt(2); diff --git a/Mage.Sets/src/mage/sets/zendikar/ArrowVolleyTrap.java b/Mage.Sets/src/mage/sets/zendikar/ArrowVolleyTrap.java index cf786931cf8..a83b34aa210 100644 --- a/Mage.Sets/src/mage/sets/zendikar/ArrowVolleyTrap.java +++ b/Mage.Sets/src/mage/sets/zendikar/ArrowVolleyTrap.java @@ -47,6 +47,7 @@ public class ArrowVolleyTrap extends CardImpl { public ArrowVolleyTrap(UUID ownerId) { super(ownerId, 2, "Arrow Volley Trap", Rarity.UNCOMMON, new CardType[]{CardType.INSTANT}, "{3}{W}{W}"); this.expansionSetCode = "ZEN"; + this.subtype.add("Trap"); // If four or more creatures are attacking, you may pay {1}{W} rather than pay Arrow Volley Trap's mana cost. this.getSpellAbility().addAlternativeCost(new ArrowVolleyTrapAlternativeCost()); From 7e9205e90966a502d55492e122c466d963434c78 Mon Sep 17 00:00:00 2001 From: Neil Gentleman Date: Mon, 19 Oct 2015 03:17:17 -0700 Subject: [PATCH 179/268] Fix incorrect CardTypes --- .../src/mage/sets/championsofkamigawa/UnearthlyBlizzard.java | 2 +- Mage.Sets/src/mage/sets/lorwyn/FodderLaunch.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Mage.Sets/src/mage/sets/championsofkamigawa/UnearthlyBlizzard.java b/Mage.Sets/src/mage/sets/championsofkamigawa/UnearthlyBlizzard.java index 242df18ed16..29f76f4196d 100644 --- a/Mage.Sets/src/mage/sets/championsofkamigawa/UnearthlyBlizzard.java +++ b/Mage.Sets/src/mage/sets/championsofkamigawa/UnearthlyBlizzard.java @@ -43,7 +43,7 @@ import mage.target.common.TargetCreaturePermanent; public class UnearthlyBlizzard extends CardImpl { public UnearthlyBlizzard(UUID ownerId) { - super(ownerId, 196, "Unearthly Blizzard", Rarity.COMMON, new CardType[]{CardType.INSTANT}, "{2}{R}"); + super(ownerId, 196, "Unearthly Blizzard", Rarity.COMMON, new CardType[]{CardType.SORCERY}, "{2}{R}"); this.expansionSetCode = "CHK"; this.subtype.add("Arcane"); diff --git a/Mage.Sets/src/mage/sets/lorwyn/FodderLaunch.java b/Mage.Sets/src/mage/sets/lorwyn/FodderLaunch.java index 5fbf233ad1c..8ebbf2b0b79 100644 --- a/Mage.Sets/src/mage/sets/lorwyn/FodderLaunch.java +++ b/Mage.Sets/src/mage/sets/lorwyn/FodderLaunch.java @@ -46,7 +46,7 @@ import mage.target.common.TargetCreaturePermanent; public class FodderLaunch extends CardImpl { public FodderLaunch(UUID ownerId) { - super(ownerId, 114, "Fodder Launch", Rarity.UNCOMMON, new CardType[]{CardType.SORCERY}, "{3}{B}"); + super(ownerId, 114, "Fodder Launch", Rarity.UNCOMMON, new CardType[]{CardType.TRIBAL, CardType.SORCERY}, "{3}{B}"); this.expansionSetCode = "LRW"; this.subtype.add("Goblin"); From 8d71ddc938ac51edf3bdf60a6af88b25dafc5c32 Mon Sep 17 00:00:00 2001 From: Neil Gentleman Date: Mon, 19 Oct 2015 03:29:44 -0700 Subject: [PATCH 180/268] Fix color for Archdemon of Greed --- Mage.Sets/src/mage/sets/darkascension/ArchdemonOfGreed.java | 1 + 1 file changed, 1 insertion(+) diff --git a/Mage.Sets/src/mage/sets/darkascension/ArchdemonOfGreed.java b/Mage.Sets/src/mage/sets/darkascension/ArchdemonOfGreed.java index 42fc893a116..3fc7222beac 100644 --- a/Mage.Sets/src/mage/sets/darkascension/ArchdemonOfGreed.java +++ b/Mage.Sets/src/mage/sets/darkascension/ArchdemonOfGreed.java @@ -65,6 +65,7 @@ public class ArchdemonOfGreed extends CardImpl { super(ownerId, 71, "Archdemon of Greed", Rarity.RARE, new CardType[]{CardType.CREATURE}, ""); this.expansionSetCode = "DKA"; this.subtype.add("Demon"); + this.color.setBlack(true); this.nightCard = true; this.canTransform = true; From f72ec06ecdeda383ba8fddabb823aa1cb7204109 Mon Sep 17 00:00:00 2001 From: LevelX2 Date: Mon, 19 Oct 2015 17:45:26 +0200 Subject: [PATCH 181/268] * Serpentine Spike - Fixed that the three targets had not to be different. --- .../battleforzendikar/SerpentineSpike.java | 21 ++++- Mage.Sets/src/mage/sets/exodus/KorChant.java | 42 +++------- .../sets/jacevsvraska/DroolingGroodion.java | 39 +++------ .../mage/sets/tempestremastered/Deadshot.java | 47 ++++------- .../mageobject/AnotherTargetPredicate.java | 72 +++++++++++++++++ Mage/src/mage/target/Target.java | 4 + Mage/src/mage/target/TargetImpl.java | 19 +++++ Mage/src/mage/target/TargetPermanent.java | 80 +++++++++---------- 8 files changed, 195 insertions(+), 129 deletions(-) create mode 100644 Mage/src/mage/filter/predicate/mageobject/AnotherTargetPredicate.java diff --git a/Mage.Sets/src/mage/sets/battleforzendikar/SerpentineSpike.java b/Mage.Sets/src/mage/sets/battleforzendikar/SerpentineSpike.java index b6de1e9f1a6..292dc45afd9 100644 --- a/Mage.Sets/src/mage/sets/battleforzendikar/SerpentineSpike.java +++ b/Mage.Sets/src/mage/sets/battleforzendikar/SerpentineSpike.java @@ -39,6 +39,7 @@ import mage.constants.Duration; import mage.constants.Outcome; import mage.constants.Rarity; import mage.filter.common.FilterCreaturePermanent; +import mage.filter.predicate.mageobject.AnotherTargetPredicate; import mage.game.Game; import mage.game.permanent.Permanent; import mage.target.common.TargetCreaturePermanent; @@ -60,9 +61,23 @@ public class SerpentineSpike extends CardImpl { this.addAbility(ability); // Serpentine Spike deals 2 damage to target creature, 3 damage to another target creature, and 4 damage to a third target creature. If a creature dealt damage this way would die this turn, exile it instead. this.getSpellAbility().addEffect(new SerpentineSpikeEffect()); - this.getSpellAbility().addTarget(new TargetCreaturePermanent(new FilterCreaturePermanent("creature (2 damage)"))); - this.getSpellAbility().addTarget(new TargetCreaturePermanent(new FilterCreaturePermanent("creature (3 damage)"))); - this.getSpellAbility().addTarget(new TargetCreaturePermanent(new FilterCreaturePermanent("creature (4 damage)"))); + + TargetCreaturePermanent target = new TargetCreaturePermanent(new FilterCreaturePermanent("creature (2 damage)")); + target.setTargetTag(1); + this.getSpellAbility().addTarget(target); + + FilterCreaturePermanent filter = new FilterCreaturePermanent("another target creature (3 damage)"); + filter.add(new AnotherTargetPredicate(2)); + target = new TargetCreaturePermanent(filter); + target.setTargetTag(2); + this.getSpellAbility().addTarget(target); + + filter = new FilterCreaturePermanent("another target creature (4 damage)"); + filter.add(new AnotherTargetPredicate(3)); + target = new TargetCreaturePermanent(filter); + target.setTargetTag(3); + this.getSpellAbility().addTarget(target); + Effect effect = new DealtDamageToCreatureBySourceDies(this, Duration.EndOfTurn); effect.setText("If a creature dealt damage this way would die this turn, exile it instead"); this.getSpellAbility().addEffect(effect); diff --git a/Mage.Sets/src/mage/sets/exodus/KorChant.java b/Mage.Sets/src/mage/sets/exodus/KorChant.java index 0269d443edd..3aa8d9effb6 100644 --- a/Mage.Sets/src/mage/sets/exodus/KorChant.java +++ b/Mage.Sets/src/mage/sets/exodus/KorChant.java @@ -35,6 +35,8 @@ import mage.constants.CardType; import mage.constants.Duration; import mage.constants.Outcome; import mage.constants.Rarity; +import mage.filter.common.FilterCreaturePermanent; +import mage.filter.predicate.mageobject.AnotherTargetPredicate; import mage.game.Game; import mage.game.events.GameEvent; import mage.target.TargetSource; @@ -53,8 +55,15 @@ public class KorChant extends CardImpl { // All damage that would be dealt this turn to target creature you control by a source of your choice is dealt to another target creature instead. this.getSpellAbility().addEffect(new KorChantEffect()); - this.getSpellAbility().addTarget(new TargetControlledCreaturePermanent()); - this.getSpellAbility().addTarget(new KorChantSecondTarget()); + TargetControlledCreaturePermanent target = new TargetControlledCreaturePermanent(); + target.setTargetTag(1); + this.getSpellAbility().addTarget(target); + + FilterCreaturePermanent filter = new FilterCreaturePermanent("another target creature"); + filter.add(new AnotherTargetPredicate(2)); + TargetCreaturePermanent target2 = new TargetCreaturePermanent(filter); + target2.setTargetTag(2); + this.getSpellAbility().addTarget(target2); } public KorChant(final KorChant card) { @@ -67,33 +76,8 @@ public class KorChant extends CardImpl { } } -class KorChantSecondTarget extends TargetCreaturePermanent { - - KorChantSecondTarget() { - super(); - this.targetName = "another creature"; - } - - KorChantSecondTarget(final KorChantSecondTarget target) { - super(target); - } - - @Override - public boolean canTarget(UUID controllerId, UUID id, Ability source, Game game) { - if (source.getTargets().get(0).getTargets().contains(id)) { - return false; - } - return super.canTarget(controllerId, id, source, game); - } - - @Override - public KorChantSecondTarget copy() { - return new KorChantSecondTarget(this); - } -} - class KorChantEffect extends RedirectionEffect { - + protected TargetSource target = new TargetSource(); KorChantEffect() { @@ -121,7 +105,7 @@ class KorChantEffect extends RedirectionEffect { public boolean checksEventType(GameEvent event, Game game) { return event.getType() == GameEvent.EventType.DAMAGE_CREATURE; } - + @Override public boolean applies(GameEvent event, Ability source, Game game) { if (event.getTargetId().equals(this.getTargetPointer().getFirst(game, source)) diff --git a/Mage.Sets/src/mage/sets/jacevsvraska/DroolingGroodion.java b/Mage.Sets/src/mage/sets/jacevsvraska/DroolingGroodion.java index b27d9824f79..dda545b51ea 100644 --- a/Mage.Sets/src/mage/sets/jacevsvraska/DroolingGroodion.java +++ b/Mage.Sets/src/mage/sets/jacevsvraska/DroolingGroodion.java @@ -44,6 +44,7 @@ import mage.constants.SubLayer; import mage.constants.Zone; import mage.filter.common.FilterControlledCreaturePermanent; import mage.filter.common.FilterCreaturePermanent; +import mage.filter.predicate.mageobject.AnotherTargetPredicate; import mage.game.Game; import mage.game.permanent.Permanent; import mage.target.common.TargetControlledCreaturePermanent; @@ -66,8 +67,17 @@ public class DroolingGroodion extends CardImpl { // {2}{B}{G}, Sacrifice a creature: Target creature gets +2/+2 until end of turn. Another target creature gets -2/-2 until end of turn. Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new DroolingGroodionEffect(), new ManaCostsImpl("{2}{B}{G}")); ability.addCost(new SacrificeTargetCost(new TargetControlledCreaturePermanent(1, 1, new FilterControlledCreaturePermanent(), true))); - ability.addTarget(new TargetCreaturePermanent(new FilterCreaturePermanent("creature (first target)"))); - ability.addTarget(new TargetOtherCreaturePermanent(new FilterCreaturePermanent("creature (second target)"))); + + TargetCreaturePermanent target = new TargetCreaturePermanent(new FilterCreaturePermanent("creature (first target)")); + target.setTargetTag(1); + ability.addTarget(target); + + FilterCreaturePermanent filter = new FilterCreaturePermanent("another target creature (second target"); + filter.add(new AnotherTargetPredicate(2)); + target = new TargetCreaturePermanent(filter); + target.setTargetTag(2); + ability.addTarget(target); + this.addAbility(ability); } @@ -112,28 +122,3 @@ class DroolingGroodionEffect extends ContinuousEffectImpl { return true; } } - -class TargetOtherCreaturePermanent extends TargetCreaturePermanent { - - public TargetOtherCreaturePermanent(FilterCreaturePermanent filter) { - super(filter); - } - - public TargetOtherCreaturePermanent(final TargetOtherCreaturePermanent target) { - super(target); - } - - @Override - public boolean canTarget(UUID controllerId, UUID id, Ability source, Game game) { - if (source.getTargets().get(0).getTargets().contains(id)) { - return false; - } - return super.canTarget(controllerId, id, source, game); - } - - @Override - public TargetOtherCreaturePermanent copy() { - return new TargetOtherCreaturePermanent(this); - } - -} diff --git a/Mage.Sets/src/mage/sets/tempestremastered/Deadshot.java b/Mage.Sets/src/mage/sets/tempestremastered/Deadshot.java index e2fd17d8826..1aa0222736a 100644 --- a/Mage.Sets/src/mage/sets/tempestremastered/Deadshot.java +++ b/Mage.Sets/src/mage/sets/tempestremastered/Deadshot.java @@ -36,29 +36,39 @@ import mage.constants.CardType; import mage.constants.Outcome; import mage.constants.Rarity; import mage.filter.common.FilterCreaturePermanent; +import mage.filter.predicate.mageobject.AnotherTargetPredicate; import mage.game.Game; import mage.game.permanent.Permanent; import mage.target.common.TargetCreaturePermanent; +import mage.target.targetpointer.SecondTargetPointer; /** * * @author fireshoes */ public class Deadshot extends CardImpl { - + private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("another target creature"); + static { + filter.add(new AnotherTargetPredicate(2)); + } + public Deadshot(UUID ownerId) { super(ownerId, 129, "Deadshot", Rarity.UNCOMMON, new CardType[]{CardType.SORCERY}, "{3}{R}"); this.expansionSetCode = "TPR"; // Tap target creature. this.getSpellAbility().addEffect(new TapTargetEffect()); - this.getSpellAbility().addTarget(new TargetCreaturePermanent()); - + TargetCreaturePermanent target = new TargetCreaturePermanent(); + target.setTargetTag(1); + this.getSpellAbility().addTarget(target); + // It deals damage equal to its power to another target creature. this.getSpellAbility().addEffect(new DeadshotDamageEffect()); - this.getSpellAbility().addTarget(new DeadshotTargetCreaturePermanent(filter)); + target = new TargetCreaturePermanent(filter); + target.setTargetTag(2); + this.getSpellAbility().addTarget(target); } public Deadshot(final Deadshot card) { @@ -80,6 +90,7 @@ class DeadshotDamageEffect extends OneShotEffect { public DeadshotDamageEffect(final DeadshotDamageEffect effect) { super(effect); + this.setTargetPointer(new SecondTargetPointer()); } @Override @@ -89,10 +100,10 @@ class DeadshotDamageEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { - Permanent ownCreature = game.getPermanent(source.getFirstTarget()); + Permanent ownCreature = game.getPermanentOrLKIBattlefield(source.getFirstTarget()); if (ownCreature != null) { int damage = ownCreature.getPower().getValue(); - Permanent targetCreature = game.getPermanent(source.getTargets().get(1).getFirstTarget()); + Permanent targetCreature = game.getPermanent(getTargetPointer().getFirst(game, source)); if (targetCreature != null) { targetCreature.damage(damage, ownCreature.getId(), game, false, true); return true; @@ -101,27 +112,3 @@ class DeadshotDamageEffect extends OneShotEffect { return false; } } - -class DeadshotTargetCreaturePermanent extends TargetCreaturePermanent { - - public DeadshotTargetCreaturePermanent(FilterCreaturePermanent filter) { - super(filter); - } - - @Override - public boolean canTarget(UUID id, Ability source, Game game) { - if (source.getTargets().getFirstTarget().equals(id)) { - return false; - } - return super.canTarget(id, source, game); - } - - @Override - public boolean canTarget(UUID controllerId, UUID id, Ability source, Game game) { - if (source.getTargets().getFirstTarget().equals(id)) { - return false; - } - return super.canTarget(controllerId, id, source, game); - } - -} \ No newline at end of file diff --git a/Mage/src/mage/filter/predicate/mageobject/AnotherTargetPredicate.java b/Mage/src/mage/filter/predicate/mageobject/AnotherTargetPredicate.java new file mode 100644 index 00000000000..cd906f4a2ac --- /dev/null +++ b/Mage/src/mage/filter/predicate/mageobject/AnotherTargetPredicate.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.filter.predicate.mageobject; + +import mage.MageObject; +import mage.filter.predicate.ObjectSourcePlayer; +import mage.filter.predicate.ObjectSourcePlayerPredicate; +import mage.game.Game; +import mage.game.stack.StackObject; +import mage.target.Target; + +/** + * All targets that are already selected in other target definitions of the + * source are omitted To use this predicate you have to set the targetTag of all + * targets involved in the card constructor to a unique value (e.g. using 1,2,3 + * for three targets) + * + * @author LevelX2 + */ +public class AnotherTargetPredicate implements ObjectSourcePlayerPredicate> { + + private final int targetTag; + + public AnotherTargetPredicate(int targetTag) { + this.targetTag = targetTag; + } + + @Override + public boolean apply(ObjectSourcePlayer input, Game game) { + StackObject source = game.getStack().getStackObject(input.getSourceId()); + if (source != null) { + for (Target target : source.getStackAbility().getTargets()) { + if (target.getTargetTag() > 0 // target is included in the target group to check + && target.getTargetTag() != targetTag // it's not the target of this predicate + && target.getTargets().contains(input.getObject().getId())) { // if the uuid already is used for another target in the group it's no allowed here + return false; + } + } + } + return true; + } + + @Override + public String toString() { + return "Another target"; + } +} diff --git a/Mage/src/mage/target/Target.java b/Mage/src/mage/target/Target.java index b6bd637b1e4..80b977f4eed 100644 --- a/Mage/src/mage/target/Target.java +++ b/Mage/src/mage/target/Target.java @@ -151,4 +151,8 @@ public interface Target extends Serializable { UUID getAbilityController(); Player getTargetController(Game game, UUID playerId); + + int getTargetTag(); + + void setTargetTag(int tag); } diff --git a/Mage/src/mage/target/TargetImpl.java b/Mage/src/mage/target/TargetImpl.java index ce0a8790f48..df09789ca13 100644 --- a/Mage/src/mage/target/TargetImpl.java +++ b/Mage/src/mage/target/TargetImpl.java @@ -70,6 +70,8 @@ public abstract class TargetImpl implements Target { protected UUID targetController = null; // if null the ability controller is the targetController protected UUID abilityController = null; // only used if target controller != ability controller + protected int targetTag; // can be set if other target check is needed (AnotherTargetPredicate) + @Override public abstract TargetImpl copy(); @@ -95,6 +97,7 @@ public abstract class TargetImpl implements Target { this.notTarget = target.notTarget; this.targetController = target.targetController; this.abilityController = target.abilityController; + this.targetTag = target.targetTag; } @Override @@ -545,4 +548,20 @@ public abstract class TargetImpl implements Target { return requiredExplicitlySet; } + @Override + public int getTargetTag() { + return targetTag; + } + + /** + * Is used to be able to check, that another target is slected within the + * group of targets of the ability with a target tag > 0. + * + * @param targetTag + */ + @Override + public void setTargetTag(int targetTag) { + this.targetTag = targetTag; + } + } diff --git a/Mage/src/mage/target/TargetPermanent.java b/Mage/src/mage/target/TargetPermanent.java index 222e08d0586..068bac9f0cb 100644 --- a/Mage/src/mage/target/TargetPermanent.java +++ b/Mage/src/mage/target/TargetPermanent.java @@ -1,44 +1,42 @@ /* -* 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.target; import java.util.HashSet; import java.util.Set; import java.util.UUID; -import mage.constants.Zone; import mage.MageObject; import mage.abilities.Ability; +import mage.constants.Zone; import mage.filter.FilterPermanent; import mage.game.Game; import mage.game.permanent.Permanent; - /** * * @author BetaSteward_at_googlemail.com @@ -50,7 +48,7 @@ public class TargetPermanent extends TargetObject { public TargetPermanent() { this(1, 1, new FilterPermanent(), false); } - + public TargetPermanent(FilterPermanent filter) { this(1, 1, filter, false); } @@ -88,8 +86,8 @@ public class TargetPermanent extends TargetObject { // first for protection from spells or abilities (e.g. protection from colored spells, r1753) // second for protection from sources (e.g. protection from artifacts + equip ability) if (!isNotTarget()) { - if (!permanent.canBeTargetedBy(game.getObject(source.getId()), controllerId, game) || - !permanent.canBeTargetedBy(game.getObject(source.getSourceId()), controllerId, game)) { + if (!permanent.canBeTargetedBy(game.getObject(source.getId()), controllerId, game) + || !permanent.canBeTargetedBy(game.getObject(source.getSourceId()), controllerId, game)) { return false; } } @@ -117,7 +115,8 @@ public class TargetPermanent extends TargetObject { /** * Checks if there are enough {@link Permanent} that can be chosen. * - * Takes into account notTarget parameter, in case it's true doesn't check for protection, shroud etc. + * Takes into account notTarget parameter, in case it's true doesn't check + * for protection, shroud etc. * * @param sourceId the target event source * @param sourceControllerId controller of the target event source @@ -132,7 +131,7 @@ public class TargetPermanent extends TargetObject { } int count = 0; MageObject targetSource = game.getObject(sourceId); - for (Permanent permanent: game.getBattlefield().getActivePermanents(filter, sourceControllerId, sourceId, game)) { + for (Permanent permanent : game.getBattlefield().getActivePermanents(filter, sourceControllerId, sourceId, game)) { if (!targets.containsKey(permanent.getId())) { if (notTarget || permanent.canBeTargetedBy(targetSource, sourceControllerId, game)) { count++; @@ -146,9 +145,10 @@ public class TargetPermanent extends TargetObject { } /** - * Checks if there are enough {@link Permanent} that can be selected. Should not be used - * for Ability targets since this does not check for protection, shroud etc. - * + * Checks if there are enough {@link Permanent} that can be selected. Should + * not be used for Ability targets since this does not check for protection, + * shroud etc. + * * @param sourceControllerId - controller of the select event * @param game * @return - true if enough valid {@link Permanent} exist @@ -162,7 +162,7 @@ public class TargetPermanent extends TargetObject { return true; } int count = 0; - for (Permanent permanent: game.getBattlefield().getActivePermanents(filter, sourceControllerId, game)) { + for (Permanent permanent : game.getBattlefield().getActivePermanents(filter, sourceControllerId, game)) { if (!targets.containsKey(permanent.getId())) { count++; if (count >= remainingTargets) { @@ -177,7 +177,7 @@ public class TargetPermanent extends TargetObject { public Set possibleTargets(UUID sourceId, UUID sourceControllerId, Game game) { Set possibleTargets = new HashSet<>(); MageObject targetSource = game.getObject(sourceId); - for (Permanent permanent: game.getBattlefield().getActivePermanents(filter, sourceControllerId, sourceId, game)) { + for (Permanent permanent : game.getBattlefield().getActivePermanents(filter, sourceControllerId, sourceId, game)) { if (!targets.containsKey(permanent.getId())) { if (notTarget || permanent.canBeTargetedBy(targetSource, sourceControllerId, game)) { possibleTargets.add(permanent.getId()); @@ -190,7 +190,7 @@ public class TargetPermanent extends TargetObject { @Override public Set possibleTargets(UUID sourceControllerId, Game game) { Set possibleTargets = new HashSet<>(); - for (Permanent permanent: game.getBattlefield().getActivePermanents(filter, sourceControllerId, game)) { + for (Permanent permanent : game.getBattlefield().getActivePermanents(filter, sourceControllerId, game)) { if (!targets.containsKey(permanent.getId())) { possibleTargets.add(permanent.getId()); } From 7c35a69360c4a3ff03cde819b80c07cffd37f5b5 Mon Sep 17 00:00:00 2001 From: LevelX2 Date: Mon, 19 Oct 2015 22:36:28 +0200 Subject: [PATCH 182/268] * Fixed a bug that if copied spells should be shuffled into the library the original spell was removed from the stack. --- .../sets/mirrodinbesieged/RedSunsZenith.java | 14 ++-- .../cards/triggers/MelekIzzetParagonTest.java | 77 +++++++++++++++++++ .../effects/common/ShuffleSpellEffect.java | 64 ++++++++------- Mage/src/mage/game/stack/Spell.java | 3 +- Mage/src/mage/players/PlayerImpl.java | 6 +- 5 files changed, 123 insertions(+), 41 deletions(-) create mode 100644 Mage.Tests/src/test/java/org/mage/test/cards/triggers/MelekIzzetParagonTest.java diff --git a/Mage.Sets/src/mage/sets/mirrodinbesieged/RedSunsZenith.java b/Mage.Sets/src/mage/sets/mirrodinbesieged/RedSunsZenith.java index 48dec655e1c..54631fd0c1e 100644 --- a/Mage.Sets/src/mage/sets/mirrodinbesieged/RedSunsZenith.java +++ b/Mage.Sets/src/mage/sets/mirrodinbesieged/RedSunsZenith.java @@ -1,16 +1,16 @@ /* * Copyright 2011 BetaSteward_at_googlemail.com. All rights reserved. - * + * * Redistribution and use in source and binary forms, with or without modification, are * permitted provided that the following conditions are met: - * + * * 1. Redistributions of source code must retain the above copyright notice, this list of * conditions and the following disclaimer. - * + * * 2. Redistributions in binary form must reproduce the above copyright notice, this list * of conditions and the following disclaimer in the documentation and/or other materials * provided with the distribution. - * + * * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR @@ -20,7 +20,7 @@ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * + * * The views and conclusions contained in the software and documentation are those of the * authors and should not be interpreted as representing official policies, either expressed * or implied, of BetaSteward_at_googlemail.com. @@ -49,7 +49,9 @@ public class RedSunsZenith extends CardImpl { super(ownerId, 74, "Red Sun's Zenith", Rarity.RARE, new CardType[]{CardType.SORCERY}, "{X}{R}"); this.expansionSetCode = "MBS"; - + // Red Sun's Zenith deals X damage to target creature or player. + // If a creature dealt damage this way would die this turn, exile it instead. + // Shuffle Red Sun's Zenith into its owner's library. this.getSpellAbility().addTarget(new TargetCreatureOrPlayer()); this.getSpellAbility().addEffect(new DamageTargetEffect(new ManacostVariableValue())); this.getSpellAbility().addEffect(new DealtDamageToCreatureBySourceDies(this, Duration.EndOfTurn)); diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/triggers/MelekIzzetParagonTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/triggers/MelekIzzetParagonTest.java new file mode 100644 index 00000000000..8560a101906 --- /dev/null +++ b/Mage.Tests/src/test/java/org/mage/test/cards/triggers/MelekIzzetParagonTest.java @@ -0,0 +1,77 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package org.mage.test.cards.triggers; + +import mage.constants.PhaseStep; +import mage.constants.Zone; +import org.junit.Test; +import org.mage.test.serverside.base.CardTestPlayerBase; + +/** + * + * @author LevelX2 + */ +public class MelekIzzetParagonTest extends CardTestPlayerBase { + + /** + * Wenn Melek, Izzet Paragon liegt und man einen Red/Blue Sun's Zenith von + * der Bib spielt, wird er nicht kopiert, auch wenn der Effekt auf dem Stack + * sichtbar ist. + * + * Meine Theorie ist, dass die Kopie beim in die Bib mischen den Originalen + * nimmt und er daher nicht mehr dem Stack ist um selbst verrechnet zu + * werden + * + */ + @Test + public void testCopyZenith() { + addCard(Zone.BATTLEFIELD, playerA, "Mountain", 5); + // Play with the top card of your library revealed. + // You may cast the top card of your library if it's an instant or sorcery card. + // Whenever you cast an instant or sorcery spell from your library, copy it. You may choose new targets for the copy. + addCard(Zone.BATTLEFIELD, playerA, "Melek, Izzet Paragon"); + + // Red Sun's Zenith deals X damage to target creature or player. + // If a creature dealt damage this way would die this turn, exile it instead. + // Shuffle Red Sun's Zenith into its owner's library. + addCard(Zone.LIBRARY, playerA, "Red Sun's Zenith"); // {X}{R} + skipInitShuffling(); + + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Red Sun's Zenith", playerB); + setChoice(playerA, "X=4"); + + setStopAt(1, PhaseStep.BEGIN_COMBAT); + execute(); + + assertGraveyardCount(playerA, "Red Sun's Zenith", 0); + + assertLife(playerA, 20); + assertLife(playerB, 12); + + } +} diff --git a/Mage/src/mage/abilities/effects/common/ShuffleSpellEffect.java b/Mage/src/mage/abilities/effects/common/ShuffleSpellEffect.java index 47b4322115a..fa8e72af499 100644 --- a/Mage/src/mage/abilities/effects/common/ShuffleSpellEffect.java +++ b/Mage/src/mage/abilities/effects/common/ShuffleSpellEffect.java @@ -1,37 +1,35 @@ /* -* 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 mage.abilities.Ability; import mage.abilities.MageSingleton; import mage.abilities.effects.OneShotEffect; -import mage.cards.Card; import mage.constants.Outcome; import mage.constants.Zone; import mage.game.Game; @@ -59,15 +57,15 @@ public class ShuffleSpellEffect extends OneShotEffect implements MageSingleton { public boolean apply(Game game, Ability source) { Player controller = game.getPlayer(source.getControllerId()); if (controller != null) { - Spell spell = game.getStack().getSpell(source.getSourceId()); + // We have to use the spell id because in case of copied spells, the sourceId can be multiple times on the stack + Spell spell = game.getStack().getSpell(source.getId()); if (spell != null) { - Card spellCard = spell.getCard(); - if (spellCard != null) { - Player owner = game.getPlayer(spellCard.getOwnerId()); + if (controller.moveCards(spell, Zone.LIBRARY, source, game) && !spell.isCopy()) { + Player owner = game.getPlayer(spell.getCard().getOwnerId()); if (owner != null) { - controller.moveCardToLibraryWithInfo(spellCard, source.getSourceId(), game, Zone.STACK, true, true); owner.shuffleLibrary(game); } + } } return true; diff --git a/Mage/src/mage/game/stack/Spell.java b/Mage/src/mage/game/stack/Spell.java index 83b99d90d46..0b0f22fb45a 100644 --- a/Mage/src/mage/game/stack/Spell.java +++ b/Mage/src/mage/game/stack/Spell.java @@ -622,7 +622,8 @@ public class Spell extends StackObjImpl implements Card { } public Spell copySpell() { - return new Spell(this.card.copy(), this.ability.copySpell(), this.controllerId, this.fromZone); + // replaced card.copy by copy (card content should no longer be changed) + return new Spell(this.card, this.ability.copySpell(), this.controllerId, this.fromZone); } @Override diff --git a/Mage/src/mage/players/PlayerImpl.java b/Mage/src/mage/players/PlayerImpl.java index 80129822440..8949f270970 100644 --- a/Mage/src/mage/players/PlayerImpl.java +++ b/Mage/src/mage/players/PlayerImpl.java @@ -3097,7 +3097,11 @@ public abstract class PlayerImpl implements Player, Serializable { break; case LIBRARY: for (Card card : cards) { - fromZone = game.getState().getZone(card.getId()); + if (card instanceof Spell) { + fromZone = game.getState().getZone(((Spell) card).getSourceId()); + } else { + fromZone = game.getState().getZone(card.getId()); + } boolean hideCard = fromZone.equals(Zone.HAND) || fromZone.equals(Zone.LIBRARY); if (moveCardToLibraryWithInfo(card, source == null ? null : source.getSourceId(), game, fromZone, true, !hideCard)) { successfulMovedCards.add(card); From 606bf4d6e0b296d21cd5ecd6bd5de828706fdc17 Mon Sep 17 00:00:00 2001 From: LevelX2 Date: Tue, 20 Oct 2015 00:44:32 +0200 Subject: [PATCH 183/268] * Fixed that it was not possible to play spells without costs with alternative costs (e.g. Ancestral Visions with Omniscience). Fixed that playing spells with alternate costs did also remove additional costs (e.g. card with entwine cast with Omniscience). --- .../src/mage/sets/onslaught/FutureSight.java | 4 +- .../keywords/SpliceOnArcaneTest.java | 2 +- .../test/cards/single/OmniscienceTest.java | 100 ++++++++++++++++++ Mage/src/mage/abilities/AbilityImpl.java | 5 +- Mage/src/mage/abilities/SpellAbility.java | 4 - .../costs/AlternativeCostSourceAbility.java | 39 ++++--- .../abilities/keyword/EntwineAbility.java | 2 +- Mage/src/mage/players/PlayerImpl.java | 26 +++-- 8 files changed, 150 insertions(+), 32 deletions(-) diff --git a/Mage.Sets/src/mage/sets/onslaught/FutureSight.java b/Mage.Sets/src/mage/sets/onslaught/FutureSight.java index 0c8dff1f1c6..929246b111d 100644 --- a/Mage.Sets/src/mage/sets/onslaught/FutureSight.java +++ b/Mage.Sets/src/mage/sets/onslaught/FutureSight.java @@ -35,7 +35,6 @@ import mage.cards.CardImpl; import mage.constants.CardType; import mage.constants.Rarity; import mage.constants.Zone; -import mage.filter.FilterCard; /** * @@ -47,11 +46,10 @@ public class FutureSight extends CardImpl { super(ownerId, 84, "Future Sight", Rarity.RARE, new CardType[]{CardType.ENCHANTMENT}, "{2}{U}{U}{U}"); this.expansionSetCode = "ONS"; - // Play with the top card of your library revealed. this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new PlayWithTheTopCardRevealedEffect())); // You may play the top card of your library. - this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new PlayTheTopCardEffect(new FilterCard()))); + this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new PlayTheTopCardEffect())); } public FutureSight(final FutureSight card) { diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/abilities/keywords/SpliceOnArcaneTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/abilities/keywords/SpliceOnArcaneTest.java index 0cd925879a7..f67350c1d85 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/abilities/keywords/SpliceOnArcaneTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/abilities/keywords/SpliceOnArcaneTest.java @@ -115,7 +115,7 @@ public class SpliceOnArcaneTest extends CardTestPlayerBase { addCard(Zone.BATTLEFIELD, playerA, "Mountain", 4); // You may exile a green card with converted mana cost X from your hand rather than pay Nourishing Shoal's mana cost. // You gain X life. - addCard(Zone.HAND, playerA, "Nourishing Shoal", 1); + addCard(Zone.HAND, playerA, "Nourishing Shoal", 1); // {X}{G}{G} addCard(Zone.HAND, playerA, "Giant Growth", 1); // 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. // Splice onto Arcane {2}{R}{R} (As you cast an Arcane spell, you may reveal this card from your hand and pay its splice cost. If you do, add this card's effects to that spell.) diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/single/OmniscienceTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/single/OmniscienceTest.java index ad4f7febe71..fe2d8ea9fb3 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/single/OmniscienceTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/single/OmniscienceTest.java @@ -192,4 +192,104 @@ public class OmniscienceTest extends CardTestPlayerBase { assertGraveyardCount(playerB, "Pillarfield Ox", 1); } + /** + * If another effect (e.g. Future Sight) allows you to cast nonland cards + * from zones other than your hand, Xmage incorrectly lets you cast those + * cards without paying their mana costs. Omniscience only lets you cast + * spells from your hand without paying their mana costs. + */ + @Test + public void testCastingWithFutureSight() { + // You may cast nonland cards from your hand without paying their mana costs. + addCard(Zone.BATTLEFIELD, playerA, "Omniscience"); + // Play with the top card of your library revealed. + // You may play the top card of your library. + addCard(Zone.BATTLEFIELD, playerA, "Future Sight", 1); + addCard(Zone.BATTLEFIELD, playerA, "Plains", 2); + + addCard(Zone.LIBRARY, playerA, "Silvercoat Lion", 1); + skipInitShuffling(); + + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Silvercoat Lion"); + setChoice(playerA, "Yes"); + + setStopAt(1, PhaseStep.BEGIN_COMBAT); + execute(); + + assertLife(playerA, 20); + assertLife(playerB, 20); + + assertPermanentCount(playerA, "Silvercoat Lion", 1); + assertTapped("Plains", true); // plains have to be tapped because {2} have to be paid + } + + /** + * If a spell has an additional cost (optional or mandatory, e.g. Entwine), + * Omniscience incorrectly allows you cast the spell as if that cost had + * been paid without paying that spell's mana cost. 117.9d If an alternative + * cost is being paid to cast a spell, any additional costs, cost increases, + * and cost reductions that affect that spell are applied to that + * alternative cost. (See rule 601.2f.) + */ + @Test + public void testCastingWithCyclonicRiftWithOverload() { + // You may cast nonland cards from your hand without paying their mana costs. + addCard(Zone.BATTLEFIELD, playerA, "Omniscience"); + addCard(Zone.BATTLEFIELD, playerA, "Plains", 2); + + // Choose one - Barbed Lightning deals 3 damage to target creature; or Barbed Lightning deals 3 damage to target player. + // Entwine {2} (Choose both if you pay the entwine cost.) + addCard(Zone.HAND, playerA, "Barbed Lightning", 1); + + // Creature - 3/3 Swampwalk + addCard(Zone.BATTLEFIELD, playerB, "Bog Wraith", 1); + + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Barbed Lightning", "Bog Wraith"); + addTarget(playerA, playerB); + + setStopAt(1, PhaseStep.BEGIN_COMBAT); + execute(); + + assertGraveyardCount(playerA, "Barbed Lightning", 1); + assertGraveyardCount(playerB, "Bog Wraith", 1); + + assertLife(playerA, 20); + assertLife(playerB, 17); + + assertTapped("Plains", true); // plains have to be tapped because {2} from Entwine have to be paid + } + + /** + * If a spell has an unpayable cost (e.g. Ancestral Vision, which has no + * mana cost), Omniscience should allow you to cast that spell without + * paying its mana cost. In the case of Ancestral Vision, for example, Xmage + * only gives you the option to suspend Ancestral Vision. 117.6a If an + * unpayable cost is increased by an effect or an additional cost is + * imposed, the cost is still unpayable. If an alternative cost is applied + * to an unpayable cost, including an effect that allows a player to cast a + * spell without paying its mana cost, the alternative cost may be paid. + */ + @Test + public void testCastingUnpayableCost() { + // You may cast nonland cards from your hand without paying their mana costs. + addCard(Zone.BATTLEFIELD, playerA, "Omniscience"); + + // Suspend 4-{U} + // Target player draws three cards. + addCard(Zone.HAND, playerA, "Ancestral Vision", 1); + + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Ancestral Vision", playerA); + addTarget(playerA, playerB); + + setStopAt(1, PhaseStep.BEGIN_COMBAT); + execute(); + + assertGraveyardCount(playerA, "Ancestral Vision", 1); + + assertHandCount(playerA, 3); + assertLife(playerA, 20); + assertLife(playerB, 20); + + } + } diff --git a/Mage/src/mage/abilities/AbilityImpl.java b/Mage/src/mage/abilities/AbilityImpl.java index d7b581515ba..659d4987fb1 100644 --- a/Mage/src/mage/abilities/AbilityImpl.java +++ b/Mage/src/mage/abilities/AbilityImpl.java @@ -471,7 +471,10 @@ public abstract class AbilityImpl implements Ability { } // controller specific alternate spell costs if (!noMana && !alternativeCostisUsed) { - if (this.getAbilityType().equals(AbilityType.SPELL)) { + if (this.getAbilityType().equals(AbilityType.SPELL) + // 117.9a Only one alternative cost can be applied to any one spell as it’s being cast. + // So an alternate spell ability can't be paid with Omniscience + && !((SpellAbility) this).getSpellAbilityType().equals(SpellAbilityType.BASE_ALTERNATE)) { for (AlternativeSourceCosts alternativeSourceCosts : controller.getAlternativeSourceCosts()) { if (alternativeSourceCosts.isAvailable(this, game)) { if (alternativeSourceCosts.askToActivateAlternativeCosts(this, game)) { diff --git a/Mage/src/mage/abilities/SpellAbility.java b/Mage/src/mage/abilities/SpellAbility.java index 1dedf4b81e7..5106b8dc61c 100644 --- a/Mage/src/mage/abilities/SpellAbility.java +++ b/Mage/src/mage/abilities/SpellAbility.java @@ -99,10 +99,6 @@ public class SpellAbility extends ActivatedAbilityImpl { && !controllerId.equals(playerId)) { return false; } - // Check if spell has no costs (not {0} mana costs), than it's not castable. E.g. for spells like Living End, that only can be cast by Suspend Ability. - if (this.getManaCosts().isEmpty() && this.getCosts().isEmpty()) { - return false; - } // Check if rule modifying events prevent to cast the spell in check playable mode if (this.isCheckPlayableMode()) { if (game.getContinuousEffects().preventedByRuleModification( diff --git a/Mage/src/mage/abilities/costs/AlternativeCostSourceAbility.java b/Mage/src/mage/abilities/costs/AlternativeCostSourceAbility.java index 5fb7fd20f90..be4893b1b45 100644 --- a/Mage/src/mage/abilities/costs/AlternativeCostSourceAbility.java +++ b/Mage/src/mage/abilities/costs/AlternativeCostSourceAbility.java @@ -29,6 +29,7 @@ package mage.abilities.costs; import java.util.Iterator; import mage.abilities.Ability; +import mage.abilities.SpellAbility; import mage.abilities.StaticAbility; import mage.abilities.condition.Condition; import mage.abilities.costs.mana.ManaCost; @@ -39,6 +40,7 @@ import mage.constants.Zone; import mage.filter.FilterCard; import mage.game.Game; import mage.players.Player; +import mage.util.CardUtil; /** * @@ -145,28 +147,39 @@ public class AlternativeCostSourceAbility extends StaticAbility implements Alter } Player player = game.getPlayer(ability.getControllerId()); if (player != null) { - Costs alternativeCosts; + Costs alternativeCostsToCheck; if (dynamicCost != null) { - alternativeCosts = new CostsImpl<>(); - alternativeCosts.add(convertToAlternativeCost(dynamicCost.getCost(ability, game))); + alternativeCostsToCheck = new CostsImpl<>(); + alternativeCostsToCheck.add(convertToAlternativeCost(dynamicCost.getCost(ability, game))); } else { - alternativeCosts = this.alternateCosts; + alternativeCostsToCheck = this.alternateCosts; } String costChoiceText; if (dynamicCost != null) { costChoiceText = dynamicCost.getText(ability, game); } else { - costChoiceText = alternativeCosts.isEmpty() ? "Cast without paying its mana cost?" : "Pay alternative costs? (" + alternativeCosts.getText() + ")"; + costChoiceText = alternativeCostsToCheck.isEmpty() ? "Cast without paying its mana cost?" : "Pay alternative costs? (" + alternativeCostsToCheck.getText() + ")"; } - if (alternativeCosts.canPay(ability, ability.getSourceId(), ability.getControllerId(), game) + if (alternativeCostsToCheck.canPay(ability, ability.getSourceId(), ability.getControllerId(), game) && player.chooseUse(Outcome.Benefit, costChoiceText, this, game)) { - ability.getManaCostsToPay().clear(); + if (ability instanceof SpellAbility) { + for (Iterator iterator = ability.getManaCostsToPay().iterator(); iterator.hasNext();) { + ManaCost manaCost = iterator.next(); + if (manaCost instanceof VariableCost) { + iterator.remove(); + } + } + CardUtil.reduceCost((SpellAbility) ability, ability.getManaCosts()); + + } else { + ability.getManaCostsToPay().clear(); + } if (!onlyMana) { ability.getCosts().clear(); } - for (Cost cost : alternativeCosts) { + for (Cost cost : alternativeCostsToCheck) { AlternativeCost2 alternateCost = (AlternativeCost2) cost; alternateCost.activate(); for (Iterator it = ((Costs) alternateCost).iterator(); it.hasNext();) { @@ -190,14 +203,14 @@ public class AlternativeCostSourceAbility extends StaticAbility implements Alter @Override public boolean isActivated(Ability source, Game game) { - Costs alternativeCosts; + Costs alternativeCostsToCheck; if (dynamicCost != null) { - alternativeCosts = new CostsImpl<>(); - alternativeCosts.add(convertToAlternativeCost(dynamicCost.getCost(source, game))); + alternativeCostsToCheck = new CostsImpl<>(); + alternativeCostsToCheck.add(convertToAlternativeCost(dynamicCost.getCost(source, game))); } else { - alternativeCosts = this.alternateCosts; + alternativeCostsToCheck = this.alternateCosts; } - for (AlternativeCost2 cost : alternativeCosts) { + for (AlternativeCost2 cost : alternativeCostsToCheck) { if (cost.isActivated(game)) { return true; } diff --git a/Mage/src/mage/abilities/keyword/EntwineAbility.java b/Mage/src/mage/abilities/keyword/EntwineAbility.java index c81d1cbd955..0604445c2a4 100644 --- a/Mage/src/mage/abilities/keyword/EntwineAbility.java +++ b/Mage/src/mage/abilities/keyword/EntwineAbility.java @@ -111,7 +111,7 @@ public class EntwineAbility extends StaticAbility implements OptionalAdditionalM if (player != null) { this.resetCosts(); if (additionalCost != null) { - if (player.chooseUse(Outcome.Benefit, new StringBuilder("Pay ").append(additionalCost.getText(false)).append(" ?").toString(), ability, game)) { + if (player.chooseUse(Outcome.Benefit, "Pay " + additionalCost.getText(false) + " ?", ability, game)) { additionalCost.activate(); for (Iterator it = ((Costs) additionalCost).iterator(); it.hasNext();) { Cost cost = (Cost) it.next(); diff --git a/Mage/src/mage/players/PlayerImpl.java b/Mage/src/mage/players/PlayerImpl.java index 8949f270970..1719603aa72 100644 --- a/Mage/src/mage/players/PlayerImpl.java +++ b/Mage/src/mage/players/PlayerImpl.java @@ -2317,15 +2317,23 @@ public abstract class PlayerImpl implements Player, Serializable { } } } - - ManaOptions abilityOptions = copy.getManaCostsToPay().getOptions(); - if (abilityOptions.size() == 0) { - return true; - } else { - for (Mana mana : abilityOptions) { - for (Mana avail : available) { - if (mana.enough(avail)) { - return true; + boolean canBeCastRegularly = true; + if (copy instanceof SpellAbility && copy.getManaCosts().isEmpty() && copy.getCosts().isEmpty()) { + // 117.6. Some mana costs contain no mana symbols. This represents an unpayable cost... + // 117.6a (...) If an alternative cost is applied to an unpayable cost, + // including an effect that allows a player to cast a spell without paying its mana cost, the alternative cost may be paid. + canBeCastRegularly = false; + } + if (canBeCastRegularly) { + ManaOptions abilityOptions = copy.getManaCostsToPay().getOptions(); + if (abilityOptions.size() == 0) { + return true; + } else { + for (Mana mana : abilityOptions) { + for (Mana avail : available) { + if (mana.enough(avail)) { + return true; + } } } } From ec9daf26a8021106b898dc6112078ed27a56c216 Mon Sep 17 00:00:00 2001 From: LoneFox Date: Tue, 20 Oct 2015 12:45:31 +0300 Subject: [PATCH 184/268] Fix Thirst's card number --- Mage.Sets/src/mage/sets/mirage/Thirst.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Mage.Sets/src/mage/sets/mirage/Thirst.java b/Mage.Sets/src/mage/sets/mirage/Thirst.java index db2df103b70..bf3c47fce7b 100644 --- a/Mage.Sets/src/mage/sets/mirage/Thirst.java +++ b/Mage.Sets/src/mage/sets/mirage/Thirst.java @@ -53,7 +53,7 @@ import mage.target.common.TargetCreaturePermanent; public class Thirst extends CardImpl { public Thirst(UUID ownerId) { - super(ownerId, 104, "Thirst", Rarity.COMMON, new CardType[]{CardType.ENCHANTMENT}, "{2}{U}"); + super(ownerId, 99, "Thirst", Rarity.COMMON, new CardType[]{CardType.ENCHANTMENT}, "{2}{U}"); this.expansionSetCode = "MIR"; this.subtype.add("Aura"); From a62222dab1d80decde59ef6cc4adc53921fcea06 Mon Sep 17 00:00:00 2001 From: LoneFox Date: Tue, 20 Oct 2015 12:46:10 +0300 Subject: [PATCH 185/268] Extract SacrificeIfCastAtInstantTimeTriggeredAbility from Necromancy to its own file. Implement the cycle of Auras from Mirage that use it. --- .../src/mage/sets/mirage/ArmorOfThorns.java | 89 +++++++++++++++++++ .../src/mage/sets/mirage/GraveServitude.java | 87 ++++++++++++++++++ .../mage/sets/mirage/LightningReflexes.java | 87 ++++++++++++++++++ Mage.Sets/src/mage/sets/mirage/Soar.java | 87 ++++++++++++++++++ .../src/mage/sets/mirage/WardOfLights.java | 83 +++++++++++++++++ .../sets/vintagemasters/ArmorOfThorns.java | 52 +++++++++++ .../src/mage/sets/visions/Necromancy.java | 85 ++---------------- ...ceIfCastAtInstantTimeTriggeredAbility.java | 82 +++++++++++++++++ 8 files changed, 572 insertions(+), 80 deletions(-) create mode 100644 Mage.Sets/src/mage/sets/mirage/ArmorOfThorns.java create mode 100644 Mage.Sets/src/mage/sets/mirage/GraveServitude.java create mode 100644 Mage.Sets/src/mage/sets/mirage/LightningReflexes.java create mode 100644 Mage.Sets/src/mage/sets/mirage/Soar.java create mode 100644 Mage.Sets/src/mage/sets/mirage/WardOfLights.java create mode 100644 Mage.Sets/src/mage/sets/vintagemasters/ArmorOfThorns.java create mode 100644 Mage/src/mage/abilities/common/SacrificeIfCastAtInstantTimeTriggeredAbility.java diff --git a/Mage.Sets/src/mage/sets/mirage/ArmorOfThorns.java b/Mage.Sets/src/mage/sets/mirage/ArmorOfThorns.java new file mode 100644 index 00000000000..5fff4649089 --- /dev/null +++ b/Mage.Sets/src/mage/sets/mirage/ArmorOfThorns.java @@ -0,0 +1,89 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.sets.mirage; + +import java.util.UUID; +import mage.ObjectColor; +import mage.abilities.Ability; +import mage.abilities.common.SacrificeIfCastAtInstantTimeTriggeredAbility; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.effects.common.AttachEffect; +import mage.abilities.effects.common.continuous.BoostEnchantedEffect; +import mage.abilities.effects.common.continuous.CastAsThoughItHadFlashSourceEffect; +import mage.abilities.keyword.EnchantAbility; +import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.Outcome; +import mage.constants.Rarity; +import mage.constants.Zone; +import mage.filter.common.FilterCreaturePermanent; +import mage.filter.predicate.Predicates; +import mage.filter.predicate.mageobject.ColorPredicate; +import mage.target.TargetPermanent; +import mage.target.common.TargetCreaturePermanent; + +/** + * + * @author LoneFox + */ +public class ArmorOfThorns extends CardImpl { + + private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("nonblack creature"); + + static { + filter.add(Predicates.not(new ColorPredicate(ObjectColor.BLACK))); + } + + public ArmorOfThorns(UUID ownerId) { + super(ownerId, 104, "Armor of Thorns", Rarity.COMMON, new CardType[]{CardType.ENCHANTMENT}, "{1}{G}"); + this.expansionSetCode = "MIR"; + this.subtype.add("Aura"); + + // You may cast Armor of Thorns as though it had flash. If you cast it any time a sorcery couldn't have been cast, the controller of the permanent it becomes sacrifices it at the beginning of the next cleanup step. + this.addAbility(new SimpleStaticAbility(Zone.ALL, new CastAsThoughItHadFlashSourceEffect(Duration.EndOfGame))); + this.addAbility(new SacrificeIfCastAtInstantTimeTriggeredAbility()); + // Enchant nonblack creature + TargetPermanent auraTarget = new TargetCreaturePermanent(filter); + this.getSpellAbility().addTarget(auraTarget); + this.getSpellAbility().addEffect(new AttachEffect(Outcome.BoostCreature)); + Ability ability = new EnchantAbility(auraTarget.getTargetName()); + this.addAbility(ability); + // Enchanted creature gets +2/+2. + this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new BoostEnchantedEffect(2, 2, Duration.WhileOnBattlefield))); + } + + public ArmorOfThorns(final ArmorOfThorns card) { + super(card); + } + + @Override + public ArmorOfThorns copy() { + return new ArmorOfThorns(this); + } +} diff --git a/Mage.Sets/src/mage/sets/mirage/GraveServitude.java b/Mage.Sets/src/mage/sets/mirage/GraveServitude.java new file mode 100644 index 00000000000..e162e3aae2d --- /dev/null +++ b/Mage.Sets/src/mage/sets/mirage/GraveServitude.java @@ -0,0 +1,87 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.sets.mirage; + +import java.util.UUID; +import mage.ObjectColor; +import mage.abilities.Ability; +import mage.abilities.common.SacrificeIfCastAtInstantTimeTriggeredAbility; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.effects.Effect; +import mage.abilities.effects.common.AttachEffect; +import mage.abilities.effects.common.continuous.BoostEnchantedEffect; +import mage.abilities.effects.common.continuous.CastAsThoughItHadFlashSourceEffect; +import mage.abilities.effects.common.continuous.SetCardColorAttachedEffect; +import mage.abilities.keyword.EnchantAbility; +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.Zone; +import mage.target.TargetPermanent; +import mage.target.common.TargetCreaturePermanent; + +/** + * + * @author LoneFox + */ +public class GraveServitude extends CardImpl { + + public GraveServitude(UUID ownerId) { + super(ownerId, 24, "Grave Servitude", Rarity.COMMON, new CardType[]{CardType.ENCHANTMENT}, "{1}{B}"); + this.expansionSetCode = "MIR"; + this.subtype.add("Aura"); + + // You may cast Grave Servitude as though it had flash. If you cast it any time a sorcery couldn't have been cast, the controller of the permanent it becomes sacrifices it at the beginning of the next cleanup step. + this.addAbility(new SimpleStaticAbility(Zone.ALL, new CastAsThoughItHadFlashSourceEffect(Duration.EndOfGame))); + this.addAbility(new SacrificeIfCastAtInstantTimeTriggeredAbility()); + // Enchant creature + TargetPermanent auraTarget = new TargetCreaturePermanent(); + this.getSpellAbility().addTarget(auraTarget); + this.getSpellAbility().addEffect(new AttachEffect(Outcome.BoostCreature)); + Ability ability = new EnchantAbility(auraTarget.getTargetName()); + this.addAbility(ability); + // Enchanted creature gets +3/-1 and is black. + ability = new SimpleStaticAbility(Zone.BATTLEFIELD, new BoostEnchantedEffect(3, -1, Duration.WhileOnBattlefield)); + Effect effect = new SetCardColorAttachedEffect(ObjectColor.BLACK, Duration.WhileOnBattlefield, AttachmentType.AURA); + effect.setText("and is black"); + ability.addEffect(effect); + this.addAbility(ability); + } + + public GraveServitude(final GraveServitude card) { + super(card); + } + + @Override + public GraveServitude copy() { + return new GraveServitude(this); + } +} diff --git a/Mage.Sets/src/mage/sets/mirage/LightningReflexes.java b/Mage.Sets/src/mage/sets/mirage/LightningReflexes.java new file mode 100644 index 00000000000..627c87926b3 --- /dev/null +++ b/Mage.Sets/src/mage/sets/mirage/LightningReflexes.java @@ -0,0 +1,87 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.sets.mirage; + +import java.util.UUID; +import mage.abilities.Ability; +import mage.abilities.common.SacrificeIfCastAtInstantTimeTriggeredAbility; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.effects.Effect; +import mage.abilities.effects.common.AttachEffect; +import mage.abilities.effects.common.continuous.BoostEnchantedEffect; +import mage.abilities.effects.common.continuous.CastAsThoughItHadFlashSourceEffect; +import mage.abilities.effects.common.continuous.GainAbilityAttachedEffect; +import mage.abilities.keyword.EnchantAbility; +import mage.abilities.keyword.FirstStrikeAbility; +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.Zone; +import mage.target.TargetPermanent; +import mage.target.common.TargetCreaturePermanent; + +/** + * + * @author LoneFox + */ +public class LightningReflexes extends CardImpl { + + public LightningReflexes(UUID ownerId) { + super(ownerId, 186, "Lightning Reflexes", Rarity.COMMON, new CardType[]{CardType.ENCHANTMENT}, "{1}{R}"); + this.expansionSetCode = "MIR"; + this.subtype.add("Aura"); + + // You may cast Lightning Reflexes as though it had flash. If you cast it any time a sorcery couldn't have been cast, the controller of the permanent it becomes sacrifices it at the beginning of the next cleanup step. + this.addAbility(new SimpleStaticAbility(Zone.ALL, new CastAsThoughItHadFlashSourceEffect(Duration.EndOfGame))); + this.addAbility(new SacrificeIfCastAtInstantTimeTriggeredAbility()); + // Enchant creature + TargetPermanent auraTarget = new TargetCreaturePermanent(); + this.getSpellAbility().addTarget(auraTarget); + this.getSpellAbility().addEffect(new AttachEffect(Outcome.BoostCreature)); + Ability ability = new EnchantAbility(auraTarget.getTargetName()); + this.addAbility(ability); + // Enchanted creature gets +1/+0 and has first strike. + ability = new SimpleStaticAbility(Zone.BATTLEFIELD, new BoostEnchantedEffect(1, 0, Duration.WhileOnBattlefield)); + Effect effect = new GainAbilityAttachedEffect(FirstStrikeAbility.getInstance(), AttachmentType.AURA); + effect.setText("and has first strike"); + ability.addEffect(effect); + this.addAbility(ability); + } + + public LightningReflexes(final LightningReflexes card) { + super(card); + } + + @Override + public LightningReflexes copy() { + return new LightningReflexes(this); + } +} diff --git a/Mage.Sets/src/mage/sets/mirage/Soar.java b/Mage.Sets/src/mage/sets/mirage/Soar.java new file mode 100644 index 00000000000..bcdd172fccd --- /dev/null +++ b/Mage.Sets/src/mage/sets/mirage/Soar.java @@ -0,0 +1,87 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.sets.mirage; + +import java.util.UUID; +import mage.abilities.Ability; +import mage.abilities.common.SacrificeIfCastAtInstantTimeTriggeredAbility; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.effects.Effect; +import mage.abilities.effects.common.AttachEffect; +import mage.abilities.effects.common.continuous.BoostEnchantedEffect; +import mage.abilities.effects.common.continuous.CastAsThoughItHadFlashSourceEffect; +import mage.abilities.effects.common.continuous.GainAbilityAttachedEffect; +import mage.abilities.keyword.EnchantAbility; +import mage.abilities.keyword.FlyingAbility; +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.Zone; +import mage.target.TargetPermanent; +import mage.target.common.TargetCreaturePermanent; + +/** + * + * @author LoneFox + */ +public class Soar extends CardImpl { + + public Soar(UUID ownerId) { + super(ownerId, 93, "Soar", Rarity.COMMON, new CardType[]{CardType.ENCHANTMENT}, "{1}{U}"); + this.expansionSetCode = "MIR"; + this.subtype.add("Aura"); + + // You may cast Soar as though it had flash. If you cast it any time a sorcery couldn't have been cast, the controller of the permanent it becomes sacrifices it at the beginning of the next cleanup step. + this.addAbility(new SimpleStaticAbility(Zone.ALL, new CastAsThoughItHadFlashSourceEffect(Duration.EndOfGame))); + this.addAbility(new SacrificeIfCastAtInstantTimeTriggeredAbility()); + // Enchant creature + TargetPermanent auraTarget = new TargetCreaturePermanent(); + this.getSpellAbility().addTarget(auraTarget); + this.getSpellAbility().addEffect(new AttachEffect(Outcome.BoostCreature)); + Ability ability = new EnchantAbility(auraTarget.getTargetName()); + this.addAbility(ability); + // Enchanted creature gets +0/+1 and has flying. + ability = new SimpleStaticAbility(Zone.BATTLEFIELD, new BoostEnchantedEffect(0, 1, Duration.WhileOnBattlefield)); + Effect effect = new GainAbilityAttachedEffect(FlyingAbility.getInstance(), AttachmentType.AURA); + effect.setText("and has flying"); + ability.addEffect(effect); + this.addAbility(ability); + } + + public Soar(final Soar card) { + super(card); + } + + @Override + public Soar copy() { + return new Soar(this); + } +} diff --git a/Mage.Sets/src/mage/sets/mirage/WardOfLights.java b/Mage.Sets/src/mage/sets/mirage/WardOfLights.java new file mode 100644 index 00000000000..844d498701f --- /dev/null +++ b/Mage.Sets/src/mage/sets/mirage/WardOfLights.java @@ -0,0 +1,83 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.sets.mirage; + +import java.util.UUID; +import mage.abilities.Ability; +import mage.abilities.common.AsEntersBattlefieldAbility; +import mage.abilities.common.SacrificeIfCastAtInstantTimeTriggeredAbility; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.effects.common.AttachEffect; +import mage.abilities.effects.common.ChooseColorEffect; +import mage.abilities.effects.common.continuous.CastAsThoughItHadFlashSourceEffect; +import mage.abilities.effects.keyword.ProtectionChosenColorAttachedEffect; +import mage.abilities.keyword.EnchantAbility; +import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.Outcome; +import mage.constants.Rarity; +import mage.constants.Zone; +import mage.target.TargetPermanent; +import mage.target.common.TargetCreaturePermanent; + +/** + * + * @author LoneFox + */ +public class WardOfLights extends CardImpl { + + public WardOfLights(UUID ownerId) { + super(ownerId, 251, "Ward of Lights", Rarity.COMMON, new CardType[]{CardType.ENCHANTMENT}, "{W}{W}"); + this.expansionSetCode = "MIR"; + this.subtype.add("Aura"); + + // You may cast Ward of Lights as though it had flash. If you cast it any time a sorcery couldn't have been cast, the controller of the permanent it becomes sacrifices it at the beginning of the next cleanup step. + this.addAbility(new SimpleStaticAbility(Zone.ALL, new CastAsThoughItHadFlashSourceEffect(Duration.EndOfGame))); + this.addAbility(new SacrificeIfCastAtInstantTimeTriggeredAbility()); + // Enchant creature + TargetPermanent auraTarget = new TargetCreaturePermanent(); + this.getSpellAbility().addTarget(auraTarget); + this.getSpellAbility().addEffect(new AttachEffect(Outcome.AddAbility)); + Ability ability = new EnchantAbility(auraTarget.getTargetName()); + this.addAbility(ability); + // As Ward of Lights enters the battlefield, choose a color. + this.addAbility(new AsEntersBattlefieldAbility(new ChooseColorEffect(Outcome.Benefit))); + // Enchanted creature has protection from the chosen color. This effect doesn't remove Ward of Lights. + this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new ProtectionChosenColorAttachedEffect(true))); + } + + public WardOfLights(final WardOfLights card) { + super(card); + } + + @Override + public WardOfLights copy() { + return new WardOfLights(this); + } +} diff --git a/Mage.Sets/src/mage/sets/vintagemasters/ArmorOfThorns.java b/Mage.Sets/src/mage/sets/vintagemasters/ArmorOfThorns.java new file mode 100644 index 00000000000..5935dd45b28 --- /dev/null +++ b/Mage.Sets/src/mage/sets/vintagemasters/ArmorOfThorns.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.vintagemasters; + +import java.util.UUID; + +/** + * + * @author LoneFox + */ +public class ArmorOfThorns extends mage.sets.mirage.ArmorOfThorns { + + public ArmorOfThorns(UUID ownerId) { + super(ownerId); + this.cardNumber = 194; + this.expansionSetCode = "VMA"; + } + + public ArmorOfThorns(final ArmorOfThorns card) { + super(card); + } + + @Override + public ArmorOfThorns copy() { + return new ArmorOfThorns(this); + } +} diff --git a/Mage.Sets/src/mage/sets/visions/Necromancy.java b/Mage.Sets/src/mage/sets/visions/Necromancy.java index 89910cb3ab9..13d1bb76169 100644 --- a/Mage.Sets/src/mage/sets/visions/Necromancy.java +++ b/Mage.Sets/src/mage/sets/visions/Necromancy.java @@ -30,23 +30,19 @@ package mage.sets.visions; import java.util.UUID; import mage.MageObjectReference; import mage.abilities.Ability; -import mage.abilities.TriggeredAbilityImpl; import mage.abilities.common.EntersBattlefieldTriggeredAbility; import mage.abilities.common.LeavesBattlefieldTriggeredAbility; +import mage.abilities.common.SacrificeIfCastAtInstantTimeTriggeredAbility; import mage.abilities.common.SimpleStaticAbility; -import mage.abilities.common.delayed.AtTheBeginOfNextCleanupDelayedTriggeredAbility; import mage.abilities.condition.common.SourceOnBattlefieldCondition; import mage.abilities.decorator.ConditionalTriggeredAbility; -import mage.abilities.effects.AsThoughEffectImpl; import mage.abilities.effects.ContinuousEffectImpl; import mage.abilities.effects.OneShotEffect; -import mage.abilities.effects.common.CreateDelayedTriggeredAbilityEffect; -import mage.abilities.effects.common.SacrificeSourceEffect; +import mage.abilities.effects.common.continuous.CastAsThoughItHadFlashSourceEffect; import mage.abilities.effects.common.continuous.SourceEffect; import mage.abilities.keyword.EnchantAbility; import mage.cards.Card; import mage.cards.CardImpl; -import mage.constants.AsThoughEffectType; import mage.constants.CardType; import mage.constants.DependencyType; import mage.constants.Duration; @@ -59,10 +55,7 @@ import mage.filter.common.FilterCreatureCard; import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.permanent.PermanentIdPredicate; import mage.game.Game; -import mage.game.events.GameEvent; -import mage.game.events.GameEvent.EventType; import mage.game.permanent.Permanent; -import mage.game.stack.Spell; import mage.players.Player; import mage.target.Target; import mage.target.common.TargetCardInGraveyard; @@ -79,8 +72,8 @@ public class Necromancy extends CardImpl { this.expansionSetCode = "VIS"; // You may cast Necromancy as though it had flash. If you cast it any time a sorcery couldn't have been cast, the controller of the permanent it becomes sacrifices it at the beginning of the next cleanup step. - this.addAbility(new SimpleStaticAbility(Zone.ALL, new CastSourceAsThoughItHadFlashEffect(this, Duration.EndOfGame, true))); - this.addAbility(new CastAtInstantTimeTriggeredAbility()); + this.addAbility(new SimpleStaticAbility(Zone.ALL, new CastAsThoughItHadFlashSourceEffect(Duration.EndOfGame))); + this.addAbility(new SacrificeIfCastAtInstantTimeTriggeredAbility()); // When Necromancy enters the battlefield, if it's on the battlefield, it becomes an Aura with "enchant creature put onto the battlefield with Necromancy." // Put target creature card from a graveyard onto the battlefield under your control and attach Necromancy to it. @@ -104,75 +97,6 @@ public class Necromancy extends CardImpl { } } -class CastSourceAsThoughItHadFlashEffect extends AsThoughEffectImpl { - - private final boolean sacrificeIfCastAsInstant; - - public CastSourceAsThoughItHadFlashEffect(Card card, Duration duration, boolean sacrificeIfCastAsInstant) { - super(AsThoughEffectType.CAST_AS_INSTANT, duration, Outcome.Benefit); - this.sacrificeIfCastAsInstant = sacrificeIfCastAsInstant; - staticText = "You may cast {this} as though it had flash"; - } - - public CastSourceAsThoughItHadFlashEffect(final CastSourceAsThoughItHadFlashEffect effect) { - super(effect); - this.sacrificeIfCastAsInstant = effect.sacrificeIfCastAsInstant; - } - - @Override - public boolean apply(Game game, Ability source) { - return true; - } - - @Override - public CastSourceAsThoughItHadFlashEffect copy() { - return new CastSourceAsThoughItHadFlashEffect(this); - } - - @Override - public boolean applies(UUID affectedSpellId, Ability source, UUID affectedControllerId, Game game) { - return source.getSourceId().equals(affectedSpellId); - } - -} - -class CastAtInstantTimeTriggeredAbility extends TriggeredAbilityImpl { - - public CastAtInstantTimeTriggeredAbility() { - super(Zone.STACK, new CreateDelayedTriggeredAbilityEffect(new AtTheBeginOfNextCleanupDelayedTriggeredAbility(new SacrificeSourceEffect()))); - } - - public CastAtInstantTimeTriggeredAbility(final CastAtInstantTimeTriggeredAbility ability) { - super(ability); - } - - @Override - public CastAtInstantTimeTriggeredAbility copy() { - return new CastAtInstantTimeTriggeredAbility(this); - } - - @Override - public boolean checkEventType(GameEvent event, Game game) { - return event.getType() == EventType.SPELL_CAST; - } - - @Override - public boolean checkTrigger(GameEvent event, Game game) { - // The sacrifice occurs only if you cast it using its own ability. If you cast it using some other - // effect (for instance, if it gained flash from Vedalken Orrery), then it won't be sacrificed. - // CHECK - Spell spell = game.getStack().getSpell(event.getTargetId()); - if (spell != null && spell.getSourceId().equals(getSourceId())) { - return !(game.isMainPhase() && game.getActivePlayerId().equals(event.getPlayerId()) && game.getStack().size() == 1); - } - return false; - } - - @Override - public String getRule() { - return "If you cast it any time a sorcery couldn't have been cast, the controller of the permanent it becomes sacrifices it at the beginning of the next cleanup step."; - } -} class NecromancyReAttachEffect extends OneShotEffect { @@ -246,6 +170,7 @@ class NecromancyLeavesBattlefieldTriggeredEffect extends OneShotEffect { } } + class NecromancyChangeAbilityEffect extends ContinuousEffectImpl implements SourceEffect { private final static Ability newAbility = new EnchantAbility("creature put onto the battlefield with Necromancy"); diff --git a/Mage/src/mage/abilities/common/SacrificeIfCastAtInstantTimeTriggeredAbility.java b/Mage/src/mage/abilities/common/SacrificeIfCastAtInstantTimeTriggeredAbility.java new file mode 100644 index 00000000000..6941a1b66b1 --- /dev/null +++ b/Mage/src/mage/abilities/common/SacrificeIfCastAtInstantTimeTriggeredAbility.java @@ -0,0 +1,82 @@ +/* + * 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.common; + +import mage.abilities.TriggeredAbilityImpl; +import mage.abilities.common.delayed.AtTheBeginOfNextCleanupDelayedTriggeredAbility; +import mage.abilities.effects.common.CreateDelayedTriggeredAbilityEffect; +import mage.abilities.effects.common.SacrificeSourceEffect; +import mage.constants.Zone; +import mage.game.Game; +import mage.game.events.GameEvent.EventType; +import mage.game.events.GameEvent; +import mage.game.stack.Spell; + +/** + * + * @author Lonefox + */ +public class SacrificeIfCastAtInstantTimeTriggeredAbility extends TriggeredAbilityImpl { + + public SacrificeIfCastAtInstantTimeTriggeredAbility() { + super(Zone.STACK, new CreateDelayedTriggeredAbilityEffect(new AtTheBeginOfNextCleanupDelayedTriggeredAbility(new SacrificeSourceEffect()))); + } + + public SacrificeIfCastAtInstantTimeTriggeredAbility(final SacrificeIfCastAtInstantTimeTriggeredAbility ability) { + super(ability); + } + + @Override + public SacrificeIfCastAtInstantTimeTriggeredAbility copy() { + return new SacrificeIfCastAtInstantTimeTriggeredAbility(this); + } + + @Override + public boolean checkEventType(GameEvent event, Game game) { + return event.getType() == EventType.SPELL_CAST; + } + + @Override + public boolean checkTrigger(GameEvent event, Game game) { + // The sacrifice occurs only if you cast it using its own ability. If you cast it using some other + // effect (for instance, if it gained flash from Vedalken Orrery), then it won't be sacrificed. + // CHECK + Spell spell = game.getStack().getSpell(event.getTargetId()); + if (spell != null && spell.getSourceId().equals(getSourceId())) { + return !(game.isMainPhase() && game.getActivePlayerId().equals(event.getPlayerId()) && game.getStack().size() == 1); + } + return false; + } + + @Override + public String getRule() { + return "If you cast it any time a sorcery couldn't have been cast, the controller of the permanent it becomes sacrifices it at the beginning of the next cleanup step."; + } +} + From 4c75c50082e7fae56b6ae08e8c5b706debfc18b9 Mon Sep 17 00:00:00 2001 From: LoneFox Date: Tue, 20 Oct 2015 13:29:04 +0300 Subject: [PATCH 186/268] Implement cards: Mystic Veil, Parapet, Relic Ward, and Spider Climb --- .../src/mage/sets/visions/MysticVeil.java | 82 +++++++++++++++++ Mage.Sets/src/mage/sets/visions/Parapet.java | 66 ++++++++++++++ .../src/mage/sets/visions/RelicWard.java | 80 +++++++++++++++++ .../src/mage/sets/visions/SpiderClimb.java | 87 +++++++++++++++++++ 4 files changed, 315 insertions(+) create mode 100644 Mage.Sets/src/mage/sets/visions/MysticVeil.java create mode 100644 Mage.Sets/src/mage/sets/visions/Parapet.java create mode 100644 Mage.Sets/src/mage/sets/visions/RelicWard.java create mode 100644 Mage.Sets/src/mage/sets/visions/SpiderClimb.java diff --git a/Mage.Sets/src/mage/sets/visions/MysticVeil.java b/Mage.Sets/src/mage/sets/visions/MysticVeil.java new file mode 100644 index 00000000000..bfcb4210d71 --- /dev/null +++ b/Mage.Sets/src/mage/sets/visions/MysticVeil.java @@ -0,0 +1,82 @@ +/* + * 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.visions; + +import java.util.UUID; +import mage.abilities.Ability; +import mage.abilities.common.SacrificeIfCastAtInstantTimeTriggeredAbility; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.effects.common.AttachEffect; +import mage.abilities.effects.common.continuous.CastAsThoughItHadFlashSourceEffect; +import mage.abilities.effects.common.continuous.GainAbilityAttachedEffect; +import mage.abilities.keyword.EnchantAbility; +import mage.abilities.keyword.ShroudAbility; +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.Zone; +import mage.target.TargetPermanent; +import mage.target.common.TargetCreaturePermanent; + +/** + + * + * @author LoneFox + */ +public class MysticVeil extends CardImpl { + + public MysticVeil(UUID ownerId) { + super(ownerId, 38, "Mystic Veil", Rarity.COMMON, new CardType[]{CardType.ENCHANTMENT}, "{1}{U}"); + this.expansionSetCode = "VIS"; + this.subtype.add("Aura"); + + // You may cast Mystic Veil as though it had flash. If you cast it any time a sorcery couldn't have been cast, the controller of the permanent it becomes sacrifices it at the beginning of the next cleanup step. + this.addAbility(new SimpleStaticAbility(Zone.ALL, new CastAsThoughItHadFlashSourceEffect(Duration.EndOfGame))); + this.addAbility(new SacrificeIfCastAtInstantTimeTriggeredAbility()); + // Enchant creature + TargetPermanent auraTarget = new TargetCreaturePermanent(); + this.getSpellAbility().addTarget(auraTarget); + this.getSpellAbility().addEffect(new AttachEffect(Outcome.AddAbility)); + Ability ability = new EnchantAbility(auraTarget.getTargetName()); + this.addAbility(ability); + // Enchanted creature has shroud. + this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new GainAbilityAttachedEffect(ShroudAbility.getInstance(), AttachmentType.AURA))); + } + + public MysticVeil(final MysticVeil card) { + super(card); + } + + @Override + public MysticVeil copy() { + return new MysticVeil(this); + } +} diff --git a/Mage.Sets/src/mage/sets/visions/Parapet.java b/Mage.Sets/src/mage/sets/visions/Parapet.java new file mode 100644 index 00000000000..d05703ebca6 --- /dev/null +++ b/Mage.Sets/src/mage/sets/visions/Parapet.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.visions; + +import java.util.UUID; +import mage.abilities.common.SacrificeIfCastAtInstantTimeTriggeredAbility; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.effects.common.continuous.BoostControlledEffect; +import mage.abilities.effects.common.continuous.CastAsThoughItHadFlashSourceEffect; +import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.Rarity; +import mage.constants.Zone; + +/** + * + * @author LoneFox + */ +public class Parapet extends CardImpl { + + public Parapet(UUID ownerId) { + super(ownerId, 114, "Parapet", Rarity.COMMON, new CardType[]{CardType.ENCHANTMENT}, "{1}{W}"); + this.expansionSetCode = "VIS"; + + // You may cast Parapet as though it had flash. If you cast it any time a sorcery couldn't have been cast, the controller of the permanent it becomes sacrifices it at the beginning of the next cleanup step. + this.addAbility(new SimpleStaticAbility(Zone.ALL, new CastAsThoughItHadFlashSourceEffect(Duration.EndOfGame))); + this.addAbility(new SacrificeIfCastAtInstantTimeTriggeredAbility()); + // Creatures you control get +0/+1. + this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new BoostControlledEffect(0, 1, Duration.WhileOnBattlefield))); + } + + public Parapet(final Parapet card) { + super(card); + } + + @Override + public Parapet copy() { + return new Parapet(this); + } +} diff --git a/Mage.Sets/src/mage/sets/visions/RelicWard.java b/Mage.Sets/src/mage/sets/visions/RelicWard.java new file mode 100644 index 00000000000..122cf167927 --- /dev/null +++ b/Mage.Sets/src/mage/sets/visions/RelicWard.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.visions; + +import java.util.UUID; +import mage.abilities.Ability; +import mage.abilities.common.SacrificeIfCastAtInstantTimeTriggeredAbility; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.effects.common.AttachEffect; +import mage.abilities.effects.common.continuous.CastAsThoughItHadFlashSourceEffect; +import mage.abilities.effects.common.continuous.GainAbilityAttachedEffect; +import mage.abilities.keyword.EnchantAbility; +import mage.abilities.keyword.ShroudAbility; +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.Zone; +import mage.target.TargetPermanent; +import mage.target.common.TargetArtifactPermanent; +/** + * + * @author LoneFox + */ +public class RelicWard extends CardImpl { + + public RelicWard(UUID ownerId) { + super(ownerId, 116, "Relic Ward", Rarity.UNCOMMON, new CardType[]{CardType.ENCHANTMENT}, "{1}{W}"); + this.expansionSetCode = "VIS"; + this.subtype.add("Aura"); + + // You may cast Relic Ward as though it had flash. If you cast it any time a sorcery couldn't have been cast, the controller of the permanent it becomes sacrifices it at the beginning of the next cleanup step. + this.addAbility(new SimpleStaticAbility(Zone.ALL, new CastAsThoughItHadFlashSourceEffect(Duration.EndOfGame))); + this.addAbility(new SacrificeIfCastAtInstantTimeTriggeredAbility()); + // Enchant artifact + TargetPermanent auraTarget = new TargetArtifactPermanent(); + this.getSpellAbility().addTarget(auraTarget); + this.getSpellAbility().addEffect(new AttachEffect(Outcome.AddAbility)); + Ability ability = new EnchantAbility(auraTarget.getTargetName()); + this.addAbility(ability); + // Enchanted artifact has shroud. + this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new GainAbilityAttachedEffect(ShroudAbility.getInstance(), AttachmentType.AURA))); + } + + public RelicWard(final RelicWard card) { + super(card); + } + + @Override + public RelicWard copy() { + return new RelicWard(this); + } +} diff --git a/Mage.Sets/src/mage/sets/visions/SpiderClimb.java b/Mage.Sets/src/mage/sets/visions/SpiderClimb.java new file mode 100644 index 00000000000..bdccf5912c6 --- /dev/null +++ b/Mage.Sets/src/mage/sets/visions/SpiderClimb.java @@ -0,0 +1,87 @@ +/* + * 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.visions; + +import java.util.UUID; +import mage.abilities.Ability; +import mage.abilities.common.SacrificeIfCastAtInstantTimeTriggeredAbility; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.effects.Effect; +import mage.abilities.effects.common.AttachEffect; +import mage.abilities.effects.common.continuous.BoostEnchantedEffect; +import mage.abilities.effects.common.continuous.CastAsThoughItHadFlashSourceEffect; +import mage.abilities.effects.common.continuous.GainAbilityAttachedEffect; +import mage.abilities.keyword.EnchantAbility; +import mage.abilities.keyword.ReachAbility; +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.Zone; +import mage.target.TargetPermanent; +import mage.target.common.TargetCreaturePermanent; + +/** + * + * @author LoneFox + */ +public class SpiderClimb extends CardImpl { + + public SpiderClimb(UUID ownerId) { + super(ownerId, 70, "Spider Climb", Rarity.COMMON, new CardType[]{CardType.ENCHANTMENT}, "{G}"); + this.expansionSetCode = "VIS"; + this.subtype.add("Aura"); + + // You may cast Spider Climb as though it had flash. If you cast it any time a sorcery couldn't have been cast, the controller of the permanent it becomes sacrifices it at the beginning of the next cleanup step. + this.addAbility(new SimpleStaticAbility(Zone.ALL, new CastAsThoughItHadFlashSourceEffect(Duration.EndOfGame))); + this.addAbility(new SacrificeIfCastAtInstantTimeTriggeredAbility()); + // Enchant creature + TargetPermanent auraTarget = new TargetCreaturePermanent(); + this.getSpellAbility().addTarget(auraTarget); + this.getSpellAbility().addEffect(new AttachEffect(Outcome.BoostCreature)); + Ability ability = new EnchantAbility(auraTarget.getTargetName()); + this.addAbility(ability); + // Enchanted creature gets +0/+3 and has reach. + ability = new SimpleStaticAbility(Zone.BATTLEFIELD, new BoostEnchantedEffect(0, 3, Duration.WhileOnBattlefield)); + Effect effect = new GainAbilityAttachedEffect(ReachAbility.getInstance(), AttachmentType.AURA); + effect.setText("and has reach"); + ability.addEffect(effect); + this.addAbility(ability); + } + + public SpiderClimb(final SpiderClimb card) { + super(card); + } + + @Override + public SpiderClimb copy() { + return new SpiderClimb(this); + } +} From bab173e8672f46329ceb1f4df325fffbcd26b7df Mon Sep 17 00:00:00 2001 From: LoneFox Date: Tue, 20 Oct 2015 13:40:16 +0300 Subject: [PATCH 187/268] Fix Call to Serve: Add missing non-black filter (was coded but not applied) and combine effects to one ability. --- .../mage/sets/avacynrestored/CallToServe.java | 24 +++++++++++++------ 1 file changed, 17 insertions(+), 7 deletions(-) diff --git a/Mage.Sets/src/mage/sets/avacynrestored/CallToServe.java b/Mage.Sets/src/mage/sets/avacynrestored/CallToServe.java index a0453080103..72e5a85d72f 100644 --- a/Mage.Sets/src/mage/sets/avacynrestored/CallToServe.java +++ b/Mage.Sets/src/mage/sets/avacynrestored/CallToServe.java @@ -28,11 +28,10 @@ package mage.sets.avacynrestored; import java.util.UUID; - -import mage.constants.*; import mage.ObjectColor; import mage.abilities.Ability; import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.effects.Effect; import mage.abilities.effects.common.AttachEffect; import mage.abilities.effects.common.continuous.AddCardSubtypeAttachedEffect; import mage.abilities.effects.common.continuous.BoostEnchantedEffect; @@ -40,6 +39,12 @@ import mage.abilities.effects.common.continuous.GainAbilityAttachedEffect; import mage.abilities.keyword.EnchantAbility; import mage.abilities.keyword.FlyingAbility; 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.Zone; import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.Predicates; import mage.filter.predicate.mageobject.ColorPredicate; @@ -51,6 +56,7 @@ import mage.target.common.TargetCreaturePermanent; * @author Loki */ public class CallToServe extends CardImpl { + private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("nonblack creature"); static { @@ -62,18 +68,22 @@ public class CallToServe extends CardImpl { this.expansionSetCode = "AVR"; this.subtype.add("Aura"); - // Enchant nonblack creature - TargetPermanent auraTarget = new TargetCreaturePermanent(); + TargetPermanent auraTarget = new TargetCreaturePermanent(filter); this.getSpellAbility().addTarget(auraTarget); this.getSpellAbility().addEffect(new AttachEffect(Outcome.BoostCreature)); Ability ability = new EnchantAbility(auraTarget.getTargetName()); this.addAbility(ability); // Enchanted creature gets +1/+2, has flying, and is an Angel in addition to its other types. - this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new BoostEnchantedEffect(1, 2, Duration.WhileOnBattlefield))); - this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new GainAbilityAttachedEffect(FlyingAbility.getInstance(), AttachmentType.AURA))); - this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new AddCardSubtypeAttachedEffect("Angel", Duration.WhileOnBattlefield, AttachmentType.AURA))); + ability = new SimpleStaticAbility(Zone.BATTLEFIELD, new BoostEnchantedEffect(1, 2, Duration.WhileOnBattlefield)); + Effect effect = new GainAbilityAttachedEffect(FlyingAbility.getInstance(), AttachmentType.AURA); + effect.setText(", has flying"); + ability.addEffect(effect); + effect = new AddCardSubtypeAttachedEffect("Angel", Duration.WhileOnBattlefield, AttachmentType.AURA); + effect.setText(", and is an Angel in addition to its other types"); + ability.addEffect(effect); + this.addAbility(ability); } public CallToServe(final CallToServe card) { From 67c64bbe9ef42dcd4b96156422e883aeab92b3f0 Mon Sep 17 00:00:00 2001 From: LoneFox Date: Tue, 20 Oct 2015 14:19:04 +0300 Subject: [PATCH 188/268] Fix some tooltip texts --- .../mage/sets/fifthedition/Shatterstorm.java | 2 +- .../mage/sets/fourthedition/EbonyHorse.java | 23 +++++++++++++------ .../src/mage/sets/iceage/FanaticalFever.java | 9 ++++++-- .../mage/sets/iceage/OrcishCannoneers.java | 5 +++- Mage.Sets/src/mage/sets/iceage/SnowHound.java | 4 ++-- .../mage/sets/masterseditionii/TimeBomb.java | 7 +++--- 6 files changed, 34 insertions(+), 16 deletions(-) diff --git a/Mage.Sets/src/mage/sets/fifthedition/Shatterstorm.java b/Mage.Sets/src/mage/sets/fifthedition/Shatterstorm.java index 8b7a9885776..ef14823483b 100644 --- a/Mage.Sets/src/mage/sets/fifthedition/Shatterstorm.java +++ b/Mage.Sets/src/mage/sets/fifthedition/Shatterstorm.java @@ -46,7 +46,7 @@ public class Shatterstorm extends CardImpl { // Destroy all artifacts. They can't be regenerated. - this.getSpellAbility().addEffect(new DestroyAllEffect(new FilterArtifactPermanent(), true)); + this.getSpellAbility().addEffect(new DestroyAllEffect(new FilterArtifactPermanent("artifacts"), true)); } public Shatterstorm(final Shatterstorm card) { diff --git a/Mage.Sets/src/mage/sets/fourthedition/EbonyHorse.java b/Mage.Sets/src/mage/sets/fourthedition/EbonyHorse.java index 943eb139161..c2601f3b37e 100644 --- a/Mage.Sets/src/mage/sets/fourthedition/EbonyHorse.java +++ b/Mage.Sets/src/mage/sets/fourthedition/EbonyHorse.java @@ -33,13 +33,19 @@ import mage.abilities.Ability; import mage.abilities.common.SimpleActivatedAbility; import mage.abilities.costs.common.TapSourceCost; import mage.abilities.costs.mana.GenericManaCost; -import mage.abilities.effects.common.*; +import mage.abilities.effects.Effect; +import mage.abilities.effects.common.PreventCombatDamageBySourceEffect; +import mage.abilities.effects.common.PreventCombatDamageToSourceEffect; +import mage.abilities.effects.common.UntapTargetEffect; import mage.cards.CardImpl; -import mage.constants.*; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.Rarity; +import mage.constants.TargetController; +import mage.constants.Zone; import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.permanent.AttackingPredicate; import mage.filter.predicate.permanent.ControllerPredicate; -import mage.target.Target; import mage.target.common.TargetCreaturePermanent; /** @@ -61,10 +67,13 @@ public class EbonyHorse extends CardImpl { // {2}, {tap}: Untap target attacking creature you control. Prevent all combat damage that would be dealt to and dealt by that creature this turn. Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new UntapTargetEffect(), new GenericManaCost(2)); ability.addCost(new TapSourceCost()); - ability.addEffect(new PreventCombatDamageToSourceEffect(Duration.EndOfTurn)); - ability.addEffect(new PreventCombatDamageBySourceEffect(Duration.EndOfTurn)); - Target target = new TargetCreaturePermanent(filter); - ability.addTarget(target); + Effect effect = new PreventCombatDamageToSourceEffect(Duration.EndOfTurn); + effect.setText("Prevent all combat damage that would be dealt to"); + ability.addEffect(effect); + effect = new PreventCombatDamageBySourceEffect(Duration.EndOfTurn); + effect.setText("and dealt by that creature this turn"); + ability.addEffect(effect); + ability.addTarget(new TargetCreaturePermanent(filter)); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/sets/iceage/FanaticalFever.java b/Mage.Sets/src/mage/sets/iceage/FanaticalFever.java index 82ecfeef4ca..c6e4ebcab53 100644 --- a/Mage.Sets/src/mage/sets/iceage/FanaticalFever.java +++ b/Mage.Sets/src/mage/sets/iceage/FanaticalFever.java @@ -28,6 +28,7 @@ package mage.sets.iceage; import java.util.UUID; +import mage.abilities.effects.Effect; import mage.abilities.effects.common.continuous.BoostTargetEffect; import mage.abilities.effects.common.continuous.GainAbilityTargetEffect; import mage.abilities.keyword.TrampleAbility; @@ -48,8 +49,12 @@ public class FanaticalFever extends CardImpl { this.expansionSetCode = "ICE"; // Target creature gets +3/+0 and gains trample until end of turn. - this.getSpellAbility().addEffect(new BoostTargetEffect(3, 0, Duration.EndOfTurn)); - this.getSpellAbility().addEffect(new GainAbilityTargetEffect(TrampleAbility.getInstance(), Duration.EndOfTurn)); + Effect effect = new BoostTargetEffect(3, 0, Duration.EndOfTurn); + effect.setText("Target creature gets +3/+0"); + this.getSpellAbility().addEffect(effect); + effect = new GainAbilityTargetEffect(TrampleAbility.getInstance(), Duration.EndOfTurn); + effect.setText("and gains trample until end of turn"); + this.getSpellAbility().addEffect(effect); this.getSpellAbility().addTarget(new TargetCreaturePermanent()); } diff --git a/Mage.Sets/src/mage/sets/iceage/OrcishCannoneers.java b/Mage.Sets/src/mage/sets/iceage/OrcishCannoneers.java index ef0cebf67d2..644e2eeb821 100644 --- a/Mage.Sets/src/mage/sets/iceage/OrcishCannoneers.java +++ b/Mage.Sets/src/mage/sets/iceage/OrcishCannoneers.java @@ -32,6 +32,7 @@ import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.SimpleActivatedAbility; import mage.abilities.costs.common.TapSourceCost; +import mage.abilities.effects.Effect; import mage.abilities.effects.common.DamageControllerEffect; import mage.abilities.effects.common.DamageTargetEffect; import mage.cards.CardImpl; @@ -57,7 +58,9 @@ public class OrcishCannoneers extends CardImpl { // {tap}: Orcish Cannoneers deals 2 damage to target creature or player and 3 damage to you. Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new DamageTargetEffect(2), new TapSourceCost()); ability.addTarget(new TargetCreatureOrPlayer()); - ability.addEffect(new DamageControllerEffect(3)); + Effect effect = new DamageControllerEffect(3); + effect.setText("and 3 damage to you"); + ability.addEffect(effect); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/sets/iceage/SnowHound.java b/Mage.Sets/src/mage/sets/iceage/SnowHound.java index fb95474fb9c..bd828411862 100644 --- a/Mage.Sets/src/mage/sets/iceage/SnowHound.java +++ b/Mage.Sets/src/mage/sets/iceage/SnowHound.java @@ -67,11 +67,11 @@ public class SnowHound extends CardImpl { // {1}, {tap}: Return Snow Hound and target green or blue creature you control to their owner's hand. Effect effect = new ReturnToHandSourceEffect(true); - effect.setText("Return Snow Hound"); + effect.setText("Return Snow Hound"); Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, effect, new ManaCostsImpl("{1}")); ability.addCost(new TapSourceCost()); effect = new ReturnToHandTargetEffect(); - effect.setText("and green or blue creature you control to their owners' hands"); + effect.setText("and target green or blue creature you control to their owners' hands"); ability.addTarget(new TargetControlledCreaturePermanent(filter)); ability.addEffect(effect); this.addAbility(ability); diff --git a/Mage.Sets/src/mage/sets/masterseditionii/TimeBomb.java b/Mage.Sets/src/mage/sets/masterseditionii/TimeBomb.java index d71d59a7ea7..1777a4ad542 100644 --- a/Mage.Sets/src/mage/sets/masterseditionii/TimeBomb.java +++ b/Mage.Sets/src/mage/sets/masterseditionii/TimeBomb.java @@ -35,6 +35,7 @@ import mage.abilities.costs.common.SacrificeSourceCost; import mage.abilities.costs.common.TapSourceCost; import mage.abilities.costs.mana.GenericManaCost; import mage.abilities.dynamicvalue.common.CountersCount; +import mage.abilities.effects.Effect; import mage.abilities.effects.common.DamageEverythingEffect; import mage.abilities.effects.common.counter.AddCountersSourceEffect; import mage.cards.CardImpl; @@ -59,9 +60,9 @@ public class TimeBomb extends CardImpl { this.addAbility(new BeginningOfUpkeepTriggeredAbility(new AddCountersSourceEffect(CounterType.TIME.createInstance(), true), TargetController.YOU, false)); // {1}, {tap}, Sacrifice Time Bomb: Time Bomb deals damage equal to the number of time counters on it to each creature and each player. - Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, - new DamageEverythingEffect(new CountersCount(CounterType.TIME), new FilterCreaturePermanent()), - new GenericManaCost(1)); + Effect effect = new DamageEverythingEffect(new CountersCount(CounterType.TIME), new FilterCreaturePermanent()); + effect.setText("{this} deals damage equal to the number of time counters on it to each creature and each player"); + Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, effect, new GenericManaCost(1)); ability.addCost(new TapSourceCost()); ability.addCost(new SacrificeSourceCost()); this.addAbility(ability); From d58288da6de565882c9045cae8afa731578c2222 Mon Sep 17 00:00:00 2001 From: LevelX2 Date: Tue, 20 Oct 2015 17:16:13 +0200 Subject: [PATCH 189/268] Some changes to RedirectionEffect class. Fixed that Harm's Way and Shaman en-Kor prevented the damage instead of only redirecting the damage. --- .../src/mage/sets/fatereforged/WildSlash.java | 8 +- .../src/mage/sets/magic2010/HarmsWay.java | 101 +++++-------- .../src/mage/sets/stronghold/NomadsEnKor.java | 2 +- .../src/mage/sets/stronghold/ShamanEnKor.java | 139 +++++------------- .../HarmsWayRedirectDamageTest.java | 53 ++++++- .../replacement/redirect/ShamenEnKorTest.java | 94 ++++++++++++ .../abilities/effects/RedirectionEffect.java | 75 +++++++--- 7 files changed, 272 insertions(+), 200 deletions(-) rename Mage.Tests/src/test/java/org/mage/test/cards/replacement/{prevent => redirect}/HarmsWayRedirectDamageTest.java (57%) create mode 100644 Mage.Tests/src/test/java/org/mage/test/cards/replacement/redirect/ShamenEnKorTest.java diff --git a/Mage.Sets/src/mage/sets/fatereforged/WildSlash.java b/Mage.Sets/src/mage/sets/fatereforged/WildSlash.java index 054006c589f..b2e5a665275 100644 --- a/Mage.Sets/src/mage/sets/fatereforged/WildSlash.java +++ b/Mage.Sets/src/mage/sets/fatereforged/WildSlash.java @@ -29,7 +29,6 @@ package mage.sets.fatereforged; import java.util.UUID; import mage.abilities.Ability; -import mage.abilities.common.SimpleStaticAbility; import mage.abilities.condition.LockedInCondition; import mage.abilities.condition.common.FerociousCondition; import mage.abilities.decorator.ConditionalContinuousRuleModifyingEffect; @@ -41,7 +40,6 @@ import mage.constants.CardType; import mage.constants.Duration; import mage.constants.Outcome; import mage.constants.Rarity; -import mage.constants.Zone; import mage.game.Game; import mage.game.events.GameEvent; import mage.target.common.TargetCreatureOrPlayer; @@ -60,12 +58,12 @@ public class WildSlash extends CardImpl { ContinuousRuleModifyingEffect effect = new DamageCantBePreventedEffect(); effect.setText("Ferocious — If you control a creature with power 4 or greater, damage can't be prevented this turn.
"); this.getSpellAbility().addEffect(new ConditionalContinuousRuleModifyingEffect(effect, - new LockedInCondition(FerociousCondition.getInstance()))); - + new LockedInCondition(FerociousCondition.getInstance()))); + // Wild Slash deals 2 damage to target creature or player. this.getSpellAbility().addEffect(new DamageTargetEffect(2)); this.getSpellAbility().addTarget(new TargetCreatureOrPlayer()); - + } public WildSlash(final WildSlash card) { diff --git a/Mage.Sets/src/mage/sets/magic2010/HarmsWay.java b/Mage.Sets/src/mage/sets/magic2010/HarmsWay.java index 12a58405a48..11cf5c7c68a 100644 --- a/Mage.Sets/src/mage/sets/magic2010/HarmsWay.java +++ b/Mage.Sets/src/mage/sets/magic2010/HarmsWay.java @@ -30,8 +30,7 @@ package mage.sets.magic2010; import java.util.UUID; import mage.MageObject; import mage.abilities.Ability; -import mage.abilities.effects.PreventionEffectData; -import mage.abilities.effects.PreventionEffectImpl; +import mage.abilities.effects.RedirectionEffect; import mage.cards.CardImpl; import mage.constants.CardType; import mage.constants.Duration; @@ -69,91 +68,65 @@ public class HarmsWay extends CardImpl { } } -class HarmsWayPreventDamageTargetEffect extends PreventionEffectImpl { - - private final TargetSource target; - +class HarmsWayPreventDamageTargetEffect extends RedirectionEffect { + + private final TargetSource damageSource; + public HarmsWayPreventDamageTargetEffect() { - super(Duration.EndOfTurn, 2, false, true); + super(Duration.EndOfTurn, 2, true); staticText = "The next 2 damage that a source of your choice would deal to you and/or permanents you control this turn is dealt to target creature or player instead"; - this.target = new TargetSource(); + this.damageSource = new TargetSource(); } public HarmsWayPreventDamageTargetEffect(final HarmsWayPreventDamageTargetEffect effect) { super(effect); - this.target = effect.target.copy(); + this.damageSource = effect.damageSource.copy(); } @Override public HarmsWayPreventDamageTargetEffect copy() { return new HarmsWayPreventDamageTargetEffect(this); } - + @Override public void init(Ability source, Game game) { - this.target.choose(Outcome.PreventDamage, source.getControllerId(), source.getSourceId(), game); + this.damageSource.choose(Outcome.PreventDamage, source.getControllerId(), source.getSourceId(), game); super.init(source, game); } @Override - public boolean replaceEvent(GameEvent event, Ability source, Game game) { - PreventionEffectData preventionData = preventDamageAction(event, source, game); - // deal damage now - if (preventionData.getPreventedDamage() > 0) { - UUID redirectTo = source.getFirstTarget(); - Permanent permanent = game.getPermanent(redirectTo); - if (permanent != null) { - game.informPlayers("Dealing " + preventionData.getPreventedDamage() + " to " + permanent.getLogName() + " instead"); - // keep the original source id as it is redirecting - permanent.damage(preventionData.getPreventedDamage(), event.getSourceId(), game, false, true); - discard(); - } - Player player = game.getPlayer(redirectTo); - if (player != null) { - game.informPlayers("Dealing " + preventionData.getPreventedDamage() + " to " + player.getLogName() + " instead"); - // keep the original source id as it is redirecting - player.damage(preventionData.getPreventedDamage(), event.getSourceId(), game, false, true); - discard(); + public boolean applies(GameEvent event, Ability source, Game game) { + // check source + MageObject object = game.getObject(event.getSourceId()); + if (object == null) { + game.informPlayers("Couldn't find source of damage"); + return false; + } + + if (!object.getId().equals(damageSource.getFirstTarget()) + && (!(object instanceof Spell) || !((Spell) object).getSourceId().equals(damageSource.getFirstTarget()))) { + return false; + } + this.redirectTarget = source.getTargets().get(0); + + // check target + // check permanent first + Permanent permanent = game.getPermanent(event.getTargetId()); + if (permanent != null) { + if (permanent.getControllerId().equals(source.getControllerId())) { + // it's your permanent + return true; } } - return false; - } - - @Override - public boolean applies(GameEvent event, Ability source, Game game) { - if (super.applies(event, source, game)) { - // check source - MageObject object = game.getObject(event.getSourceId()); - if (object == null) { - game.informPlayers("Couldn't find source of damage"); - return false; - } - - if (!object.getId().equals(target.getFirstTarget()) - && (!(object instanceof Spell) || !((Spell) object).getSourceId().equals(target.getFirstTarget()))) { - return false; - } - - // check target - // check permanent first - Permanent permanent = game.getPermanent(event.getTargetId()); - if (permanent != null) { - if (permanent.getControllerId().equals(source.getControllerId())) { - // it's your permanent - return true; - } - } - // check player - Player player = game.getPlayer(event.getTargetId()); - if (player != null) { - if (player.getId().equals(source.getControllerId())) { - // it is you - return true; - } + // check player + Player player = game.getPlayer(event.getTargetId()); + if (player != null) { + if (player.getId().equals(source.getControllerId())) { + // it is you + return true; } } return false; } } - diff --git a/Mage.Sets/src/mage/sets/stronghold/NomadsEnKor.java b/Mage.Sets/src/mage/sets/stronghold/NomadsEnKor.java index 2c2bf9a230f..c1dbfdd8b84 100644 --- a/Mage.Sets/src/mage/sets/stronghold/NomadsEnKor.java +++ b/Mage.Sets/src/mage/sets/stronghold/NomadsEnKor.java @@ -55,7 +55,7 @@ public class NomadsEnKor extends CardImpl { this.toughness = new MageInt(1); // {0}: The next 1 damage that would be dealt to Nomads en-Kor this turn is dealt to target creature you control instead. - Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new ShamanEnKorPreventionEffect(), new GenericManaCost(0)); + Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new ShamanEnKorRedirectFromItselfEffect(), new GenericManaCost(0)); ability.addTarget(new TargetControlledCreaturePermanent()); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/sets/stronghold/ShamanEnKor.java b/Mage.Sets/src/mage/sets/stronghold/ShamanEnKor.java index 97c5d5349e0..0bac73f71d5 100644 --- a/Mage.Sets/src/mage/sets/stronghold/ShamanEnKor.java +++ b/Mage.Sets/src/mage/sets/stronghold/ShamanEnKor.java @@ -29,14 +29,12 @@ package mage.sets.stronghold; import java.util.UUID; import mage.MageInt; -import mage.MageObject; +import mage.MageObjectReference; import mage.abilities.Ability; import mage.abilities.common.SimpleActivatedAbility; import mage.abilities.costs.mana.GenericManaCost; import mage.abilities.costs.mana.ManaCostsImpl; -import mage.abilities.effects.PreventionEffectData; -import mage.abilities.effects.PreventionEffectImpl; -import mage.abilities.effects.ReplacementEffectImpl; +import mage.abilities.effects.RedirectionEffect; import mage.cards.CardImpl; import mage.constants.CardType; import mage.constants.Duration; @@ -44,11 +42,10 @@ import mage.constants.Outcome; import mage.constants.Rarity; import mage.constants.Zone; import mage.game.Game; -import mage.game.events.DamageEvent; import mage.game.events.GameEvent; import mage.game.events.GameEvent.EventType; -import mage.game.permanent.Permanent; import mage.players.Player; +import mage.target.TargetPermanent; import mage.target.TargetSource; import mage.target.common.TargetControlledCreaturePermanent; import mage.target.common.TargetCreaturePermanent; @@ -70,12 +67,12 @@ public class ShamanEnKor extends CardImpl { this.toughness = new MageInt(2); // {0}: The next 1 damage that would be dealt to Shaman en-Kor this turn is dealt to target creature you control instead. - Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new ShamanEnKorPreventionEffect(), new GenericManaCost(0)); + Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new ShamanEnKorRedirectFromItselfEffect(), new GenericManaCost(0)); ability.addTarget(new TargetControlledCreaturePermanent()); this.addAbility(ability); - + // {1}{W}: The next time a source of your choice would deal damage to target creature this turn, that damage is dealt to Shaman en-Kor instead. - ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new ShamanEnKorReplacementEffect(), new ManaCostsImpl("{1}{W}")); + ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new ShamanEnKorRedirectFromTargetEffect(), new ManaCostsImpl("{1}{W}")); ability.addTarget(new TargetCreaturePermanent()); this.addAbility(ability); } @@ -90,129 +87,69 @@ public class ShamanEnKor extends CardImpl { } } -class ShamanEnKorPreventionEffect extends PreventionEffectImpl { - - ShamanEnKorPreventionEffect() { - super(Duration.EndOfTurn, 1, false); +class ShamanEnKorRedirectFromItselfEffect extends RedirectionEffect { + + ShamanEnKorRedirectFromItselfEffect() { + super(Duration.EndOfTurn, 1, true); staticText = "The next 1 damage that would be dealt to {this} this turn is dealt to target creature you control instead."; } - - ShamanEnKorPreventionEffect(final ShamanEnKorPreventionEffect effect) { + + ShamanEnKorRedirectFromItselfEffect(final ShamanEnKorRedirectFromItselfEffect effect) { super(effect); } - + @Override - public ShamanEnKorPreventionEffect copy() { - return new ShamanEnKorPreventionEffect(this); + public ShamanEnKorRedirectFromItselfEffect copy() { + return new ShamanEnKorRedirectFromItselfEffect(this); } - - @Override - public boolean replaceEvent(GameEvent event, Ability source, Game game) { - PreventionEffectData preventionResult = preventDamageAction(event, source, game); - if (preventionResult.getPreventedDamage() > 0) { - Permanent redirectTo = game.getPermanent(getTargetPointer().getFirst(game, source)); - if (redirectTo != null) { - game.informPlayers("Dealing " + preventionResult.getPreventedDamage() + " to " + redirectTo.getName() + " instead."); - DamageEvent damageEvent = (DamageEvent) event; - redirectTo.damage(preventionResult.getPreventedDamage(), event.getSourceId(), game, damageEvent.isCombatDamage(), damageEvent.isPreventable(), event.getAppliedEffects()); - } - } - return false; - } - + @Override public boolean applies(GameEvent event, Ability source, Game game) { - if (!this.used && super.applies(event, source, game)) { - if (event.getTargetId().equals(source.getSourceId())) { - return game.getPermanent(getTargetPointer().getFirst(game, source)) != null; - } + if (event.getTargetId().equals(source.getSourceId())) { + this.redirectTarget = source.getTargets().get(0); + return true; } return false; } } -class ShamanEnKorReplacementEffect extends ReplacementEffectImpl { - - protected TargetSource targetSource; +class ShamanEnKorRedirectFromTargetEffect extends RedirectionEffect { - ShamanEnKorReplacementEffect() { - super(Duration.EndOfTurn, Outcome.RedirectDamage); + protected MageObjectReference sourceObject; + + ShamanEnKorRedirectFromTargetEffect() { + super(Duration.EndOfTurn, Integer.MAX_VALUE, true); staticText = "The next time a source of your choice would deal damage to target creature this turn, that damage is dealt to {this} instead"; } - ShamanEnKorReplacementEffect(final ShamanEnKorReplacementEffect effect) { + ShamanEnKorRedirectFromTargetEffect(final ShamanEnKorRedirectFromTargetEffect effect) { super(effect); - targetSource = effect.targetSource; + sourceObject = effect.sourceObject; } @Override public void init(Ability source, Game game) { Player player = game.getPlayer(source.getControllerId()); - TargetSource target = new TargetSource(); - target.setNotTarget(true); if (player != null) { + TargetSource target = new TargetSource(); target.choose(Outcome.PreventDamage, player.getId(), source.getSourceId(), game); - this.targetSource = target; + this.sourceObject = new MageObjectReference(target.getFirstTarget(), game); + } else { + discard(); } } - + @Override public boolean checksEventType(GameEvent event, Game game) { return event.getType() == EventType.DAMAGE_CREATURE; } - - @Override - public boolean applies(GameEvent event, Ability source, Game game) { - if (!this.used) { - if (targetSource != null) { - if (event.getSourceId().equals(targetSource.getFirstTarget())) { - // check source - MageObject object = game.getObject(event.getSourceId()); - if (object == null) { - game.informPlayers("Couldn't find source of damage"); - return false; - } - else { - if (event.getTargetId().equals(source.getFirstTarget())) { - Permanent permanent = game.getPermanent(source.getFirstTarget()); - if (permanent != null) { - return true; - } - } - } - } - } - } - return false; - } @Override - public boolean replaceEvent(GameEvent event, Ability source, Game game) { - DamageEvent damageEvent = (DamageEvent)event; - Permanent sourcePermanent = game.getPermanent(source.getSourceId()); - if (sourcePermanent != null) { - // get name of old target - Permanent targetPermanent = game.getPermanent(event.getTargetId()); - StringBuilder message = new StringBuilder(); - message.append(sourcePermanent.getName()).append(": gets "); - message.append(damageEvent.getAmount()).append(" damage redirected from "); - if (targetPermanent != null) { - message.append(targetPermanent.getName()); - } - else { - Player targetPlayer = game.getPlayer(event.getTargetId()); - if (targetPlayer != null) { - message.append(targetPlayer.getLogName()); - } - else { - message.append("unknown"); - } - } - game.informPlayers(message.toString()); - // redirect damage - this.used = true; - sourcePermanent.damage(damageEvent.getAmount(), damageEvent.getSourceId(), game, damageEvent.isCombatDamage(), damageEvent.isPreventable(), event.getAppliedEffects()); - return true; + public boolean applies(GameEvent event, Ability source, Game game) { + if (sourceObject.equals(new MageObjectReference(event.getSourceId(), game))) { + redirectTarget = new TargetPermanent(); + redirectTarget.add(source.getSourceId(), game); + return event.getTargetId().equals(getTargetPointer().getFirst(game, source)); } return false; } @@ -223,7 +160,7 @@ class ShamanEnKorReplacementEffect extends ReplacementEffectImpl { } @Override - public ShamanEnKorReplacementEffect copy() { - return new ShamanEnKorReplacementEffect(this); + public ShamanEnKorRedirectFromTargetEffect copy() { + return new ShamanEnKorRedirectFromTargetEffect(this); } } diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/replacement/prevent/HarmsWayRedirectDamageTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/replacement/redirect/HarmsWayRedirectDamageTest.java similarity index 57% rename from Mage.Tests/src/test/java/org/mage/test/cards/replacement/prevent/HarmsWayRedirectDamageTest.java rename to Mage.Tests/src/test/java/org/mage/test/cards/replacement/redirect/HarmsWayRedirectDamageTest.java index f609e5ed8e8..7f7508a5ab6 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/replacement/prevent/HarmsWayRedirectDamageTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/replacement/redirect/HarmsWayRedirectDamageTest.java @@ -1,4 +1,4 @@ -package org.mage.test.cards.replacement.prevent; +package org.mage.test.cards.replacement.redirect; import mage.constants.PhaseStep; import mage.constants.Zone; @@ -6,15 +6,17 @@ import org.junit.Test; import org.mage.test.serverside.base.CardTestPlayerBase; /** - * Harm's Way: - * The next 2 damage that a source of your choice would deal to you and/or permanents you control this turn is dealt to target creature or player instead. + * Harm's Way: The next 2 damage that a source of your choice would deal to you + * and/or permanents you control this turn is dealt to target creature or player + * instead. * * @author noxx */ public class HarmsWayRedirectDamageTest extends CardTestPlayerBase { /** - * Tests that 2 of 3 damage is redirected while 1 damage is still dealt to original target + * Tests that 2 of 3 damage is redirected while 1 damage is still dealt to + * original target */ @Test public void testRedirectTwoDamage() { @@ -51,7 +53,7 @@ public class HarmsWayRedirectDamageTest extends CardTestPlayerBase { attack(2, playerB, "Craw Wurm"); castSpell(2, PhaseStep.DECLARE_BLOCKERS, playerA, "Harm's Way", playerB); setChoice(playerA, "Craw Wurm"); - + setStopAt(2, PhaseStep.END_TURN); execute(); @@ -79,8 +81,11 @@ public class HarmsWayRedirectDamageTest extends CardTestPlayerBase { addCard(Zone.BATTLEFIELD, playerB, "Magma Phoenix"); castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Harm's Way", playerB); - setChoice(playerA, "Magma Phoenix"); - /** When Magma Phoenix dies, Magma Phoenix deals 3 damage to each creature and each player **/ + setChoice(playerA, "Magma Phoenix"); + /** + * When Magma Phoenix dies, Magma Phoenix deals 3 damage to each + * creature and each player * + */ castSpell(1, PhaseStep.POSTCOMBAT_MAIN, playerA, "Lightning Bolt", "Magma Phoenix"); setStopAt(1, PhaseStep.POSTCOMBAT_MAIN); @@ -91,4 +96,38 @@ public class HarmsWayRedirectDamageTest extends CardTestPlayerBase { assertLife(playerB, 15); // 3 damage from dying Phoenix directly and 2 redirected damage from playerA } + /** + * Tests that not preventable damage is redirected + */ + @Test + public void testRedirectNotPreventableDamage() { + addCard(Zone.BATTLEFIELD, playerA, "Mountain"); + // Ferocious If you control a creature with power 4 or greater, damage can't be prevented this turn. + // Wild Slash deals 2 damage to target creature or player. + addCard(Zone.HAND, playerA, "Wild Slash"); // {R} + addCard(Zone.BATTLEFIELD, playerA, "Serra Angel"); + addCard(Zone.BATTLEFIELD, playerA, "Silvercoat Lion"); + + // The next 2 damage that a source of your choice would deal to you and/or permanents + // you control this turn is dealt to target creature or player instead. + addCard(Zone.HAND, playerB, "Harm's Way"); // {W} + addCard(Zone.BATTLEFIELD, playerB, "Plains"); + addCard(Zone.BATTLEFIELD, playerB, "Birds of Paradise"); + + // the 2 damage can't be prevented and have to be redirected to Silvercoat Lion of player A + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Wild Slash", "Birds of Paradise"); + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerB, "Harm's Way", "Silvercoat Lion", "Wild Slash"); + setChoice(playerB, "Wild Slash"); + + setStopAt(1, PhaseStep.BEGIN_COMBAT); + execute(); + + assertGraveyardCount(playerA, "Wild Slash", 1); + assertGraveyardCount(playerB, "Harm's Way", 1); + assertPermanentCount(playerB, "Birds of Paradise", 1); + assertGraveyardCount(playerA, "Silvercoat Lion", 1); + assertLife(playerA, 20); + assertLife(playerB, 20); + } + } diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/replacement/redirect/ShamenEnKorTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/replacement/redirect/ShamenEnKorTest.java new file mode 100644 index 00000000000..a8ffe681e75 --- /dev/null +++ b/Mage.Tests/src/test/java/org/mage/test/cards/replacement/redirect/ShamenEnKorTest.java @@ -0,0 +1,94 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package org.mage.test.cards.replacement.redirect; + +import mage.constants.PhaseStep; +import mage.constants.Zone; +import org.junit.Test; +import org.mage.test.serverside.base.CardTestPlayerBase; + +/** + * + * @author LevelX2 + */ +public class ShamenEnKorTest extends CardTestPlayerBase { + + /** + * Tests that 2 of 3 damage is redirected while 1 damage is still dealt to + * original target + */ + @Test + public void testFirstAbilityNonCombatDamage() { + addCard(Zone.HAND, playerA, "Lightning Bolt"); + addCard(Zone.BATTLEFIELD, playerA, "Mountain"); + + // {0}: The next 1 damage that would be dealt to Shaman en-Kor this turn is dealt to target creature you control instead. + // {1}{W}: The next time a source of your choice would deal damage to target creature this turn, that damage is dealt to Shaman en-Kor instead. + addCard(Zone.BATTLEFIELD, playerB, "Shaman en-Kor"); // 1/2 + addCard(Zone.BATTLEFIELD, playerB, "Silvercoat Lion"); // 2/2 + + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Lightning Bolt", "Shaman en-Kor"); + + activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerB, "{0}: The next 1 damage", "Silvercoat Lion", "Lightning Bolt"); + activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerB, "{0}: The next 1 damage", "Silvercoat Lion", "Lightning Bolt"); + + setStopAt(1, PhaseStep.BEGIN_COMBAT); + execute(); + + assertGraveyardCount(playerA, "Lightning Bolt", 1); + assertPermanentCount(playerB, "Shaman en-Kor", 1); + assertGraveyardCount(playerB, "Silvercoat Lion", 1); + + } + + @Test + public void testSecondAbilityNonCombatDamage() { + addCard(Zone.HAND, playerA, "Lightning Bolt"); + addCard(Zone.BATTLEFIELD, playerA, "Mountain"); + + // {0}: The next 1 damage that would be dealt to Shaman en-Kor this turn is dealt to target creature you control instead. + // {1}{W}: The next time a source of your choice would deal damage to target creature this turn, that damage is dealt to Shaman en-Kor instead. + addCard(Zone.BATTLEFIELD, playerB, "Shaman en-Kor"); // 1/2 + addCard(Zone.BATTLEFIELD, playerB, "Plains", 2); + addCard(Zone.BATTLEFIELD, playerB, "Silvercoat Lion"); // 2/2 + + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Lightning Bolt", "Silvercoat Lion"); + + activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerB, "{1}{W}: The next time", "Silvercoat Lion", "Lightning Bolt"); + setChoice(playerB, "Lightning Bolt"); + + setStopAt(1, PhaseStep.BEGIN_COMBAT); + execute(); + + assertGraveyardCount(playerA, "Lightning Bolt", 1); + assertPermanentCount(playerB, "Silvercoat Lion", 1); + assertGraveyardCount(playerB, "Shaman en-Kor", 1); + + } + +} diff --git a/Mage/src/mage/abilities/effects/RedirectionEffect.java b/Mage/src/mage/abilities/effects/RedirectionEffect.java index 6c339460edf..b30400e656e 100644 --- a/Mage/src/mage/abilities/effects/RedirectionEffect.java +++ b/Mage/src/mage/abilities/effects/RedirectionEffect.java @@ -1,16 +1,16 @@ /* * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. - * + * * Redistribution and use in source and binary forms, with or without modification, are * permitted provided that the following conditions are met: - * + * * 1. Redistributions of source code must retain the above copyright notice, this list of * conditions and the following disclaimer. - * + * * 2. Redistributions in binary form must reproduce the above copyright notice, this list * of conditions and the following disclaimer in the documentation and/or other materials * provided with the distribution. - * + * * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR @@ -20,14 +20,14 @@ * 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; +import mage.MageObject; import mage.abilities.Ability; import mage.constants.Duration; import mage.constants.EffectType; @@ -46,36 +46,67 @@ import mage.target.Target; public abstract class RedirectionEffect extends ReplacementEffectImpl { protected Target redirectTarget; + protected int amountToRedirect; + protected boolean oneUsage; public RedirectionEffect(Duration duration) { + this(duration, Integer.MAX_VALUE, false); + } + + public RedirectionEffect(Duration duration, int amountToRedirect, boolean oneUsage) { super(duration, Outcome.RedirectDamage); this.effectType = EffectType.REDIRECTION; + this.amountToRedirect = amountToRedirect; + this.oneUsage = oneUsage; } public RedirectionEffect(final RedirectionEffect effect) { super(effect); this.redirectTarget = effect.redirectTarget; + this.amountToRedirect = effect.amountToRedirect; + this.oneUsage = effect.oneUsage; } @Override - public boolean apply(Game game, Ability source) { - return true; - } - - @Override - public boolean replaceEvent(GameEvent event, Ability source, Game game) { - DamageEvent damageEvent = (DamageEvent)event; - Permanent permanent = game.getPermanent(redirectTarget.getFirstTarget()); - if (permanent != null) { - permanent.damage(damageEvent.getAmount(), event.getSourceId(), game, damageEvent.isCombatDamage(), damageEvent.isPreventable(), event.getAppliedEffects()); - return true; - } - Player player = game.getPlayer(redirectTarget.getFirstTarget()); - if (player != null) { - player.damage(damageEvent.getAmount(), event.getSourceId(), game, damageEvent.isCombatDamage(), damageEvent.isPreventable(), event.getAppliedEffects()); - return true; + public boolean checksEventType(GameEvent event, Game game) { + switch (event.getType()) { + case DAMAGE_CREATURE: + case DAMAGE_PLAYER: + case DAMAGE_PLANESWALKER: + return true; } return false; } + @Override + public boolean replaceEvent(GameEvent event, Ability source, Game game) { + MageObject sourceObject = game.getObject(source.getSourceId()); + DamageEvent damageEvent = (DamageEvent) event; + int restDamage = 0; + int damageToRedirect = event.getAmount(); + if (damageEvent.getAmount() > amountToRedirect) { + restDamage = damageEvent.getAmount() - amountToRedirect; + damageToRedirect = amountToRedirect; + } + if (damageToRedirect > 0 && oneUsage) { + this.discard(); + } + Permanent permanent = game.getPermanent(redirectTarget.getFirstTarget()); + if (permanent != null) { + permanent.damage(damageToRedirect, event.getSourceId(), game, damageEvent.isCombatDamage(), damageEvent.isPreventable(), event.getAppliedEffects()); + game.informPlayers(sourceObject.getLogName() + ": Redirected " + damageToRedirect + " damage to " + permanent.getLogName()); + } else { + Player player = game.getPlayer(redirectTarget.getFirstTarget()); + if (player != null) { + player.damage(damageToRedirect, event.getSourceId(), game, damageEvent.isCombatDamage(), damageEvent.isPreventable(), event.getAppliedEffects()); + game.informPlayers(sourceObject.getLogName() + ": Redirected " + damageToRedirect + " damage to " + player.getLogName()); + } + } + if (restDamage > 0) { + damageEvent.setAmount(restDamage); + return false; + } + return true; + } + } From bf2992fc42a3181b753d8b5c0b19f1fc062a09a3 Mon Sep 17 00:00:00 2001 From: fireshoes Date: Tue, 20 Oct 2015 14:52:39 -0500 Subject: [PATCH 190/268] Added Commander 2015 set; added Eternal Witness and Kalemne, Disciple of Iroas cards to C15. --- .../dl/sources/MagicCardsImageSource.java | 1 + .../dl/sources/WizardCardsImageSource.java | 1 + .../src/main/resources/image.url.properties | 4 +- Mage.Sets/src/mage/sets/Commander2015.java | 52 +++++++ .../sets/commander2015/EternalWitness.java | 52 +++++++ .../commander2015/KalemneDiscipleOfIroas.java | 129 ++++++++++++++++++ Mage/src/mage/counters/CounterType.java | 1 + Utils/known-sets.txt | 1 + Utils/mtg-cards-data.txt | 2 + Utils/mtg-sets-data.txt | 1 + 10 files changed, 242 insertions(+), 2 deletions(-) create mode 100644 Mage.Sets/src/mage/sets/Commander2015.java create mode 100644 Mage.Sets/src/mage/sets/commander2015/EternalWitness.java create mode 100644 Mage.Sets/src/mage/sets/commander2015/KalemneDiscipleOfIroas.java diff --git a/Mage.Client/src/main/java/org/mage/plugins/card/dl/sources/MagicCardsImageSource.java b/Mage.Client/src/main/java/org/mage/plugins/card/dl/sources/MagicCardsImageSource.java index 23c02863284..68877f48eb8 100644 --- a/Mage.Client/src/main/java/org/mage/plugins/card/dl/sources/MagicCardsImageSource.java +++ b/Mage.Client/src/main/java/org/mage/plugins/card/dl/sources/MagicCardsImageSource.java @@ -16,6 +16,7 @@ public class MagicCardsImageSource implements CardImageSource { private static final Map setNameTokenReplacement = new HashMap() { { + put("C15", "commander-2015"); put("ORG", "oath-of-the-gatewatch"); put("EXP", "zendikar-expeditions"); put("BFZ", "battle-for-zendikar"); diff --git a/Mage.Client/src/main/java/org/mage/plugins/card/dl/sources/WizardCardsImageSource.java b/Mage.Client/src/main/java/org/mage/plugins/card/dl/sources/WizardCardsImageSource.java index 3e1ed8c95b3..9a1c93babe8 100644 --- a/Mage.Client/src/main/java/org/mage/plugins/card/dl/sources/WizardCardsImageSource.java +++ b/Mage.Client/src/main/java/org/mage/plugins/card/dl/sources/WizardCardsImageSource.java @@ -99,6 +99,7 @@ public class WizardCardsImageSource implements CardImageSource { setsAliases.put("BTD", "Beatdown Box Set"); setsAliases.put("C13", "Commander 2013 Edition"); setsAliases.put("C14", "Commander 2014"); + setsAliases.put("C15", "Commander 2015"); setsAliases.put("CHK", "Champions of Kamigawa"); setsAliases.put("CHR", "Chronicles"); setsAliases.put("CMD", "Magic: The Gathering-Commander"); diff --git a/Mage.Client/src/main/resources/image.url.properties b/Mage.Client/src/main/resources/image.url.properties index fc6e7f06ec3..3617a698f38 100644 --- a/Mage.Client/src/main/resources/image.url.properties +++ b/Mage.Client/src/main/resources/image.url.properties @@ -64,6 +64,6 @@ ddd=gvl unh=uh dde=pvc # Remove setname as soon as the images can be downloaded -ignore.urls=TOK, OGW +ignore.urls=TOK, OGW, C15 # sets ordered by release time (newest goes first) -token.lookup.order=OGW,EXP,DDP,BFZ,FVD,FVE,FVL,FVR,V12,V13,V14,V15,TPR,MPRP,DD3,DDO,ORI,MM2,PTC,DTK,FRF,KTK,M15,VMA,CNS,JOU,BNG,THS,DDL,M14,MMA,DGM,GTC,RTR,M13,AVR,DDI,DKA,ISD,M12,NPH,MBS,SOM,M11,ROE,DDE,WWK,ZEN,M10,GVL,ARB,DVD,CFX,JVC,ALA,EVE,SHM,EVG,MOR,LRW,10E,CLS,CHK,GRC \ No newline at end of file +token.lookup.order=C15,OGW,EXP,DDP,BFZ,FVD,FVE,FVL,FVR,V12,V13,V14,V15,TPR,MPRP,DD3,DDO,ORI,MM2,PTC,DTK,FRF,KTK,M15,VMA,CNS,JOU,BNG,THS,DDL,M14,MMA,DGM,GTC,RTR,M13,AVR,DDI,DKA,ISD,M12,NPH,MBS,SOM,M11,ROE,DDE,WWK,ZEN,M10,GVL,ARB,DVD,CFX,JVC,ALA,EVE,SHM,EVG,MOR,LRW,10E,CLS,CHK,GRC \ No newline at end of file diff --git a/Mage.Sets/src/mage/sets/Commander2015.java b/Mage.Sets/src/mage/sets/Commander2015.java new file mode 100644 index 00000000000..d1069bda220 --- /dev/null +++ b/Mage.Sets/src/mage/sets/Commander2015.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; + +import java.util.GregorianCalendar; +import mage.cards.ExpansionSet; +import mage.constants.SetType; + +/** + * + * @author fireshoes + */ + +public class Commander2015 extends ExpansionSet { + + private static final Commander2015 fINSTANCE = new Commander2015(); + + public static Commander2015 getInstance() { + return fINSTANCE; + } + + private Commander2015() { + super("Commander 2015 Edition", "C15", "mage.sets.commander2015", new GregorianCalendar(2015, 11, 13).getTime(), SetType.SUPPLEMENTAL); + this.blockName = "Command Zone"; + } + +} diff --git a/Mage.Sets/src/mage/sets/commander2015/EternalWitness.java b/Mage.Sets/src/mage/sets/commander2015/EternalWitness.java new file mode 100644 index 00000000000..6d8b8f5065b --- /dev/null +++ b/Mage.Sets/src/mage/sets/commander2015/EternalWitness.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.commander2015; + +import java.util.UUID; + +/** + * + * @author fireshoes + */ +public class EternalWitness extends mage.sets.fifthdawn.EternalWitness { + + public EternalWitness(UUID ownerId) { + super(ownerId); + this.cardNumber = 183; + this.expansionSetCode = "C15"; + } + + public EternalWitness(final EternalWitness card) { + super(card); + } + + @Override + public EternalWitness copy() { + return new EternalWitness(this); + } +} diff --git a/Mage.Sets/src/mage/sets/commander2015/KalemneDiscipleOfIroas.java b/Mage.Sets/src/mage/sets/commander2015/KalemneDiscipleOfIroas.java new file mode 100644 index 00000000000..bd681bd53b1 --- /dev/null +++ b/Mage.Sets/src/mage/sets/commander2015/KalemneDiscipleOfIroas.java @@ -0,0 +1,129 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.sets.commander2015; + +import java.util.UUID; +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.common.SpellCastControllerTriggeredAbility; +import mage.abilities.dynamicvalue.DynamicValue; +import mage.abilities.effects.Effect; +import mage.abilities.effects.common.continuous.BoostSourceEffect; +import mage.abilities.effects.common.counter.AddCountersControllerEffect; +import mage.abilities.keyword.DoubleStrikeAbility; +import mage.abilities.keyword.VigilanceAbility; +import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.Rarity; +import mage.constants.Zone; +import mage.counters.CounterType; +import mage.filter.Filter; +import mage.filter.FilterSpell; +import mage.filter.predicate.mageobject.CardTypePredicate; +import mage.filter.predicate.mageobject.ConvertedManaCostPredicate; +import mage.game.Game; +import mage.players.Player; + +/** + * + * @author fireshoes + */ +public class KalemneDiscipleOfIroas extends CardImpl { + + private static final FilterSpell filterSpell = new FilterSpell("a creature spell with converted mana cost 5 or greater"); + + static { + filterSpell.add(new CardTypePredicate(CardType.CREATURE)); + filterSpell.add(new ConvertedManaCostPredicate(Filter.ComparisonType.GreaterThan, 4)); + } + + public KalemneDiscipleOfIroas(UUID ownerId) { + super(ownerId, 999, "Kalemne, Disciple of Iroas", Rarity.MYTHIC, new CardType[]{CardType.CREATURE}, "{2}{R}{W}"); + this.expansionSetCode = "C15"; + this.supertype.add("Legendary"); + this.subtype.add("Giant"); + this.subtype.add("Soldier"); + this.power = new MageInt(3); + this.toughness = new MageInt(3); + + // Double strike + this.addAbility(DoubleStrikeAbility.getInstance()); + + // Vigilance + this.addAbility(VigilanceAbility.getInstance()); + + // Whenever you cast a creature spell with converted mana cost 5 or greater, you get an experience counter. + Effect effect = new AddCountersControllerEffect(CounterType.EXPERIENCE.createInstance(1), false); + effect.setText("you get an experience counter"); + Ability ability = new SpellCastControllerTriggeredAbility(effect, filterSpell, false); + this.addAbility(ability); + + // Kalemne, Disciple of Iroas gets +1/+1 for each experience counter you have. + DynamicValue value = new SourceControllerExperienceCountersCount(); + this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new BoostSourceEffect(value, value, Duration.WhileOnBattlefield))); + } + + public KalemneDiscipleOfIroas(final KalemneDiscipleOfIroas card) { + super(card); + } + + @Override + public KalemneDiscipleOfIroas copy() { + return new KalemneDiscipleOfIroas(this); + } +} + +class SourceControllerExperienceCountersCount implements DynamicValue { + + @Override + public int calculate(Game game, Ability sourceAbility, Effect effect) { + int amount = 0; + Player player = game.getPlayer(sourceAbility.getControllerId()); + if (player != null) { + amount = player.getCounters().getCount(CounterType.EXPERIENCE); + } + return amount; + } + + @Override + public DynamicValue copy() { + return new SourceControllerExperienceCountersCount(); + } + + @Override + public String toString() { + return "1"; + } + + @Override + public String getMessage() { + return "experience counter you have"; + } +} diff --git a/Mage/src/mage/counters/CounterType.java b/Mage/src/mage/counters/CounterType.java index f7537638758..907e0cc8526 100644 --- a/Mage/src/mage/counters/CounterType.java +++ b/Mage/src/mage/counters/CounterType.java @@ -53,6 +53,7 @@ public enum CounterType { DOOM("doom"), ELIXIR("elixir"), EON("eon"), + EXPERIENCE("experience"), EYEBALL("eyeball"), FADE("fade"), FATE("fate"), diff --git a/Utils/known-sets.txt b/Utils/known-sets.txt index 9b462e003ae..a63078e0d91 100644 --- a/Utils/known-sets.txt +++ b/Utils/known-sets.txt @@ -14,6 +14,7 @@ Classic Sixth Edition|classicsixthedition| Coldsnap|coldsnap| Commander 2013 Edition|commander2013| Commander 2014 Edition|commander2014| +Commander 2015|commander2015| Conflux|conflux| Dark Ascension|darkascension| Darksteel|darksteel| diff --git a/Utils/mtg-cards-data.txt b/Utils/mtg-cards-data.txt index 9146198e3b3..5845fd2d74b 100644 --- a/Utils/mtg-cards-data.txt +++ b/Utils/mtg-cards-data.txt @@ -27631,3 +27631,5 @@ Swamp|Battle for Zendikar|262|L||Basic Land - Swamp|||({t}: Add {B} to your m Swamp|Battle for Zendikar|264|L||Basic Land - Swamp|||({t}: Add {B} to your mana pool.)| Swamp|Battle for Zendikar|260|L||Basic Land - Swamp|||({t}: Add {B} to your mana pool.)| Swamp|Battle for Zendikar|261|L||Basic Land - Swamp|||({t}: Add {B} to your mana pool.)| +Eternal Witness|Commander 2015|183|U|{1}{G}{G}|Creature - Human Shaman|2|1|When Eternal Witness enters the battlefield, you may return target card from your graveyard to your hand.| +Kalemne, Disciple of Iroas|Commander 2015|999|M|{2}{R}{W}|Legendary Creature - Giant Soldier|3|3|Double strike, vigilance$Whenever you cast a creature spell with converted mana cost 5 or greater, you get an experience counter.$Kalemne, Disciple of Iroas gets +1/+1 for each experience counter you have.| \ No newline at end of file diff --git a/Utils/mtg-sets-data.txt b/Utils/mtg-sets-data.txt index 83e479e4585..83318ee3973 100644 --- a/Utils/mtg-sets-data.txt +++ b/Utils/mtg-sets-data.txt @@ -25,6 +25,7 @@ Chronicles|CHR| Clash Pack|CLASH| Commander 2013 Edition|C13| Commander 2014 Edition|C14| +Commander 2015|C15| Conflux|CON| Coldsnap|CSP| Dark Ascension|DKA| From 701a722904ce191689ccff71cc7c0b35bcc6dc59 Mon Sep 17 00:00:00 2001 From: LevelX2 Date: Tue, 20 Oct 2015 22:58:24 +0200 Subject: [PATCH 191/268] * Fixed some redirect effect sthat were implemented as prevention effects (fixes #1216). --- .../sets/betrayersofkamigawa/WardOfPiety.java | 42 ++++------- .../sets/championsofkamigawa/VassalsDuty.java | 40 +++-------- .../sets/planechase/RaziaBorosArchangel.java | 66 +++++++---------- .../src/mage/sets/stronghold/NomadsEnKor.java | 6 +- .../src/mage/sets/stronghold/ShamanEnKor.java | 30 +------- .../sets/tempestremastered/SpiritEnKor.java | 53 ++------------ .../sets/tempestremastered/WarriorEnKor.java | 51 +------------ .../replacement/redirect/WardOfPietyTest.java | 71 +++++++++++++++++++ ...edirectDamageFromSourceToTargetEffect.java | 42 +++++++++++ 9 files changed, 176 insertions(+), 225 deletions(-) create mode 100644 Mage.Tests/src/test/java/org/mage/test/cards/replacement/redirect/WardOfPietyTest.java create mode 100644 Mage/src/mage/abilities/effects/common/RedirectDamageFromSourceToTargetEffect.java diff --git a/Mage.Sets/src/mage/sets/betrayersofkamigawa/WardOfPiety.java b/Mage.Sets/src/mage/sets/betrayersofkamigawa/WardOfPiety.java index 1edee8058ed..94b13e99c31 100644 --- a/Mage.Sets/src/mage/sets/betrayersofkamigawa/WardOfPiety.java +++ b/Mage.Sets/src/mage/sets/betrayersofkamigawa/WardOfPiety.java @@ -28,11 +28,11 @@ package mage.sets.betrayersofkamigawa; import java.util.UUID; +import mage.MageObjectReference; import mage.abilities.Ability; import mage.abilities.common.SimpleActivatedAbility; import mage.abilities.costs.mana.ManaCostsImpl; -import mage.abilities.effects.PreventionEffectData; -import mage.abilities.effects.PreventionEffectImpl; +import mage.abilities.effects.RedirectionEffect; import mage.abilities.effects.common.AttachEffect; import mage.abilities.keyword.EnchantAbility; import mage.cards.CardImpl; @@ -44,7 +44,6 @@ import mage.constants.Zone; import mage.game.Game; import mage.game.events.GameEvent; import mage.game.permanent.Permanent; -import mage.players.Player; import mage.target.TargetPermanent; import mage.target.common.TargetCreatureOrPlayer; import mage.target.common.TargetCreaturePermanent; @@ -60,7 +59,6 @@ public class WardOfPiety extends CardImpl { this.expansionSetCode = "BOK"; this.subtype.add("Aura"); - // Enchant creature TargetPermanent auraTarget = new TargetCreaturePermanent(); this.getSpellAbility().addTarget(auraTarget); @@ -84,10 +82,12 @@ public class WardOfPiety extends CardImpl { } } -class WardOfPietyPreventDamageTargetEffect extends PreventionEffectImpl { +class WardOfPietyPreventDamageTargetEffect extends RedirectionEffect { + + protected MageObjectReference redirectToObject; public WardOfPietyPreventDamageTargetEffect() { - super(Duration.EndOfTurn, 1, false, true); + super(Duration.EndOfTurn, 1, true); staticText = "The next 1 damage that would be dealt to enchanted creature this turn is dealt to target creature or player instead"; } @@ -106,35 +106,21 @@ class WardOfPietyPreventDamageTargetEffect extends PreventionEffectImpl { } @Override - public boolean replaceEvent(GameEvent event, Ability source, Game game) { - PreventionEffectData preventionData = preventDamageAction(event, source, game); - // deal damage now - if (preventionData.getPreventedDamage() > 0) { - Permanent permanent = game.getPermanent(getTargetPointer().getFirst(game, source)); - if (permanent != null) { - game.informPlayers("Dealing " + preventionData.getPreventedDamage() + " damage to " + permanent.getLogName() + " instead"); - // keep the original source id as it is redirecting - permanent.damage(preventionData.getPreventedDamage(), event.getSourceId(), game, false, true); - } - Player player = game.getPlayer(getTargetPointer().getFirst(game, source)); - if (player != null) { - game.informPlayers("Dealing " + preventionData.getPreventedDamage() + " damage to " + player.getLogName() + " instead"); - // keep the original source id as it is redirecting - player.damage(preventionData.getPreventedDamage(), event.getSourceId(), game, false, true); - } - } - return false; + public void init(Ability source, Game game) { + super.init(source, game); + redirectToObject = new MageObjectReference(source.getTargets().get(0).getFirstTarget(), game); } @Override public boolean applies(GameEvent event, Ability source, Game game) { - if (super.applies(event, source, game)) { - Permanent enchantment = game.getPermanent(source.getSourceId()); - if (enchantment != null && event.getTargetId().equals(enchantment.getAttachedTo())) { + Permanent enchantment = game.getPermanent(source.getSourceId()); + if (enchantment != null && event.getTargetId().equals(enchantment.getAttachedTo())) { + if (redirectToObject.equals(new MageObjectReference(source.getTargets().get(0).getFirstTarget(), game))) { + redirectTarget = source.getTargets().get(0); return true; } } return false; } -} \ No newline at end of file +} diff --git a/Mage.Sets/src/mage/sets/championsofkamigawa/VassalsDuty.java b/Mage.Sets/src/mage/sets/championsofkamigawa/VassalsDuty.java index 71230bc44e6..abd2d87510e 100644 --- a/Mage.Sets/src/mage/sets/championsofkamigawa/VassalsDuty.java +++ b/Mage.Sets/src/mage/sets/championsofkamigawa/VassalsDuty.java @@ -31,8 +31,7 @@ import java.util.UUID; import mage.abilities.Ability; import mage.abilities.common.SimpleActivatedAbility; import mage.abilities.costs.mana.GenericManaCost; -import mage.abilities.effects.PreventionEffectData; -import mage.abilities.effects.PreventionEffectImpl; +import mage.abilities.effects.RedirectionEffect; import mage.cards.CardImpl; import mage.constants.CardType; import mage.constants.Duration; @@ -42,8 +41,7 @@ import mage.filter.common.FilterControlledCreaturePermanent; import mage.filter.predicate.mageobject.SupertypePredicate; import mage.game.Game; import mage.game.events.GameEvent; -import mage.game.permanent.Permanent; -import mage.players.Player; +import mage.target.TargetPlayer; import mage.target.common.TargetControlledCreaturePermanent; /** @@ -53,6 +51,7 @@ import mage.target.common.TargetControlledCreaturePermanent; public class VassalsDuty extends CardImpl { private static final FilterControlledCreaturePermanent filter = new FilterControlledCreaturePermanent("legendary creature you control"); + static { filter.add(new SupertypePredicate("Legendary")); } @@ -61,10 +60,9 @@ public class VassalsDuty extends CardImpl { super(ownerId, 48, "Vassal's Duty", Rarity.RARE, new CardType[]{CardType.ENCHANTMENT}, "{3}{W}"); this.expansionSetCode = "CHK"; - // {1}: The next 1 damage that would be dealt to target legendary creature you control this turn is dealt to you instead. Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new VassalsDutyPreventDamageTargetEffect(Duration.EndOfTurn, 1), new GenericManaCost(1)); - ability.addTarget(new TargetControlledCreaturePermanent(1,1,filter, false)); + ability.addTarget(new TargetControlledCreaturePermanent(1, 1, filter, false)); this.addAbility(ability); } @@ -78,10 +76,10 @@ public class VassalsDuty extends CardImpl { } } -class VassalsDutyPreventDamageTargetEffect extends PreventionEffectImpl { +class VassalsDutyPreventDamageTargetEffect extends RedirectionEffect { public VassalsDutyPreventDamageTargetEffect(Duration duration, int amount) { - super(duration, amount, false); + super(duration, amount, true); staticText = "The next " + amount + " damage that would be dealt to target legendary creature you control this turn is dealt to you instead"; } @@ -94,29 +92,13 @@ class VassalsDutyPreventDamageTargetEffect extends PreventionEffectImpl { return new VassalsDutyPreventDamageTargetEffect(this); } - @Override - public boolean replaceEvent(GameEvent event, Ability source, Game game) { - PreventionEffectData preventionResult = preventDamageAction(event, source, game); - // deal damage now - if (preventionResult.getPreventedDamage() > 0) { - UUID redirectTo = source.getControllerId(); - Player player = game.getPlayer(redirectTo); - if (player != null) { - game.informPlayers("Dealing " + preventionResult.getPreventedDamage() + " to " + player.getLogName() + " instead"); - // keep the original source id as it is redirecting - player.damage(preventionResult.getPreventedDamage(), event.getSourceId(), game, false, true); - } - } - // damage amount is reduced or set to 0 so complete replacement of damage event is never neccessary - return false; - } - @Override public boolean applies(GameEvent event, Ability source, Game game) { - if (!this.used && super.applies(event, source, game)) { - if (event.getTargetId().equals(getTargetPointer().getFirst(game, source))) { - return game.getPermanent(event.getTargetId()) != null; - } + if (event.getTargetId().equals(getTargetPointer().getFirst(game, source))) { + TargetPlayer target = new TargetPlayer(); + target.add(source.getControllerId(), game); + redirectTarget = target; + return true; } return false; } diff --git a/Mage.Sets/src/mage/sets/planechase/RaziaBorosArchangel.java b/Mage.Sets/src/mage/sets/planechase/RaziaBorosArchangel.java index 720d19460c3..be5502dbe76 100644 --- a/Mage.Sets/src/mage/sets/planechase/RaziaBorosArchangel.java +++ b/Mage.Sets/src/mage/sets/planechase/RaziaBorosArchangel.java @@ -29,11 +29,12 @@ package mage.sets.planechase; import java.util.UUID; import mage.MageInt; +import mage.MageObjectReference; import mage.abilities.Ability; import mage.abilities.common.SimpleActivatedAbility; import mage.abilities.costs.common.TapSourceCost; import mage.abilities.effects.Effect; -import mage.abilities.effects.PreventionEffectImpl; +import mage.abilities.effects.RedirectionEffect; import mage.abilities.keyword.FlyingAbility; import mage.abilities.keyword.HasteAbility; import mage.abilities.keyword.VigilanceAbility; @@ -42,9 +43,11 @@ 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.mageobject.AnotherTargetPredicate; import mage.game.Game; import mage.game.events.GameEvent; -import mage.game.permanent.Permanent; +import mage.target.Target; import mage.target.common.TargetControlledCreaturePermanent; import mage.target.common.TargetCreaturePermanent; @@ -72,11 +75,18 @@ public class RaziaBorosArchangel extends CardImpl { // Haste this.addAbility(HasteAbility.getInstance()); - // {tap}: The next 3 damage that would be dealt to target creature you control this turn is dealt to another target creature instead. + // {T}: The next 3 damage that would be dealt to target creature you control this turn is dealt to another target creature instead. Effect effect = new RaziaBorosArchangelEffect(Duration.EndOfTurn, 3); Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, effect, new TapSourceCost()); - ability.addTarget(new TargetControlledCreaturePermanent()); - ability.addTarget(new TargetCreaturePermanent()); + Target target = new TargetControlledCreaturePermanent(); + target.setTargetTag(1); + ability.addTarget(target); + + FilterCreaturePermanent filter = new FilterCreaturePermanent("creature (damage is redirected to)"); + filter.add(new AnotherTargetPredicate(2)); + target = new TargetCreaturePermanent(filter); + target.setTargetTag(2); + ability.addTarget(target); this.addAbility(ability); } @@ -91,19 +101,17 @@ public class RaziaBorosArchangel extends CardImpl { } } -class RaziaBorosArchangelEffect extends PreventionEffectImpl { +class RaziaBorosArchangelEffect extends RedirectionEffect { - private int amount; + protected MageObjectReference redirectToObject; public RaziaBorosArchangelEffect(Duration duration, int amount) { - super(duration); - this.amount = amount; + super(duration, 3, true); staticText = "The next " + amount + " damage that would be dealt to target creature you control this turn is dealt to another target creature instead"; } public RaziaBorosArchangelEffect(final RaziaBorosArchangelEffect effect) { super(effect); - this.amount = effect.amount; } @Override @@ -117,42 +125,16 @@ class RaziaBorosArchangelEffect extends PreventionEffectImpl { } @Override - public boolean replaceEvent(GameEvent event, Ability source, Game game) { - GameEvent preventEvent = new GameEvent(GameEvent.EventType.PREVENT_DAMAGE, source.getFirstTarget(), source.getSourceId(), source.getControllerId(), event.getAmount(), false); - if (!game.replaceEvent(preventEvent)) { - int prevented; - if (event.getAmount() >= this.amount) { - int damage = amount; - event.setAmount(event.getAmount() - amount); - this.used = true; - game.fireEvent(GameEvent.getEvent(GameEvent.EventType.PREVENTED_DAMAGE, source.getFirstTarget(), source.getSourceId(), source.getControllerId(), damage)); - prevented = damage; - } else { - int damage = event.getAmount(); - event.setAmount(0); - amount -= damage; - game.fireEvent(GameEvent.getEvent(GameEvent.EventType.PREVENTED_DAMAGE, source.getFirstTarget(), source.getSourceId(), source.getControllerId(), damage)); - prevented = damage; - } - - // deal damage now - if (prevented > 0) { - UUID redirectTo = source.getTargets().get(1).getFirstTarget(); - Permanent permanent = game.getPermanent(redirectTo); - if (permanent != null) { - game.informPlayers("Dealing " + prevented + " to " + permanent.getName() + " instead"); - // keep the original source id as it is redirecting - permanent.damage(prevented, event.getSourceId(), game, false, true); - } - } - } - return false; + public void init(Ability source, Game game) { + super.init(source, game); + redirectToObject = new MageObjectReference(source.getTargets().get(1).getFirstTarget(), game); } @Override public boolean applies(GameEvent event, Ability source, Game game) { - if (!this.used && super.applies(event, source, game)) { - if (source.getTargets().getFirstTarget().equals(event.getTargetId())) { + if (event.getTargetId().equals(getTargetPointer().getFirst(game, source))) { + if (redirectToObject.equals(new MageObjectReference(source.getTargets().get(1).getFirstTarget(), game))) { + redirectTarget = source.getTargets().get(1); return true; } } diff --git a/Mage.Sets/src/mage/sets/stronghold/NomadsEnKor.java b/Mage.Sets/src/mage/sets/stronghold/NomadsEnKor.java index c1dbfdd8b84..1c3d0aa8da8 100644 --- a/Mage.Sets/src/mage/sets/stronghold/NomadsEnKor.java +++ b/Mage.Sets/src/mage/sets/stronghold/NomadsEnKor.java @@ -32,8 +32,10 @@ import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.SimpleActivatedAbility; import mage.abilities.costs.mana.GenericManaCost; +import mage.abilities.effects.common.RedirectDamageFromSourceToTargetEffect; import mage.cards.CardImpl; import mage.constants.CardType; +import mage.constants.Duration; import mage.constants.Rarity; import mage.constants.Zone; import mage.target.common.TargetControlledCreaturePermanent; @@ -55,7 +57,7 @@ public class NomadsEnKor extends CardImpl { this.toughness = new MageInt(1); // {0}: The next 1 damage that would be dealt to Nomads en-Kor this turn is dealt to target creature you control instead. - Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new ShamanEnKorRedirectFromItselfEffect(), new GenericManaCost(0)); + Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new RedirectDamageFromSourceToTargetEffect(Duration.EndOfTurn, 1, true), new GenericManaCost(0)); ability.addTarget(new TargetControlledCreaturePermanent()); this.addAbility(ability); } @@ -68,4 +70,4 @@ public class NomadsEnKor extends CardImpl { public NomadsEnKor copy() { return new NomadsEnKor(this); } -} \ No newline at end of file +} diff --git a/Mage.Sets/src/mage/sets/stronghold/ShamanEnKor.java b/Mage.Sets/src/mage/sets/stronghold/ShamanEnKor.java index 0bac73f71d5..e112c7f7821 100644 --- a/Mage.Sets/src/mage/sets/stronghold/ShamanEnKor.java +++ b/Mage.Sets/src/mage/sets/stronghold/ShamanEnKor.java @@ -35,6 +35,7 @@ import mage.abilities.common.SimpleActivatedAbility; import mage.abilities.costs.mana.GenericManaCost; import mage.abilities.costs.mana.ManaCostsImpl; import mage.abilities.effects.RedirectionEffect; +import mage.abilities.effects.common.RedirectDamageFromSourceToTargetEffect; import mage.cards.CardImpl; import mage.constants.CardType; import mage.constants.Duration; @@ -67,7 +68,8 @@ public class ShamanEnKor extends CardImpl { this.toughness = new MageInt(2); // {0}: The next 1 damage that would be dealt to Shaman en-Kor this turn is dealt to target creature you control instead. - Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new ShamanEnKorRedirectFromItselfEffect(), new GenericManaCost(0)); + Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, + new RedirectDamageFromSourceToTargetEffect(Duration.EndOfTurn, 1, true), new GenericManaCost(0)); ability.addTarget(new TargetControlledCreaturePermanent()); this.addAbility(ability); @@ -87,32 +89,6 @@ public class ShamanEnKor extends CardImpl { } } -class ShamanEnKorRedirectFromItselfEffect extends RedirectionEffect { - - ShamanEnKorRedirectFromItselfEffect() { - super(Duration.EndOfTurn, 1, true); - staticText = "The next 1 damage that would be dealt to {this} this turn is dealt to target creature you control instead."; - } - - ShamanEnKorRedirectFromItselfEffect(final ShamanEnKorRedirectFromItselfEffect effect) { - super(effect); - } - - @Override - public ShamanEnKorRedirectFromItselfEffect copy() { - return new ShamanEnKorRedirectFromItselfEffect(this); - } - - @Override - public boolean applies(GameEvent event, Ability source, Game game) { - if (event.getTargetId().equals(source.getSourceId())) { - this.redirectTarget = source.getTargets().get(0); - return true; - } - return false; - } -} - class ShamanEnKorRedirectFromTargetEffect extends RedirectionEffect { protected MageObjectReference sourceObject; diff --git a/Mage.Sets/src/mage/sets/tempestremastered/SpiritEnKor.java b/Mage.Sets/src/mage/sets/tempestremastered/SpiritEnKor.java index e07c177ea74..4b4998f4949 100644 --- a/Mage.Sets/src/mage/sets/tempestremastered/SpiritEnKor.java +++ b/Mage.Sets/src/mage/sets/tempestremastered/SpiritEnKor.java @@ -32,18 +32,13 @@ import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.SimpleActivatedAbility; import mage.abilities.costs.mana.GenericManaCost; -import mage.abilities.effects.PreventionEffectData; -import mage.abilities.effects.PreventionEffectImpl; +import mage.abilities.effects.common.RedirectDamageFromSourceToTargetEffect; import mage.abilities.keyword.FlyingAbility; import mage.cards.CardImpl; import mage.constants.CardType; import mage.constants.Duration; import mage.constants.Rarity; import mage.constants.Zone; -import mage.game.Game; -import mage.game.events.DamageEvent; -import mage.game.events.GameEvent; -import mage.game.permanent.Permanent; import mage.target.common.TargetControlledCreaturePermanent; /** @@ -62,9 +57,10 @@ public class SpiritEnKor extends CardImpl { // Flying this.addAbility(FlyingAbility.getInstance()); - + // {0}: The next 1 damage that would be dealt to Spirit en-Kor this turn is dealt to target creature you control instead. - Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new SpiritEnKorPreventionEffect(), new GenericManaCost(0)); + Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, + new RedirectDamageFromSourceToTargetEffect(Duration.EndOfTurn, 1, true), new GenericManaCost(0)); ability.addTarget(new TargetControlledCreaturePermanent()); this.addAbility(ability); } @@ -78,44 +74,3 @@ public class SpiritEnKor extends CardImpl { return new SpiritEnKor(this); } } - -class SpiritEnKorPreventionEffect extends PreventionEffectImpl { - - SpiritEnKorPreventionEffect() { - super(Duration.EndOfTurn, 1, false); - staticText = "The next 1 damage that would be dealt to {this} this turn is dealt to target creature you control instead."; - } - - SpiritEnKorPreventionEffect(final SpiritEnKorPreventionEffect effect) { - super(effect); - } - - @Override - public SpiritEnKorPreventionEffect copy() { - return new SpiritEnKorPreventionEffect(this); - } - - @Override - public boolean replaceEvent(GameEvent event, Ability source, Game game) { - PreventionEffectData preventionResult = preventDamageAction(event, source, game); - if (preventionResult.getPreventedDamage() > 0) { - Permanent redirectTo = game.getPermanent(getTargetPointer().getFirst(game, source)); - if (redirectTo != null) { - game.informPlayers("Dealing " + preventionResult.getPreventedDamage() + " to " + redirectTo.getName() + " instead."); - DamageEvent damageEvent = (DamageEvent) event; - redirectTo.damage(preventionResult.getPreventedDamage(), event.getSourceId(), game, damageEvent.isCombatDamage(), damageEvent.isPreventable(), event.getAppliedEffects()); - } - } - return false; - } - - @Override - public boolean applies(GameEvent event, Ability source, Game game) { - if (!this.used && super.applies(event, source, game)) { - if (event.getTargetId().equals(source.getSourceId())) { - return game.getPermanent(getTargetPointer().getFirst(game, source)) != null; - } - } - return false; - } -} \ No newline at end of file diff --git a/Mage.Sets/src/mage/sets/tempestremastered/WarriorEnKor.java b/Mage.Sets/src/mage/sets/tempestremastered/WarriorEnKor.java index 4d991b1b1f0..4587dbd24e6 100644 --- a/Mage.Sets/src/mage/sets/tempestremastered/WarriorEnKor.java +++ b/Mage.Sets/src/mage/sets/tempestremastered/WarriorEnKor.java @@ -32,17 +32,12 @@ import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.SimpleActivatedAbility; import mage.abilities.costs.mana.GenericManaCost; -import mage.abilities.effects.PreventionEffectData; -import mage.abilities.effects.PreventionEffectImpl; +import mage.abilities.effects.common.RedirectDamageFromSourceToTargetEffect; import mage.cards.CardImpl; import mage.constants.CardType; import mage.constants.Duration; import mage.constants.Rarity; import mage.constants.Zone; -import mage.game.Game; -import mage.game.events.DamageEvent; -import mage.game.events.GameEvent; -import mage.game.permanent.Permanent; import mage.target.common.TargetControlledCreaturePermanent; /** @@ -61,7 +56,8 @@ public class WarriorEnKor extends CardImpl { this.toughness = new MageInt(2); // {0}: The next 1 damage that would be dealt to Warrior en-Kor this turn is dealt to target creature you control instead. - Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new WarriorEnKorPreventionEffect(), new GenericManaCost(0)); + Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, + new RedirectDamageFromSourceToTargetEffect(Duration.EndOfTurn, 1, true), new GenericManaCost(0)); ability.addTarget(new TargetControlledCreaturePermanent()); this.addAbility(ability); } @@ -75,44 +71,3 @@ public class WarriorEnKor extends CardImpl { return new WarriorEnKor(this); } } - -class WarriorEnKorPreventionEffect extends PreventionEffectImpl { - - WarriorEnKorPreventionEffect() { - super(Duration.EndOfTurn, 1, false); - staticText = "The next 1 damage that would be dealt to {this} this turn is dealt to target creature you control instead."; - } - - WarriorEnKorPreventionEffect(final WarriorEnKorPreventionEffect effect) { - super(effect); - } - - @Override - public WarriorEnKorPreventionEffect copy() { - return new WarriorEnKorPreventionEffect(this); - } - - @Override - public boolean replaceEvent(GameEvent event, Ability source, Game game) { - PreventionEffectData preventionResult = preventDamageAction(event, source, game); - if (preventionResult.getPreventedDamage() > 0) { - Permanent redirectTo = game.getPermanent(getTargetPointer().getFirst(game, source)); - if (redirectTo != null) { - game.informPlayers("Dealing " + preventionResult.getPreventedDamage() + " to " + redirectTo.getName() + " instead."); - DamageEvent damageEvent = (DamageEvent) event; - redirectTo.damage(preventionResult.getPreventedDamage(), event.getSourceId(), game, damageEvent.isCombatDamage(), damageEvent.isPreventable(), event.getAppliedEffects()); - } - } - return false; - } - - @Override - public boolean applies(GameEvent event, Ability source, Game game) { - if (!this.used && super.applies(event, source, game)) { - if (event.getTargetId().equals(source.getSourceId())) { - return game.getPermanent(getTargetPointer().getFirst(game, source)) != null; - } - } - return false; - } -} \ No newline at end of file diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/replacement/redirect/WardOfPietyTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/replacement/redirect/WardOfPietyTest.java new file mode 100644 index 00000000000..17b12464d7f --- /dev/null +++ b/Mage.Tests/src/test/java/org/mage/test/cards/replacement/redirect/WardOfPietyTest.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 org.mage.test.cards.replacement.redirect; + +import mage.constants.PhaseStep; +import mage.constants.Zone; +import org.junit.Test; +import org.mage.test.serverside.base.CardTestPlayerBase; + +/** + * + * @author LevelX2 + */ +public class WardOfPietyTest extends CardTestPlayerBase { + + @Test + public void testNonCombatDamageToPlayer() { + addCard(Zone.HAND, playerB, "Lightning Bolt"); + addCard(Zone.BATTLEFIELD, playerB, "Mountain"); + + // Enchant creature + // {1}{W}: The next 1 damage that would be dealt to enchanted creature this turn is dealt to target creature or player instead. + addCard(Zone.HAND, playerA, "Ward of Piety"); // {1}{W} + addCard(Zone.BATTLEFIELD, playerA, "Silvercoat Lion"); // 2/2 + addCard(Zone.BATTLEFIELD, playerA, "Plains", 6); + + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Ward of Piety", "Silvercoat Lion"); + + activateAbility(1, PhaseStep.BEGIN_COMBAT, playerA, "{1}{W}: The next 1 damage", playerB); + activateAbility(1, PhaseStep.BEGIN_COMBAT, playerA, "{1}{W}: The next 1 damage", playerB); + + castSpell(1, PhaseStep.POSTCOMBAT_MAIN, playerB, "Lightning Bolt", "Silvercoat Lion"); + + setStopAt(1, PhaseStep.END_TURN); + execute(); + + assertGraveyardCount(playerB, "Lightning Bolt", 1); + assertPermanentCount(playerA, "Ward of Piety", 1); + assertPermanentCount(playerA, "Silvercoat Lion", 1); + + assertLife(playerA, 20); + assertLife(playerB, 18); + + } + +} diff --git a/Mage/src/mage/abilities/effects/common/RedirectDamageFromSourceToTargetEffect.java b/Mage/src/mage/abilities/effects/common/RedirectDamageFromSourceToTargetEffect.java new file mode 100644 index 00000000000..61b35d63abd --- /dev/null +++ b/Mage/src/mage/abilities/effects/common/RedirectDamageFromSourceToTargetEffect.java @@ -0,0 +1,42 @@ +/* + * To change this license header, choose License Headers in Project Properties. + * To change this template file, choose Tools | Templates + * and open the template in the editor. + */ +package mage.abilities.effects.common; + +import mage.abilities.Ability; +import mage.abilities.effects.RedirectionEffect; +import mage.constants.Duration; +import mage.game.Game; +import mage.game.events.GameEvent; + +/** + * + * @author LevelX2 + */ +public class RedirectDamageFromSourceToTargetEffect extends RedirectionEffect { + + public RedirectDamageFromSourceToTargetEffect(Duration duration, int amountToRedirect, boolean oneUsage) { + super(duration, amountToRedirect, oneUsage); + staticText = "The next " + amountToRedirect + " damage that would be dealt to {this} this turn is dealt to target creature you control instead."; + } + + public RedirectDamageFromSourceToTargetEffect(final RedirectDamageFromSourceToTargetEffect effect) { + super(effect); + } + + @Override + public RedirectDamageFromSourceToTargetEffect copy() { + return new RedirectDamageFromSourceToTargetEffect(this); + } + + @Override + public boolean applies(GameEvent event, Ability source, Game game) { + if (event.getTargetId().equals(source.getSourceId())) { + this.redirectTarget = source.getTargets().get(0); + return true; + } + return false; + } +} From 32429b4a4c4f0d8fbc3601f03bebe7dd1da10c92 Mon Sep 17 00:00:00 2001 From: LevelX2 Date: Tue, 20 Oct 2015 23:26:35 +0200 Subject: [PATCH 192/268] * Lightning Storm - Fixed that the always only the original controller was asked to change the target. --- Mage.Sets/src/mage/sets/coldsnap/LightningStorm.java | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/Mage.Sets/src/mage/sets/coldsnap/LightningStorm.java b/Mage.Sets/src/mage/sets/coldsnap/LightningStorm.java index fd05403b5b5..4505fa176ca 100644 --- a/Mage.Sets/src/mage/sets/coldsnap/LightningStorm.java +++ b/Mage.Sets/src/mage/sets/coldsnap/LightningStorm.java @@ -29,6 +29,7 @@ package mage.sets.coldsnap; import java.util.UUID; import mage.abilities.Ability; +import mage.abilities.ActivatedAbilityImpl; import mage.abilities.common.SimpleActivatedAbility; import mage.abilities.costs.common.DiscardTargetCost; import mage.abilities.dynamicvalue.DynamicValue; @@ -59,7 +60,6 @@ public class LightningStorm extends CardImpl { super(ownerId, 89, "Lightning Storm", Rarity.UNCOMMON, new CardType[]{CardType.INSTANT}, "{1}{R}{R}"); this.expansionSetCode = "CSP"; - // Lightning Storm deals X damage to target creature or player, where X is 3 plus the number of charge counters on it. Effect effect = new DamageTargetEffect(new LightningStormCountCondition(CounterType.CHARGE)); effect.setText("{this} deals X damage to target creature or player, where X is 3 plus the number of charge counters on it"); @@ -67,7 +67,7 @@ public class LightningStorm extends CardImpl { this.getSpellAbility().addTarget(new TargetCreatureOrPlayer()); // Discard a land card: Put two charge counters on Lightning Storm. You may choose a new target for it. Any player may activate this ability but only if Lightning Storm is on the stack. SimpleActivatedAbility ability = new SimpleActivatedAbility(Zone.STACK, - new LightningStormAddCounterEffect() , + new LightningStormAddCounterEffect(), new DiscardTargetCost(new TargetCardInHand(new FilterLandCard()))); ability.setMayActivate(TargetController.ANY); ability.addEffect(new InfoEffect("Any player may activate this ability but only if {this} is on the stack")); @@ -85,6 +85,7 @@ public class LightningStorm extends CardImpl { } class LightningStormCountCondition implements DynamicValue { + private final CounterType counter; public LightningStormCountCondition(CounterType counter) { @@ -141,7 +142,7 @@ class LightningStormAddCounterEffect extends OneShotEffect { Spell spell = game.getStack().getSpell(source.getSourceId()); if (spell != null) { spell.addCounters(CounterType.CHARGE.createInstance(2), game); - return spell.chooseNewTargets(game, source.getControllerId(), false, false, null); + return spell.chooseNewTargets(game, ((ActivatedAbilityImpl) source).getActivatorId(), false, false, null); } return false; } From 1b71f505064b82893003207fc29954de533fbed5 Mon Sep 17 00:00:00 2001 From: LevelX2 Date: Tue, 20 Oct 2015 23:48:51 +0200 Subject: [PATCH 193/268] * Pattern of Rebirth - Fixed that the player that may search was not always the controller of the enchanted creature. --- .../sets/urzasdestiny/PatternOfRebirth.java | 8 ++++---- .../common/DiesAttachedTriggeredAbility.java | 19 +++++++++++++++++++ Mage/src/mage/constants/SetTargetPointer.java | 4 ++-- 3 files changed, 25 insertions(+), 6 deletions(-) diff --git a/Mage.Sets/src/mage/sets/urzasdestiny/PatternOfRebirth.java b/Mage.Sets/src/mage/sets/urzasdestiny/PatternOfRebirth.java index 017063b773e..038d5fda7dc 100644 --- a/Mage.Sets/src/mage/sets/urzasdestiny/PatternOfRebirth.java +++ b/Mage.Sets/src/mage/sets/urzasdestiny/PatternOfRebirth.java @@ -32,12 +32,13 @@ import mage.abilities.Ability; import mage.abilities.common.DiesAttachedTriggeredAbility; import mage.abilities.effects.Effect; import mage.abilities.effects.common.AttachEffect; -import mage.abilities.effects.common.search.SearchLibraryPutInPlayEffect; +import mage.abilities.effects.common.search.SearchLibraryPutInPlayTargetPlayerEffect; import mage.abilities.keyword.EnchantAbility; import mage.cards.CardImpl; import mage.constants.CardType; import mage.constants.Outcome; import mage.constants.Rarity; +import mage.constants.SetTargetPointer; import mage.filter.common.FilterCreatureCard; import mage.target.TargetPermanent; import mage.target.common.TargetCardInLibrary; @@ -54,7 +55,6 @@ public class PatternOfRebirth extends CardImpl { this.expansionSetCode = "UDS"; this.subtype.add("Aura"); - // Enchant creature TargetPermanent auraTarget = new TargetCreaturePermanent(); this.getSpellAbility().addTarget(auraTarget); @@ -63,9 +63,9 @@ public class PatternOfRebirth extends CardImpl { this.addAbility(ability); // When enchanted creature dies, that creature's controller may search his or her library for a creature card and put that card onto the battlefield. If that player does, he or she shuffles his or her library. - Effect effect = new SearchLibraryPutInPlayEffect(new TargetCardInLibrary(new FilterCreatureCard()), false, true, Outcome.PutCreatureInPlay); + Effect effect = new SearchLibraryPutInPlayTargetPlayerEffect(new TargetCardInLibrary(new FilterCreatureCard()), false, true, Outcome.PutCreatureInPlay); effect.setText("that creature's controller may search his or her library for a creature card and put that card onto the battlefield. If that player does, he or she shuffles his or her library"); - this.addAbility(new DiesAttachedTriggeredAbility(effect, "enchanted creature", true, true)); + this.addAbility(new DiesAttachedTriggeredAbility(effect, "enchanted creature", true, true, SetTargetPointer.ATTACHED_TO_CONTROLLER)); } diff --git a/Mage/src/mage/abilities/common/DiesAttachedTriggeredAbility.java b/Mage/src/mage/abilities/common/DiesAttachedTriggeredAbility.java index 963df6092bc..11d4a2764f3 100644 --- a/Mage/src/mage/abilities/common/DiesAttachedTriggeredAbility.java +++ b/Mage/src/mage/abilities/common/DiesAttachedTriggeredAbility.java @@ -2,11 +2,13 @@ package mage.abilities.common; import mage.abilities.TriggeredAbilityImpl; import mage.abilities.effects.Effect; +import mage.constants.SetTargetPointer; import mage.constants.Zone; import mage.game.Game; import mage.game.events.GameEvent; import mage.game.events.ZoneChangeEvent; import mage.game.permanent.Permanent; +import mage.target.targetpointer.FixedTarget; /** * "When enchanted/equipped creature dies" triggered ability @@ -17,6 +19,7 @@ public class DiesAttachedTriggeredAbility extends TriggeredAbilityImpl { private String attachedDescription; private boolean diesRuleText; + protected SetTargetPointer setTargetPointer; public DiesAttachedTriggeredAbility(Effect effect, String attachedDescription) { this(effect, attachedDescription, false); @@ -27,15 +30,21 @@ public class DiesAttachedTriggeredAbility extends TriggeredAbilityImpl { } public DiesAttachedTriggeredAbility(Effect effect, String attachedDescription, boolean optional, boolean diesRuleText) { + this(effect, attachedDescription, optional, diesRuleText, SetTargetPointer.NONE); + } + + public DiesAttachedTriggeredAbility(Effect effect, String attachedDescription, boolean optional, boolean diesRuleText, SetTargetPointer setTargetPointer) { super(Zone.ALL, effect, optional); // because the trigger only triggers if the object was attached, it doesn't matter where the Attachment was moved to (e.g. by replacement effect) after the trigger triggered, so Zone.all this.attachedDescription = attachedDescription; this.diesRuleText = diesRuleText; + this.setTargetPointer = setTargetPointer; } public DiesAttachedTriggeredAbility(final DiesAttachedTriggeredAbility ability) { super(ability); this.attachedDescription = ability.attachedDescription; this.diesRuleText = ability.diesRuleText; + this.setTargetPointer = ability.setTargetPointer; } @Override @@ -69,6 +78,16 @@ public class DiesAttachedTriggeredAbility extends TriggeredAbilityImpl { if (triggered) { for (Effect effect : getEffects()) { effect.setValue("attachedTo", zEvent.getTarget()); + if (setTargetPointer.equals(SetTargetPointer.ATTACHED_TO_CONTROLLER)) { + Permanent attachment = game.getPermanentOrLKIBattlefield(getSourceId()); + if (attachment != null && attachment.getAttachedTo() != null) { + Permanent attachedTo = (Permanent) game.getLastKnownInformation(attachment.getAttachedTo(), Zone.BATTLEFIELD, attachment.getAttachedToZoneChangeCounter()); + if (attachedTo != null) { + effect.setTargetPointer(new FixedTarget(attachedTo.getControllerId())); + } + } + + } } return true; } diff --git a/Mage/src/mage/constants/SetTargetPointer.java b/Mage/src/mage/constants/SetTargetPointer.java index 6aeca5e026d..9f4acc8876d 100644 --- a/Mage/src/mage/constants/SetTargetPointer.java +++ b/Mage/src/mage/constants/SetTargetPointer.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.constants; /** @@ -33,5 +32,6 @@ package mage.constants; * @author LevelX2 */ public enum SetTargetPointer { - NONE, PLAYER, SPELL, CARD, PERMANENT; + + NONE, PLAYER, SPELL, CARD, PERMANENT, ATTACHED_TO_CONTROLLER; } From 2b68d3e0a931e4420ca58066446735524b0fb8cb Mon Sep 17 00:00:00 2001 From: LevelX2 Date: Wed, 21 Oct 2015 08:03:05 +0200 Subject: [PATCH 194/268] xmage 1.4.4v9 --- Utils/release/getting_implemented_cards.txt | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Utils/release/getting_implemented_cards.txt b/Utils/release/getting_implemented_cards.txt index f922aab6fba..bd7cacbd8a5 100644 --- a/Utils/release/getting_implemented_cards.txt +++ b/Utils/release/getting_implemented_cards.txt @@ -36,6 +36,9 @@ git log 7650f53dee0b4d480d2a63befed72b6c8197e752..head --diff-filter=A --name-st since 1.4.4.v8 git log 8c7dc7b2da3630b6dfec1390854fa2be11631c79..head --diff-filter=A --name-status | sed -ne "s/^A[^u]Mage.Sets\/src\/mage\/sets\///p" | sort > added_cards.txt +since 1.4.4.v9 +git log 1b71f505064b82893003207fc29954de533fbed5..head --diff-filter=A --name-status | sed -ne "s/^A[^u]Mage.Sets\/src\/mage\/sets\///p" | sort > added_cards.txt + 3. Copy added_cards.txt to trunk\Utils folder 4. Run script: > perl extract_in_wiki_format.perl From d20bbcfe0b616b987eccbb4aeb83355d80608f9e Mon Sep 17 00:00:00 2001 From: LevelX2 Date: Wed, 21 Oct 2015 15:14:20 +0200 Subject: [PATCH 195/268] * Fixed that permanents brought onto battlefield by search abilities were always tapped. --- .../enters/SearchEntersBattlefieldTest.java | 59 +++++++++++++++++++ .../search/SearchLibraryPutInPlayEffect.java | 2 +- 2 files changed, 60 insertions(+), 1 deletion(-) create mode 100644 Mage.Tests/src/test/java/org/mage/test/cards/abilities/enters/SearchEntersBattlefieldTest.java diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/abilities/enters/SearchEntersBattlefieldTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/abilities/enters/SearchEntersBattlefieldTest.java new file mode 100644 index 00000000000..b097f3a7eef --- /dev/null +++ b/Mage.Tests/src/test/java/org/mage/test/cards/abilities/enters/SearchEntersBattlefieldTest.java @@ -0,0 +1,59 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package org.mage.test.cards.abilities.enters; + +import mage.constants.PhaseStep; +import mage.constants.Zone; +import org.junit.Test; +import org.mage.test.serverside.base.CardTestPlayerBase; + +/** + * + * @author LevelX2 + */ +public class SearchEntersBattlefieldTest extends CardTestPlayerBase { + + @Test + public void testLandAfterFetchUntapped() { + addCard(Zone.HAND, playerA, "Verdant Catacombs"); + addCard(Zone.LIBRARY, playerA, "Forest"); + + playLand(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Verdant Catacombs"); + + activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "{T}, Pay"); + setChoice(playerA, "Forest"); + setStopAt(1, PhaseStep.END_TURN); + execute(); + + assertGraveyardCount(playerA, "Verdant Catacombs", 1); + assertPermanentCount(playerA, "Forest", 1); + assertTapped("Forest", false); + + } + +} diff --git a/Mage/src/mage/abilities/effects/common/search/SearchLibraryPutInPlayEffect.java b/Mage/src/mage/abilities/effects/common/search/SearchLibraryPutInPlayEffect.java index c92cbb7540e..de9c442f289 100644 --- a/Mage/src/mage/abilities/effects/common/search/SearchLibraryPutInPlayEffect.java +++ b/Mage/src/mage/abilities/effects/common/search/SearchLibraryPutInPlayEffect.java @@ -90,7 +90,7 @@ public class SearchLibraryPutInPlayEffect extends SearchEffect { if (player.searchLibrary(target, game)) { if (target.getTargets().size() > 0) { player.moveCards(new CardsImpl(target.getTargets()).getCards(game), - Zone.BATTLEFIELD, source, game, true, false, false, null); + Zone.BATTLEFIELD, source, game, tapped, false, false, null); } player.shuffleLibrary(game); return true; From d906fc8c006219ba30caee47b3fe9e342174fdb9 Mon Sep 17 00:00:00 2001 From: LevelX2 Date: Wed, 21 Oct 2015 15:35:58 +0200 Subject: [PATCH 196/268] * Fixed that damage redirection to planeswalker did cause an exception. --- .../RedirectDamageToPlaneswalkerTest.java | 70 +++++++++++++++++++ .../abilities/effects/RedirectionEffect.java | 7 +- 2 files changed, 73 insertions(+), 4 deletions(-) create mode 100644 Mage.Tests/src/test/java/org/mage/test/cards/planeswalker/RedirectDamageToPlaneswalkerTest.java diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/planeswalker/RedirectDamageToPlaneswalkerTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/planeswalker/RedirectDamageToPlaneswalkerTest.java new file mode 100644 index 00000000000..3b95c44288e --- /dev/null +++ b/Mage.Tests/src/test/java/org/mage/test/cards/planeswalker/RedirectDamageToPlaneswalkerTest.java @@ -0,0 +1,70 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package org.mage.test.cards.planeswalker; + +import mage.constants.PhaseStep; +import mage.constants.Zone; +import mage.counters.CounterType; +import org.junit.Test; +import org.mage.test.serverside.base.CardTestPlayerBase; + +/** + * + * @author LevelX2 + */ +public class RedirectDamageToPlaneswalkerTest extends CardTestPlayerBase { + + @Test + public void testDirectDamage() { + // +2: Look at the top card of target player's library. You may put that card on the bottom of that player's library. + // 0: Draw three cards, then put two cards from your hand on top of your library in any order. + // −1: Return target creature to its owner's hand. + addCard(Zone.BATTLEFIELD, playerA, "Jace, the Mind Sculptor"); // starts with 3 Loyality counters + + addCard(Zone.BATTLEFIELD, playerB, "Mountain", 1); + addCard(Zone.HAND, playerB, "Lightning Bolt"); + + activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "+2:", playerB); + + castSpell(1, PhaseStep.POSTCOMBAT_MAIN, playerB, "Lightning Bolt", playerA); + setChoice(playerB, "Yes"); + + setStopAt(1, PhaseStep.END_TURN); + execute(); + + assertPermanentCount(playerA, "Jace, the Mind Sculptor", 1); + assertCounterCount("Jace, the Mind Sculptor", CounterType.LOYALTY, 2); // 3 + 2 - 3 = 2 + + assertGraveyardCount(playerB, "Lightning Bolt", 1); + + assertLife(playerA, 20); + assertLife(playerB, 20); + + } + +} diff --git a/Mage/src/mage/abilities/effects/RedirectionEffect.java b/Mage/src/mage/abilities/effects/RedirectionEffect.java index b30400e656e..7979ad8f1b1 100644 --- a/Mage/src/mage/abilities/effects/RedirectionEffect.java +++ b/Mage/src/mage/abilities/effects/RedirectionEffect.java @@ -27,7 +27,6 @@ */ package mage.abilities.effects; -import mage.MageObject; import mage.abilities.Ability; import mage.constants.Duration; import mage.constants.EffectType; @@ -80,7 +79,7 @@ public abstract class RedirectionEffect extends ReplacementEffectImpl { @Override public boolean replaceEvent(GameEvent event, Ability source, Game game) { - MageObject sourceObject = game.getObject(source.getSourceId()); + String sourceLogName = source != null ? game.getObject(source.getSourceId()).getLogName() + ": " : ""; DamageEvent damageEvent = (DamageEvent) event; int restDamage = 0; int damageToRedirect = event.getAmount(); @@ -94,12 +93,12 @@ public abstract class RedirectionEffect extends ReplacementEffectImpl { Permanent permanent = game.getPermanent(redirectTarget.getFirstTarget()); if (permanent != null) { permanent.damage(damageToRedirect, event.getSourceId(), game, damageEvent.isCombatDamage(), damageEvent.isPreventable(), event.getAppliedEffects()); - game.informPlayers(sourceObject.getLogName() + ": Redirected " + damageToRedirect + " damage to " + permanent.getLogName()); + game.informPlayers(sourceLogName + "Redirected " + damageToRedirect + " damage to " + permanent.getLogName()); } else { Player player = game.getPlayer(redirectTarget.getFirstTarget()); if (player != null) { player.damage(damageToRedirect, event.getSourceId(), game, damageEvent.isCombatDamage(), damageEvent.isPreventable(), event.getAppliedEffects()); - game.informPlayers(sourceObject.getLogName() + ": Redirected " + damageToRedirect + " damage to " + player.getLogName()); + game.informPlayers(sourceLogName + "Redirected " + damageToRedirect + " damage to " + player.getLogName()); } } if (restDamage > 0) { From 601dd29c9e77c39352fcf13167d1c1eb3bee82ea Mon Sep 17 00:00:00 2001 From: LevelX2 Date: Wed, 21 Oct 2015 15:44:22 +0200 Subject: [PATCH 197/268] * Golgari Grave-Troll - Fixed that it always came to battlefield with 0 +1/+1 counters. --- Mage.Sets/src/mage/sets/ravnica/GolgariGraveTroll.java | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/Mage.Sets/src/mage/sets/ravnica/GolgariGraveTroll.java b/Mage.Sets/src/mage/sets/ravnica/GolgariGraveTroll.java index 1673b718af2..d0c851b05b3 100644 --- a/Mage.Sets/src/mage/sets/ravnica/GolgariGraveTroll.java +++ b/Mage.Sets/src/mage/sets/ravnica/GolgariGraveTroll.java @@ -28,10 +28,6 @@ package mage.sets.ravnica; import java.util.UUID; -import mage.constants.CardType; -import mage.constants.Outcome; -import mage.constants.Rarity; -import mage.constants.Zone; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.EntersBattlefieldAbility; @@ -42,6 +38,10 @@ import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.RegenerateSourceEffect; import mage.abilities.keyword.DredgeAbility; import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.Outcome; +import mage.constants.Rarity; +import mage.constants.Zone; import mage.counters.CounterType; import mage.filter.common.FilterCreatureCard; import mage.filter.predicate.mageobject.CardTypePredicate; @@ -104,7 +104,7 @@ class GolgariGraveTrollEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { Player player = game.getPlayer(source.getControllerId()); - Permanent permanent = game.getPermanent(source.getSourceId()); + Permanent permanent = game.getPermanentEntering(source.getSourceId()); if (permanent != null && player != null) { int amount = player.getGraveyard().count(filter, game); if (amount > 0) { From 0f3a72de06f4dabf1bad1f9417647cc1480fd4c6 Mon Sep 17 00:00:00 2001 From: LevelX2 Date: Wed, 21 Oct 2015 15:45:21 +0200 Subject: [PATCH 198/268] * Ulasht, the Hate Seed - Fixed that it always came to battlefield with zero +1/+1 counters. --- Mage.Sets/src/mage/sets/guildpact/UlashtTheHateSeed.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Mage.Sets/src/mage/sets/guildpact/UlashtTheHateSeed.java b/Mage.Sets/src/mage/sets/guildpact/UlashtTheHateSeed.java index 6d99f312a7e..7903fdc13dc 100644 --- a/Mage.Sets/src/mage/sets/guildpact/UlashtTheHateSeed.java +++ b/Mage.Sets/src/mage/sets/guildpact/UlashtTheHateSeed.java @@ -73,7 +73,7 @@ public class UlashtTheHateSeed extends CardImpl { // Ulasht, the Hate Seed enters the battlefield with a +1/+1 counter on it for each other red creature you control and a +1/+1 counter on it for each other green creature you control. this.addAbility(new EntersBattlefieldAbility(new UlashtTheHateSeedEffect(), "with a +1/+1 counter on it for each other red creature you control and a +1/+1 counter on it for each other green creature you control.")); - + // {1}, Remove a +1/+1 counter from Ulasht: Choose one - Ulasht deals 1 damage to target creature; Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new DamageTargetEffect(1), new GenericManaCost(1)); ability.addCost(new RemoveCountersSourceCost(CounterType.P1P1.createInstance())); @@ -101,7 +101,7 @@ class UlashtTheHateSeedEffect extends OneShotEffect { private static final FilterControlledCreaturePermanent filterGreen = new FilterControlledCreaturePermanent(); private static final FilterControlledCreaturePermanent filterRed = new FilterControlledCreaturePermanent(); - + static { filterGreen.add(new AnotherPredicate()); filterGreen.add(new ColorPredicate(ObjectColor.GREEN)); @@ -121,7 +121,7 @@ class UlashtTheHateSeedEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { Player player = game.getPlayer(source.getControllerId()); - Permanent permanent = game.getPermanent(source.getSourceId()); + Permanent permanent = game.getPermanentEntering(source.getSourceId()); if (permanent != null && player != null) { int amount = game.getBattlefield().count(filterRed, source.getSourceId(), source.getControllerId(), game); amount += game.getBattlefield().count(filterGreen, source.getSourceId(), source.getControllerId(), game); @@ -138,4 +138,4 @@ class UlashtTheHateSeedEffect extends OneShotEffect { return new UlashtTheHateSeedEffect(this); } -} \ No newline at end of file +} From 353ddd9dfe83f849e2d65adeac27727b6bf360fd Mon Sep 17 00:00:00 2001 From: LevelX2 Date: Wed, 21 Oct 2015 15:45:43 +0200 Subject: [PATCH 199/268] * Unbreathing Horde - Fixed that it always came to battlefield with zero +1/+1 counters. --- Mage.Sets/src/mage/sets/innistrad/UnbreathingHorde.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Mage.Sets/src/mage/sets/innistrad/UnbreathingHorde.java b/Mage.Sets/src/mage/sets/innistrad/UnbreathingHorde.java index c51d4a005b9..75a7eed6473 100644 --- a/Mage.Sets/src/mage/sets/innistrad/UnbreathingHorde.java +++ b/Mage.Sets/src/mage/sets/innistrad/UnbreathingHorde.java @@ -102,7 +102,7 @@ class UnbreathingHordeEffect1 extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { Player player = game.getPlayer(source.getControllerId()); - Permanent permanent = game.getPermanent(source.getSourceId()); + Permanent permanent = game.getPermanentEntering(source.getSourceId()); if (permanent != null && player != null) { int amount = game.getBattlefield().countAll(filter1, source.getControllerId(), game) - 1; amount += player.getGraveyard().count(filter2, game); From f7c354afd3b6f19c8ec332d555db39d2cd910d87 Mon Sep 17 00:00:00 2001 From: LevelX2 Date: Wed, 21 Oct 2015 17:02:51 +0200 Subject: [PATCH 200/268] * Living Lore - Fixed that it did not get the +1/+1 counters as it entered the battlefield. --- .../mage/sets/dragonsoftarkir/LivingLore.java | 29 ++++++++++--------- .../src/mage/sets/tenthedition/Clone.java | 5 ---- .../SetPowerToughnessSourceEffect.java | 19 +++++------- 3 files changed, 24 insertions(+), 29 deletions(-) diff --git a/Mage.Sets/src/mage/sets/dragonsoftarkir/LivingLore.java b/Mage.Sets/src/mage/sets/dragonsoftarkir/LivingLore.java index 627a332ce4b..354d93ddef3 100644 --- a/Mage.Sets/src/mage/sets/dragonsoftarkir/LivingLore.java +++ b/Mage.Sets/src/mage/sets/dragonsoftarkir/LivingLore.java @@ -71,7 +71,7 @@ public class LivingLore extends CardImpl { this.addAbility(new EntersBattlefieldAbility(new LivingLoreExileEffect(), "exile an instant or sorcery card from your graveyard")); // Living Lore's power and toughness are each equal to the exiled card's converted mana cost. - this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new LivingLoreSetPowerToughnessSourceEffect())); + this.addAbility(new SimpleStaticAbility(Zone.ALL, new LivingLoreSetPowerToughnessSourceEffect())); // Whenever Living Lore deals combat damage, you may sacrifice it. If you do, you may cast the exiled card without paying its mana cost. this.addAbility(new DealsCombatDamageTriggeredAbility(new LivingLoreSacrificeEffect(), true)); @@ -106,14 +106,14 @@ class LivingLoreExileEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { Player controller = game.getPlayer(source.getControllerId()); - MageObject sourceObject = source.getSourceObject(game); - if (sourceObject != null && controller != null){ + Permanent sourcePermanent = game.getPermanentEntering(source.getSourceId()); + if (sourcePermanent != null && controller != null) { TargetCardInYourGraveyard target = new TargetCardInYourGraveyard(new FilterInstantOrSorceryCard("instant or sorcery card from your graveyard")); if (controller.chooseTarget(outcome, target, source, game)) { - UUID exileId = CardUtil.getExileZoneId(game, source.getSourceId(), source.getSourceObjectZoneChangeCounter()); + UUID exileId = CardUtil.getExileZoneId(game, source.getSourceId(), game.getState().getZoneChangeCounter(source.getSourceId()) + 1); Card card = controller.getGraveyard().get(target.getFirstTarget(), game); if (card != null) { - controller.moveCardToExileWithInfo(card, exileId, sourceObject.getIdName(), source.getSourceId(), game, Zone.GRAVEYARD, true); + controller.moveCardsToExile(card, source, game, true, exileId, sourcePermanent.getIdName()); } } return true; @@ -126,7 +126,7 @@ class LivingLoreExileEffect extends OneShotEffect { class LivingLoreSetPowerToughnessSourceEffect extends ContinuousEffectImpl { public LivingLoreSetPowerToughnessSourceEffect() { - super(Duration.WhileOnBattlefield, Layer.PTChangingEffects_7, SubLayer.SetPT_7b, Outcome.BoostCreature); + super(Duration.Custom, Layer.PTChangingEffects_7, SubLayer.SetPT_7b, Outcome.BoostCreature); staticText = "{this}'s power and toughness are each equal to the exiled card's converted mana cost"; } @@ -141,20 +141,23 @@ class LivingLoreSetPowerToughnessSourceEffect extends ContinuousEffectImpl { @Override public boolean apply(Game game, Ability source) { - MageObject mageObject = source.getSourceObject(game); Permanent permanent = game.getPermanent(source.getSourceId()); - if (permanent != null && mageObject == null && new MageObjectReference(permanent, game).refersTo(mageObject, game)) { - discard(); - return false; + int zcc = game.getState().getZoneChangeCounter(source.getSourceId()); + if (permanent == null) { + permanent = game.getPermanentEntering(source.getSourceId()); + zcc++; } - UUID exileId = CardUtil.getExileZoneId(game, source.getSourceId(), source.getSourceObjectZoneChangeCounter()); + if (permanent == null) { + return true; + } + UUID exileId = CardUtil.getExileZoneId(game, source.getSourceId(), zcc); if (exileId != null) { ExileZone exileZone = game.getExile().getExileZone(exileId); if (exileZone == null) { return false; } Card exiledCard = null; - for (Card card :exileZone.getCards(game)) { + for (Card card : exileZone.getCards(game)) { exiledCard = card; break; } @@ -197,7 +200,7 @@ class LivingLoreSacrificeEffect extends OneShotEffect { ExileZone exileZone = game.getExile().getExileZone(exileId); Card exiledCard = null; if (exileZone != null) { - for (Card card :exileZone.getCards(game)) { + for (Card card : exileZone.getCards(game)) { exiledCard = card; break; } diff --git a/Mage.Sets/src/mage/sets/tenthedition/Clone.java b/Mage.Sets/src/mage/sets/tenthedition/Clone.java index 6869479699a..6fa99a23821 100644 --- a/Mage.Sets/src/mage/sets/tenthedition/Clone.java +++ b/Mage.Sets/src/mage/sets/tenthedition/Clone.java @@ -50,11 +50,6 @@ public class Clone extends CardImpl { this.toughness = new MageInt(0); // You may have Clone enter the battlefield as a copy of any creature on the battlefield. -// ; -// Ability ability = new SimpleStaticAbility(Zone.BATTLEFIELD, new EntersBattlefieldEffect( -// new CopyPermanentEffect(), -// "You may have {this} enter the battlefield as a copy of any creature on the battlefield", -// true)); this.addAbility(new EntersBattlefieldAbility(new CopyPermanentEffect(), true)); } diff --git a/Mage/src/mage/abilities/effects/common/continuous/SetPowerToughnessSourceEffect.java b/Mage/src/mage/abilities/effects/common/continuous/SetPowerToughnessSourceEffect.java index d523a5cbd06..1c2e3dbc87a 100644 --- a/Mage/src/mage/abilities/effects/common/continuous/SetPowerToughnessSourceEffect.java +++ b/Mage/src/mage/abilities/effects/common/continuous/SetPowerToughnessSourceEffect.java @@ -36,7 +36,6 @@ import mage.constants.Layer; import mage.constants.Outcome; import mage.constants.SubLayer; import mage.game.Game; -import mage.game.permanent.Permanent; /** * @@ -75,19 +74,17 @@ public class SetPowerToughnessSourceEffect extends ContinuousEffectImpl { @Override public boolean apply(Game game, Ability source) { - MageObject mageObject = game.getObject(source.getSourceId()); + MageObject mageObject = game.getPermanentEntering(source.getSourceId()); if (mageObject == null) { - game.getPermanentEntering(source.getSourceId()); + if (duration.equals(Duration.Custom) || isTemporary()) { + mageObject = game.getPermanent(source.getSourceId()); + } else { + mageObject = game.getObject(source.getSourceId()); + } } if (mageObject == null) { - if (duration.equals(Duration.Custom)) { - discard(); - } - return false; - } else if (isTemporary()) { // it's somehow w - if (!(mageObject instanceof Permanent)) { - return false; - } + discard(); + return true; } if (amount != null) { int value = amount.calculate(game, source, this); From c9cb53101d5c36a79e84680bcd925285a3adab2a Mon Sep 17 00:00:00 2001 From: LevelX2 Date: Wed, 21 Oct 2015 17:05:36 +0200 Subject: [PATCH 201/268] * Path to Exile - Fixed that the land was put unter control of the controller of Path to Exile to the battlefield. --- Mage.Sets/src/mage/sets/conflux/PathToExile.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Mage.Sets/src/mage/sets/conflux/PathToExile.java b/Mage.Sets/src/mage/sets/conflux/PathToExile.java index 63f6a0c889a..ed66cc9597d 100644 --- a/Mage.Sets/src/mage/sets/conflux/PathToExile.java +++ b/Mage.Sets/src/mage/sets/conflux/PathToExile.java @@ -98,7 +98,7 @@ class PathToExileEffect extends OneShotEffect { if (player.searchLibrary(target, game)) { Card card = player.getLibrary().getCard(target.getFirstTarget(), game); if (card != null) { - controller.moveCards(card, Zone.BATTLEFIELD, source, game, true, false, false, null); + player.moveCards(card, Zone.BATTLEFIELD, source, game, true, false, false, null); } } player.shuffleLibrary(game); From da47f41682e2568a213898d34fe3ab197b56c25e Mon Sep 17 00:00:00 2001 From: LevelX2 Date: Wed, 21 Oct 2015 17:11:35 +0200 Subject: [PATCH 202/268] * Tooth and Nail - Fixed that second mode did not put the selected creature cards to battlefield. --- Mage.Sets/src/mage/sets/modernmasters/ToothAndNail.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Mage.Sets/src/mage/sets/modernmasters/ToothAndNail.java b/Mage.Sets/src/mage/sets/modernmasters/ToothAndNail.java index 30762aeb3d7..478914ee117 100644 --- a/Mage.Sets/src/mage/sets/modernmasters/ToothAndNail.java +++ b/Mage.Sets/src/mage/sets/modernmasters/ToothAndNail.java @@ -102,7 +102,7 @@ class ToothAndNailPutCreatureOnBattlefieldEffect extends OneShotEffect { TargetCardInHand target = new TargetCardInHand(0, 2, new FilterCreatureCard("creature cards")); if (controller.choose(Outcome.PutCreatureInPlay, target, source.getSourceId(), game)) { - return controller.moveCards(new CardsImpl(getTargetPointer().getTargets(game, source)).getCards(game), + return controller.moveCards(new CardsImpl(target.getTargets()).getCards(game), Zone.BATTLEFIELD, source, game, true, false, false, null); } return false; From 511fb378388af8b6e23a102b567a14ee990e95d1 Mon Sep 17 00:00:00 2001 From: LevelX2 Date: Wed, 21 Oct 2015 19:08:00 +0200 Subject: [PATCH 203/268] * Utopia Sprawl - Fixed that the color choice was not working. --- .../mage/sets/dissension/UtopiaSprawl.java | 61 +++---------------- 1 file changed, 8 insertions(+), 53 deletions(-) diff --git a/Mage.Sets/src/mage/sets/dissension/UtopiaSprawl.java b/Mage.Sets/src/mage/sets/dissension/UtopiaSprawl.java index c92e93989b1..de6633ee6af 100644 --- a/Mage.Sets/src/mage/sets/dissension/UtopiaSprawl.java +++ b/Mage.Sets/src/mage/sets/dissension/UtopiaSprawl.java @@ -32,20 +32,18 @@ import mage.Mana; import mage.ObjectColor; import mage.abilities.Ability; import mage.abilities.common.AsEntersBattlefieldAbility; -import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.AttachEffect; +import mage.abilities.effects.common.ChooseColorEffect; import mage.abilities.effects.common.ManaEffect; import mage.abilities.keyword.EnchantAbility; import mage.abilities.mana.TriggeredManaAbility; import mage.cards.CardImpl; -import mage.choices.ChoiceColor; import mage.constants.CardType; import mage.constants.ColoredManaSymbol; import mage.constants.Outcome; import mage.constants.Rarity; import mage.constants.Zone; import mage.filter.common.FilterLandPermanent; -import mage.filter.predicate.mageobject.SubtypePredicate; import mage.game.Game; import mage.game.events.GameEvent; import mage.game.events.GameEvent.EventType; @@ -60,18 +58,13 @@ import mage.target.common.TargetLandPermanent; */ public class UtopiaSprawl extends CardImpl { - private static final FilterLandPermanent filter = new FilterLandPermanent("Forest"); + private static final FilterLandPermanent filter = new FilterLandPermanent("Forest", "Forest"); - static { - filter.add(new SubtypePredicate("Forest")); - } - public UtopiaSprawl(UUID ownerId) { super(ownerId, 99, "Utopia Sprawl", Rarity.COMMON, new CardType[]{CardType.ENCHANTMENT}, "{G}"); this.expansionSetCode = "DIS"; this.subtype.add("Aura"); - // Enchant Forest TargetPermanent auraTarget = new TargetLandPermanent(filter); this.getSpellAbility().addTarget(auraTarget); @@ -79,7 +72,7 @@ public class UtopiaSprawl extends CardImpl { Ability ability = new EnchantAbility(auraTarget.getTargetName()); this.addAbility(ability); // As Utopia Sprawl enters the battlefield, choose a color. - this.addAbility(new AsEntersBattlefieldAbility(new ChooseColorEffect())); + this.addAbility(new AsEntersBattlefieldAbility(new ChooseColorEffect(Outcome.Detriment))); // Whenever enchanted Forest is tapped for mana, its controller adds one mana of the chosen color to his or her mana pool. this.addAbility(new UtopiaSprawlTriggeredAbility()); } @@ -94,42 +87,8 @@ public class UtopiaSprawl extends CardImpl { } } -class ChooseColorEffect extends OneShotEffect { - - public ChooseColorEffect() { - super(Outcome.BoostCreature); - staticText = "choose a color"; - } - - public ChooseColorEffect(final ChooseColorEffect effect) { - super(effect); - } - - @Override - public boolean apply(Game game, Ability source) { - Player player = game.getPlayer(source.getControllerId()); - Permanent permanent = game.getPermanent(source.getSourceId()); - if (player != null && permanent != null) { - ChoiceColor colorChoice = new ChoiceColor(); - if (player.choose(Outcome.Neutral, colorChoice, game)) { - game.informPlayers(permanent.getName() + ": " + player.getLogName() + " has chosen " + colorChoice.getChoice()); - game.getState().setValue(permanent.getId() + "_color", colorChoice.getColor()); - permanent.addInfo("chosen color", "Chosen color: " + colorChoice.getColor().getDescription() + "", game); - } - } - return false; - } - - @Override - public ChooseColorEffect copy() { - return new ChooseColorEffect(this); - } - -} - class UtopiaSprawlTriggeredAbility extends TriggeredManaAbility { - public UtopiaSprawlTriggeredAbility() { super(Zone.BATTLEFIELD, new UtopiaSprawlEffect()); } @@ -146,10 +105,7 @@ class UtopiaSprawlTriggeredAbility extends TriggeredManaAbility { @Override public boolean checkTrigger(GameEvent event, Game game) { Permanent enchantment = game.getPermanent(this.getSourceId()); - if (enchantment != null && event.getSourceId().equals(enchantment.getAttachedTo())) { - return true; - } - return false; + return enchantment != null && event.getSourceId().equals(enchantment.getAttachedTo()); } @Override @@ -159,11 +115,10 @@ class UtopiaSprawlTriggeredAbility extends TriggeredManaAbility { @Override public String getRule() { - return "Whenever enchanted Forest is tapped for mana, its controller adds one mana of the chosen color to his or her mana pool"; + return "Whenever enchanted Forest is tapped for mana, its controller adds one mana of the chosen color to his or her mana pool."; } } - class UtopiaSprawlEffect extends ManaEffect { public UtopiaSprawlEffect() { @@ -178,9 +133,9 @@ class UtopiaSprawlEffect extends ManaEffect { @Override public boolean apply(Game game, Ability source) { Permanent enchantment = game.getPermanent(source.getSourceId()); - if(enchantment != null){ + if (enchantment != null) { Permanent land = game.getPermanent(enchantment.getAttachedTo()); - if(land != null){ + if (land != null) { Player player = game.getPlayer(land.getControllerId()); if (player != null) { player.getManaPool().addMana(getMana(game, source), game, source); @@ -205,4 +160,4 @@ class UtopiaSprawlEffect extends ManaEffect { public UtopiaSprawlEffect copy() { return new UtopiaSprawlEffect(this); } -} \ No newline at end of file +} From 4629366ae7a29edf12d428e45638a0273953fd3f Mon Sep 17 00:00:00 2001 From: LevelX2 Date: Wed, 21 Oct 2015 20:16:52 +0200 Subject: [PATCH 204/268] * Fixed that spells without mana costs but suspend could be cast with no mana (e.g. Ancestral Vision). --- .../cards/abilities/keywords/SuspendTest.java | 16 +++++++++++++++ Mage/src/mage/players/PlayerImpl.java | 20 ++++++++++++++++++- 2 files changed, 35 insertions(+), 1 deletion(-) diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/abilities/keywords/SuspendTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/abilities/keywords/SuspendTest.java index 9ed98cca08f..8e66883abc3 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/abilities/keywords/SuspendTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/abilities/keywords/SuspendTest.java @@ -147,4 +147,20 @@ public class SuspendTest extends CardTestPlayerBase { assertCounterOnExiledCardCount("Deep-Sea Kraken", CounterType.TIME, 8); // -1 from spell of player B } + + @Test + public void testAncestralVisionCantBeCastDirectly() { + // Suspend 4-{U} + // Target player draws three cards. + addCard(Zone.HAND, playerA, "Ancestral Vision", 1); + + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Ancestral Vision", playerA); + + setStopAt(1, PhaseStep.BEGIN_COMBAT); + execute(); + + assertHandCount(playerA, 1); + assertHandCount(playerA, "Ancestral Vision", 1); + + } } diff --git a/Mage/src/mage/players/PlayerImpl.java b/Mage/src/mage/players/PlayerImpl.java index 1719603aa72..cdeb49c91a4 100644 --- a/Mage/src/mage/players/PlayerImpl.java +++ b/Mage/src/mage/players/PlayerImpl.java @@ -1217,11 +1217,15 @@ public abstract class PlayerImpl implements Player, Serializable { public LinkedHashMap getUseableActivatedAbilities(MageObject object, Zone zone, Game game) { LinkedHashMap useable = new LinkedHashMap<>(); boolean canUse = !(object instanceof Permanent) || ((Permanent) object).canUseActivatedAbilities(game); + ManaOptions availableMana = null; +// ManaOptions availableMana = getManaAvailable(game); // can only be activated if mana calculation works flawless otherwise player can't play spells they could play if calculation would work correctly +// availableMana.addMana(manaPool.getMana()); for (Ability ability : object.getAbilities()) { if (canUse || ability.getAbilityType().equals(AbilityType.SPECIAL_ACTION)) { if (ability.getZone().match(zone)) { if (ability instanceof ActivatedAbility) { - if (((ActivatedAbility) ability).canActivate(playerId, game)) { + if (canPlay(((ActivatedAbility) ability), availableMana, object, game)) { +// if (((ActivatedAbility) ability).canActivate(playerId, game)) { useable.put(ability.getId(), (ActivatedAbility) ability); } } else if (ability instanceof AlternativeSourceCosts) { @@ -2297,6 +2301,14 @@ public abstract class PlayerImpl implements Player, Serializable { return result; } + /** + * + * @param ability + * @param available if null, it won't be checked if enough mana is available + * @param sourceObject + * @param game + * @return + */ protected boolean canPlay(ActivatedAbility ability, ManaOptions available, MageObject sourceObject, Game game) { if (!(ability instanceof ManaAbility)) { ActivatedAbility copy = ability.copy(); @@ -2329,6 +2341,9 @@ public abstract class PlayerImpl implements Player, Serializable { if (abilityOptions.size() == 0) { return true; } else { + if (available == null) { + return true; + } for (Mana mana : abilityOptions) { for (Mana avail : available) { if (mana.enough(avail)) { @@ -2377,6 +2392,9 @@ public abstract class PlayerImpl implements Player, Serializable { if (manaCosts.size() == 0) { return true; } else { + if (available == null) { + return true; + } for (Mana mana : manaCosts.getOptions()) { for (Mana avail : available) { if (mana.enough(avail)) { From 305712806ccdaed941630df5f095f73de5b049ab Mon Sep 17 00:00:00 2001 From: LevelX2 Date: Wed, 21 Oct 2015 20:24:39 +0200 Subject: [PATCH 205/268] * Cursed Scroll - Fixed that the card name dialog was not opened. --- Mage.Sets/src/mage/sets/tempest/CursedScroll.java | 15 +++++++-------- .../abilities/effects/common/NameACardEffect.java | 2 +- 2 files changed, 8 insertions(+), 9 deletions(-) diff --git a/Mage.Sets/src/mage/sets/tempest/CursedScroll.java b/Mage.Sets/src/mage/sets/tempest/CursedScroll.java index 110111ffe08..2f2c326a895 100644 --- a/Mage.Sets/src/mage/sets/tempest/CursedScroll.java +++ b/Mage.Sets/src/mage/sets/tempest/CursedScroll.java @@ -29,9 +29,6 @@ package mage.sets.tempest; import java.util.UUID; import mage.MageObject; - -import mage.constants.CardType; -import mage.constants.Rarity; import mage.abilities.Ability; import mage.abilities.common.SimpleActivatedAbility; import mage.abilities.costs.common.TapSourceCost; @@ -42,7 +39,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.game.Game; import mage.game.permanent.Permanent; @@ -91,15 +90,15 @@ class CursedScrollEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { - Player you = game.getPlayer(source.getControllerId()); + Player controller = game.getPlayer(source.getControllerId()); MageObject sourceObject = game.getObject(source.getSourceId()); String cardName = (String) game.getState().getValue(source.getSourceId().toString() + NameACardEffect.INFO_KEY); - if (sourceObject != null && you != null && cardName != null && !cardName.isEmpty()) { - if (you.getHand().size() > 0) { + if (sourceObject != null && controller != null && cardName != null && !cardName.isEmpty()) { + if (controller.getHand().size() > 0) { Cards revealed = new CardsImpl(); - Card card = you.getHand().getRandom(game); + Card card = controller.getHand().getRandom(game); revealed.add(card); - you.revealCards(sourceObject.getName(), revealed, game); + controller.revealCards(sourceObject.getIdName(), revealed, game); if (card.getName().equals(cardName)) { Permanent creature = game.getPermanent(targetPointer.getFirst(game, source)); if (creature != null) { diff --git a/Mage/src/mage/abilities/effects/common/NameACardEffect.java b/Mage/src/mage/abilities/effects/common/NameACardEffect.java index 1a642fac0f0..7cf32682fa6 100644 --- a/Mage/src/mage/abilities/effects/common/NameACardEffect.java +++ b/Mage/src/mage/abilities/effects/common/NameACardEffect.java @@ -73,7 +73,7 @@ public class NameACardEffect extends OneShotEffect { Player controller = game.getPlayer(source.getControllerId()); MageObject sourceObject = game.getPermanentEntering(source.getSourceId()); if (sourceObject == null) { - game.getObject(source.getSourceId()); + sourceObject = game.getObject(source.getSourceId()); } if (controller != null && sourceObject != null) { Choice cardChoice = new ChoiceImpl(); From 7ac0fe65ef56667554e946a1b519e8bf82337ece Mon Sep 17 00:00:00 2001 From: LevelX2 Date: Wed, 21 Oct 2015 23:24:04 +0200 Subject: [PATCH 206/268] * Fixed bug that prevented to use mana abilities manually. --- Mage.Common/src/mage/utils/MageVersion.java | 2 +- .../src/mage/player/human/HumanPlayer.java | 5 ++++- Mage/src/mage/players/PlayerImpl.java | 7 +++++-- 3 files changed, 10 insertions(+), 4 deletions(-) diff --git a/Mage.Common/src/mage/utils/MageVersion.java b/Mage.Common/src/mage/utils/MageVersion.java index bc712e76d26..e364f13edc9 100644 --- a/Mage.Common/src/mage/utils/MageVersion.java +++ b/Mage.Common/src/mage/utils/MageVersion.java @@ -41,7 +41,7 @@ public class MageVersion implements Serializable, Comparable { public final static int MAGE_VERSION_MAJOR = 1; public final static int MAGE_VERSION_MINOR = 4; public final static int MAGE_VERSION_PATCH = 4; - public final static String MAGE_VERSION_MINOR_PATCH = "v9"; + public final static String MAGE_VERSION_MINOR_PATCH = "v10"; public final static String MAGE_VERSION_INFO = ""; private final int major; diff --git a/Mage.Server.Plugins/Mage.Player.Human/src/mage/player/human/HumanPlayer.java b/Mage.Server.Plugins/Mage.Player.Human/src/mage/player/human/HumanPlayer.java index ce033535822..96a5dfc7ebe 100644 --- a/Mage.Server.Plugins/Mage.Player.Human/src/mage/player/human/HumanPlayer.java +++ b/Mage.Server.Plugins/Mage.Player.Human/src/mage/player/human/HumanPlayer.java @@ -47,6 +47,7 @@ import mage.abilities.SpellAbility; import mage.abilities.TriggeredAbility; import mage.abilities.costs.VariableCost; import mage.abilities.costs.common.SacrificeSourceCost; +import mage.abilities.costs.common.TapSourceCost; import mage.abilities.costs.mana.ManaCost; import mage.abilities.costs.mana.ManaCostsImpl; import mage.abilities.costs.mana.PhyrexianManaCost; @@ -1222,7 +1223,9 @@ public class HumanPlayer extends PlayerImpl { updateGameStatePriority("activateAbility", game); if (abilities.size() == 1 && suppressAbilityPicker(abilities.values().iterator().next())) { ActivatedAbility ability = abilities.values().iterator().next(); - if (ability.getTargets().size() != 0 || !(ability.getCosts().size() == 1 && ability.getCosts().get(0) instanceof SacrificeSourceCost)) { + if (ability.getTargets().size() != 0 + || !(ability.getCosts().size() == 1 && ability.getCosts().get(0) instanceof SacrificeSourceCost) + || !(ability.getCosts().size() == 2 && ability.getCosts().get(0) instanceof TapSourceCost && ability.getCosts().get(0) instanceof SacrificeSourceCost)) { activateAbility(ability, game); return; } diff --git a/Mage/src/mage/players/PlayerImpl.java b/Mage/src/mage/players/PlayerImpl.java index cdeb49c91a4..20b7bfafe96 100644 --- a/Mage/src/mage/players/PlayerImpl.java +++ b/Mage/src/mage/players/PlayerImpl.java @@ -1224,8 +1224,11 @@ public abstract class PlayerImpl implements Player, Serializable { if (canUse || ability.getAbilityType().equals(AbilityType.SPECIAL_ACTION)) { if (ability.getZone().match(zone)) { if (ability instanceof ActivatedAbility) { - if (canPlay(((ActivatedAbility) ability), availableMana, object, game)) { -// if (((ActivatedAbility) ability).canActivate(playerId, game)) { + if (ability instanceof ManaAbility) { + if (((ActivatedAbility) ability).canActivate(playerId, game)) { + useable.put(ability.getId(), (ActivatedAbility) ability); + } + } else if (canPlay(((ActivatedAbility) ability), availableMana, object, game)) { useable.put(ability.getId(), (ActivatedAbility) ability); } } else if (ability instanceof AlternativeSourceCosts) { From 9863bce6655dd6d1cfef5748591394306d549ff9 Mon Sep 17 00:00:00 2001 From: LevelX2 Date: Wed, 21 Oct 2015 23:56:51 +0200 Subject: [PATCH 207/268] xmage 1.4.4v11 --- Mage.Common/src/mage/utils/MageVersion.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Mage.Common/src/mage/utils/MageVersion.java b/Mage.Common/src/mage/utils/MageVersion.java index e364f13edc9..560f6c74042 100644 --- a/Mage.Common/src/mage/utils/MageVersion.java +++ b/Mage.Common/src/mage/utils/MageVersion.java @@ -41,7 +41,7 @@ public class MageVersion implements Serializable, Comparable { public final static int MAGE_VERSION_MAJOR = 1; public final static int MAGE_VERSION_MINOR = 4; public final static int MAGE_VERSION_PATCH = 4; - public final static String MAGE_VERSION_MINOR_PATCH = "v10"; + public final static String MAGE_VERSION_MINOR_PATCH = "v11"; public final static String MAGE_VERSION_INFO = ""; private final int major; From 1758b62f5844a11dd9bc43ef59d861b0e4a4c8be Mon Sep 17 00:00:00 2001 From: LevelX2 Date: Thu, 22 Oct 2015 00:07:30 +0200 Subject: [PATCH 208/268] * Fixed a bug for cards that choose a mode as entering the battlefield (e.g. Outpost Siege). --- .../mage/abilities/effects/common/ChooseModeEffect.java | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/Mage/src/mage/abilities/effects/common/ChooseModeEffect.java b/Mage/src/mage/abilities/effects/common/ChooseModeEffect.java index 796f3e7fce7..65f31d139c2 100644 --- a/Mage/src/mage/abilities/effects/common/ChooseModeEffect.java +++ b/Mage/src/mage/abilities/effects/common/ChooseModeEffect.java @@ -69,6 +69,9 @@ public class ChooseModeEffect extends OneShotEffect { public boolean apply(Game game, Ability source) { Player controller = game.getPlayer(source.getControllerId()); Permanent sourcePermanent = game.getPermanent(source.getSourceId()); + if (sourcePermanent == null) { + sourcePermanent = game.getPermanentEntering(source.getSourceId()); + } if (controller != null) { Choice choice = new ChoiceImpl(true); choice.setMessage(choiceMessage); @@ -80,8 +83,9 @@ public class ChooseModeEffect extends OneShotEffect { controller.choose(Outcome.Neutral, choice, game); } if (choice.isChosen()) { - if (!game.isSimulation()) + if (!game.isSimulation()) { game.informPlayers(new StringBuilder(sourcePermanent.getLogName()).append(": ").append(controller.getLogName()).append(" has chosen ").append(choice.getChoice()).toString()); + } game.getState().setValue(source.getSourceId() + "_modeChoice", choice.getChoice()); sourcePermanent.addInfo("_modeChoice", "Chosen mode: " + choice.getChoice() + "", game); } @@ -93,7 +97,7 @@ public class ChooseModeEffect extends OneShotEffect { private String setText() { StringBuilder sb = new StringBuilder("choose "); int count = 0; - for (String choice: modes) { + for (String choice : modes) { count++; sb.append(choice); if (count + 1 < modes.size()) { From ae69986aef21f38fc434664e731292c49e7b31f0 Mon Sep 17 00:00:00 2001 From: LevelX2 Date: Thu, 22 Oct 2015 01:00:17 +0200 Subject: [PATCH 209/268] * Fixed a bug that the AI did not handle to target a card in its hand (e.g. Chrome Mox). --- .../java/mage/player/ai/ComputerPlayer.java | 5 ++- .../src/mage/sets/mirrodin/ChromeMox.java | 43 +++++++++++-------- .../effects/common/ChooseModeEffect.java | 2 +- 3 files changed, 30 insertions(+), 20 deletions(-) diff --git a/Mage.Server.Plugins/Mage.Player.AI/src/main/java/mage/player/ai/ComputerPlayer.java b/Mage.Server.Plugins/Mage.Player.AI/src/main/java/mage/player/ai/ComputerPlayer.java index f8666697568..d967799a0d1 100644 --- a/Mage.Server.Plugins/Mage.Player.AI/src/main/java/mage/player/ai/ComputerPlayer.java +++ b/Mage.Server.Plugins/Mage.Player.AI/src/main/java/mage/player/ai/ComputerPlayer.java @@ -322,9 +322,10 @@ public class ComputerPlayer extends PlayerImpl implements Player { return target.isChosen(); } - if (target instanceof TargetCardInHand) { + if (target instanceof TargetCardInHand + || (target.getZone().equals(Zone.HAND) && (target instanceof TargetCard))) { List cards = new ArrayList<>(); - for (UUID cardId : ((TargetCardInHand) target).possibleTargets(sourceId, this.getId(), game)) { + for (UUID cardId : target.possibleTargets(sourceId, this.getId(), game)) { Card card = game.getCard(cardId); if (card != null) { cards.add(card); diff --git a/Mage.Sets/src/mage/sets/mirrodin/ChromeMox.java b/Mage.Sets/src/mage/sets/mirrodin/ChromeMox.java index 73fff870bc8..a480d10d23e 100644 --- a/Mage.Sets/src/mage/sets/mirrodin/ChromeMox.java +++ b/Mage.Sets/src/mage/sets/mirrodin/ChromeMox.java @@ -29,6 +29,7 @@ package mage.sets.mirrodin; import java.util.List; import java.util.UUID; +import mage.MageObject; import mage.Mana; import mage.ObjectColor; import mage.abilities.Ability; @@ -52,6 +53,8 @@ import mage.game.Game; import mage.game.permanent.Permanent; import mage.players.Player; import mage.target.TargetCard; +import mage.util.CardUtil; +import mage.util.GameLog; /** * @@ -82,9 +85,11 @@ public class ChromeMox extends CardImpl { class ChromeMoxEffect extends OneShotEffect { private static final FilterCard filter = new FilterCard("nonartifact, nonland card"); + static { filter.add(Predicates.not(Predicates.or(new CardTypePredicate(CardType.LAND), new CardTypePredicate(CardType.ARTIFACT)))); } + public ChromeMoxEffect() { super(Outcome.Benefit); staticText = "exile a nonartifact, nonland card from your hand"; @@ -96,21 +101,29 @@ class ChromeMoxEffect extends OneShotEffect { @java.lang.Override public boolean apply(Game game, Ability source) { - Player player = game.getPlayer(source.getControllerId()); - if (player.getHand().size() > 0) { + Player controller = game.getPlayer(source.getControllerId()); + MageObject sourceObject = source.getSourceObject(game); + if (controller != null && sourceObject != null) { TargetCard target = new TargetCard(Zone.HAND, filter); - player.choose(Outcome.Benefit, target, source.getSourceId(), game); - Card card = player.getHand().get(target.getFirstTarget(), game); - if (card != null) { - card.moveToExile(getId(), "Chrome Mox (Imprint)", source.getSourceId(), game); - Permanent permanent = game.getPermanent(source.getSourceId()); - if (permanent != null) { - permanent.imprint(card.getId(), game); - } - return true; + target.setNotTarget(true); + Card cardToImprint = null; + Permanent sourcePermanent = game.getPermanent(source.getSourceId()); + if (controller.getHand().size() > 0 && controller.choose(Outcome.Benefit, target, source.getSourceId(), game)) { + cardToImprint = controller.getHand().get(target.getFirstTarget(), game); } + if (sourcePermanent != null) { + if (cardToImprint != null) { + controller.moveCardsToExile(cardToImprint, source, game, true, source.getSourceId(), sourceObject.getIdName() + " (Imprint)"); + sourcePermanent.imprint(cardToImprint.getId(), game); + sourcePermanent.addInfo("imprint", CardUtil.addToolTipMarkTags("[Imprinted card - " + GameLog.getColoredObjectIdNameForTooltip(cardToImprint) + "]"), game); + } else { + sourcePermanent.addInfo("imprint", CardUtil.addToolTipMarkTags("[Imprinted card - None]"), game); + } + } + return true; + } - return true; + return false; } @java.lang.Override @@ -118,12 +131,10 @@ class ChromeMoxEffect extends OneShotEffect { return new ChromeMoxEffect(this); } - } class ChromeMoxManaEffect extends ManaEffect { - ChromeMoxManaEffect() { super(); staticText = "Add one mana of any of the exiled card's colors to your mana pool"; @@ -133,8 +144,6 @@ class ChromeMoxManaEffect extends ManaEffect { super(effect); } - - @java.lang.Override public ChromeMoxManaEffect copy() { return new ChromeMoxManaEffect(this); @@ -202,4 +211,4 @@ class ChromeMoxManaEffect extends ManaEffect { return null; } -} \ No newline at end of file +} diff --git a/Mage/src/mage/abilities/effects/common/ChooseModeEffect.java b/Mage/src/mage/abilities/effects/common/ChooseModeEffect.java index 65f31d139c2..bdfac9f3216 100644 --- a/Mage/src/mage/abilities/effects/common/ChooseModeEffect.java +++ b/Mage/src/mage/abilities/effects/common/ChooseModeEffect.java @@ -84,7 +84,7 @@ public class ChooseModeEffect extends OneShotEffect { } if (choice.isChosen()) { if (!game.isSimulation()) { - game.informPlayers(new StringBuilder(sourcePermanent.getLogName()).append(": ").append(controller.getLogName()).append(" has chosen ").append(choice.getChoice()).toString()); + game.informPlayers(sourcePermanent.getLogName() + ": " + controller.getLogName() + " has chosen " + choice.getChoice()); } game.getState().setValue(source.getSourceId() + "_modeChoice", choice.getChoice()); sourcePermanent.addInfo("_modeChoice", "Chosen mode: " + choice.getChoice() + "", game); From 02f88b94c07f8f2999c2632a2774c0d344e71da1 Mon Sep 17 00:00:00 2001 From: LevelX2 Date: Thu, 22 Oct 2015 09:15:48 +0200 Subject: [PATCH 210/268] * Kaalia of the Vast - Fixed that the selected creature card from hand was not put to battlefield. --- Mage.Sets/src/mage/sets/commander/KaaliaOfTheVast.java | 1 - 1 file changed, 1 deletion(-) diff --git a/Mage.Sets/src/mage/sets/commander/KaaliaOfTheVast.java b/Mage.Sets/src/mage/sets/commander/KaaliaOfTheVast.java index bc05511f481..ab1c397d693 100644 --- a/Mage.Sets/src/mage/sets/commander/KaaliaOfTheVast.java +++ b/Mage.Sets/src/mage/sets/commander/KaaliaOfTheVast.java @@ -160,7 +160,6 @@ class KaaliaOfTheVastEffect extends OneShotEffect { if (card != null && game.getCombat() != null) { UUID defenderId = game.getCombat().getDefendingPlayerId(source.getSourceId(), game); if (defenderId != null) { - controller.getHand().remove(card); controller.moveCards(card, Zone.BATTLEFIELD, source, game, true, false, false, null); Permanent creature = game.getPermanent(cardId); if (creature != null) { From d26b8aeae06f9d52083cb583ad24ebd30d6ab500 Mon Sep 17 00:00:00 2001 From: LevelX2 Date: Thu, 22 Oct 2015 13:31:32 +0200 Subject: [PATCH 211/268] * The Great Aurora - Fixed that the lands came always tapped onto the battlefield. * Some minor changes to card movement. --- .../mage/sets/gatecrash/EnterTheInfinite.java | 42 ++++++++--------- .../sets/magicorigins/TheGreatAurora.java | 2 +- .../src/mage/sets/tempest/DreamCache.java | 47 ++++++++----------- .../mage/sets/venservskoth/SawtoothLoon.java | 27 +++++------ .../sets/worldwake/JaceTheMindSculptor.java | 27 ++++------- ...dHandLibraryForCardNameAndExileEffect.java | 29 ++---------- 6 files changed, 66 insertions(+), 108 deletions(-) diff --git a/Mage.Sets/src/mage/sets/gatecrash/EnterTheInfinite.java b/Mage.Sets/src/mage/sets/gatecrash/EnterTheInfinite.java index a53a1e0b985..b0710850a27 100644 --- a/Mage.Sets/src/mage/sets/gatecrash/EnterTheInfinite.java +++ b/Mage.Sets/src/mage/sets/gatecrash/EnterTheInfinite.java @@ -27,6 +27,7 @@ */ package mage.sets.gatecrash; +import java.util.UUID; import mage.abilities.Ability; import mage.abilities.dynamicvalue.DynamicValue; import mage.abilities.effects.Effect; @@ -35,14 +36,17 @@ import mage.abilities.effects.common.DrawCardSourceControllerEffect; import mage.abilities.effects.common.continuous.MaximumHandSizeControllerEffect; import mage.cards.Card; import mage.cards.CardImpl; -import mage.constants.*; +import mage.cards.CardsImpl; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.Outcome; +import mage.constants.PhaseStep; +import mage.constants.Rarity; import mage.game.Game; import mage.game.turn.Step; import mage.players.Player; import mage.target.common.TargetCardInHand; -import java.util.UUID; - /** * * @author LevelX2 @@ -53,8 +57,7 @@ public class EnterTheInfinite extends CardImpl { super(ownerId, 34, "Enter the Infinite", Rarity.MYTHIC, new CardType[]{CardType.SORCERY}, "{8}{U}{U}{U}{U}"); this.expansionSetCode = "GTC"; - - // Draw cards equal to the number of cards in your library, + // Draw cards equal to the number of cards in your library, this.getSpellAbility().addEffect(new DrawCardSourceControllerEffect(new CardsInControllerLibraryCount())); //then put a card from your hand on top of your library. this.getSpellAbility().addEffect(new PutCardOnLibraryEffect()); @@ -72,8 +75,8 @@ public class EnterTheInfinite extends CardImpl { } } - class CardsInControllerLibraryCount implements DynamicValue { + @Override public int calculate(Game game, Ability sourceAbility, Effect effect) { if (sourceAbility != null) { @@ -119,14 +122,13 @@ class PutCardOnLibraryEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { - Player player = game.getPlayer(source.getControllerId()); - if (player != null) { + Player controller = game.getPlayer(source.getControllerId()); + if (controller != null) { TargetCardInHand target = new TargetCardInHand(); - player.chooseTarget(Outcome.ReturnToHand, target, source, game); - Card card = player.getHand().get(target.getFirstTarget(), game); + controller.chooseTarget(Outcome.ReturnToHand, target, source, game); + Card card = controller.getHand().get(target.getFirstTarget(), game); if (card != null) { - player.getHand().remove(card); - card.moveToZone(Zone.LIBRARY, source.getSourceId(), game, true); + controller.putCardsOnTopOfLibrary(new CardsImpl(card), game, source, false); } return true; } @@ -134,29 +136,27 @@ class PutCardOnLibraryEffect extends OneShotEffect { } } +class MaximumHandSizeEffect extends MaximumHandSizeControllerEffect { -class MaximumHandSizeEffect extends MaximumHandSizeControllerEffect{ - - public MaximumHandSizeEffect(){ + public MaximumHandSizeEffect() { super(Integer.MAX_VALUE, Duration.Custom, MaximumHandSizeControllerEffect.HandSizeModification.SET); staticText = "You have no maximum hand size until your next turn"; } - - public MaximumHandSizeEffect(final MaximumHandSizeEffect effect) { + + public MaximumHandSizeEffect(final MaximumHandSizeEffect effect) { super(effect); } - + @Override public boolean isInactive(Ability source, Game game) { - if (game.getPhase().getStep().getType() == PhaseStep.UNTAP && game.getStep().getStepPart() == Step.StepPart.PRE) - { + if (game.getPhase().getStep().getType() == PhaseStep.UNTAP && game.getStep().getStepPart() == Step.StepPart.PRE) { if (game.getActivePlayerId().equals(source.getControllerId())) { return true; } } return false; } - + @Override public MaximumHandSizeEffect copy() { return new MaximumHandSizeEffect(this); diff --git a/Mage.Sets/src/mage/sets/magicorigins/TheGreatAurora.java b/Mage.Sets/src/mage/sets/magicorigins/TheGreatAurora.java index 2fcfe39ffe4..82e8cf76365 100644 --- a/Mage.Sets/src/mage/sets/magicorigins/TheGreatAurora.java +++ b/Mage.Sets/src/mage/sets/magicorigins/TheGreatAurora.java @@ -147,7 +147,7 @@ class TheGreatAuroraEffect extends OneShotEffect { toBattlefield.addAll(target.getTargets()); } } - return controller.moveCards(toBattlefield.getCards(game), Zone.BATTLEFIELD, source, game, true, false, true, null); + return controller.moveCards(toBattlefield.getCards(game), Zone.BATTLEFIELD, source, game, false, false, true, null); } return false; } diff --git a/Mage.Sets/src/mage/sets/tempest/DreamCache.java b/Mage.Sets/src/mage/sets/tempest/DreamCache.java index 6d223175be0..0aa934b4bf7 100644 --- a/Mage.Sets/src/mage/sets/tempest/DreamCache.java +++ b/Mage.Sets/src/mage/sets/tempest/DreamCache.java @@ -30,12 +30,13 @@ package mage.sets.tempest; import java.util.UUID; import mage.abilities.Ability; import mage.abilities.effects.OneShotEffect; -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.FilterCard; import mage.game.Game; import mage.players.Player; import mage.target.common.TargetCardInHand; @@ -50,7 +51,6 @@ public class DreamCache extends CardImpl { super(ownerId, 59, "Dream Cache", Rarity.COMMON, new CardType[]{CardType.SORCERY}, "{2}{U}"); this.expansionSetCode = "TMP"; - // Draw three cards, then put two cards from your hand both on top of your library or both on the bottom of your library. this.getSpellAbility().addEffect(new DreamCacheEffect()); } @@ -71,7 +71,7 @@ class DreamCacheEffect extends OneShotEffect { super(Outcome.DrawCard); this.staticText = "Draw three cards, then put two cards from your hand both on top of your library or both on the bottom of your library."; } - + public DreamCacheEffect(final DreamCacheEffect effect) { super(effect); } @@ -80,33 +80,26 @@ class DreamCacheEffect extends OneShotEffect { public DreamCacheEffect copy() { return new DreamCacheEffect(this); } - + @Override public boolean apply(Game game, Ability source) { - Player player = game.getPlayer(source.getControllerId()); - if (player != null) { - player.drawCards(3, game); - - boolean putOnTop = player.chooseUse(Outcome.Neutral, "Put cards on top?", source, game); - putInLibrary(player, source, game, putOnTop); - putInLibrary(player, source, game, putOnTop); - + Player controller = game.getPlayer(source.getControllerId()); + if (controller != null) { + controller.drawCards(3, game); + boolean putOnTop = controller.chooseUse(Outcome.Neutral, "Put cards on top?", source, game); + TargetCardInHand target = new TargetCardInHand(2, 2, new FilterCard()); + controller.chooseTarget(Outcome.Detriment, target, source, game); + Cards cardsToLibrary = new CardsImpl(target.getTargets()); + if (!cardsToLibrary.isEmpty()) { + if (putOnTop) { + controller.putCardsOnTopOfLibrary(cardsToLibrary, game, source, false); + } else { + controller.putCardsOnBottomOfLibrary(cardsToLibrary, game, source, false); + } + } return true; } return false; } - - private boolean putInLibrary(Player player, Ability source, Game game, boolean putOnTop) { - if (player.getHand().size() > 0) { - TargetCardInHand target = new TargetCardInHand(); - player.chooseTarget(Outcome.Detriment, target, source, game); - Card card = player.getHand().get(target.getFirstTarget(), game); - if (card != null) { - player.getHand().remove(card); - card.moveToZone(Zone.LIBRARY, source.getSourceId(), game, putOnTop); - return true; - } - } - return false; - } + } diff --git a/Mage.Sets/src/mage/sets/venservskoth/SawtoothLoon.java b/Mage.Sets/src/mage/sets/venservskoth/SawtoothLoon.java index ccef7acff4d..a4c3ff1e73c 100644 --- a/Mage.Sets/src/mage/sets/venservskoth/SawtoothLoon.java +++ b/Mage.Sets/src/mage/sets/venservskoth/SawtoothLoon.java @@ -35,12 +35,13 @@ import mage.abilities.common.EntersBattlefieldTriggeredAbility; import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.ReturnToHandChosenControlledPermanentEffect; import mage.abilities.keyword.FlyingAbility; -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.FilterCard; import mage.filter.common.FilterControlledCreaturePermanent; import mage.filter.predicate.Predicates; import mage.filter.predicate.mageobject.ColorPredicate; @@ -58,8 +59,8 @@ public class SawtoothLoon extends CardImpl { static { Predicates.or( - new ColorPredicate(ObjectColor.WHITE), - new ColorPredicate(ObjectColor.BLUE)); + new ColorPredicate(ObjectColor.WHITE), + new ColorPredicate(ObjectColor.BLUE)); } public SawtoothLoon(UUID ownerId) { @@ -110,21 +111,15 @@ class SawtoothLoonEffect extends OneShotEffect { Player controller = game.getPlayer(source.getControllerId()); if (controller != null) { controller.drawCards(2, game); - putOnLibrary(controller, source, game); - putOnLibrary(controller, source, game); + TargetCardInHand target = new TargetCardInHand(2, 2, new FilterCard()); + controller.chooseTarget(Outcome.Detriment, target, source, game); + Cards cardsToLibrary = new CardsImpl(target.getTargets()); + if (!cardsToLibrary.isEmpty()) { + controller.putCardsOnBottomOfLibrary(cardsToLibrary, game, source, false); + } return true; } return false; } - private boolean putOnLibrary(Player player, Ability source, Game game) { - TargetCardInHand target = new TargetCardInHand(); - player.chooseTarget(Outcome.ReturnToHand, target, source, game); - Card card = player.getHand().get(target.getFirstTarget(), game); - if (card != null) { - player.getHand().remove(card); - player.moveCardToLibraryWithInfo(card, source.getSourceId(), game, Zone.HAND, false, false); - } - return true; - } } diff --git a/Mage.Sets/src/mage/sets/worldwake/JaceTheMindSculptor.java b/Mage.Sets/src/mage/sets/worldwake/JaceTheMindSculptor.java index d68cd5c7eda..26c00ef4c85 100644 --- a/Mage.Sets/src/mage/sets/worldwake/JaceTheMindSculptor.java +++ b/Mage.Sets/src/mage/sets/worldwake/JaceTheMindSculptor.java @@ -41,6 +41,7 @@ import mage.constants.CardType; import mage.constants.Outcome; import mage.constants.Rarity; import mage.constants.Zone; +import mage.filter.FilterCard; import mage.game.Game; import mage.players.Player; import mage.target.TargetPlayer; @@ -148,27 +149,19 @@ class JaceTheMindSculptorEffect2 extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { - Player player = game.getPlayer(source.getControllerId()); - if (player != null) { - player.drawCards(3, game); - putOnLibrary(player, source, game); - putOnLibrary(player, source, game); + Player controller = game.getPlayer(source.getControllerId()); + if (controller != null) { + controller.drawCards(3, game); + TargetCardInHand target = new TargetCardInHand(2, 2, new FilterCard()); + controller.chooseTarget(Outcome.Detriment, target, source, game); + Cards cardsToLibrary = new CardsImpl(target.getTargets()); + if (!cardsToLibrary.isEmpty()) { + controller.putCardsOnTopOfLibrary(cardsToLibrary, game, source, true); + } return true; } return false; } - - private boolean putOnLibrary(Player player, Ability source, Game game) { - TargetCardInHand target = new TargetCardInHand(); - player.chooseTarget(Outcome.ReturnToHand, target, source, game); - Card card = player.getHand().get(target.getFirstTarget(), game); - if (card != null) { - player.getHand().remove(card); - player.moveCardToLibraryWithInfo(card, source.getSourceId(), game, Zone.HAND, true, false); - } - return true; - } - } class JaceTheMindSculptorEffect3 extends OneShotEffect { diff --git a/Mage/src/mage/abilities/effects/common/search/SearchTargetGraveyardHandLibraryForCardNameAndExileEffect.java b/Mage/src/mage/abilities/effects/common/search/SearchTargetGraveyardHandLibraryForCardNameAndExileEffect.java index dd9c3c94e60..3f14a35fd38 100644 --- a/Mage/src/mage/abilities/effects/common/search/SearchTargetGraveyardHandLibraryForCardNameAndExileEffect.java +++ b/Mage/src/mage/abilities/effects/common/search/SearchTargetGraveyardHandLibraryForCardNameAndExileEffect.java @@ -27,12 +27,10 @@ */ package mage.abilities.effects.common.search; -import java.util.List; import java.util.UUID; import mage.abilities.Ability; import mage.abilities.Mode; import mage.abilities.effects.OneShotEffect; -import mage.cards.Card; import mage.cards.Cards; import mage.cards.CardsImpl; import mage.constants.Outcome; @@ -98,14 +96,7 @@ public abstract class SearchTargetGraveyardHandLibraryForCardNameAndExileEffect filter.setMessage("card named " + cardName + " in the graveyard of " + targetPlayer.getLogName()); TargetCard target = new TargetCard((graveyardExileOptional ? 0 : cardsCount), cardsCount, Zone.GRAVEYARD, filter); if (controller.choose(Outcome.Exile, targetPlayer.getGraveyard(), target, game)) { - List targets = target.getTargets(); - for (UUID targetId : targets) { - Card targetCard = targetPlayer.getGraveyard().get(targetId, game); - if (targetCard != null) { - targetPlayer.getGraveyard().remove(targetCard); - controller.moveCardToExileWithInfo(targetCard, null, null, source.getSourceId(), game, Zone.GRAVEYARD, true); - } - } + controller.moveCards(new CardsImpl(target.getTargets()), Zone.EXILED, source, game); } } @@ -114,14 +105,7 @@ public abstract class SearchTargetGraveyardHandLibraryForCardNameAndExileEffect filter.setMessage("card named " + cardName + " in the hand of " + targetPlayer.getLogName()); TargetCard target = new TargetCard(0, cardsCount, Zone.HAND, filter); if (controller.choose(Outcome.Exile, targetPlayer.getHand(), target, game)) { - List targets = target.getTargets(); - for (UUID targetId : targets) { - Card targetCard = targetPlayer.getHand().get(targetId, game); - if (targetCard != null) { - targetPlayer.getHand().remove(targetCard); - controller.moveCardToExileWithInfo(targetCard, null, null, source.getSourceId(), game, Zone.HAND, true); - } - } + controller.moveCards(new CardsImpl(target.getTargets()), Zone.EXILED, source, game); } // cards in Library @@ -131,15 +115,8 @@ public abstract class SearchTargetGraveyardHandLibraryForCardNameAndExileEffect filter.setMessage("card named " + cardName + " in the library of " + targetPlayer.getLogName()); TargetCardInLibrary targetLib = new TargetCardInLibrary(0, cardsCount, filter); if (controller.choose(Outcome.Exile, cardsInLibrary, targetLib, game)) { - List targets = targetLib.getTargets(); - for (UUID targetId : targets) { - Card targetCard = targetPlayer.getLibrary().remove(targetId, game); - if (targetCard != null) { - controller.moveCardToExileWithInfo(targetCard, null, null, source.getSourceId(), game, Zone.LIBRARY, true); - } - } + controller.moveCards(new CardsImpl(target.getTargets()), Zone.EXILED, source, game); } - targetPlayer.shuffleLibrary(game); } From af67e27bcd920b32e96dfd9b74bcbb6e3c3c40eb Mon Sep 17 00:00:00 2001 From: LevelX2 Date: Thu, 22 Oct 2015 15:37:58 +0200 Subject: [PATCH 212/268] * Alesha, Who Smiles at Death - Fixed that the move card to battlefield worked not correctly. --- .../mage/sets/fatereforged/AleshaWhoSmilesAtDeath.java | 10 ++++------ .../serverside/base/impl/CardTestPlayerAPIImpl.java | 8 ++++++-- 2 files changed, 10 insertions(+), 8 deletions(-) diff --git a/Mage.Sets/src/mage/sets/fatereforged/AleshaWhoSmilesAtDeath.java b/Mage.Sets/src/mage/sets/fatereforged/AleshaWhoSmilesAtDeath.java index 48380d0e00c..512e63ad699 100644 --- a/Mage.Sets/src/mage/sets/fatereforged/AleshaWhoSmilesAtDeath.java +++ b/Mage.Sets/src/mage/sets/fatereforged/AleshaWhoSmilesAtDeath.java @@ -45,7 +45,6 @@ import mage.filter.Filter; import mage.filter.common.FilterCreatureCard; import mage.filter.predicate.mageobject.PowerPredicate; import mage.game.Game; -import mage.game.permanent.Permanent; import mage.players.Player; import mage.target.common.TargetCardInYourGraveyard; @@ -72,11 +71,11 @@ public class AleshaWhoSmilesAtDeath extends CardImpl { // First strike this.addAbility(FirstStrikeAbility.getInstance()); - + // Whenever Alesha, Who Smiles at Death attacks, you may pay {W/B}{W/B}. If you do, return target creature card with power 2 or less from your graveyard to the battlefield tapped and attacking. Ability ability = new AttacksTriggeredAbility(new DoIfCostPaid(new AleshaWhoSmilesAtDeathEffect(), new ManaCostsImpl("{W/B}{W/B}")), false); ability.addTarget(new TargetCardInYourGraveyard(filter)); - this.addAbility(ability); + this.addAbility(ability); } public AleshaWhoSmilesAtDeath(final AleshaWhoSmilesAtDeath card) { @@ -107,9 +106,8 @@ class AleshaWhoSmilesAtDeathEffect extends OneShotEffect { if (controller != null) { Card card = game.getCard(getTargetPointer().getFirst(game, source)); if (card != null) { - if (card.putOntoBattlefield(game, Zone.GRAVEYARD, source.getSourceId(), source.getControllerId(), true)) { - Permanent permanent = game.getPermanent(card.getId()); - game.getCombat().addAttackingCreature(permanent.getId(), game); + if (controller.moveCards(card, Zone.BATTLEFIELD, source, game, true, false, false, null)) { + game.getCombat().addAttackingCreature(card.getId(), game); } } return true; diff --git a/Mage.Tests/src/test/java/org/mage/test/serverside/base/impl/CardTestPlayerAPIImpl.java b/Mage.Tests/src/test/java/org/mage/test/serverside/base/impl/CardTestPlayerAPIImpl.java index 8611baa943c..4b9cc8f0eb5 100644 --- a/Mage.Tests/src/test/java/org/mage/test/serverside/base/impl/CardTestPlayerAPIImpl.java +++ b/Mage.Tests/src/test/java/org/mage/test/serverside/base/impl/CardTestPlayerAPIImpl.java @@ -614,14 +614,18 @@ public abstract class CardTestPlayerAPIImpl extends MageTestPlayerBase implement * @param count Expected count. */ public void assertCounterCount(String cardName, CounterType type, int count) throws AssertionError { + this.assertCounterCount(null, cardName, type, count); + } + + public void assertCounterCount(Player player, String cardName, CounterType type, int count) throws AssertionError { Permanent found = null; for (Permanent permanent : currentGame.getBattlefield().getAllActivePermanents()) { - if (permanent.getName().equals(cardName)) { + if (permanent.getName().equals(cardName) && (player == null || permanent.getControllerId().equals(player.getId()))) { found = permanent; break; } } - Assert.assertNotNull("There is no such permanent on the battlefield, cardName=" + cardName, found); + Assert.assertNotNull("There is no such permanent " + (player == null ? "" : "for player " + player.getName()) + " on the battlefield, cardName=" + cardName, found); Assert.assertEquals("(Battlefield) Counter counts are not equal (" + cardName + ":" + type + ")", count, found.getCounters().getCount(type)); } From 2aaea46dc6339c255062d8c73a26ff9fb53ea45f Mon Sep 17 00:00:00 2001 From: LevelX2 Date: Thu, 22 Oct 2015 15:38:50 +0200 Subject: [PATCH 213/268] * Fixed that the exile and return effect of the flip planeswalker did not always work correctly. --- .../cards/copy/CleverImpersonatorTest.java | 104 ++++++++++++++++++ ...lkerEntersWithLoyalityCountersAbility.java | 2 +- ...ExileAndReturnTransformedSourceEffect.java | 11 +- Mage/src/mage/game/GameImpl.java | 2 +- 4 files changed, 111 insertions(+), 8 deletions(-) diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/copy/CleverImpersonatorTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/copy/CleverImpersonatorTest.java index c045c0998af..ba0ab31d770 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/copy/CleverImpersonatorTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/copy/CleverImpersonatorTest.java @@ -29,6 +29,7 @@ package org.mage.test.cards.copy; import mage.constants.PhaseStep; import mage.constants.Zone; +import mage.counters.CounterType; import org.junit.Test; import org.mage.test.serverside.base.CardTestPlayerBase; @@ -72,4 +73,107 @@ public class CleverImpersonatorTest extends CardTestPlayerBase { assertPermanentCount(playerB, "Gilded Drake", 1); assertPermanentCount(playerB, "Pillarfield Ox", 1); } + + /** + * Copy a planeswalker on the battlefield + */ + @Test + public void testCopyPlaneswalker() { + addCard(Zone.BATTLEFIELD, playerA, "Island", 4); + + // You may have Clever Impersonator enter the battlefield as a copy of any nonland permanent on the battlefield. + addCard(Zone.HAND, playerA, "Clever Impersonator", 1); // {2}{U}{U} + + // +2: Each player discards a card. + // -X: Return target nonlegendary creature with converted mana cost X from your graveyard to the battlefield. + // -8: You get an emblem with "Whenever a creature dies, return it to the battlefield under your control at the beginning of the next end step."; + addCard(Zone.BATTLEFIELD, playerB, "Liliana, Defiant Necromancer", 1); + + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Clever Impersonator"); + setChoice(playerA, "Liliana, Defiant Necromancer"); + activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "+2: Each player discards a card"); + + setStopAt(1, PhaseStep.BEGIN_COMBAT); + execute(); + + assertHandCount(playerA, "Clever Impersonator", 0); + assertCounterCount(playerB, "Liliana, Defiant Necromancer", CounterType.LOYALTY, 3); // 3 + assertPermanentCount(playerB, "Liliana, Defiant Necromancer", 1); + assertPermanentCount(playerA, "Liliana, Defiant Necromancer", 1); + assertCounterCount(playerA, "Liliana, Defiant Necromancer", CounterType.LOYALTY, 5); // 3 + 2 + } + + /** + * I had an Alesha, Who Smiles at Death returning a Clever Impersonator who + * was supposed to copy a flipped Liliana, Defiant Necromancer, but it + * entered the battlefield with 0 loyalty and died immediately. If I am not + * mistaken it should have entered with 3 loyalty (see Gatherer entry). + */ + @Test + public void testCopyPlaneswalkerFromGraveyard() { + addCard(Zone.BATTLEFIELD, playerA, "Plains", 2); + // First strike + // Whenever Alesha, Who Smiles at Death attacks, you may pay {W/B}{W/B}. If you do, return target creature card with power 2 or less from your graveyard to the battlefield tapped and attacking. + addCard(Zone.BATTLEFIELD, playerA, "Alesha, Who Smiles at Death", 1); // {2}{R} - 3/2 + + // You may have Clever Impersonator enter the battlefield as a copy of any nonland permanent on the battlefield. + addCard(Zone.GRAVEYARD, playerA, "Clever Impersonator", 1); // {2}{U}{U} + + // +2: Each player discards a card. + // -X: Return target nonlegendary creature with converted mana cost X from your graveyard to the battlefield. + // -8: You get an emblem with "Whenever a creature dies, return it to the battlefield under your control at the beginning of the next end step."; + addCard(Zone.BATTLEFIELD, playerB, "Liliana, Defiant Necromancer", 1); + + attack(1, playerA, "Alesha, Who Smiles at Death"); + addTarget(playerA, "Clever Impersonator"); + setChoice(playerA, "Liliana, Defiant Necromancer"); + + setStopAt(1, PhaseStep.END_TURN); + execute(); + + assertTapped("Alesha, Who Smiles at Death", true); + assertLife(playerB, 17); + assertGraveyardCount(playerA, "Clever Impersonator", 0); + + assertCounterCount(playerB, "Liliana, Defiant Necromancer", CounterType.LOYALTY, 3); // 3 + assertPermanentCount(playerB, "Liliana, Defiant Necromancer", 1); + assertPermanentCount(playerA, "Liliana, Defiant Necromancer", 1); + assertCounterCount(playerA, "Liliana, Defiant Necromancer", CounterType.LOYALTY, 5); // 3 + 2 + } + + /** + * So I copied Jace, Vryns Prodigy with Clever Impersonator (it was tapped + * and I needed a blocker for a token...), and Jace got to survive until the + * next turn. When I looted, he flipped, and I got an error message I + * couldn't get rid of, forcing me to concede. I'm not sure what the correct + * outcome is rules-wise. + */ + @Test + public void testCopyCreatureOfFlipPlaneswalker() { + addCard(Zone.BATTLEFIELD, playerA, "Island", 4); + + // {T}: Draw a card, then discard a card. If there are five or more cards in your graveyard, exile Jace, Vryn's Prodigy, then return him to the battefield transformed under his owner's control. + addCard(Zone.BATTLEFIELD, playerA, "Jace, Vryn's Prodigy", 1); // {2}{R} - 3/2 + + // You may have Clever Impersonator enter the battlefield as a copy of any nonland permanent on the battlefield. + addCard(Zone.HAND, playerA, "Clever Impersonator", 1); // {2}{U}{U} + addCard(Zone.GRAVEYARD, playerA, "Mountain", 4); + + addCard(Zone.BATTLEFIELD, playerB, "Pillarfield Ox", 1); + + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Clever Impersonator"); + setChoice(playerA, "Jace, Vryn's Prodigy"); + addTarget(playerA, "Jace, Vryn's Prodigy[only copy]"); // keep the copied Jace + + activateAbility(3, PhaseStep.PRECOMBAT_MAIN, playerA, "{T}: Draw a card"); + setChoice(playerA, "Pillarfield Ox"); + + setStopAt(3, PhaseStep.BEGIN_COMBAT); + execute(); + + assertGraveyardCount(playerA, "Jace, Vryn's Prodigy", 1); + assertPermanentCount(playerA, "Pillarfield Ox", 1); + + } + } diff --git a/Mage/src/mage/abilities/common/PlanswalkerEntersWithLoyalityCountersAbility.java b/Mage/src/mage/abilities/common/PlanswalkerEntersWithLoyalityCountersAbility.java index aad230eaf2d..05e208b0815 100644 --- a/Mage/src/mage/abilities/common/PlanswalkerEntersWithLoyalityCountersAbility.java +++ b/Mage/src/mage/abilities/common/PlanswalkerEntersWithLoyalityCountersAbility.java @@ -24,7 +24,7 @@ public class PlanswalkerEntersWithLoyalityCountersAbility extends EntersBattlefi } @Override - public EntersBattlefieldAbility copy() { + public PlanswalkerEntersWithLoyalityCountersAbility copy() { return new PlanswalkerEntersWithLoyalityCountersAbility(this); } } diff --git a/Mage/src/mage/abilities/effects/common/ExileAndReturnTransformedSourceEffect.java b/Mage/src/mage/abilities/effects/common/ExileAndReturnTransformedSourceEffect.java index 72874fb2fd0..6f3170a0700 100644 --- a/Mage/src/mage/abilities/effects/common/ExileAndReturnTransformedSourceEffect.java +++ b/Mage/src/mage/abilities/effects/common/ExileAndReturnTransformedSourceEffect.java @@ -61,12 +61,11 @@ public class ExileAndReturnTransformedSourceEffect extends OneShotEffect { Permanent sourceObject = game.getPermanent(source.getSourceId()); Player controller = game.getPlayer(source.getControllerId()); if (sourceObject != null && controller != null && sourceObject.getZoneChangeCounter(game) == source.getSourceObjectZoneChangeCounter()) { - Card card = (Card) sourceObject; - if (controller.moveCards(card, Zone.BATTLEFIELD, Zone.EXILED, source, game)) { - Player owner = game.getPlayer(card.getOwnerId()); - if (owner != null) { - game.getState().setValue(TransformAbility.VALUE_KEY_ENTER_TRANSFORMED + source.getSourceId(), Boolean.TRUE); - owner.moveCards(card, Zone.BATTLEFIELD, source, game); + if (controller.moveCards(sourceObject, Zone.EXILED, source, game)) { + game.getState().setValue(TransformAbility.VALUE_KEY_ENTER_TRANSFORMED + source.getSourceId(), Boolean.TRUE); + Card cardFromExile = game.getCard(source.getSourceId()); + if (cardFromExile != null) { + controller.moveCards(cardFromExile, Zone.BATTLEFIELD, source, game, false, false, true, null); if (additionalEffect != null) { if (additionalEffect instanceof ContinuousEffect) { game.addEffect((ContinuousEffect) additionalEffect, source); diff --git a/Mage/src/mage/game/GameImpl.java b/Mage/src/mage/game/GameImpl.java index 816db0ded7b..ba89c05297f 100644 --- a/Mage/src/mage/game/GameImpl.java +++ b/Mage/src/mage/game/GameImpl.java @@ -1876,7 +1876,7 @@ public abstract class GameImpl implements Game, Serializable { Player controller = this.getPlayer(legend.getControllerId()); if (controller != null) { Target targetLegendaryToKeep = new TargetPermanent(filterLegendName); - targetLegendaryToKeep.setTargetName(new StringBuilder(legend.getName()).append(" to keep (Legendary Rule)?").toString()); + targetLegendaryToKeep.setTargetName(legend.getName() + " to keep (Legendary Rule)?"); controller.chooseTarget(Outcome.Benefit, targetLegendaryToKeep, null, this); for (Permanent dupLegend : getBattlefield().getActivePermanents(filterLegendName, legend.getControllerId(), this)) { if (!targetLegendaryToKeep.getTargets().contains(dupLegend.getId())) { From ff71654a5f4d5f085765af45f08b7bf1521670b9 Mon Sep 17 00:00:00 2001 From: fireshoes Date: Thu, 22 Oct 2015 15:24:23 -0500 Subject: [PATCH 214/268] Added Adam Styborski's Pauper Cube and Army of Allah card. --- .../cubes/AdamStyborskisPauperCube.java | 454 ++++++++++++++++++ Mage.Server/config/config.xml | 1 + Mage.Server/release/config/config.xml | 1 + .../mage/sets/arabiannights/ArmyOfAllah.java | 62 +++ 4 files changed, 518 insertions(+) create mode 100644 Mage.Server.Plugins/Mage.Tournament.BoosterDraft/src/mage/tournament/cubes/AdamStyborskisPauperCube.java create mode 100644 Mage.Sets/src/mage/sets/arabiannights/ArmyOfAllah.java diff --git a/Mage.Server.Plugins/Mage.Tournament.BoosterDraft/src/mage/tournament/cubes/AdamStyborskisPauperCube.java b/Mage.Server.Plugins/Mage.Tournament.BoosterDraft/src/mage/tournament/cubes/AdamStyborskisPauperCube.java new file mode 100644 index 00000000000..66ab2c5a67f --- /dev/null +++ b/Mage.Server.Plugins/Mage.Tournament.BoosterDraft/src/mage/tournament/cubes/AdamStyborskisPauperCube.java @@ -0,0 +1,454 @@ +/* + * 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.tournament.cubes; + +import mage.game.draft.DraftCube; +import mage.game.draft.DraftCube.CardIdentity; + +/** + * + * @author fireshoes + */ +public class AdamStyborskisPauperCube extends DraftCube { + +public AdamStyborskisPauperCube() { + super("Adam Styborkski's Cube (411 cards)"); // https://docs.google.com/spreadsheets/d/12iQhC4bHqFW7hEWxPBjyC8yBDehFZ0_4DkqzyA8EL3o/edit#gid=0 + + cubeCards.add(new CardIdentity("Act of Treason", "")); + cubeCards.add(new CardIdentity("Adventuring Gear", "")); + cubeCards.add(new CardIdentity("Aerie Ouphes", "")); + cubeCards.add(new CardIdentity("AEther Adept", "")); + cubeCards.add(new CardIdentity("AEthersnipe", "")); + cubeCards.add(new CardIdentity("Agony Warp", "")); + cubeCards.add(new CardIdentity("Ambush Viper", "")); + cubeCards.add(new CardIdentity("Apex Hawks", "")); + cubeCards.add(new CardIdentity("Arachnus Web", "")); + cubeCards.add(new CardIdentity("Arc Lightning", "")); + cubeCards.add(new CardIdentity("Armillary Sphere", "")); + cubeCards.add(new CardIdentity("Army of Allah", "")); + cubeCards.add(new CardIdentity("Arrest", "")); + cubeCards.add(new CardIdentity("Ashes to Ashes", "")); + cubeCards.add(new CardIdentity("Assault Zeppelid", "")); + cubeCards.add(new CardIdentity("Attended Knight", "")); + cubeCards.add(new CardIdentity("Auger Spree", "")); + cubeCards.add(new CardIdentity("Aven Riftwatcher", "")); + cubeCards.add(new CardIdentity("Aven Surveyor", "")); + cubeCards.add(new CardIdentity("Azorius Guildgate", "")); + cubeCards.add(new CardIdentity("Baleful Eidolon", "")); + cubeCards.add(new CardIdentity("Barbed Lightning", "")); + cubeCards.add(new CardIdentity("Barren Moor", "")); + cubeCards.add(new CardIdentity("Basking Rootwalla", "")); + cubeCards.add(new CardIdentity("Battle Screech", "")); + cubeCards.add(new CardIdentity("Beetleback Chief", "")); + cubeCards.add(new CardIdentity("Beetleform Mage", "")); + cubeCards.add(new CardIdentity("Blade of the Sixth Pride", "")); + cubeCards.add(new CardIdentity("Blastoderm", "")); + cubeCards.add(new CardIdentity("Blazing Torch", "")); + cubeCards.add(new CardIdentity("Blightning", "")); + cubeCards.add(new CardIdentity("Blinding Beam", "")); + cubeCards.add(new CardIdentity("Bloodfell Caves", "")); + cubeCards.add(new CardIdentity("Blossoming Sands", "")); + cubeCards.add(new CardIdentity("Bonded Construct", "")); + cubeCards.add(new CardIdentity("Bonds of Faith", "")); + cubeCards.add(new CardIdentity("Bonesplitter", "")); + cubeCards.add(new CardIdentity("Boomerang", "")); + cubeCards.add(new CardIdentity("Borderland Marauder", "")); + cubeCards.add(new CardIdentity("Boros Guildgate", "")); + cubeCards.add(new CardIdentity("Branching Bolt", "")); + cubeCards.add(new CardIdentity("Brute Force", "")); + cubeCards.add(new CardIdentity("Burst Lightning", "")); + cubeCards.add(new CardIdentity("Butcher Ghoul", "")); + cubeCards.add(new CardIdentity("Cadaver Imp", "")); + cubeCards.add(new CardIdentity("Cage of Hands", "")); + cubeCards.add(new CardIdentity("Calcite Snapper", "")); + cubeCards.add(new CardIdentity("Capsize", "")); + cubeCards.add(new CardIdentity("Carnivorous Death-Parrot", "")); + cubeCards.add(new CardIdentity("Carnophage", "")); + cubeCards.add(new CardIdentity("Cathodion", "")); + cubeCards.add(new CardIdentity("Cavern Harpy", "")); + cubeCards.add(new CardIdentity("Centaur Healer", "")); + cubeCards.add(new CardIdentity("Centaur's Herald", "")); + cubeCards.add(new CardIdentity("Center Soul", "")); + cubeCards.add(new CardIdentity("Chain Lightning", "")); + cubeCards.add(new CardIdentity("Chainer's Edict", "")); + cubeCards.add(new CardIdentity("Citanul Woodreaders", "")); + cubeCards.add(new CardIdentity("Claustrophobia", "")); + cubeCards.add(new CardIdentity("Clay Statue", "")); + cubeCards.add(new CardIdentity("Cloaked Siren", "")); + cubeCards.add(new CardIdentity("Cloud of Faeries", "")); + cubeCards.add(new CardIdentity("Cloudshift", "")); + cubeCards.add(new CardIdentity("Coalition Honor Guard", "")); + cubeCards.add(new CardIdentity("Cogwork Librarian", "")); + cubeCards.add(new CardIdentity("Colossal Might", "")); + cubeCards.add(new CardIdentity("Compulsive Research", "")); + cubeCards.add(new CardIdentity("Consume Strength", "")); + cubeCards.add(new CardIdentity("Corrupted Zendikon", "")); + cubeCards.add(new CardIdentity("Counterspell", "")); + cubeCards.add(new CardIdentity("Crippling Fatigue", "")); + cubeCards.add(new CardIdentity("Crocanura", "")); + cubeCards.add(new CardIdentity("Crypt Rats", "")); + cubeCards.add(new CardIdentity("Crystallization", "")); + cubeCards.add(new CardIdentity("Cultivate", "")); + cubeCards.add(new CardIdentity("Cunning Strike", "")); + cubeCards.add(new CardIdentity("Curse of Chains", "")); + cubeCards.add(new CardIdentity("Custodi Squire", "")); + cubeCards.add(new CardIdentity("Daring Skyjek", "")); + cubeCards.add(new CardIdentity("Daru Lancer", "")); + cubeCards.add(new CardIdentity("Dauthi Horror", "")); + cubeCards.add(new CardIdentity("Dauthi Marauder", "")); + cubeCards.add(new CardIdentity("Dauthi Mercenary", "")); + cubeCards.add(new CardIdentity("Dauthi Slayer", "")); + cubeCards.add(new CardIdentity("Dead Reveler", "")); + cubeCards.add(new CardIdentity("Dead Weight", "")); + cubeCards.add(new CardIdentity("Death Denied", "")); + cubeCards.add(new CardIdentity("Deep Analysis", "")); + cubeCards.add(new CardIdentity("Deprive", "")); + cubeCards.add(new CardIdentity("Deputy of Acquittals", "")); + cubeCards.add(new CardIdentity("Desert", "")); + cubeCards.add(new CardIdentity("Devour Flesh", "")); + cubeCards.add(new CardIdentity("Diabolic Edict", "")); + cubeCards.add(new CardIdentity("Dimir Guildgate", "")); + cubeCards.add(new CardIdentity("Disfigure", "")); + cubeCards.add(new CardIdentity("Dismal Backwater", "")); + cubeCards.add(new CardIdentity("Distortion Strike", "")); + cubeCards.add(new CardIdentity("Doom Blade", "")); + cubeCards.add(new CardIdentity("Doomed Traveler", "")); + cubeCards.add(new CardIdentity("Dragon Fodder", "")); + cubeCards.add(new CardIdentity("Driver of the Dead", "")); + cubeCards.add(new CardIdentity("Dynacharge", "")); + cubeCards.add(new CardIdentity("Elephant Ambush", "")); + cubeCards.add(new CardIdentity("Elephant Guide", "")); + cubeCards.add(new CardIdentity("Elusive Spellfist", "")); + cubeCards.add(new CardIdentity("Enhanced Awareness", "")); + cubeCards.add(new CardIdentity("Epic Confrontation", "")); + cubeCards.add(new CardIdentity("Errant Ephemeron", "")); + cubeCards.add(new CardIdentity("Esper Cormorants", "")); + cubeCards.add(new CardIdentity("Essence Scatter", "")); + cubeCards.add(new CardIdentity("Ethereal Armor", "")); + cubeCards.add(new CardIdentity("Evincar's Justice", "")); + cubeCards.add(new CardIdentity("Evolution Charm", "")); + cubeCards.add(new CardIdentity("Evolving Wilds", "")); + cubeCards.add(new CardIdentity("Exclude", "")); + cubeCards.add(new CardIdentity("Eye of Nowhere", "")); + cubeCards.add(new CardIdentity("Faceless Butcher", "")); + cubeCards.add(new CardIdentity("Faith's Fetters", "")); + cubeCards.add(new CardIdentity("Fall of the Hammer", "")); + cubeCards.add(new CardIdentity("Farseek", "")); + cubeCards.add(new CardIdentity("Feat of Resistance", "")); + cubeCards.add(new CardIdentity("Feeling of Dread", "")); + cubeCards.add(new CardIdentity("Fellwar Stone", "")); + cubeCards.add(new CardIdentity("Fervent Cathar", "")); + cubeCards.add(new CardIdentity("Fire Ambush", "")); + cubeCards.add(new CardIdentity("Fireblast", "")); + cubeCards.add(new CardIdentity("Firebolt", "")); + cubeCards.add(new CardIdentity("Firefiend Elemental", "")); + cubeCards.add(new CardIdentity("Fireslinger", "")); + cubeCards.add(new CardIdentity("Fists of Ironwood", "")); + cubeCards.add(new CardIdentity("Flayer Husk", "")); + cubeCards.add(new CardIdentity("Flurry of Horns", "")); + cubeCards.add(new CardIdentity("Font of Return", "")); + cubeCards.add(new CardIdentity("Fortify", "")); + cubeCards.add(new CardIdentity("Foul Spirit", "")); + cubeCards.add(new CardIdentity("Frilled Oculus", "")); + cubeCards.add(new CardIdentity("Frostburn Weird", "")); + cubeCards.add(new CardIdentity("Fyndhorn Elves", "")); + cubeCards.add(new CardIdentity("Garruk's Companion", "")); + cubeCards.add(new CardIdentity("Gathan Raiders", "")); + cubeCards.add(new CardIdentity("Gather the Townsfolk", "")); + cubeCards.add(new CardIdentity("Ghastly Demise", "")); + cubeCards.add(new CardIdentity("Ghirapur Gearcrafter", "")); + cubeCards.add(new CardIdentity("Ghitu Slinger", "")); + cubeCards.add(new CardIdentity("Giant Growth", "")); + cubeCards.add(new CardIdentity("Gideon's Lawkeeper", "")); + cubeCards.add(new CardIdentity("Goblin Heelcutter", "")); + cubeCards.add(new CardIdentity("Gods Willing", "")); + cubeCards.add(new CardIdentity("Goldmeadow Harrier", "")); + cubeCards.add(new CardIdentity("Golgari Guildgate", "")); + cubeCards.add(new CardIdentity("Gore-House Chainwalker", "")); + cubeCards.add(new CardIdentity("Gravedigger", "")); + cubeCards.add(new CardIdentity("Gray Merchant of Asphodel", "")); + cubeCards.add(new CardIdentity("Grim Contest", "")); + cubeCards.add(new CardIdentity("Grisly Salvage", "")); + cubeCards.add(new CardIdentity("Gruul Guildgate", "")); + cubeCards.add(new CardIdentity("Gryff Vanguard", "")); + cubeCards.add(new CardIdentity("Guardian Automaton", "")); + cubeCards.add(new CardIdentity("Guardian of the Guildpact", "")); + cubeCards.add(new CardIdentity("Gurmag Angler", "")); + cubeCards.add(new CardIdentity("Halimar Depths", "")); + cubeCards.add(new CardIdentity("Halimar Wavewatch", "")); + cubeCards.add(new CardIdentity("Harrow", "")); + cubeCards.add(new CardIdentity("Harsh Sustenance", "")); + cubeCards.add(new CardIdentity("Hissing Iguanar", "")); + cubeCards.add(new CardIdentity("Hooting Mandrills", "")); + cubeCards.add(new CardIdentity("Hyena Umbra", "")); + cubeCards.add(new CardIdentity("Hymn to Tourach", "")); + cubeCards.add(new CardIdentity("Imperiosaur", "")); + cubeCards.add(new CardIdentity("Incinerate", "")); + cubeCards.add(new CardIdentity("Inner-Flame Acolyte", "")); + cubeCards.add(new CardIdentity("Into the Roil", "")); + cubeCards.add(new CardIdentity("Izzet Chronarch", "")); + cubeCards.add(new CardIdentity("Izzet Guildgate", "")); + cubeCards.add(new CardIdentity("Jilt", "")); + cubeCards.add(new CardIdentity("Journey to Nowhere", "")); + cubeCards.add(new CardIdentity("Jungle Hollow", "")); + cubeCards.add(new CardIdentity("Kabuto Moth", "")); + cubeCards.add(new CardIdentity("Keldon Marauders", "")); + cubeCards.add(new CardIdentity("Khalni Garden", "")); + cubeCards.add(new CardIdentity("Kingpin's Pet", "")); + cubeCards.add(new CardIdentity("Kodama's Reach", "")); + cubeCards.add(new CardIdentity("Kor Skyfisher", "")); + cubeCards.add(new CardIdentity("Kozilek's Predator", "")); + cubeCards.add(new CardIdentity("Krenko's Command", "")); + cubeCards.add(new CardIdentity("Krosan Tusker", "")); + cubeCards.add(new CardIdentity("Kruin Striker", "")); + cubeCards.add(new CardIdentity("Lash Out", "")); + cubeCards.add(new CardIdentity("Last Gasp", "")); + cubeCards.add(new CardIdentity("Leonin Bola", "")); + cubeCards.add(new CardIdentity("Leonin Scimitar", "")); + cubeCards.add(new CardIdentity("Lightning Bolt", "")); + cubeCards.add(new CardIdentity("Lightning Strike", "")); + cubeCards.add(new CardIdentity("Liliana's Specter", "")); + cubeCards.add(new CardIdentity("Llanowar Elves", "")); + cubeCards.add(new CardIdentity("Lone Missionary", "")); + cubeCards.add(new CardIdentity("Looter il-Kor", "")); + cubeCards.add(new CardIdentity("Lotus Path Djinn", "")); + cubeCards.add(new CardIdentity("Loyal Cathar", "")); + cubeCards.add(new CardIdentity("Loyal Pegasus", "")); + cubeCards.add(new CardIdentity("Lurking Automaton", "")); + cubeCards.add(new CardIdentity("Makeshift Mauler", "")); + cubeCards.add(new CardIdentity("Mana Leak", "")); + cubeCards.add(new CardIdentity("Man-o'-War", "")); + cubeCards.add(new CardIdentity("Mardu Hordechief", "")); + cubeCards.add(new CardIdentity("Mardu Scout", "")); + cubeCards.add(new CardIdentity("Mardu Skullhunter", "")); + cubeCards.add(new CardIdentity("Martial Glory", "")); + cubeCards.add(new CardIdentity("Maul Splicer", "")); + cubeCards.add(new CardIdentity("Maze of Ith", "")); + cubeCards.add(new CardIdentity("Merfolk Looter", "")); + cubeCards.add(new CardIdentity("Mind Stone", "")); + cubeCards.add(new CardIdentity("Minotaur Skullcleaver", "")); + cubeCards.add(new CardIdentity("Mire Boa", "")); + cubeCards.add(new CardIdentity("Miscalculation", "")); + cubeCards.add(new CardIdentity("Mishra's Factory", "")); + cubeCards.add(new CardIdentity("Mist Raven", "")); + cubeCards.add(new CardIdentity("Mogg Fanatic", "")); + cubeCards.add(new CardIdentity("Mogg Flunkies", "")); + cubeCards.add(new CardIdentity("Mogg War Marshal", "")); + cubeCards.add(new CardIdentity("Moldervine Cloak", "")); + cubeCards.add(new CardIdentity("Momentary Blink", "")); + cubeCards.add(new CardIdentity("Morgue Theft", "")); + cubeCards.add(new CardIdentity("Mulldrifter", "")); + cubeCards.add(new CardIdentity("Nameless Inversion", "")); + cubeCards.add(new CardIdentity("Narcolepsy", "")); + cubeCards.add(new CardIdentity("Necromancer's Assistant", "")); + cubeCards.add(new CardIdentity("Nessian Asp", "")); + cubeCards.add(new CardIdentity("Nest Invader", "")); + cubeCards.add(new CardIdentity("Nezumi Cutthroat", "")); + cubeCards.add(new CardIdentity("Nightscape Familiar", "")); + cubeCards.add(new CardIdentity("Ninja of the Deep Hours", "")); + cubeCards.add(new CardIdentity("Oblivion Ring", "")); + cubeCards.add(new CardIdentity("Okiba-Gang Shinobi", "")); + cubeCards.add(new CardIdentity("Omenspeaker", "")); + cubeCards.add(new CardIdentity("Orzhov Guildgate", "")); + cubeCards.add(new CardIdentity("Otherworldly Journey", "")); + cubeCards.add(new CardIdentity("Pacifism", "")); + cubeCards.add(new CardIdentity("Path of Anger's Flame", "")); + cubeCards.add(new CardIdentity("Penumbra Spider", "")); + cubeCards.add(new CardIdentity("Perilous Myr", "")); + cubeCards.add(new CardIdentity("Pestermite", "")); + cubeCards.add(new CardIdentity("Pestilence", "")); + cubeCards.add(new CardIdentity("Phantom Nomad", "")); + cubeCards.add(new CardIdentity("Phantom Tiger", "")); + cubeCards.add(new CardIdentity("Pharika's Chosen", "")); + cubeCards.add(new CardIdentity("Phyrexian Rager", "")); + cubeCards.add(new CardIdentity("Pillory of the Sleepless", "")); + cubeCards.add(new CardIdentity("Pit Fight", "")); + cubeCards.add(new CardIdentity("Pit Keeper", "")); + cubeCards.add(new CardIdentity("Plated Geopede", "")); + cubeCards.add(new CardIdentity("Plover Knights", "")); + cubeCards.add(new CardIdentity("Porcelain Legionnaire", "")); + cubeCards.add(new CardIdentity("Pouncing Kavu", "")); + cubeCards.add(new CardIdentity("Predatory Nightstalker", "")); + cubeCards.add(new CardIdentity("Preordain", "")); + cubeCards.add(new CardIdentity("Prey Upon", "")); + cubeCards.add(new CardIdentity("Prismatic Lens", "")); + cubeCards.add(new CardIdentity("Prismatic Strands", "")); + cubeCards.add(new CardIdentity("Pristine Talisman", "")); + cubeCards.add(new CardIdentity("Probe", "")); + cubeCards.add(new CardIdentity("Prophetic Prism", "")); + cubeCards.add(new CardIdentity("Putrid Leech", "")); + cubeCards.add(new CardIdentity("Pyrotechnics", "")); + cubeCards.add(new CardIdentity("Qasali Pridemage", "")); + cubeCards.add(new CardIdentity("Raise the Alarm", "")); + cubeCards.add(new CardIdentity("Rakdos Guildgate", "")); + cubeCards.add(new CardIdentity("Rakdos Shred-Freak", "")); + cubeCards.add(new CardIdentity("Rampant Growth", "")); + cubeCards.add(new CardIdentity("Rancor", "")); + cubeCards.add(new CardIdentity("Ranger's Guile", "")); + cubeCards.add(new CardIdentity("Ray of Command", "")); + cubeCards.add(new CardIdentity("Razorfin Hunter", "")); + cubeCards.add(new CardIdentity("Reckless Charge", "")); + cubeCards.add(new CardIdentity("Reclaim", "")); + cubeCards.add(new CardIdentity("Recoil", "")); + cubeCards.add(new CardIdentity("Remove Soul", "")); + cubeCards.add(new CardIdentity("Rend Flesh", "")); + cubeCards.add(new CardIdentity("Rendclaw Trow", "")); + cubeCards.add(new CardIdentity("Rhox Maulers", "")); + cubeCards.add(new CardIdentity("Rishadan Airship", "")); + cubeCards.add(new CardIdentity("River Boa", "")); + cubeCards.add(new CardIdentity("Ronin Houndmaster", "")); + cubeCards.add(new CardIdentity("Rugged Highlands", "")); + cubeCards.add(new CardIdentity("Runed Servitor", "")); + cubeCards.add(new CardIdentity("Rushing River", "")); + cubeCards.add(new CardIdentity("Safehold Elite", "")); + cubeCards.add(new CardIdentity("Sakura-Tribe Elder", "")); + cubeCards.add(new CardIdentity("Sandsteppe Outcast", "")); + cubeCards.add(new CardIdentity("Sangrite Backlash", "")); + cubeCards.add(new CardIdentity("Sarkhan's Rage", "")); + cubeCards.add(new CardIdentity("Savage Punch", "")); + cubeCards.add(new CardIdentity("Savage Surge", "")); + cubeCards.add(new CardIdentity("Scatter the Seeds", "")); + cubeCards.add(new CardIdentity("Scion of the Wild", "")); + cubeCards.add(new CardIdentity("Scoured Barrens", "")); + cubeCards.add(new CardIdentity("Scuzzback Marauders", "")); + cubeCards.add(new CardIdentity("Searing Blaze", "")); + cubeCards.add(new CardIdentity("Searing Spear", "")); + cubeCards.add(new CardIdentity("Sejiri Steppe", "")); + cubeCards.add(new CardIdentity("Selesnya Guildgate", "")); + cubeCards.add(new CardIdentity("Sentinel Spider", "")); + cubeCards.add(new CardIdentity("Seraph of Dawn", "")); + cubeCards.add(new CardIdentity("Serrated Arrows", "")); + cubeCards.add(new CardIdentity("Shaper Parasite", "")); + cubeCards.add(new CardIdentity("Shelter", "")); + cubeCards.add(new CardIdentity("Shimmering Glasskite", "")); + cubeCards.add(new CardIdentity("Shimmering Grotto", "")); + cubeCards.add(new CardIdentity("Sigil Blessing", "")); + cubeCards.add(new CardIdentity("Silent Departure", "")); + cubeCards.add(new CardIdentity("Simic Guildgate", "")); + cubeCards.add(new CardIdentity("Skinthinner", "")); + cubeCards.add(new CardIdentity("Skirk Marauder", "")); + cubeCards.add(new CardIdentity("Skyknight Legionnaire", "")); + cubeCards.add(new CardIdentity("Skywinder Drake", "")); + cubeCards.add(new CardIdentity("Slash Panther", "")); + cubeCards.add(new CardIdentity("Slippery Bogle", "")); + cubeCards.add(new CardIdentity("Snakeform", "")); + cubeCards.add(new CardIdentity("Snap", "")); + cubeCards.add(new CardIdentity("Snuff Out", "")); + cubeCards.add(new CardIdentity("Soltari Emissary", "")); + cubeCards.add(new CardIdentity("Soltari Lancer", "")); + cubeCards.add(new CardIdentity("Soltari Trooper", "")); + cubeCards.add(new CardIdentity("Soul Manipulation", "")); + cubeCards.add(new CardIdentity("Sparksmith", "")); + cubeCards.add(new CardIdentity("Sphere of the Suns", "")); + cubeCards.add(new CardIdentity("Spined Thopter", "")); + cubeCards.add(new CardIdentity("Splatter Thug", "")); + cubeCards.add(new CardIdentity("Staggershock", "")); + cubeCards.add(new CardIdentity("Stampeding Elk Herd", "")); + cubeCards.add(new CardIdentity("Stave Off", "")); + cubeCards.add(new CardIdentity("Stealer of Secrets", "")); + cubeCards.add(new CardIdentity("Stitched Drake", "")); + cubeCards.add(new CardIdentity("Stormfront Pegasus", "")); + cubeCards.add(new CardIdentity("Stormscape Apprentice", "")); + cubeCards.add(new CardIdentity("Strider Harness", "")); + cubeCards.add(new CardIdentity("Strip Mine", "")); + cubeCards.add(new CardIdentity("Sultai Scavenger", "")); + cubeCards.add(new CardIdentity("Suppression Bonds", "")); + cubeCards.add(new CardIdentity("Suq'Ata Lancer", "")); + cubeCards.add(new CardIdentity("Swiftwater Cliffs", "")); + cubeCards.add(new CardIdentity("Sylvok Lifestaff", "")); + cubeCards.add(new CardIdentity("Tail Slash", "")); + cubeCards.add(new CardIdentity("Teetering Peaks", "")); + cubeCards.add(new CardIdentity("Temporal Isolation", "")); + cubeCards.add(new CardIdentity("Tenement Crasher", "")); + cubeCards.add(new CardIdentity("Terminate", "")); + cubeCards.add(new CardIdentity("Terramorphic Expanse", "")); + cubeCards.add(new CardIdentity("Test of Faith", "")); + cubeCards.add(new CardIdentity("Thornweald Archer", "")); + cubeCards.add(new CardIdentity("Thornwood Falls", "")); + cubeCards.add(new CardIdentity("Thought Courier", "")); + cubeCards.add(new CardIdentity("Thundering Giant", "")); + cubeCards.add(new CardIdentity("Thundering Tanadon", "")); + cubeCards.add(new CardIdentity("Time to Feed", "")); + cubeCards.add(new CardIdentity("Tithe Drinker", "")); + cubeCards.add(new CardIdentity("Totem-Guide Hartebeest", "")); + cubeCards.add(new CardIdentity("Tragic Slip", "")); + cubeCards.add(new CardIdentity("Tranquil Cove", "")); + cubeCards.add(new CardIdentity("Travel Preparations", "")); + cubeCards.add(new CardIdentity("Treasure Cruise", "")); + cubeCards.add(new CardIdentity("Triplicate Spirits", "")); + cubeCards.add(new CardIdentity("Trumpet Blast", "")); + cubeCards.add(new CardIdentity("Tumble Magnet", "")); + cubeCards.add(new CardIdentity("Twin Bolt", "")); + cubeCards.add(new CardIdentity("Typhoid Rats", "")); + cubeCards.add(new CardIdentity("Ulamog's Crusher", "")); + cubeCards.add(new CardIdentity("Undying Evil", "")); + cubeCards.add(new CardIdentity("Unearth", "")); + cubeCards.add(new CardIdentity("Unknown Shores", "")); + cubeCards.add(new CardIdentity("Unmake", "")); + cubeCards.add(new CardIdentity("Vampire Interloper", "")); + cubeCards.add(new CardIdentity("Vampire Lacerator", "")); + cubeCards.add(new CardIdentity("Vault Skirge", "")); + cubeCards.add(new CardIdentity("Vendetta", "")); + cubeCards.add(new CardIdentity("Veteran's Sidearm", "")); + cubeCards.add(new CardIdentity("Viashino Firstblade", "")); + cubeCards.add(new CardIdentity("Vines of Vastwood", "")); + cubeCards.add(new CardIdentity("Voidwielder", "")); + cubeCards.add(new CardIdentity("Volcanic Hammer", "")); + cubeCards.add(new CardIdentity("Vulshok Morningstar", "")); + cubeCards.add(new CardIdentity("Vulshok Sorcerer", "")); + cubeCards.add(new CardIdentity("Vulturous Aven", "")); + cubeCards.add(new CardIdentity("Wakedancer", "")); + cubeCards.add(new CardIdentity("Walker of the Grove", "")); + cubeCards.add(new CardIdentity("Wall of Roots", "")); + cubeCards.add(new CardIdentity("War Flare", "")); + cubeCards.add(new CardIdentity("Warren Pilferers", "")); + cubeCards.add(new CardIdentity("Waterfront Bouncer", "")); + cubeCards.add(new CardIdentity("Wayfarer's Bauble", "")); + cubeCards.add(new CardIdentity("Whirlpool Whelm", "")); + cubeCards.add(new CardIdentity("Whispers of the Muse", "")); + cubeCards.add(new CardIdentity("Whispersilk Cloak", "")); + cubeCards.add(new CardIdentity("Whitemane Lion", "")); + cubeCards.add(new CardIdentity("Wickerbough Elder", "")); + cubeCards.add(new CardIdentity("Wild Instincts", "")); + cubeCards.add(new CardIdentity("Wild Mongrel", "")); + cubeCards.add(new CardIdentity("Wild Nacatl", "")); + cubeCards.add(new CardIdentity("Wildsize", "")); + cubeCards.add(new CardIdentity("Will-Forged Golem", "")); + cubeCards.add(new CardIdentity("Wind-Scarred Crag", "")); + cubeCards.add(new CardIdentity("Wingcrafter", "")); + cubeCards.add(new CardIdentity("Wingsteed Rider", "")); + cubeCards.add(new CardIdentity("Withdraw", "")); + cubeCards.add(new CardIdentity("Wojek Halberdiers", "")); + cubeCards.add(new CardIdentity("Wrecking Ball", "")); + cubeCards.add(new CardIdentity("Yavimaya Elder", "")); + cubeCards.add(new CardIdentity("Yotian Soldier", "")); + cubeCards.add(new CardIdentity("Young Wolf", "")); + cubeCards.add(new CardIdentity("Youthful Knight", "")); + cubeCards.add(new CardIdentity("Zhur-Taa Swine", "")); + } +} diff --git a/Mage.Server/config/config.xml b/Mage.Server/config/config.xml index b51b2a2564d..f2538da69c7 100644 --- a/Mage.Server/config/config.xml +++ b/Mage.Server/config/config.xml @@ -65,6 +65,7 @@ + diff --git a/Mage.Server/release/config/config.xml b/Mage.Server/release/config/config.xml index 92ff87d7d58..42a18288e51 100644 --- a/Mage.Server/release/config/config.xml +++ b/Mage.Server/release/config/config.xml @@ -44,6 +44,7 @@ + diff --git a/Mage.Sets/src/mage/sets/arabiannights/ArmyOfAllah.java b/Mage.Sets/src/mage/sets/arabiannights/ArmyOfAllah.java new file mode 100644 index 00000000000..77bc94ac9a7 --- /dev/null +++ b/Mage.Sets/src/mage/sets/arabiannights/ArmyOfAllah.java @@ -0,0 +1,62 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.sets.arabiannights; + +import java.util.UUID; +import mage.abilities.effects.common.continuous.BoostAllEffect; +import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.Rarity; +import mage.filter.common.FilterAttackingCreature; + +/** + * + * @author fireshoes + */ +public class ArmyOfAllah extends CardImpl { + + private static final FilterAttackingCreature filter = new FilterAttackingCreature("Attacking creatures"); + + public ArmyOfAllah(UUID ownerId) { + super(ownerId, 56, "Army of Allah", Rarity.COMMON, new CardType[]{CardType.INSTANT}, "{1}{W}{W}"); + this.expansionSetCode = "ARN"; + + // Attacking creatures get +2/+0 until end of turn. + this.getSpellAbility().addEffect(new BoostAllEffect(2, 0, Duration.EndOfTurn, filter, false)); + } + + public ArmyOfAllah(final ArmyOfAllah card) { + super(card); + } + + @Override + public ArmyOfAllah copy() { + return new ArmyOfAllah(this); + } +} From 92bcd0d522bf2f19efc863b2021de70f4e8b82d2 Mon Sep 17 00:00:00 2001 From: LevelX2 Date: Thu, 22 Oct 2015 23:02:07 +0200 Subject: [PATCH 215/268] * Changed some more card movement handling. --- .../mage/sets/scarsofmirrodin/CloneShell.java | 32 +++---- .../scarsofmirrodin/GethLordOfTheVault.java | 36 ++++---- .../sets/scarsofmirrodin/NimDeathmantle.java | 23 ++--- .../mage/sets/scarsofmirrodin/ShapeAnew.java | 4 +- .../sets/shadowmoor/DemigodOfRevenge.java | 6 +- .../sets/shardsofalara/ClarionUltimatum.java | 41 ++++----- .../sets/shardsofalara/PrinceOfThralls.java | 23 ++--- .../mage/sets/shardsofalara/RealmRazer.java | 25 +++--- .../sets/theros/RescueFromTheUnderworld.java | 88 +++++++++---------- .../sets/timespiral/LimDulTheNecromancer.java | 23 ++--- .../sets/vintagemasters/NorwoodPriestess.java | 17 ++-- .../src/mage/sets/visions/Desertion.java | 32 ++++--- .../mage/sets/worldwake/AgadeemOccultist.java | 17 ++-- .../mage/sets/zendikar/ExplorersScope.java | 14 +-- .../src/mage/sets/zendikar/Gigantiform.java | 11 ++- .../sets/zendikar/QuestForTheHolyRelic.java | 27 +++--- .../cards/copy/CleverImpersonatorTest.java | 2 + 17 files changed, 197 insertions(+), 224 deletions(-) diff --git a/Mage.Sets/src/mage/sets/scarsofmirrodin/CloneShell.java b/Mage.Sets/src/mage/sets/scarsofmirrodin/CloneShell.java index 4f984aaf754..68eae298900 100644 --- a/Mage.Sets/src/mage/sets/scarsofmirrodin/CloneShell.java +++ b/Mage.Sets/src/mage/sets/scarsofmirrodin/CloneShell.java @@ -27,8 +27,8 @@ */ package mage.sets.scarsofmirrodin; -import mage.constants.CardType; -import mage.constants.Rarity; +import java.util.List; +import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.DiesTriggeredAbility; @@ -38,7 +38,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.FilterCard; import mage.game.Game; @@ -46,9 +48,6 @@ import mage.game.permanent.Permanent; import mage.players.Player; import mage.target.TargetCard; -import java.util.List; -import java.util.UUID; - /** * @author nantuko */ @@ -161,19 +160,22 @@ class CloneShellDiesEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { - Permanent permanent = (Permanent) game.getLastKnownInformation(source.getSourceId(), Zone.BATTLEFIELD); - if (permanent != null) { - List imprinted = permanent.getImprinted(); - if (imprinted.size() > 0) { - Card imprintedCard = game.getCard(imprinted.get(0)); - imprintedCard.setFaceDown(false, game); - if (imprintedCard.getCardType().contains(CardType.CREATURE)) { - imprintedCard.putOntoBattlefield(game, Zone.EXILED, source.getSourceId(), source.getControllerId()); + Player controller = game.getPlayer(source.getControllerId()); + if (controller != null) { + Permanent permanent = (Permanent) game.getLastKnownInformation(source.getSourceId(), Zone.BATTLEFIELD); + if (permanent != null) { + List imprinted = permanent.getImprinted(); + if (imprinted.size() > 0) { + Card imprintedCard = game.getCard(imprinted.get(0)); + imprintedCard.setFaceDown(false, game); + if (imprintedCard.getCardType().contains(CardType.CREATURE)) { + controller.moveCards(imprintedCard, Zone.BATTLEFIELD, source, game); + } } } + return true; } - - return true; + return false; } @Override diff --git a/Mage.Sets/src/mage/sets/scarsofmirrodin/GethLordOfTheVault.java b/Mage.Sets/src/mage/sets/scarsofmirrodin/GethLordOfTheVault.java index 28f18c2e72b..7e0ccb7435d 100644 --- a/Mage.Sets/src/mage/sets/scarsofmirrodin/GethLordOfTheVault.java +++ b/Mage.Sets/src/mage/sets/scarsofmirrodin/GethLordOfTheVault.java @@ -25,14 +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.Outcome; -import mage.constants.Rarity; -import mage.constants.Zone; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.SimpleActivatedAbility; @@ -41,6 +36,10 @@ import mage.abilities.effects.OneShotEffect; import mage.abilities.keyword.IntimidateAbility; import mage.cards.Card; import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.Outcome; +import mage.constants.Rarity; +import mage.constants.Zone; import mage.filter.Filter; import mage.filter.FilterCard; import mage.filter.predicate.Predicates; @@ -57,7 +56,7 @@ import mage.target.common.TargetCardInOpponentsGraveyard; */ public class GethLordOfTheVault extends CardImpl { - public GethLordOfTheVault (UUID ownerId) { + public GethLordOfTheVault(UUID ownerId) { super(ownerId, 64, "Geth, Lord of the Vault", Rarity.MYTHIC, new CardType[]{CardType.CREATURE}, "{4}{B}{B}"); this.expansionSetCode = "SOM"; this.supertype.add("Legendary"); @@ -82,15 +81,15 @@ public class GethLordOfTheVault extends CardImpl { ability.getTargets().clear(); FilterCard filter = new FilterCard(new StringBuilder("artifact or creature card with converted mana cost ").append(xValue).append(" from an opponent's graveyard").toString()); filter.add(Predicates.or( - new CardTypePredicate(CardType.ARTIFACT), - new CardTypePredicate(CardType.CREATURE))); + new CardTypePredicate(CardType.ARTIFACT), + new CardTypePredicate(CardType.CREATURE))); filter.add(new ConvertedManaCostPredicate(Filter.ComparisonType.Equal, xValue)); Target target = new TargetCardInOpponentsGraveyard(filter); ability.addTarget(target); } } - public GethLordOfTheVault (final GethLordOfTheVault card) { + public GethLordOfTheVault(final GethLordOfTheVault card) { super(card); } @@ -100,6 +99,7 @@ public class GethLordOfTheVault extends CardImpl { } } + class GethLordOfTheVaultEffect extends OneShotEffect { public GethLordOfTheVaultEffect() { @@ -113,15 +113,19 @@ class GethLordOfTheVaultEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { - Card card = game.getCard(getTargetPointer().getFirst(game, source)); - if (card != null) { - card.putOntoBattlefield(game, Zone.GRAVEYARD, source.getSourceId(), source.getControllerId(), true); - Player player = game.getPlayer(card.getOwnerId()); - if (player != null) { - player.moveCards(player.getLibrary().getTopCards(game, card.getManaCost().convertedManaCost()), Zone.LIBRARY, Zone.GRAVEYARD, source, game); + Player controller = game.getPlayer(source.getControllerId()); + if (controller != null) { + Card card = game.getCard(getTargetPointer().getFirst(game, source)); + if (card != null) { + controller.moveCards(card, Zone.BATTLEFIELD, source, game, true, false, false, null); + Player player = game.getPlayer(card.getOwnerId()); + if (player != null) { + player.moveCards(player.getLibrary().getTopCards(game, card.getManaCost().convertedManaCost()), Zone.GRAVEYARD, source, game); + } } + return true; } - return true; + return false; } @Override diff --git a/Mage.Sets/src/mage/sets/scarsofmirrodin/NimDeathmantle.java b/Mage.Sets/src/mage/sets/scarsofmirrodin/NimDeathmantle.java index 45f8b9878cc..0de1da15612 100644 --- a/Mage.Sets/src/mage/sets/scarsofmirrodin/NimDeathmantle.java +++ b/Mage.Sets/src/mage/sets/scarsofmirrodin/NimDeathmantle.java @@ -113,18 +113,8 @@ class NimDeathmantleTriggeredAbility extends TriggeredAbilityImpl { @Override public boolean checkTrigger(GameEvent event, Game game) { - // make sure card is on battlefield - UUID sourceId = getSourceId(); - if (game.getPermanent(sourceId) == null) { - // or it is being removed - if (game.getLastKnownInformation(sourceId, Zone.BATTLEFIELD) == null) { - return false; - } - } - ZoneChangeEvent zEvent = (ZoneChangeEvent) event; Permanent permanent = zEvent.getTarget(); - if (permanent != null && permanent.getControllerId().equals(this.controllerId) && zEvent.getToZone() == Zone.GRAVEYARD @@ -159,29 +149,28 @@ class NimDeathmantleEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { - Player player = game.getPlayer(source.getControllerId()); + Player controller = game.getPlayer(source.getControllerId()); Permanent equipment = game.getPermanent(source.getSourceId()); - if (player != null && equipment != null) { - if (player.chooseUse(Outcome.Benefit, equipment.getName() + " - Pay " + cost.getText() + "?", source, game)) { + if (controller != null && equipment != null) { + if (controller.chooseUse(Outcome.Benefit, equipment.getName() + " - Pay " + cost.getText() + "?", source, game)) { cost.clearPaid(); if (cost.pay(source, game, source.getSourceId(), source.getControllerId(), false)) { UUID target = targetPointer.getFirst(game, source); - if (target != null && equipment != null) { + if (target != null) { Card card = game.getCard(target); // check if it's still in graveyard if (card != null && game.getState().getZone(card.getId()).equals(Zone.GRAVEYARD)) { - Player owner = game.getPlayer(card.getOwnerId()); - if (card.putOntoBattlefield(game, Zone.GRAVEYARD, source.getSourceId(), source.getControllerId())) { + if (controller.moveCards(card, Zone.BATTLEFIELD, source, game)) { Permanent permanent = game.getPermanent(card.getId()); if (permanent != null) { permanent.addAttachment(equipment.getId(), game); - return true; } } } } } } + return true; } return false; diff --git a/Mage.Sets/src/mage/sets/scarsofmirrodin/ShapeAnew.java b/Mage.Sets/src/mage/sets/scarsofmirrodin/ShapeAnew.java index b02ce34d87e..c42e48fa8e1 100644 --- a/Mage.Sets/src/mage/sets/scarsofmirrodin/ShapeAnew.java +++ b/Mage.Sets/src/mage/sets/scarsofmirrodin/ShapeAnew.java @@ -115,9 +115,9 @@ public class ShapeAnew extends CardImpl { } targetController.revealCards(sourcePermanent.getIdName(), revealed, game); if (artifactCard != null) { - artifactCard.putOntoBattlefield(game, Zone.LIBRARY, source.getSourceId(), targetController.getId()); + targetController.moveCards(artifactCard, Zone.BATTLEFIELD, source, game); } - targetController.moveCards(nonArtifactCards, null, Zone.LIBRARY, source, game); + targetController.putCardsOnTopOfLibrary(nonArtifactCards, game, source, false); targetController.shuffleLibrary(game); return true; } diff --git a/Mage.Sets/src/mage/sets/shadowmoor/DemigodOfRevenge.java b/Mage.Sets/src/mage/sets/shadowmoor/DemigodOfRevenge.java index 85977dde261..73181fa222e 100644 --- a/Mage.Sets/src/mage/sets/shadowmoor/DemigodOfRevenge.java +++ b/Mage.Sets/src/mage/sets/shadowmoor/DemigodOfRevenge.java @@ -34,7 +34,6 @@ import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.CastSourceTriggeredAbility; import mage.abilities.keyword.FlyingAbility; import mage.abilities.keyword.HasteAbility; -import mage.cards.Card; import mage.cards.CardImpl; import mage.constants.CardType; import mage.constants.Outcome; @@ -106,10 +105,7 @@ class DemigodOfRevengeReturnEffect extends OneShotEffect { public boolean apply(Game game, Ability source) { Player controller = game.getPlayer(source.getControllerId()); if (controller != null) { - for (Card creature : controller.getGraveyard().getCards(filter, game)) { - creature.putOntoBattlefield(game, Zone.GRAVEYARD, source.getSourceId(), source.getControllerId()); - } - return true; + return controller.moveCards(controller.getGraveyard().getCards(filter, game), Zone.BATTLEFIELD, source, game); } return false; } diff --git a/Mage.Sets/src/mage/sets/shardsofalara/ClarionUltimatum.java b/Mage.Sets/src/mage/sets/shardsofalara/ClarionUltimatum.java index 180c48059a7..86ba12cbe9c 100644 --- a/Mage.Sets/src/mage/sets/shardsofalara/ClarionUltimatum.java +++ b/Mage.Sets/src/mage/sets/shardsofalara/ClarionUltimatum.java @@ -28,16 +28,18 @@ package mage.sets.shardsofalara; import java.util.ArrayList; +import java.util.LinkedHashSet; import java.util.List; +import java.util.Set; import java.util.UUID; -import mage.constants.CardType; -import mage.constants.Outcome; -import mage.constants.Rarity; -import mage.constants.Zone; import mage.abilities.Ability; import mage.abilities.effects.OneShotEffect; import mage.cards.Card; import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.Outcome; +import mage.constants.Rarity; +import mage.constants.Zone; import mage.filter.FilterCard; import mage.filter.predicate.mageobject.NamePredicate; import mage.game.Game; @@ -56,7 +58,6 @@ public class ClarionUltimatum extends CardImpl { super(ownerId, 163, "Clarion Ultimatum", Rarity.RARE, new CardType[]{CardType.SORCERY}, "{G}{G}{W}{W}{W}{U}{U}"); this.expansionSetCode = "ALA"; - // Choose five permanents you control. For each of those permanents, you may search your library for a card with the same name as that permanent. Put those cards onto the battlefield tapped, then shuffle your library. this.getSpellAbility().addEffect(new ClarionUltimatumEffect()); } @@ -90,32 +91,28 @@ class ClarionUltimatumEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { - Player player = game.getPlayer(source.getControllerId()); + Player controller = game.getPlayer(source.getControllerId()); int permanentsCount = game.getBattlefield().getAllActivePermanents(source.getControllerId()).size(); - if (player == null || permanentsCount < 1) { + if (controller == null || permanentsCount < 1) { return false; } TargetControlledPermanent permanentsTarget = new TargetControlledPermanent(Math.min(permanentsCount, 5)); - player.choose(Outcome.Benefit, permanentsTarget, source.getSourceId(), game); + controller.choose(Outcome.Benefit, permanentsTarget, source.getSourceId(), game); - List chosenCards = new ArrayList(); - List namesFiltered = new ArrayList(); + Set chosenCards = new LinkedHashSet<>(); + List namesFiltered = new ArrayList<>(); List permanents = permanentsTarget.getTargets(); for (UUID permanentId : permanents) { Permanent permanent = game.getPermanent(permanentId); final String cardName = permanent.getName(); if (!namesFiltered.contains(cardName)) { - StringBuilder sb = new StringBuilder(); - sb.append("Search for ").append(cardName).append(" in your library?"); - - if (player.chooseUse(Outcome.PutCardInPlay, sb.toString(), source, game)) { + if (controller.chooseUse(Outcome.PutCardInPlay, "Search for " + cardName + " in your library?", source, game)) { FilterCard filter = new FilterCard("card named " + cardName); filter.add(new NamePredicate(cardName)); TargetCardInLibrary target = new TargetCardInLibrary(filter); - - if (player.searchLibrary(target, game)) { - Card card = player.getLibrary().getCard(target.getFirstTarget(), game); + if (controller.searchLibrary(target, game)) { + Card card = controller.getLibrary().getCard(target.getFirstTarget(), game); if (card != null) { chosenCards.add(card); } @@ -126,14 +123,8 @@ class ClarionUltimatumEffect extends OneShotEffect { } } - for (Card card : chosenCards) { - card.putOntoBattlefield(game, Zone.LIBRARY, source.getSourceId(), source.getControllerId()); - Permanent permanent = game.getPermanent(card.getId()); - if (permanent != null) { - permanent.setTapped(true); - } - } - player.shuffleLibrary(game); + controller.moveCards(chosenCards, Zone.BATTLEFIELD, source, game, true, false, false, null); + controller.shuffleLibrary(game); return true; } } diff --git a/Mage.Sets/src/mage/sets/shardsofalara/PrinceOfThralls.java b/Mage.Sets/src/mage/sets/shardsofalara/PrinceOfThralls.java index 20d8e4118bf..f8643ddaf9e 100644 --- a/Mage.Sets/src/mage/sets/shardsofalara/PrinceOfThralls.java +++ b/Mage.Sets/src/mage/sets/shardsofalara/PrinceOfThralls.java @@ -104,7 +104,7 @@ class PrinceOfThrallsTriggeredAbility extends TriggeredAbilityImpl { Permanent permanent = (Permanent) game.getLastKnownInformation(event.getTargetId(), Zone.BATTLEFIELD); if (game.getOpponents(this.getControllerId()).contains(permanent.getControllerId())) { for (Effect effect : getEffects()) { - effect.setTargetPointer(new FixedTarget(event.getTargetId())); + effect.setTargetPointer(new FixedTarget(event.getTargetId(), game.getState().getZoneChangeCounter(event.getTargetId()))); } return true; } @@ -137,18 +137,21 @@ class PrinceOfThrallsEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { + Player controller = game.getPlayer(source.getControllerId()); Card card = game.getCard(targetPointer.getFirst(game, source)); - Permanent permanent = (Permanent) game.getLastKnownInformation(card.getId(), Zone.BATTLEFIELD); - Player opponent = game.getPlayer(permanent.getControllerId()); - if (opponent != null && card != null && permanent != null && source.getControllerId() != null) { - PayLifeCost cost = new PayLifeCost(3); - if (opponent.chooseUse(Outcome.Neutral, cost.getText() + " or " + permanent.getName() + " comes back into the battlefield under opponents control", source, game)) { - cost.clearPaid(); - if (cost.pay(source, game, source.getSourceId(), opponent.getId(), true)) { - return true; + Permanent permanent = (Permanent) game.getLastKnownInformation(targetPointer.getFirst(game, source), Zone.BATTLEFIELD); + if (controller != null && card != null && permanent != null) { + Player opponent = game.getPlayer(permanent.getControllerId()); + if (opponent != null) { + PayLifeCost cost = new PayLifeCost(3); + if (opponent.chooseUse(Outcome.Neutral, cost.getText() + " or " + card.getLogName() + " comes back into the battlefield under opponents control", source, game)) { + cost.clearPaid(); + if (cost.pay(source, game, source.getSourceId(), opponent.getId(), true)) { + return true; + } } + controller.moveCards(card, Zone.BATTLEFIELD, source, game); } - card.putOntoBattlefield(game, Zone.GRAVEYARD, id, source.getControllerId()); return true; } return false; diff --git a/Mage.Sets/src/mage/sets/shardsofalara/RealmRazer.java b/Mage.Sets/src/mage/sets/shardsofalara/RealmRazer.java index 4399d836446..0f7291ab53e 100644 --- a/Mage.Sets/src/mage/sets/shardsofalara/RealmRazer.java +++ b/Mage.Sets/src/mage/sets/shardsofalara/RealmRazer.java @@ -29,22 +29,21 @@ package mage.sets.shardsofalara; import java.util.List; 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.common.LeavesBattlefieldTriggeredAbility; import mage.abilities.effects.OneShotEffect; -import mage.cards.Card; import mage.cards.CardImpl; +import mage.constants.CardType; import mage.constants.Outcome; +import mage.constants.Rarity; import mage.constants.Zone; import mage.filter.common.FilterLandPermanent; import mage.game.ExileZone; import mage.game.Game; import mage.game.permanent.Permanent; +import mage.players.Player; /** * @@ -95,7 +94,7 @@ class ExileAllEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { List permanents = game.getBattlefield().getActivePermanents(new FilterLandPermanent(), source.getControllerId(), source.getSourceId(), game); - for (Permanent permanent: permanents) { + for (Permanent permanent : permanents) { permanent.moveToExile(source.getSourceId(), "Realm Razer", source.getSourceId(), game); } return true; @@ -103,7 +102,6 @@ class ExileAllEffect extends OneShotEffect { } - class RealmRazerEffect extends OneShotEffect { public RealmRazerEffect() { @@ -122,17 +120,14 @@ class RealmRazerEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { - ExileZone exZone = game.getExile().getExileZone(source.getSourceId()); - if (exZone != null) { - for (Card card : exZone.getCards(game)) { - if (card != null) { - if(card.putOntoBattlefield(game, Zone.EXILED, source.getSourceId(), card.getOwnerId())){ - game.getPermanent(card.getId()).setTapped(true); - } - } + Player controller = game.getPlayer(source.getControllerId()); + if (controller != null) { + ExileZone exZone = game.getExile().getExileZone(source.getSourceId()); + if (exZone != null) { + return controller.moveCards(exZone.getCards(game), Zone.BATTLEFIELD, source, game, true, false, false, null); } return true; } return false; } -} \ No newline at end of file +} diff --git a/Mage.Sets/src/mage/sets/theros/RescueFromTheUnderworld.java b/Mage.Sets/src/mage/sets/theros/RescueFromTheUnderworld.java index 6878692be27..d5e83a36b87 100644 --- a/Mage.Sets/src/mage/sets/theros/RescueFromTheUnderworld.java +++ b/Mage.Sets/src/mage/sets/theros/RescueFromTheUnderworld.java @@ -57,20 +57,24 @@ import mage.target.common.TargetControlledCreaturePermanent; /** * - * Once you announce you’re casting Rescue from the Underworld, no player may attempt to - * stop you from casting the spell by removing the creature you want to sacrifice. + * Once you announce you’re casting Rescue from the Underworld, no player may + * attempt to stop you from casting the spell by removing the creature you want + * to sacrifice. * - * If you sacrifice a creature token to cast Rescue from the Underworld, it won’t return - * to the battlefield, although the target creature card will. + * If you sacrifice a creature token to cast Rescue from the Underworld, it + * won’t return to the battlefield, although the target creature card will. * - * If either the sacrificed creature or the target creature card leaves the graveyard - * before the delayed triggered ability resolves during your next upkeep, it won’t return. + * If either the sacrificed creature or the target creature card leaves the + * graveyard before the delayed triggered ability resolves during your next + * upkeep, it won’t return. * - * However, if the sacrificed creature is put into another public zone instead of the graveyard, - * perhaps because it’s your commander or because of another replacement effect, it will return - * to the battlefield from the zone it went to. + * However, if the sacrificed creature is put into another public zone instead + * of the graveyard, perhaps because it’s your commander or because of another + * replacement effect, it will return to the battlefield from the zone it went + * to. * - * Rescue from the Underworld is exiled as it resolves, not later as its delayed trigger resolves. + * Rescue from the Underworld is exiled as it resolves, not later as its delayed + * trigger resolves. * * * @author LevelX2 @@ -81,9 +85,8 @@ public class RescueFromTheUnderworld extends CardImpl { super(ownerId, 102, "Rescue from the Underworld", Rarity.UNCOMMON, new CardType[]{CardType.INSTANT}, "{4}{B}"); this.expansionSetCode = "THS"; - // As an additional cost to cast Rescue from the Underworld, sacrifice a creature. - this.getSpellAbility().addCost(new SacrificeTargetCost(new TargetControlledCreaturePermanent(1,1,new FilterControlledCreaturePermanent("a creature"), false))); + this.getSpellAbility().addCost(new SacrificeTargetCost(new TargetControlledCreaturePermanent(1, 1, new FilterControlledCreaturePermanent("a creature"), false))); // Choose target creature card in your graveyard. Return that card and the sacrificed card to the battlefield under your control at the beginning of your next upkeep. Exile Rescue from the Underworld. this.getSpellAbility().addEffect(new RescueFromTheUnderworldTextEffect()); @@ -151,15 +154,15 @@ class RescueFromTheUnderworldCreateDelayedTriggeredAbilityEffect extends OneShot delayedAbility.setControllerId(source.getControllerId()); delayedAbility.setSourceObject(source.getSourceObject(game), game); delayedAbility.getTargets().addAll(source.getTargets()); - for(Effect effect : delayedAbility.getEffects()) { + for (Effect effect : delayedAbility.getEffects()) { effect.getTargetPointer().init(game, source); } // add the sacrificed creature as target - for (Cost cost :source.getCosts()) { + for (Cost cost : source.getCosts()) { if (cost instanceof SacrificeTargetCost) { SacrificeTargetCost sacCost = (SacrificeTargetCost) cost; TargetCardInGraveyard target = new TargetCardInGraveyard(); - for(Permanent permanent : sacCost.getPermanents()) { + for (Permanent permanent : sacCost.getPermanents()) { target.add(permanent.getId(), game); delayedAbility.getTargets().add(target); } @@ -214,20 +217,12 @@ class RescueFromTheUnderworldDelayedTriggeredAbility extends DelayedTriggeredAbi class RescueFromTheUnderworldReturnEffect extends OneShotEffect { - private boolean tapped; - public RescueFromTheUnderworldReturnEffect() { - this(false); - } - - public RescueFromTheUnderworldReturnEffect(boolean tapped) { super(Outcome.PutCreatureInPlay); - this.tapped = tapped; } public RescueFromTheUnderworldReturnEffect(final RescueFromTheUnderworldReturnEffect effect) { super(effect); - this.tapped = effect.tapped; } @Override @@ -237,39 +232,36 @@ class RescueFromTheUnderworldReturnEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { - boolean result = false; - // Target card comes only back if in graveyard - for (UUID targetId: getTargetPointer().getTargets(game, source)) { - Card card = game.getCard(targetId); - if (card != null) { - Player player = game.getPlayer(card.getOwnerId()); - if (player != null) { - if(card.putOntoBattlefield(game, Zone.GRAVEYARD, source.getSourceId(), source.getControllerId(), tapped)){ - result = true; - } + Player controller = game.getPlayer(source.getControllerId()); + if (controller != null) { + // Target card comes only back if in graveyard + for (UUID targetId : getTargetPointer().getTargets(game, source)) { + Card card = game.getCard(targetId); + if (card != null) { + controller.moveCards(card, Zone.BATTLEFIELD, source, game); } } - } - // However, if the sacrificed creature is put into another public zone instead of the graveyard, - // perhaps because it’s your commander or because of another replacement effect, it will return - // to the battlefield from the zone it went to. - if (source.getTargets().get(1) != null) { - for (UUID targetId: ((Target) source.getTargets().get(1)).getTargets()) { - Card card = game.getCard(targetId); - if (card != null && !card.isFaceDown(game)) { - Player player = game.getPlayer(card.getOwnerId()); - if (player != null) { - Zone currentZone = game.getState().getZone(card.getId()); - if (currentZone.equals(Zone.COMMAND) || currentZone.equals(Zone.GRAVEYARD) || currentZone.equals(Zone.EXILED)) { - if(card.putOntoBattlefield(game, currentZone, source.getSourceId(), source.getControllerId(), false)){ - result = true; + // However, if the sacrificed creature is put into another public zone instead of the graveyard, + // perhaps because it’s your commander or because of another replacement effect, it will return + // to the battlefield from the zone it went to. + if (source.getTargets().get(1) != null) { + for (UUID targetId : ((Target) source.getTargets().get(1)).getTargets()) { + Card card = game.getCard(targetId); + if (card != null && !card.isFaceDown(game)) { + Player player = game.getPlayer(card.getOwnerId()); + if (player != null) { + Zone currentZone = game.getState().getZone(card.getId()); + if (currentZone.equals(Zone.COMMAND) || currentZone.equals(Zone.GRAVEYARD) || currentZone.equals(Zone.EXILED)) { + return player.moveCards(card, Zone.BATTLEFIELD, source, game); } } } } } + return true; } - return result; + return false; + } } diff --git a/Mage.Sets/src/mage/sets/timespiral/LimDulTheNecromancer.java b/Mage.Sets/src/mage/sets/timespiral/LimDulTheNecromancer.java index daf9621e884..7839ac9c469 100644 --- a/Mage.Sets/src/mage/sets/timespiral/LimDulTheNecromancer.java +++ b/Mage.Sets/src/mage/sets/timespiral/LimDulTheNecromancer.java @@ -52,6 +52,7 @@ import mage.filter.predicate.mageobject.SubtypePredicate; import mage.filter.predicate.permanent.ControllerPredicate; import mage.game.Game; import mage.game.permanent.Permanent; +import mage.players.Player; import mage.target.TargetPermanent; import mage.target.targetpointer.FixedTarget; @@ -116,17 +117,19 @@ class LimDulTheNecromancerEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { - Card card = game.getCard(targetPointer.getFirst(game, source)); - if (card != null) { - Zone currentZone = game.getState().getZone(card.getId()); - if (card.putOntoBattlefield(game, currentZone, source.getSourceId(), source.getControllerId()) - && card.getCardType().contains(CardType.CREATURE)) { - Permanent creature = game.getPermanent(card.getId()); - ContinuousEffect effect = new AddCardSubTypeTargetEffect("Zombie", Duration.WhileOnBattlefield); - effect.setTargetPointer(new FixedTarget(creature.getId())); - game.addEffect(effect, source); - return true; + Player controller = game.getPlayer(source.getControllerId()); + if (controller != null) { + Card card = game.getCard(targetPointer.getFirst(game, source)); + if (card != null) { + if (controller.moveCards(card, Zone.BATTLEFIELD, source, game) + && card.getCardType().contains(CardType.CREATURE)) { + Permanent creature = game.getPermanent(card.getId()); + ContinuousEffect effect = new AddCardSubTypeTargetEffect("Zombie", Duration.WhileOnBattlefield); + effect.setTargetPointer(new FixedTarget(creature.getId())); + game.addEffect(effect, source); + } } + return true; } return false; } diff --git a/Mage.Sets/src/mage/sets/vintagemasters/NorwoodPriestess.java b/Mage.Sets/src/mage/sets/vintagemasters/NorwoodPriestess.java index 423afe9b1c1..b1ca906bdae 100644 --- a/Mage.Sets/src/mage/sets/vintagemasters/NorwoodPriestess.java +++ b/Mage.Sets/src/mage/sets/vintagemasters/NorwoodPriestess.java @@ -62,7 +62,7 @@ public class NorwoodPriestess extends CardImpl { this.toughness = new MageInt(1); // {tap}: You may put a green creature card from your hand onto the battlefield. Activate this ability only during your turn, before attackers are declared. - Ability ability = new ActivateIfConditionActivatedAbility(Zone.BATTLEFIELD, + Ability ability = new ActivateIfConditionActivatedAbility(Zone.BATTLEFIELD, new NorwoodPriestessEffect(), new TapSourceCost(), MyTurnBeforeAttackersDeclaredCondition.getInstance()); this.addAbility(ability); } @@ -80,9 +80,9 @@ public class NorwoodPriestess extends CardImpl { class NorwoodPriestessEffect extends OneShotEffect { private static final String choiceText = "Put a green creature card from your hand onto the battlefield?"; - + private static final FilterCreatureCard filter = new FilterCreatureCard("a green creature card"); - + static { filter.add(new ColorPredicate(ObjectColor.GREEN)); } @@ -103,19 +103,18 @@ class NorwoodPriestessEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { - Player player = game.getPlayer(source.getControllerId()); - if (player == null || !player.chooseUse(Outcome.PutCreatureInPlay, choiceText, source, game)) { + Player controller = game.getPlayer(source.getControllerId()); + if (controller == null || !controller.chooseUse(Outcome.PutCreatureInPlay, choiceText, source, game)) { return false; } TargetCardInHand target = new TargetCardInHand(filter); - if (player.choose(Outcome.PutCreatureInPlay, target, source.getSourceId(), game)) { + if (controller.choose(Outcome.PutCreatureInPlay, target, source.getSourceId(), game)) { Card card = game.getCard(target.getFirstTarget()); if (card != null) { - card.putOntoBattlefield(game, Zone.HAND, source.getSourceId(), source.getControllerId()); - return true; + return controller.moveCards(card, Zone.BATTLEFIELD, source, game); } } return false; } -} \ No newline at end of file +} diff --git a/Mage.Sets/src/mage/sets/visions/Desertion.java b/Mage.Sets/src/mage/sets/visions/Desertion.java index 5c2f1b08387..c375729596b 100644 --- a/Mage.Sets/src/mage/sets/visions/Desertion.java +++ b/Mage.Sets/src/mage/sets/visions/Desertion.java @@ -44,6 +44,7 @@ import mage.game.Game; import mage.game.events.GameEvent; import mage.game.stack.Spell; import mage.game.stack.StackObject; +import mage.players.Player; import mage.target.TargetSpell; /** @@ -99,24 +100,27 @@ class DesertionEffect extends OneShotEffect { public boolean apply(Game game, Ability source) { UUID objectId = source.getFirstTarget(); UUID sourceId = source.getSourceId(); - - StackObject stackObject = game.getStack().getStackObject(objectId); - if (stackObject != null && !game.replaceEvent(GameEvent.getEvent(GameEvent.EventType.COUNTER, objectId, sourceId, stackObject.getControllerId()))) { - if (stackObject instanceof Spell) { - game.rememberLKI(objectId, Zone.STACK, (Spell) stackObject); - game.getStack().remove(stackObject); - if (!((Spell) stackObject).isCopiedSpell() && filter.match(stackObject, source.getSourceId(), source.getControllerId(), game)) { - MageObject card = game.getObject(stackObject.getSourceId()); - if (card instanceof Card) { - ((Card) card).putOntoBattlefield(game, Zone.STACK, source.getSourceId(), source.getControllerId()); + Player controller = game.getPlayer(source.getControllerId()); + if (controller != null) { + StackObject stackObject = game.getStack().getStackObject(objectId); + if (stackObject != null && !game.replaceEvent(GameEvent.getEvent(GameEvent.EventType.COUNTER, objectId, sourceId, stackObject.getControllerId()))) { + if (stackObject instanceof Spell) { + game.rememberLKI(objectId, Zone.STACK, (Spell) stackObject); + game.getStack().remove(stackObject); + if (!((Spell) stackObject).isCopiedSpell() && filter.match(stackObject, source.getSourceId(), source.getControllerId(), game)) { + MageObject card = game.getObject(stackObject.getSourceId()); + if (card instanceof Card) { + controller.moveCards((Card) card, Zone.BATTLEFIELD, source, game); + } + } else { + stackObject.counter(sourceId, game); } - } else { - stackObject.counter(sourceId, game); + game.fireEvent(GameEvent.getEvent(GameEvent.EventType.COUNTERED, objectId, sourceId, stackObject.getControllerId())); + return true; } - game.fireEvent(GameEvent.getEvent(GameEvent.EventType.COUNTERED, objectId, sourceId, stackObject.getControllerId())); - return true; } } + return false; } diff --git a/Mage.Sets/src/mage/sets/worldwake/AgadeemOccultist.java b/Mage.Sets/src/mage/sets/worldwake/AgadeemOccultist.java index 7deedb8ceb2..69342ccaf85 100644 --- a/Mage.Sets/src/mage/sets/worldwake/AgadeemOccultist.java +++ b/Mage.Sets/src/mage/sets/worldwake/AgadeemOccultist.java @@ -28,9 +28,6 @@ package mage.sets.worldwake; import java.util.UUID; - -import mage.constants.CardType; -import mage.constants.Rarity; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.SimpleActivatedAbility; @@ -38,7 +35,9 @@ import mage.abilities.costs.common.TapSourceCost; import mage.abilities.effects.OneShotEffect; import mage.cards.Card; import mage.cards.CardImpl; +import mage.constants.CardType; import mage.constants.Outcome; +import mage.constants.Rarity; import mage.constants.Zone; import mage.filter.FilterCard; import mage.filter.predicate.mageobject.CardTypePredicate; @@ -96,32 +95,30 @@ class AgadeemOccultistEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { - - Player you = game.getPlayer(source.getControllerId()); + Player controller = game.getPlayer(source.getControllerId()); int allycount = 0; for (Permanent permanent : game.getBattlefield().getAllActivePermanents(source.getControllerId())) { if (permanent.hasSubtype("Ally")) { allycount++; } } - FilterCard filter = new FilterCard("creature card in an opponent's graveyard"); filter.add(new CardTypePredicate(CardType.CREATURE)); TargetCardInOpponentsGraveyard target = new TargetCardInOpponentsGraveyard(1, 1, filter); - if (you != null) { + if (controller != null) { if (target.canChoose(source.getControllerId(), game) - && you.choose(Outcome.GainControl, target, source.getSourceId(), game)) { + && controller.choose(Outcome.GainControl, target, source.getSourceId(), game)) { if (!target.getTargets().isEmpty()) { Card card = game.getCard(target.getFirstTarget()); if (card != null) { if (card.getManaCost().convertedManaCost() <= allycount) { - card.putOntoBattlefield(game, Zone.GRAVEYARD, source.getSourceId(), source.getControllerId()); - return true; + return controller.moveCards(card, Zone.BATTLEFIELD, source, game); } } } } + return true; } return false; } diff --git a/Mage.Sets/src/mage/sets/zendikar/ExplorersScope.java b/Mage.Sets/src/mage/sets/zendikar/ExplorersScope.java index 7ced325384c..a81413a9cbf 100644 --- a/Mage.Sets/src/mage/sets/zendikar/ExplorersScope.java +++ b/Mage.Sets/src/mage/sets/zendikar/ExplorersScope.java @@ -29,10 +29,6 @@ package mage.sets.zendikar; import java.util.UUID; import mage.MageObject; -import mage.constants.CardType; -import mage.constants.Outcome; -import mage.constants.Rarity; -import mage.constants.Zone; import mage.abilities.Ability; import mage.abilities.common.AttacksAttachedTriggeredAbility; import mage.abilities.costs.mana.GenericManaCost; @@ -42,6 +38,10 @@ 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.game.Game; import mage.players.Player; @@ -56,9 +56,9 @@ public class ExplorersScope extends CardImpl { this.expansionSetCode = "ZEN"; this.subtype.add("Equipment"); - // Whenever equipped creature attacks, look at the top card of your library. If it's a land card, you may put it onto the battlefield tapped. + // Whenever equipped creature attacks, look at the top card of your library. If it's a land card, you may put it onto the battlefield tapped. this.addAbility(new AttacksAttachedTriggeredAbility(new ExplorersScopeEffect())); - + // Equip ({1}: Attach to target creature you control. Equip only as a sorcery.) this.addAbility(new EquipAbility(Outcome.AddAbility, new GenericManaCost(1))); } @@ -105,7 +105,7 @@ class ExplorersScopeEffect extends OneShotEffect { if (card.getCardType().contains(CardType.LAND)) { String message = "Put " + card.getLogName() + " onto the battlefield tapped?"; if (controller.chooseUse(Outcome.PutLandInPlay, message, source, game)) { - card.putOntoBattlefield(game, Zone.LIBRARY, source.getSourceId(), source.getControllerId(), true); + controller.moveCards(card, Zone.BATTLEFIELD, source, game, true, false, false, null); } } } diff --git a/Mage.Sets/src/mage/sets/zendikar/Gigantiform.java b/Mage.Sets/src/mage/sets/zendikar/Gigantiform.java index 15d9f689266..d4f19449b93 100644 --- a/Mage.Sets/src/mage/sets/zendikar/Gigantiform.java +++ b/Mage.Sets/src/mage/sets/zendikar/Gigantiform.java @@ -68,7 +68,6 @@ public class Gigantiform extends CardImpl { this.expansionSetCode = "ZEN"; this.subtype.add("Aura"); - // Kicker {4} this.addAbility(new KickerAbility("{4}")); @@ -143,14 +142,14 @@ class GigantiformEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { - Player player = game.getPlayer(source.getControllerId()); + Player controller = game.getPlayer(source.getControllerId()); TargetCardInLibrary target = new TargetCardInLibrary(filter); - if (player != null && player.searchLibrary(target, game)) { - Card card = player.getLibrary().getCard(target.getFirstTarget(), game); + if (controller != null && controller.searchLibrary(target, game)) { + Card card = controller.getLibrary().getCard(target.getFirstTarget(), game); if (card != null) { - card.putOntoBattlefield(game, Zone.LIBRARY, source.getSourceId(), source.getControllerId()); + controller.moveCards(card, Zone.BATTLEFIELD, source, game); } - player.shuffleLibrary(game); + controller.shuffleLibrary(game); return true; } return false; diff --git a/Mage.Sets/src/mage/sets/zendikar/QuestForTheHolyRelic.java b/Mage.Sets/src/mage/sets/zendikar/QuestForTheHolyRelic.java index 5c17c3c360b..dd7ee2ac455 100644 --- a/Mage.Sets/src/mage/sets/zendikar/QuestForTheHolyRelic.java +++ b/Mage.Sets/src/mage/sets/zendikar/QuestForTheHolyRelic.java @@ -28,11 +28,6 @@ package mage.sets.zendikar; import java.util.UUID; - -import mage.constants.CardType; -import mage.constants.Outcome; -import mage.constants.Rarity; -import mage.constants.Zone; import mage.abilities.Ability; import mage.abilities.common.SimpleActivatedAbility; import mage.abilities.common.SpellCastControllerTriggeredAbility; @@ -42,6 +37,10 @@ import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.counter.AddCountersSourceEffect; import mage.cards.Card; import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.Outcome; +import mage.constants.Rarity; +import mage.constants.Zone; import mage.counters.CounterType; import mage.filter.FilterCard; import mage.filter.FilterSpell; @@ -61,6 +60,7 @@ import mage.target.common.TargetControlledCreaturePermanent; public class QuestForTheHolyRelic extends CardImpl { private static final FilterSpell filter = new FilterSpell("a creature spell"); + static { filter.add(new CardTypePredicate(CardType.CREATURE)); } @@ -69,7 +69,6 @@ public class QuestForTheHolyRelic extends CardImpl { super(ownerId, 33, "Quest for the Holy Relic", Rarity.UNCOMMON, new CardType[]{CardType.ENCHANTMENT}, "{W}"); this.expansionSetCode = "ZEN"; - // Whenever you cast a creature spell, you may put a quest counter on Quest for the Holy Relic. this.addAbility(new SpellCastControllerTriggeredAbility(new AddCountersSourceEffect(CounterType.QUEST.createInstance()), filter, true)); // Remove five quest counters from Quest for the Holy Relic and sacrifice it: Search your library for an Equipment card, put it onto the battlefield, and attach it to a creature you control. Then shuffle your library. @@ -106,28 +105,26 @@ class QuestForTheHolyRelicEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { - Player player = game.getPlayer(source.getControllerId()); - if (player == null) { + Player controller = game.getPlayer(source.getControllerId()); + if (controller == null) { return false; } FilterCard filter = new FilterCard("Equipment"); filter.add(new SubtypePredicate("Equipment")); TargetCardInLibrary target = new TargetCardInLibrary(filter); - if (player.searchLibrary(target, game)) { - Card card = player.getLibrary().getCard(target.getFirstTarget(), game); - if (card != null) { - card.putOntoBattlefield(game, Zone.LIBRARY, source.getSourceId(), source.getControllerId()); + if (controller.searchLibrary(target, game)) { + Card card = controller.getLibrary().getCard(target.getFirstTarget(), game); + if (card != null && controller.moveCards(card, Zone.BATTLEFIELD, source, game)) { Permanent equipment = game.getPermanent(card.getId()); - Target targetCreature = new TargetControlledCreaturePermanent(); - if (equipment != null && player.choose(Outcome.BoostCreature, targetCreature, source.getSourceId(), game)) { + if (equipment != null && controller.choose(Outcome.BoostCreature, targetCreature, source.getSourceId(), game)) { Permanent permanent = game.getPermanent(targetCreature.getFirstTarget()); permanent.addAttachment(equipment.getId(), game); } } } - player.shuffleLibrary(game); + controller.shuffleLibrary(game); return true; } } diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/copy/CleverImpersonatorTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/copy/CleverImpersonatorTest.java index ba0ab31d770..06a37801110 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/copy/CleverImpersonatorTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/copy/CleverImpersonatorTest.java @@ -128,6 +128,8 @@ public class CleverImpersonatorTest extends CardTestPlayerBase { addTarget(playerA, "Clever Impersonator"); setChoice(playerA, "Liliana, Defiant Necromancer"); + activateAbility(1, PhaseStep.POSTCOMBAT_MAIN, playerA, "+2: Each player discards a card"); + setStopAt(1, PhaseStep.END_TURN); execute(); From 317f18220b19620dfd274c2fb8d753001ccfe992 Mon Sep 17 00:00:00 2001 From: LoneFox Date: Fri, 23 Oct 2015 08:50:32 +0300 Subject: [PATCH 216/268] Implement cards: Elvish Vanguard, Lys Alana Scarblade, Prowess of the Fair, and Symbiotic Elf --- .../mage/sets/lorwyn/LysAlanaScarblade.java | 90 +++++++++++++++++++ .../mage/sets/lorwyn/ProwessOfTheFair.java | 75 ++++++++++++++++ .../mage/sets/onslaught/ElvishVanguard.java | 75 ++++++++++++++++ .../src/mage/sets/onslaught/SymbioticElf.java | 64 +++++++++++++ 4 files changed, 304 insertions(+) create mode 100644 Mage.Sets/src/mage/sets/lorwyn/LysAlanaScarblade.java create mode 100644 Mage.Sets/src/mage/sets/lorwyn/ProwessOfTheFair.java create mode 100644 Mage.Sets/src/mage/sets/onslaught/ElvishVanguard.java create mode 100644 Mage.Sets/src/mage/sets/onslaught/SymbioticElf.java diff --git a/Mage.Sets/src/mage/sets/lorwyn/LysAlanaScarblade.java b/Mage.Sets/src/mage/sets/lorwyn/LysAlanaScarblade.java new file mode 100644 index 00000000000..5cdc7019042 --- /dev/null +++ b/Mage.Sets/src/mage/sets/lorwyn/LysAlanaScarblade.java @@ -0,0 +1,90 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.sets.lorwyn; + +import java.util.UUID; +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.costs.common.DiscardCardCost; +import mage.abilities.costs.common.TapSourceCost; +import mage.abilities.dynamicvalue.common.PermanentsOnBattlefieldCount; +import mage.abilities.dynamicvalue.common.SignInversionDynamicValue; +import mage.abilities.effects.Effect; +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.constants.Zone; +import mage.filter.FilterCard; +import mage.filter.common.FilterControlledPermanent; +import mage.filter.predicate.mageobject.SubtypePredicate; +import mage.target.common.TargetCreaturePermanent; + +/** + * + * @author LoneFox + */ +public class LysAlanaScarblade extends CardImpl { + + private static final FilterControlledPermanent filter1 = new FilterControlledPermanent(); + private static final FilterCard filter2 = new FilterCard("an Elf card"); + + static { + filter1.add(new SubtypePredicate("Elf")); + filter2.add(new SubtypePredicate("Elf")); + } + + public LysAlanaScarblade(UUID ownerId) { + super(ownerId, 122, "Lys Alana Scarblade", Rarity.UNCOMMON, new CardType[]{CardType.CREATURE}, "{2}{B}"); + this.expansionSetCode = "LRW"; + this.subtype.add("Elf"); + this.subtype.add("Assassin"); + this.power = new MageInt(1); + this.toughness = new MageInt(1); + + // {tap}, Discard an Elf card: Target creature gets -X/-X until end of turn, where X is the number of Elves you control. + SignInversionDynamicValue count = new SignInversionDynamicValue(new PermanentsOnBattlefieldCount(filter1)); + Effect effect = new BoostTargetEffect(count, count, Duration.EndOfTurn); + effect.setText("target creature gets -X/-X until end of turn, where X is the number of Elves you control"); + Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, effect, new TapSourceCost()); + ability.addCost(new DiscardCardCost(filter2)); + ability.addTarget(new TargetCreaturePermanent()); + this.addAbility(ability); + } + + public LysAlanaScarblade(final LysAlanaScarblade card) { + super(card); + } + + @Override + public LysAlanaScarblade copy() { + return new LysAlanaScarblade(this); + } +} diff --git a/Mage.Sets/src/mage/sets/lorwyn/ProwessOfTheFair.java b/Mage.Sets/src/mage/sets/lorwyn/ProwessOfTheFair.java new file mode 100644 index 00000000000..09eb350a4b8 --- /dev/null +++ b/Mage.Sets/src/mage/sets/lorwyn/ProwessOfTheFair.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.lorwyn; + +import java.util.UUID; +import mage.abilities.common.PutIntoGraveFromBattlefieldAllTriggeredAbility; +import mage.abilities.effects.common.CreateTokenEffect; +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.SubtypePredicate; +import mage.filter.predicate.permanent.AnotherPredicate; +import mage.filter.predicate.permanent.TokenPredicate; +import mage.game.permanent.token.ElfToken; + +/** + * + * @author LoneFox + */ +public class ProwessOfTheFair extends CardImpl { + + private static final FilterPermanent filter = new FilterPermanent("another nontoken Elf"); + + static { + filter.add(new SubtypePredicate("Elf")); + filter.add(new AnotherPredicate()); + filter.add(Predicates.not(new TokenPredicate())); + } + + public ProwessOfTheFair(UUID ownerId) { + super(ownerId, 136, "Prowess of the Fair", Rarity.UNCOMMON, new CardType[]{CardType.TRIBAL, CardType.ENCHANTMENT}, "{1}{B}"); + this.expansionSetCode = "LRW"; + this.subtype.add("Elf"); + + // Whenever another nontoken Elf is put into your graveyard from the battlefield, you may put a 1/1 green Elf Warrior creature token onto the battlefield. + this.addAbility(new PutIntoGraveFromBattlefieldAllTriggeredAbility(new CreateTokenEffect(new ElfToken()), + true, filter, false, true)); + } + + public ProwessOfTheFair(final ProwessOfTheFair card) { + super(card); + } + + @Override + public ProwessOfTheFair copy() { + return new ProwessOfTheFair(this); + } +} diff --git a/Mage.Sets/src/mage/sets/onslaught/ElvishVanguard.java b/Mage.Sets/src/mage/sets/onslaught/ElvishVanguard.java new file mode 100644 index 00000000000..1f876e83614 --- /dev/null +++ b/Mage.Sets/src/mage/sets/onslaught/ElvishVanguard.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.onslaught; + +import java.util.UUID; +import mage.MageInt; +import mage.abilities.common.EntersBattlefieldAllTriggeredAbility; +import mage.abilities.effects.common.counter.AddCountersSourceEffect; +import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.Rarity; +import mage.counters.CounterType; +import mage.filter.FilterPermanent; +import mage.filter.predicate.mageobject.SubtypePredicate; +import mage.filter.predicate.permanent.AnotherPredicate; + +/** + * + * @author LoneFox + */ +public class ElvishVanguard extends CardImpl { + + private static final FilterPermanent filter = new FilterPermanent("another Elf"); + + static { + filter.add(new SubtypePredicate("Elf")); + filter.add(new AnotherPredicate()); + } + + public ElvishVanguard(UUID ownerId) { + super(ownerId, 259, "Elvish Vanguard", Rarity.RARE, new CardType[]{CardType.CREATURE}, "{1}{G}"); + this.expansionSetCode = "ONS"; + this.subtype.add("Elf"); + this.subtype.add("Warrior"); + this.power = new MageInt(1); + this.toughness = new MageInt(1); + + // Whenever another Elf enters the battlefield, put a +1/+1 counter on Elvish Vanguard. + this.addAbility(new EntersBattlefieldAllTriggeredAbility(new AddCountersSourceEffect(CounterType.P1P1.createInstance()), filter)); + } + + public ElvishVanguard(final ElvishVanguard card) { + super(card); + } + + @Override + public ElvishVanguard copy() { + return new ElvishVanguard(this); + } +} diff --git a/Mage.Sets/src/mage/sets/onslaught/SymbioticElf.java b/Mage.Sets/src/mage/sets/onslaught/SymbioticElf.java new file mode 100644 index 00000000000..4ad72947189 --- /dev/null +++ b/Mage.Sets/src/mage/sets/onslaught/SymbioticElf.java @@ -0,0 +1,64 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.sets.onslaught; + +import java.util.UUID; +import mage.MageInt; +import mage.abilities.common.DiesTriggeredAbility; +import mage.abilities.effects.common.CreateTokenEffect; +import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.Rarity; +import mage.game.permanent.token.InsectToken; + +/** + * + * @author LoneFox + */ +public class SymbioticElf extends CardImpl { + + public SymbioticElf(UUID ownerId) { + super(ownerId, 288, "Symbiotic Elf", Rarity.COMMON, new CardType[]{CardType.CREATURE}, "{3}{G}"); + this.expansionSetCode = "ONS"; + this.subtype.add("Elf"); + this.power = new MageInt(2); + this.toughness = new MageInt(2); + + // When Symbiotic Elf dies, put two 1/1 green Insect creature tokens onto the battlefield. + this.addAbility(new DiesTriggeredAbility(new CreateTokenEffect(new InsectToken(), 2))); + } + + public SymbioticElf(final SymbioticElf card) { + super(card); + } + + @Override + public SymbioticElf copy() { + return new SymbioticElf(this); + } +} From a7eb019986264744b66d74c3602f70812ee2cc78 Mon Sep 17 00:00:00 2001 From: LevelX2 Date: Fri, 23 Oct 2015 07:50:43 +0200 Subject: [PATCH 217/268] * Fixed not working enters the battlefield effect of Lorwyn lands (tapped & 2 chanrge counters). --- Mage.Sets/src/mage/sets/lorwyn/VividCrag.java | 19 ++++++++----------- .../src/mage/sets/lorwyn/VividCreek.java | 19 ++++++++----------- .../src/mage/sets/lorwyn/VividGrove.java | 19 ++++++++----------- .../src/mage/sets/lorwyn/VividMarsh.java | 19 ++++++++----------- .../src/mage/sets/lorwyn/VividMeadow.java | 19 ++++++++----------- 5 files changed, 40 insertions(+), 55 deletions(-) diff --git a/Mage.Sets/src/mage/sets/lorwyn/VividCrag.java b/Mage.Sets/src/mage/sets/lorwyn/VividCrag.java index db911ac24fa..a2a1f9af187 100644 --- a/Mage.Sets/src/mage/sets/lorwyn/VividCrag.java +++ b/Mage.Sets/src/mage/sets/lorwyn/VividCrag.java @@ -27,22 +27,19 @@ */ package mage.sets.lorwyn; -import mage.constants.CardType; -import mage.constants.Rarity; +import java.util.UUID; import mage.abilities.Ability; -import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.common.EntersBattlefieldAbility; import mage.abilities.costs.common.RemoveCountersSourceCost; -import mage.abilities.effects.EntersBattlefieldEffect; import mage.abilities.effects.common.TapSourceEffect; import mage.abilities.effects.common.counter.AddCountersSourceEffect; import mage.abilities.mana.AnyColorManaAbility; import mage.abilities.mana.RedManaAbility; import mage.cards.CardImpl; -import mage.constants.Zone; +import mage.constants.CardType; +import mage.constants.Rarity; import mage.counters.CounterType; -import java.util.UUID; - /** * * @author Loki @@ -53,13 +50,13 @@ public class VividCrag extends CardImpl { super(ownerId, 275, "Vivid Crag", Rarity.UNCOMMON, new CardType[]{CardType.LAND}, ""); this.expansionSetCode = "LRW"; // Vivid Crag enters the battlefield tapped with two charge counters on it. - EntersBattlefieldEffect effect = new EntersBattlefieldEffect(new TapSourceEffect(true), "{this} enters the battlefield tapped with two charge counters on it"); - effect.addEffect(new AddCountersSourceEffect(CounterType.CHARGE.createInstance(2))); - this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, effect)); + Ability ability = new EntersBattlefieldAbility(new TapSourceEffect(true), false, null, "{this} enters the battlefield tapped with two charge counters on it", null); + ability.addEffect(new AddCountersSourceEffect(CounterType.CHARGE.createInstance(2))); + this.addAbility(ability); // {tap}: Add {R} to your mana pool. this.addAbility(new RedManaAbility()); // {tap}, Remove a charge counter from Vivid Crag: Add one mana of any color to your mana pool. - Ability ability = new AnyColorManaAbility(); + ability = new AnyColorManaAbility(); ability.addCost(new RemoveCountersSourceCost(CounterType.CHARGE.createInstance(1))); this.addAbility(ability); diff --git a/Mage.Sets/src/mage/sets/lorwyn/VividCreek.java b/Mage.Sets/src/mage/sets/lorwyn/VividCreek.java index d81545b95fc..308795ad88a 100644 --- a/Mage.Sets/src/mage/sets/lorwyn/VividCreek.java +++ b/Mage.Sets/src/mage/sets/lorwyn/VividCreek.java @@ -27,22 +27,19 @@ */ package mage.sets.lorwyn; -import mage.constants.CardType; -import mage.constants.Rarity; +import java.util.UUID; import mage.abilities.Ability; -import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.common.EntersBattlefieldAbility; import mage.abilities.costs.common.RemoveCountersSourceCost; -import mage.abilities.effects.EntersBattlefieldEffect; import mage.abilities.effects.common.TapSourceEffect; import mage.abilities.effects.common.counter.AddCountersSourceEffect; import mage.abilities.mana.AnyColorManaAbility; import mage.abilities.mana.BlueManaAbility; import mage.cards.CardImpl; -import mage.constants.Zone; +import mage.constants.CardType; +import mage.constants.Rarity; import mage.counters.CounterType; -import java.util.UUID; - /** * * @author Loki @@ -53,13 +50,13 @@ public class VividCreek extends CardImpl { super(ownerId, 276, "Vivid Creek", Rarity.UNCOMMON, new CardType[]{CardType.LAND}, ""); this.expansionSetCode = "LRW"; // Vivid Creek enters the battlefield tapped with two charge counters on it. - EntersBattlefieldEffect effect = new EntersBattlefieldEffect(new TapSourceEffect(true), "{this} enters the battlefield tapped with two charge counters on it"); - effect.addEffect(new AddCountersSourceEffect(CounterType.CHARGE.createInstance(2))); - this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, effect)); + Ability ability = new EntersBattlefieldAbility(new TapSourceEffect(true), false, null, "{this} enters the battlefield tapped with two charge counters on it", null); + ability.addEffect(new AddCountersSourceEffect(CounterType.CHARGE.createInstance(2))); + this.addAbility(ability); // {tap}: Add {U} to your mana pool. this.addAbility(new BlueManaAbility()); // {tap}, Remove a charge counter from Vivid Creek: Add one mana of any color to your mana pool. - Ability ability = new AnyColorManaAbility(); + ability = new AnyColorManaAbility(); ability.addCost(new RemoveCountersSourceCost(CounterType.CHARGE.createInstance(1))); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/sets/lorwyn/VividGrove.java b/Mage.Sets/src/mage/sets/lorwyn/VividGrove.java index 69edf5be55d..07ba8af8c82 100644 --- a/Mage.Sets/src/mage/sets/lorwyn/VividGrove.java +++ b/Mage.Sets/src/mage/sets/lorwyn/VividGrove.java @@ -27,22 +27,19 @@ */ package mage.sets.lorwyn; -import mage.constants.CardType; -import mage.constants.Rarity; +import java.util.UUID; import mage.abilities.Ability; -import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.common.EntersBattlefieldAbility; import mage.abilities.costs.common.RemoveCountersSourceCost; -import mage.abilities.effects.EntersBattlefieldEffect; import mage.abilities.effects.common.TapSourceEffect; import mage.abilities.effects.common.counter.AddCountersSourceEffect; import mage.abilities.mana.AnyColorManaAbility; import mage.abilities.mana.GreenManaAbility; import mage.cards.CardImpl; -import mage.constants.Zone; +import mage.constants.CardType; +import mage.constants.Rarity; import mage.counters.CounterType; -import java.util.UUID; - /** * * @author Loki @@ -53,13 +50,13 @@ public class VividGrove extends CardImpl { super(ownerId, 277, "Vivid Grove", Rarity.UNCOMMON, new CardType[]{CardType.LAND}, ""); this.expansionSetCode = "LRW"; // Vivid Grove enters the battlefield tapped with two charge counters on it. - EntersBattlefieldEffect effect = new EntersBattlefieldEffect(new TapSourceEffect(true), "{this} enters the battlefield tapped with two charge counters on it"); - effect.addEffect(new AddCountersSourceEffect(CounterType.CHARGE.createInstance(2))); - this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, effect)); + Ability ability = new EntersBattlefieldAbility(new TapSourceEffect(true), false, null, "{this} enters the battlefield tapped with two charge counters on it", null); + ability.addEffect(new AddCountersSourceEffect(CounterType.CHARGE.createInstance(2))); + this.addAbility(ability); // {tap}: Add {G} to your mana pool. this.addAbility(new GreenManaAbility()); // {tap}, Remove a charge counter from Vivid Grove: Add one mana of any color to your mana pool. - Ability ability = new AnyColorManaAbility(); + ability = new AnyColorManaAbility(); ability.addCost(new RemoveCountersSourceCost(CounterType.CHARGE.createInstance(1))); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/sets/lorwyn/VividMarsh.java b/Mage.Sets/src/mage/sets/lorwyn/VividMarsh.java index ad6e4d8435c..85748e6f602 100644 --- a/Mage.Sets/src/mage/sets/lorwyn/VividMarsh.java +++ b/Mage.Sets/src/mage/sets/lorwyn/VividMarsh.java @@ -27,22 +27,19 @@ */ package mage.sets.lorwyn; -import mage.constants.CardType; -import mage.constants.Rarity; +import java.util.UUID; import mage.abilities.Ability; -import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.common.EntersBattlefieldAbility; import mage.abilities.costs.common.RemoveCountersSourceCost; -import mage.abilities.effects.EntersBattlefieldEffect; import mage.abilities.effects.common.TapSourceEffect; import mage.abilities.effects.common.counter.AddCountersSourceEffect; import mage.abilities.mana.AnyColorManaAbility; import mage.abilities.mana.BlackManaAbility; import mage.cards.CardImpl; -import mage.constants.Zone; +import mage.constants.CardType; +import mage.constants.Rarity; import mage.counters.CounterType; -import java.util.UUID; - /** * * @author Loki @@ -54,13 +51,13 @@ public class VividMarsh extends CardImpl { this.expansionSetCode = "LRW"; // Vivid Marsh enters the battlefield tapped with two charge counters on it. - EntersBattlefieldEffect effect = new EntersBattlefieldEffect(new TapSourceEffect(true), "{this} enters the battlefield tapped with two charge counters on it"); - effect.addEffect(new AddCountersSourceEffect(CounterType.CHARGE.createInstance(2))); - this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, effect)); + Ability ability = new EntersBattlefieldAbility(new TapSourceEffect(true), false, null, "{this} enters the battlefield tapped with two charge counters on it", null); + ability.addEffect(new AddCountersSourceEffect(CounterType.CHARGE.createInstance(2))); + this.addAbility(ability); // {tap}: Add {B} to your mana pool. this.addAbility(new BlackManaAbility()); // {tap}, Remove a charge counter from Vivid Marsh: Add one mana of any color to your mana pool. - Ability ability = new AnyColorManaAbility(); + ability = new AnyColorManaAbility(); ability.addCost(new RemoveCountersSourceCost(CounterType.CHARGE.createInstance(1))); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/sets/lorwyn/VividMeadow.java b/Mage.Sets/src/mage/sets/lorwyn/VividMeadow.java index 432d65ef859..a5998b765f8 100644 --- a/Mage.Sets/src/mage/sets/lorwyn/VividMeadow.java +++ b/Mage.Sets/src/mage/sets/lorwyn/VividMeadow.java @@ -27,22 +27,19 @@ */ package mage.sets.lorwyn; -import mage.constants.CardType; -import mage.constants.Rarity; +import java.util.UUID; import mage.abilities.Ability; -import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.common.EntersBattlefieldAbility; import mage.abilities.costs.common.RemoveCountersSourceCost; -import mage.abilities.effects.EntersBattlefieldEffect; import mage.abilities.effects.common.TapSourceEffect; import mage.abilities.effects.common.counter.AddCountersSourceEffect; import mage.abilities.mana.AnyColorManaAbility; import mage.abilities.mana.WhiteManaAbility; import mage.cards.CardImpl; -import mage.constants.Zone; +import mage.constants.CardType; +import mage.constants.Rarity; import mage.counters.CounterType; -import java.util.UUID; - /** * * @author Loki @@ -53,13 +50,13 @@ public class VividMeadow extends CardImpl { super(ownerId, 279, "Vivid Meadow", Rarity.UNCOMMON, new CardType[]{CardType.LAND}, ""); this.expansionSetCode = "LRW"; // Vivid Meadow enters the battlefield tapped with two charge counters on it. - EntersBattlefieldEffect effect = new EntersBattlefieldEffect(new TapSourceEffect(true), "{this} enters the battlefield tapped with two charge counters on it"); - effect.addEffect(new AddCountersSourceEffect(CounterType.CHARGE.createInstance(2))); - this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, effect)); + Ability ability = new EntersBattlefieldAbility(new TapSourceEffect(true), false, null, "{this} enters the battlefield tapped with two charge counters on it", null); + ability.addEffect(new AddCountersSourceEffect(CounterType.CHARGE.createInstance(2))); + this.addAbility(ability); // {tap}: Add {W} to your mana pool. this.addAbility(new WhiteManaAbility()); // {tap}, Remove a charge counter from Vivid Meadow: Add one mana of any color to your mana pool. - Ability ability = new AnyColorManaAbility(); + ability = new AnyColorManaAbility(); ability.addCost(new RemoveCountersSourceCost(CounterType.CHARGE.createInstance(1))); this.addAbility(ability); } From 71825043c556a7f4ec49eef67c387193fa2f264d Mon Sep 17 00:00:00 2001 From: LevelX2 Date: Fri, 23 Oct 2015 07:52:04 +0200 Subject: [PATCH 218/268] * Enduring Scalelord - Fixed triggered ability not working for replcament effects adding counters to permenents entering the battlefield. --- .../src/mage/sets/dragonsoftarkir/EnduringScalelord.java | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/Mage.Sets/src/mage/sets/dragonsoftarkir/EnduringScalelord.java b/Mage.Sets/src/mage/sets/dragonsoftarkir/EnduringScalelord.java index a73926993d6..92ea2e6444a 100644 --- a/Mage.Sets/src/mage/sets/dragonsoftarkir/EnduringScalelord.java +++ b/Mage.Sets/src/mage/sets/dragonsoftarkir/EnduringScalelord.java @@ -92,12 +92,15 @@ class EnduringScalelordTriggeredAbility extends TriggeredAbilityImpl { return event.getType() == GameEvent.EventType.COUNTERS_ADDED; } - @Override public boolean checkTrigger(GameEvent event, Game game) { if (event.getData().equals(CounterType.P1P1.getName())) { Permanent permanent = game.getPermanentOrLKIBattlefield(event.getTargetId()); - return (!event.getTargetId().equals(this.getSourceId()) + if (permanent == null) { + permanent = game.getPermanentEntering(event.getTargetId()); + } + return (permanent != null + && !event.getTargetId().equals(this.getSourceId()) && permanent.getCardType().contains(CardType.CREATURE) && permanent.getControllerId().equals(this.getControllerId())); } From 9b1ef021f5177108e444e214eafdbc3a55f29198 Mon Sep 17 00:00:00 2001 From: RegurKenaid Date: Fri, 23 Oct 2015 16:25:49 +0600 Subject: [PATCH 219/268] TN fix Cards must enter the battlefield UNTAPPED. --- Mage.Sets/src/mage/sets/modernmasters/ToothAndNail.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Mage.Sets/src/mage/sets/modernmasters/ToothAndNail.java b/Mage.Sets/src/mage/sets/modernmasters/ToothAndNail.java index 478914ee117..1ce14ebe81c 100644 --- a/Mage.Sets/src/mage/sets/modernmasters/ToothAndNail.java +++ b/Mage.Sets/src/mage/sets/modernmasters/ToothAndNail.java @@ -103,7 +103,7 @@ class ToothAndNailPutCreatureOnBattlefieldEffect extends OneShotEffect { TargetCardInHand target = new TargetCardInHand(0, 2, new FilterCreatureCard("creature cards")); if (controller.choose(Outcome.PutCreatureInPlay, target, source.getSourceId(), game)) { return controller.moveCards(new CardsImpl(target.getTargets()).getCards(game), - Zone.BATTLEFIELD, source, game, true, false, false, null); + Zone.BATTLEFIELD, source, game, false, false, false, null); } return false; } From f14cbb7f362a6acc176cbe173d0a1ed41f70e244 Mon Sep 17 00:00:00 2001 From: LevelX2 Date: Fri, 23 Oct 2015 18:25:36 +0200 Subject: [PATCH 220/268] * Fixed a bug with removing spells from stack (e.g. Split Second had some problems) fixes #1333. --- .../test/cards/copy/IsochronScepterTest.java | 73 ++++++++++++------- Mage/src/mage/game/stack/Spell.java | 7 +- 2 files changed, 48 insertions(+), 32 deletions(-) diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/copy/IsochronScepterTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/copy/IsochronScepterTest.java index 71506a20563..2036f56dc25 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/copy/IsochronScepterTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/copy/IsochronScepterTest.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; @@ -39,16 +38,13 @@ import org.mage.test.serverside.base.CardTestPlayerBase; */ public class IsochronScepterTest extends CardTestPlayerBase { - /** - * Isochron Scepter - * Artifact, 2 (2) - * Imprint — When Isochron Scepter enters the battlefield, you may exile an - * instant card with converted mana cost 2 or less from your hand. - * {2}, {T}: You may copy the exiled card. If you do, you may cast the copy - * without paying its mana cost. - * - */ + * Isochron Scepter Artifact, 2 (2) Imprint — When Isochron Scepter enters + * the battlefield, you may exile an instant card with converted mana cost 2 + * or less from your hand. {2}, {T}: You may copy the exiled card. If you + * do, you may cast the copy without paying its mana cost. + * + */ @Test public void testImprint() { addCard(Zone.BATTLEFIELD, playerA, "Forest", 4); @@ -64,9 +60,9 @@ public class IsochronScepterTest extends CardTestPlayerBase { assertPermanentCount(playerA, "Isochron Scepter", 1); assertExileCount("Lightning Bolt", 1); assertLife(playerB, 20); - + } - + @Test public void testCopyCard() { addCard(Zone.BATTLEFIELD, playerA, "Forest", 4); @@ -86,7 +82,7 @@ public class IsochronScepterTest extends CardTestPlayerBase { assertExileCount("Lightning Bolt", 1); assertGraveyardCount(playerA, "Lightning Bolt", 0); assertLife(playerB, 17); - + } @Test @@ -108,20 +104,33 @@ public class IsochronScepterTest extends CardTestPlayerBase { assertExileCount("Lightning Bolt", 1); assertGraveyardCount(playerA, "Lightning Bolt", 0); assertLife(playerB, 20); - + } - + + /** + * Not sure if it's triggered by just casting Angel's Grace or by casting it + * from an Isochron Scepter, but when the bug happens neither player is able + * to play spells or activate abilities anymore for the rest of the game. + * + * Maybe something related to Split Second? + */ @Test public void testAngelsGrace() { addCard(Zone.BATTLEFIELD, playerA, "Plains", 4); addCard(Zone.HAND, playerA, "Isochron Scepter"); + // Split second (As long as this spell is on the stack, players can't cast spells or activate abilities that aren't mana abilities.) + // You can't lose the game this turn and your opponents can't win the game this turn. + // Until end of turn, damage that would reduce your life total to less than 1 reduces it to 1 instead. + addCard(Zone.HAND, playerA, "Angel's Grace"); - addCard(Zone.BATTLEFIELD, playerB, "Dross Crocodile", 4); + addCard(Zone.BATTLEFIELD, playerB, "Dross Crocodile", 4);// 5/1 + addCard(Zone.HAND, playerB, "Lightning Bolt", 2); + addCard(Zone.BATTLEFIELD, playerB, "Mountain", 2); castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Isochron Scepter"); addTarget(playerA, "Angel's Grace"); - + attack(2, playerB, "Dross Crocodile"); attack(2, playerB, "Dross Crocodile"); attack(2, playerB, "Dross Crocodile"); @@ -131,24 +140,34 @@ public class IsochronScepterTest extends CardTestPlayerBase { setChoice(playerA, "Yes"); setChoice(playerA, "Yes"); - setStopAt(2, PhaseStep.END_COMBAT); + // Damage life loss is reduced to 0 because of Angel's Grace effect active + castSpell(2, PhaseStep.POSTCOMBAT_MAIN, playerB, "Lightning Bolt", playerA); + + // Spells can be cast again + castSpell(3, PhaseStep.PRECOMBAT_MAIN, playerB, "Lightning Bolt", "Dross Crocodile"); + + setStopAt(3, PhaseStep.BEGIN_COMBAT); execute(); - assertPermanentCount(playerA, "Isochron Scepter", 1); assertExileCount("Angel's Grace", 1); assertGraveyardCount(playerA, "Angel's Grace", 0); assertLife(playerA, 1); assertLife(playerB, 20); + assertGraveyardCount(playerB, "Lightning Bolt", 2); + assertGraveyardCount(playerB, "Dross Crocodile", 1); + assertPermanentCount(playerB, "Dross Crocodile", 3); + assertPermanentCount(playerA, "Isochron Scepter", 1); + } - + /** - * Resolving a Silence cast from exile via Isochron Scepter during my opponent's upkeep does - * not prevent that opponent from casting spells that turn. - * + * Resolving a Silence cast from exile via Isochron Scepter during my + * opponent's upkeep does not prevent that opponent from casting spells that + * turn. + * */ - @Test public void testSilence() { addCard(Zone.BATTLEFIELD, playerA, "Plains", 4); @@ -160,7 +179,7 @@ public class IsochronScepterTest extends CardTestPlayerBase { castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Isochron Scepter"); addTarget(playerA, "Silence"); - + activateAbility(2, PhaseStep.UPKEEP, playerA, "{2},{T}:"); setChoice(playerA, "Yes"); setChoice(playerA, "Yes"); @@ -175,6 +194,6 @@ public class IsochronScepterTest extends CardTestPlayerBase { assertHandCount(playerB, "Silvercoat Lion", 1); assertPermanentCount(playerB, "Silvercoat Lion", 0); - - } + + } } diff --git a/Mage/src/mage/game/stack/Spell.java b/Mage/src/mage/game/stack/Spell.java index 0b0f22fb45a..58d81e3fe6e 100644 --- a/Mage/src/mage/game/stack/Spell.java +++ b/Mage/src/mage/game/stack/Spell.java @@ -207,11 +207,8 @@ public class Spell extends StackObjImpl implements Card { } } if (game.getState().getZone(card.getMainCard().getId()) == Zone.STACK) { - if (isCopy() == card.isCopy()) { - Player player = game.getPlayer(getControllerId()); - if (player != null) { - player.moveCards(card, Zone.STACK, Zone.GRAVEYARD, ability, game); - } + if (!isCopy()) { + controller.moveCards(card, Zone.GRAVEYARD, ability, game); } } return result; From 3f8ae0cf61d502fb559f9808cadd2886248e028d Mon Sep 17 00:00:00 2001 From: LevelX2 Date: Fri, 23 Oct 2015 18:33:31 +0200 Subject: [PATCH 221/268] * Infinite Obliteration - Fixed that the cards from players library were not exiled (also realted to other cards that use that effect class). --- ...archTargetGraveyardHandLibraryForCardNameAndExileEffect.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Mage/src/mage/abilities/effects/common/search/SearchTargetGraveyardHandLibraryForCardNameAndExileEffect.java b/Mage/src/mage/abilities/effects/common/search/SearchTargetGraveyardHandLibraryForCardNameAndExileEffect.java index 3f14a35fd38..26a88824f6c 100644 --- a/Mage/src/mage/abilities/effects/common/search/SearchTargetGraveyardHandLibraryForCardNameAndExileEffect.java +++ b/Mage/src/mage/abilities/effects/common/search/SearchTargetGraveyardHandLibraryForCardNameAndExileEffect.java @@ -115,7 +115,7 @@ public abstract class SearchTargetGraveyardHandLibraryForCardNameAndExileEffect filter.setMessage("card named " + cardName + " in the library of " + targetPlayer.getLogName()); TargetCardInLibrary targetLib = new TargetCardInLibrary(0, cardsCount, filter); if (controller.choose(Outcome.Exile, cardsInLibrary, targetLib, game)) { - controller.moveCards(new CardsImpl(target.getTargets()), Zone.EXILED, source, game); + controller.moveCards(new CardsImpl(targetLib.getTargets()), Zone.EXILED, source, game); } targetPlayer.shuffleLibrary(game); } From 4b18825c96e0f418cc393eaa9c8255a42e94c9a1 Mon Sep 17 00:00:00 2001 From: LoneFox Date: Sat, 24 Oct 2015 07:32:03 +0300 Subject: [PATCH 222/268] Implement cards: Cenn's Heir, Kinsbaile Borderguard, Kithkin Harbinger, and Kithkin Mourncaller Note: Currently Kithkin Mourncaller does not work due to missing LKI about attacking. --- Mage.Sets/src/mage/sets/lorwyn/CennsHeir.java | 77 ++++++++++++ .../mage/sets/lorwyn/KithkinHarbinger.java | 73 +++++++++++ .../mage/sets/lorwyn/KithkinMourncaller.java | 74 +++++++++++ .../morningtide/KinsbaileBorderguard.java | 117 ++++++++++++++++++ 4 files changed, 341 insertions(+) create mode 100644 Mage.Sets/src/mage/sets/lorwyn/CennsHeir.java create mode 100644 Mage.Sets/src/mage/sets/lorwyn/KithkinHarbinger.java create mode 100644 Mage.Sets/src/mage/sets/lorwyn/KithkinMourncaller.java create mode 100644 Mage.Sets/src/mage/sets/morningtide/KinsbaileBorderguard.java diff --git a/Mage.Sets/src/mage/sets/lorwyn/CennsHeir.java b/Mage.Sets/src/mage/sets/lorwyn/CennsHeir.java new file mode 100644 index 00000000000..558b973c1ab --- /dev/null +++ b/Mage.Sets/src/mage/sets/lorwyn/CennsHeir.java @@ -0,0 +1,77 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.sets.lorwyn; + +import java.util.UUID; +import mage.MageInt; +import mage.abilities.common.AttacksTriggeredAbility; +import mage.abilities.dynamicvalue.common.PermanentsOnBattlefieldCount; +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.filter.common.FilterAttackingCreature; +import mage.filter.predicate.mageobject.SubtypePredicate; +import mage.filter.predicate.permanent.AnotherPredicate; + +/** + * + * @author LoneFox + */ +public class CennsHeir extends CardImpl { + + private static final FilterAttackingCreature filter = new FilterAttackingCreature("other attacking Kithkin"); + + static { + filter.add(new SubtypePredicate("Kithkin")); + filter.add(new AnotherPredicate()); + } + + public CennsHeir(UUID ownerId) { + super(ownerId, 8, "Cenn's Heir", Rarity.COMMON, new CardType[]{CardType.CREATURE}, "{1}{W}"); + this.expansionSetCode = "LRW"; + this.subtype.add("Kithkin"); + this.subtype.add("Soldier"); + this.power = new MageInt(1); + this.toughness = new MageInt(1); + + // Whenever Cenn's Heir attacks, it gets +1/+1 until end of turn for each other attacking Kithkin. + PermanentsOnBattlefieldCount count = new PermanentsOnBattlefieldCount(filter); + this.addAbility(new AttacksTriggeredAbility(new BoostSourceEffect(count, count, Duration.EndOfTurn, true), false)); + } + + public CennsHeir(final CennsHeir card) { + super(card); + } + + @Override + public CennsHeir copy() { + return new CennsHeir(this); + } +} diff --git a/Mage.Sets/src/mage/sets/lorwyn/KithkinHarbinger.java b/Mage.Sets/src/mage/sets/lorwyn/KithkinHarbinger.java new file mode 100644 index 00000000000..3ff7e1a031f --- /dev/null +++ b/Mage.Sets/src/mage/sets/lorwyn/KithkinHarbinger.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.lorwyn; + +import java.util.UUID; +import mage.MageInt; +import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.effects.common.search.SearchLibraryPutOnLibraryEffect; +import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.Rarity; +import mage.filter.FilterCard; +import mage.filter.predicate.mageobject.SubtypePredicate; +import mage.target.common.TargetCardInLibrary; + +/** + * + * @author LoneFox + */ +public class KithkinHarbinger extends CardImpl { + + public static final FilterCard filter = new FilterCard("Kithkin card"); + + static { + filter.add(new SubtypePredicate("Kithkin")); + } + + public KithkinHarbinger(UUID ownerId) { + super(ownerId, 26, "Kithkin Harbinger", Rarity.UNCOMMON, new CardType[]{CardType.CREATURE}, "{2}{W}"); + this.expansionSetCode = "LRW"; + this.subtype.add("Kithkin"); + this.subtype.add("Wizard"); + this.power = new MageInt(1); + this.toughness = new MageInt(3); + + // When Kithkin Harbinger enters the battlefield, you may search your library for a Kithkin card, reveal it, then shuffle your library and put that card on top of it. + this.addAbility(new EntersBattlefieldTriggeredAbility(new SearchLibraryPutOnLibraryEffect(new TargetCardInLibrary(filter), true, true), true)); + } + + public KithkinHarbinger(final KithkinHarbinger card) { + super(card); + } + + @Override + public KithkinHarbinger copy() { + return new KithkinHarbinger(this); + } +} diff --git a/Mage.Sets/src/mage/sets/lorwyn/KithkinMourncaller.java b/Mage.Sets/src/mage/sets/lorwyn/KithkinMourncaller.java new file mode 100644 index 00000000000..76267304715 --- /dev/null +++ b/Mage.Sets/src/mage/sets/lorwyn/KithkinMourncaller.java @@ -0,0 +1,74 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.sets.lorwyn; + +import java.util.UUID; +import mage.MageInt; +import mage.abilities.common.PutIntoGraveFromBattlefieldAllTriggeredAbility; +import mage.abilities.effects.common.DrawCardSourceControllerEffect; +import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.Rarity; +import mage.filter.common.FilterAttackingCreature; +import mage.filter.predicate.Predicates; +import mage.filter.predicate.mageobject.SubtypePredicate; + +/** + * + * @author LoneFox + */ +public class KithkinMourncaller extends CardImpl { + + private static final FilterAttackingCreature filter = new FilterAttackingCreature("an attacking Kithkin or Elf"); + + static { + filter.add(Predicates.or(new SubtypePredicate("Kithkin"), new SubtypePredicate("Elf"))); + } + + public KithkinMourncaller(UUID ownerId) { + super(ownerId, 224, "Kithkin Mourncaller", Rarity.UNCOMMON, new CardType[]{CardType.CREATURE}, "{2}{G}"); + this.expansionSetCode = "LRW"; + this.subtype.add("Kithkin"); + this.subtype.add("Scout"); + this.power = new MageInt(2); + this.toughness = new MageInt(2); + + // Whenever an attacking Kithkin or Elf is put into your graveyard from the battlefield, you may draw a card. + this.addAbility(new PutIntoGraveFromBattlefieldAllTriggeredAbility(new DrawCardSourceControllerEffect(1), + true, filter, false, true)); + } + + public KithkinMourncaller(final KithkinMourncaller card) { + super(card); + } + + @Override + public KithkinMourncaller copy() { + return new KithkinMourncaller(this); + } +} diff --git a/Mage.Sets/src/mage/sets/morningtide/KinsbaileBorderguard.java b/Mage.Sets/src/mage/sets/morningtide/KinsbaileBorderguard.java new file mode 100644 index 00000000000..5080aa2baa5 --- /dev/null +++ b/Mage.Sets/src/mage/sets/morningtide/KinsbaileBorderguard.java @@ -0,0 +1,117 @@ +/* + * 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.morningtide; + +import java.util.UUID; +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.DiesTriggeredAbility; +import mage.abilities.common.EntersBattlefieldAbility; +import mage.abilities.dynamicvalue.DynamicValue; +import mage.abilities.dynamicvalue.common.PermanentsOnBattlefieldCount; +import mage.abilities.effects.Effect; +import mage.abilities.effects.common.CreateTokenEffect; +import mage.abilities.effects.common.counter.AddCountersSourceEffect; +import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.Rarity; +import mage.counters.Counter; +import mage.counters.CounterType; +import mage.filter.common.FilterControlledPermanent; +import mage.filter.predicate.mageobject.SubtypePredicate; +import mage.game.Game; +import mage.game.permanent.Permanent; +import mage.game.permanent.token.KithkinToken; + +/** + * + * @author LoneFox + */ +public class KinsbaileBorderguard extends CardImpl { + + private static final FilterControlledPermanent filter = new FilterControlledPermanent(); + + static { + filter.add(new SubtypePredicate("Kithkin")); + } + + public KinsbaileBorderguard(UUID ownerId) { + super(ownerId, 14, "Kinsbaile Borderguard", Rarity.RARE, new CardType[]{CardType.CREATURE}, "{1}{W}{W}"); + this.expansionSetCode = "MOR"; + this.subtype.add("Kithkin"); + this.subtype.add("Soldier"); + this.power = new MageInt(1); + this.toughness = new MageInt(1); + + // Kinsbaile Borderguard enters the battlefield with a +1/+1 counter on it for each other Kithkin you control. + this.addAbility(new EntersBattlefieldAbility(new AddCountersSourceEffect(CounterType.P1P1.createInstance(0), + new PermanentsOnBattlefieldCount(filter), true), "with a +1/+1 counter on it for each other Kithkin you control")); + // When Kinsbaile Borderguard dies, put a 1/1 white Kithkin Soldier creature token onto the battlefield for each counter on it. + this.addAbility(new DiesTriggeredAbility(new CreateTokenEffect(new KithkinToken(), new AllCountersCount()))); + } + + public KinsbaileBorderguard(final KinsbaileBorderguard card) { + super(card); + } + + @Override + public KinsbaileBorderguard copy() { + return new KinsbaileBorderguard(this); + } +} + +class AllCountersCount implements DynamicValue { + + @Override + public int calculate(Game game, Ability sourceAbility, Effect effect) { + Permanent sourcePermanent = game.getPermanentOrLKIBattlefield(sourceAbility.getSourceId()); + if(sourcePermanent != null) { + int total = 0; + for(Counter counter : sourcePermanent.getCounters().values()) { + total += counter.getCount(); + } + return total; + } + return 0; + } + + @Override + public DynamicValue copy() { + return new AllCountersCount(); + } + + @Override + public String getMessage() { + return "for each counter on it"; + } + + @Override + public String toString() { + return "1"; + } +} From d42e5fed789eb6853eeea81f13d03d5d6230c1af Mon Sep 17 00:00:00 2001 From: Toby Lawrence Date: Sun, 25 Oct 2015 17:58:20 -0400 Subject: [PATCH 223/268] Razorverge Thicket should enter untapped only if you control two or less lands. --- .../scarsofmirrodin/RazorvergeThicket.java | 2 +- .../conditional/RazorvergeThicketTest.java | 39 +++++++++++++++++++ 2 files changed, 40 insertions(+), 1 deletion(-) create mode 100644 Mage.Tests/src/test/java/org/mage/test/cards/conditional/RazorvergeThicketTest.java diff --git a/Mage.Sets/src/mage/sets/scarsofmirrodin/RazorvergeThicket.java b/Mage.Sets/src/mage/sets/scarsofmirrodin/RazorvergeThicket.java index ae33a638f33..dc1ac788117 100644 --- a/Mage.Sets/src/mage/sets/scarsofmirrodin/RazorvergeThicket.java +++ b/Mage.Sets/src/mage/sets/scarsofmirrodin/RazorvergeThicket.java @@ -54,7 +54,7 @@ public class RazorvergeThicket extends CardImpl { super(ownerId, 228, "Razorverge Thicket", Rarity.RARE, new CardType[]{CardType.LAND}, null); this.expansionSetCode = "SOM"; - Condition controls = new InvertCondition(new PermanentsOnTheBattlefieldCondition(filter, PermanentsOnTheBattlefieldCondition.CountType.FEWER_THAN, 4)); + Condition controls = new InvertCondition(new PermanentsOnTheBattlefieldCondition(filter, PermanentsOnTheBattlefieldCondition.CountType.FEWER_THAN, 3)); String abilityText = "tap it unless you control fewer than 3 lands"; this.addAbility(new EntersBattlefieldAbility(new ConditionalOneShotEffect(new TapSourceEffect(), controls, abilityText), abilityText)); this.addAbility(new GreenManaAbility()); diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/conditional/RazorvergeThicketTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/conditional/RazorvergeThicketTest.java new file mode 100644 index 00000000000..01705b7a0e1 --- /dev/null +++ b/Mage.Tests/src/test/java/org/mage/test/cards/conditional/RazorvergeThicketTest.java @@ -0,0 +1,39 @@ +package org.mage.test.cards.conditional; + +import mage.constants.PhaseStep; +import mage.constants.Zone; +import org.junit.Test; +import org.mage.test.serverside.base.CardTestPlayerBase; + +/** + * @author tobz + */ +public class RazorvergeThicketTest extends CardTestPlayerBase { + + @Test + public void testEntersTappedForThreeLands() { + addCard(Zone.BATTLEFIELD, playerA, "Island", 3); + addCard(Zone.HAND, playerA, "Razorverge Thicket"); + + playLand(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Razorverge Thicket"); + + setStopAt(1, PhaseStep.BEGIN_COMBAT); + execute(); + + assertTapped("Razorverge Thicket", true); + } + + @Test + public void testEntersUntappedForTwoLands() { + addCard(Zone.BATTLEFIELD, playerA, "Island", 2); + addCard(Zone.HAND, playerA, "Razorverge Thicket"); + + playLand(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Razorverge Thicket"); + + setStopAt(1, PhaseStep.BEGIN_COMBAT); + execute(); + + assertTapped("Razorverge Thicket", false); + } + +} From 59357b8da13e9291328f12fda5d4035373e44fa2 Mon Sep 17 00:00:00 2001 From: LoneFox Date: Mon, 26 Oct 2015 18:12:37 +0200 Subject: [PATCH 224/268] Implement cards: Charging Slateback, Krosan Groundshaker, Snarling Undorak, and Spurred Wolverine --- .../sets/onslaught/ChargingSlateback.java | 66 ++++++++++++++ .../sets/onslaught/KrosanGroundshaker.java | 79 +++++++++++++++++ .../mage/sets/onslaught/SnarlingUndorak.java | 81 ++++++++++++++++++ .../mage/sets/onslaught/SpurredWolverine.java | 85 +++++++++++++++++++ 4 files changed, 311 insertions(+) create mode 100644 Mage.Sets/src/mage/sets/onslaught/ChargingSlateback.java create mode 100644 Mage.Sets/src/mage/sets/onslaught/KrosanGroundshaker.java create mode 100644 Mage.Sets/src/mage/sets/onslaught/SnarlingUndorak.java create mode 100644 Mage.Sets/src/mage/sets/onslaught/SpurredWolverine.java diff --git a/Mage.Sets/src/mage/sets/onslaught/ChargingSlateback.java b/Mage.Sets/src/mage/sets/onslaught/ChargingSlateback.java new file mode 100644 index 00000000000..85e7d4663c3 --- /dev/null +++ b/Mage.Sets/src/mage/sets/onslaught/ChargingSlateback.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.MageInt; +import mage.abilities.common.CantBlockAbility; +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.keyword.MorphAbility; +import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.Rarity; + +/** + * + * @author LoneFox + */ +public class ChargingSlateback extends CardImpl { + + public ChargingSlateback(UUID ownerId) { + super(ownerId, 194, "Charging Slateback", Rarity.COMMON, new CardType[]{CardType.CREATURE}, "{4}{R}"); + this.expansionSetCode = "ONS"; + this.subtype.add("Beast"); + this.power = new MageInt(4); + this.toughness = new MageInt(3); + + // Charging Slateback can't block. + this.addAbility(new CantBlockAbility()); + // Morph {4}{R} + this.addAbility(new MorphAbility(this, new ManaCostsImpl("{4}{R}"))); + } + + public ChargingSlateback(final ChargingSlateback card) { + super(card); + } + + @Override + public ChargingSlateback copy() { + return new ChargingSlateback(this); + } +} diff --git a/Mage.Sets/src/mage/sets/onslaught/KrosanGroundshaker.java b/Mage.Sets/src/mage/sets/onslaught/KrosanGroundshaker.java new file mode 100644 index 00000000000..e33d105a911 --- /dev/null +++ b/Mage.Sets/src/mage/sets/onslaught/KrosanGroundshaker.java @@ -0,0 +1,79 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.sets.onslaught; + +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.TrampleAbility; +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.mageobject.SubtypePredicate; +import mage.target.common.TargetCreaturePermanent; + +/** + * + * @author LoneFox + */ +public class KrosanGroundshaker extends CardImpl { + + private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("Beast creature"); + + static { + filter.add(new SubtypePredicate("Beast")); + } + + public KrosanGroundshaker(UUID ownerId) { + super(ownerId, 271, "Krosan Groundshaker", Rarity.UNCOMMON, new CardType[]{CardType.CREATURE}, "{4}{G}{G}{G}"); + this.expansionSetCode = "ONS"; + this.subtype.add("Beast"); + this.power = new MageInt(6); + this.toughness = new MageInt(6); + + // {G}: Target Beast creature gains trample until end of turn. + Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new GainAbilityTargetEffect(TrampleAbility.getInstance(), Duration.EndOfTurn), new ManaCostsImpl("{G}")); + ability.addTarget(new TargetCreaturePermanent(filter)); + this.addAbility(ability); + } + + public KrosanGroundshaker(final KrosanGroundshaker card) { + super(card); + } + + @Override + public KrosanGroundshaker copy() { + return new KrosanGroundshaker(this); + } +} diff --git a/Mage.Sets/src/mage/sets/onslaught/SnarlingUndorak.java b/Mage.Sets/src/mage/sets/onslaught/SnarlingUndorak.java new file mode 100644 index 00000000000..b7f2be02a46 --- /dev/null +++ b/Mage.Sets/src/mage/sets/onslaught/SnarlingUndorak.java @@ -0,0 +1,81 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.sets.onslaught; + +import java.util.UUID; +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.effects.common.continuous.BoostTargetEffect; +import mage.abilities.keyword.MorphAbility; +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.mageobject.SubtypePredicate; +import mage.target.common.TargetCreaturePermanent; + +/** + * + * @author LoneFox + */ +public class SnarlingUndorak extends CardImpl { + + private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("Beast creature"); + + static { + filter.add(new SubtypePredicate("Beast")); + } + + public SnarlingUndorak(UUID ownerId) { + super(ownerId, 283, "Snarling Undorak", Rarity.COMMON, new CardType[]{CardType.CREATURE}, "{2}{G}{G}"); + this.expansionSetCode = "ONS"; + this.subtype.add("Beast"); + this.power = new MageInt(3); + this.toughness = new MageInt(3); + + // {2}{G}: Target Beast creature gets +1/+1 until end of turn. + Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new BoostTargetEffect(1, 1, Duration.EndOfTurn), new ManaCostsImpl("{2}{G}")); + ability.addTarget(new TargetCreaturePermanent(filter)); + this.addAbility(ability); + // Morph {1}{G}{G} + this.addAbility(new MorphAbility(this, new ManaCostsImpl("{1}{G}{G}"))); + } + + public SnarlingUndorak(final SnarlingUndorak card) { + super(card); + } + + @Override + public SnarlingUndorak copy() { + return new SnarlingUndorak(this); + } +} diff --git a/Mage.Sets/src/mage/sets/onslaught/SpurredWolverine.java b/Mage.Sets/src/mage/sets/onslaught/SpurredWolverine.java new file mode 100644 index 00000000000..10ad8ce064d --- /dev/null +++ b/Mage.Sets/src/mage/sets/onslaught/SpurredWolverine.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.onslaught; + +import java.util.UUID; +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.costs.common.TapTargetCost; +import mage.abilities.effects.common.continuous.GainAbilityTargetEffect; +import mage.abilities.keyword.FirstStrikeAbility; +import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.Rarity; +import mage.constants.Zone; +import mage.filter.common.FilterControlledPermanent; +import mage.filter.predicate.Predicates; +import mage.filter.predicate.mageobject.SubtypePredicate; +import mage.filter.predicate.permanent.TappedPredicate; +import mage.target.common.TargetControlledPermanent; +import mage.target.common.TargetCreaturePermanent; + +/** + * + * @author LoneFox + */ +public class SpurredWolverine extends CardImpl { + + private static final FilterControlledPermanent filter = new FilterControlledPermanent("untapped Beasts you control"); + + static { + filter.add(Predicates.not(new TappedPredicate())); + filter.add(new SubtypePredicate("Beast")); + } + + public SpurredWolverine(UUID ownerId) { + super(ownerId, 237, "Spurred Wolverine", Rarity.COMMON, new CardType[]{CardType.CREATURE}, "{4}{R}"); + this.expansionSetCode = "ONS"; + this.subtype.add("Wolverine"); + this.subtype.add("Beast"); + this.power = new MageInt(3); + this.toughness = new MageInt(2); + + // Tap two untapped Beasts you control: Target creature gains first strike until end of turn. + Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new GainAbilityTargetEffect( + FirstStrikeAbility.getInstance(), Duration.EndOfTurn), new TapTargetCost(new TargetControlledPermanent(2, 2, filter, false))); + ability.addTarget(new TargetCreaturePermanent()); + this.addAbility(ability); + } + + public SpurredWolverine(final SpurredWolverine card) { + super(card); + } + + @Override + public SpurredWolverine copy() { + return new SpurredWolverine(this); + } +} From 2a0c48e1699dc4d580906cd8a97d39bec48f026c Mon Sep 17 00:00:00 2001 From: LoneFox Date: Mon, 26 Oct 2015 18:55:25 +0200 Subject: [PATCH 225/268] Implement cards: Aven Brigadier, Catapult Squad, Dive Bomber, and Grassland Crusader --- .../mage/sets/onslaught/AvenBrigadier.java | 81 ++++++++++++++++++ .../mage/sets/onslaught/CatapultSquad.java | 83 +++++++++++++++++++ .../src/mage/sets/onslaught/DiveBomber.java | 76 +++++++++++++++++ .../sets/onslaught/GrasslandCrusader.java | 81 ++++++++++++++++++ 4 files changed, 321 insertions(+) create mode 100644 Mage.Sets/src/mage/sets/onslaught/AvenBrigadier.java create mode 100644 Mage.Sets/src/mage/sets/onslaught/CatapultSquad.java create mode 100644 Mage.Sets/src/mage/sets/onslaught/DiveBomber.java create mode 100644 Mage.Sets/src/mage/sets/onslaught/GrasslandCrusader.java diff --git a/Mage.Sets/src/mage/sets/onslaught/AvenBrigadier.java b/Mage.Sets/src/mage/sets/onslaught/AvenBrigadier.java new file mode 100644 index 00000000000..8c3e7032911 --- /dev/null +++ b/Mage.Sets/src/mage/sets/onslaught/AvenBrigadier.java @@ -0,0 +1,81 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.sets.onslaught; + +import java.util.UUID; +import mage.MageInt; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.effects.common.continuous.BoostAllEffect; +import mage.abilities.keyword.FlyingAbility; +import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.Rarity; +import mage.constants.Zone; +import mage.filter.common.FilterCreaturePermanent; +import mage.filter.predicate.mageobject.SubtypePredicate; + +/** + * + * @author LoneFox + */ +public class AvenBrigadier extends CardImpl { + + private static final FilterCreaturePermanent filter1 = new FilterCreaturePermanent("Bird creatures"); + private static final FilterCreaturePermanent filter2 = new FilterCreaturePermanent("Soldier creatures"); + + static { + filter1.add(new SubtypePredicate("Bird")); + filter2.add(new SubtypePredicate("Soldier")); + } + + public AvenBrigadier(UUID ownerId) { + super(ownerId, 7, "Aven Brigadier", Rarity.RARE, new CardType[]{CardType.CREATURE}, "{3}{W}{W}{W}"); + this.expansionSetCode = "ONS"; + this.subtype.add("Bird"); + this.subtype.add("Soldier"); + this.power = new MageInt(3); + this.toughness = new MageInt(5); + + // Flying + this.addAbility(FlyingAbility.getInstance()); + // Other Bird creatures get +1/+1. + this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new BoostAllEffect(1, 1, Duration.WhileOnBattlefield, filter1, true))); + // Other Soldier creatures get +1/+1. + this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new BoostAllEffect(1, 1, Duration.WhileOnBattlefield, filter2, true))); + } + + public AvenBrigadier(final AvenBrigadier card) { + super(card); + } + + @Override + public AvenBrigadier copy() { + return new AvenBrigadier(this); + } +} diff --git a/Mage.Sets/src/mage/sets/onslaught/CatapultSquad.java b/Mage.Sets/src/mage/sets/onslaught/CatapultSquad.java new file mode 100644 index 00000000000..b2d86150117 --- /dev/null +++ b/Mage.Sets/src/mage/sets/onslaught/CatapultSquad.java @@ -0,0 +1,83 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.sets.onslaught; + +import java.util.UUID; +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.costs.common.TapTargetCost; +import mage.abilities.effects.common.DamageTargetEffect; +import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.Rarity; +import mage.constants.Zone; +import mage.filter.common.FilterAttackingOrBlockingCreature; +import mage.filter.common.FilterControlledPermanent; +import mage.filter.predicate.Predicates; +import mage.filter.predicate.mageobject.SubtypePredicate; +import mage.filter.predicate.permanent.TappedPredicate; +import mage.target.common.TargetControlledPermanent; +import mage.target.common.TargetCreaturePermanent; + +/** + * + * @author LoneFox + */ +public class CatapultSquad extends CardImpl { + + private static final FilterControlledPermanent filter = new FilterControlledPermanent("untapped Soldiers you control"); + + static { + filter.add(Predicates.not(new TappedPredicate())); + filter.add(new SubtypePredicate("Soldier")); + } + + public CatapultSquad(UUID ownerId) { + super(ownerId, 11, "Catapult Squad", Rarity.UNCOMMON, new CardType[]{CardType.CREATURE}, "{1}{W}"); + this.expansionSetCode = "ONS"; + this.subtype.add("Human"); + this.subtype.add("Soldier"); + this.power = new MageInt(2); + this.toughness = new MageInt(1); + + // Tap two untapped Soldiers you control: Catapult Squad deals 2 damage to target attacking or blocking creature. + Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new DamageTargetEffect(2), new TapTargetCost(new TargetControlledPermanent(2, 2, filter, false))); + ability.addTarget(new TargetCreaturePermanent(new FilterAttackingOrBlockingCreature())); + this.addAbility(ability); + } + + public CatapultSquad(final CatapultSquad card) { + super(card); + } + + @Override + public CatapultSquad copy() { + return new CatapultSquad(this); + } +} diff --git a/Mage.Sets/src/mage/sets/onslaught/DiveBomber.java b/Mage.Sets/src/mage/sets/onslaught/DiveBomber.java new file mode 100644 index 00000000000..48a017e5c78 --- /dev/null +++ b/Mage.Sets/src/mage/sets/onslaught/DiveBomber.java @@ -0,0 +1,76 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.sets.onslaught; + +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.costs.common.TapSourceCost; +import mage.abilities.effects.common.DamageTargetEffect; +import mage.abilities.keyword.FlyingAbility; +import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.Rarity; +import mage.constants.Zone; +import mage.filter.common.FilterAttackingOrBlockingCreature; +import mage.target.common.TargetCreaturePermanent; + +/** + * + * @author LoneFox + */ +public class DiveBomber extends CardImpl { + + public DiveBomber(UUID ownerId) { + super(ownerId, 26, "Dive Bomber", Rarity.COMMON, new CardType[]{CardType.CREATURE}, "{3}{W}"); + this.expansionSetCode = "ONS"; + this.subtype.add("Bird"); + this.subtype.add("Soldier"); + this.power = new MageInt(2); + this.toughness = new MageInt(2); + + // Flying + this.addAbility(FlyingAbility.getInstance()); + // {tap}, Sacrifice Dive Bomber: Dive Bomber deals 2 damage to target attacking or blocking creature. + Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new DamageTargetEffect(2), new TapSourceCost()); + ability.addCost(new SacrificeSourceCost()); + ability.addTarget(new TargetCreaturePermanent(new FilterAttackingOrBlockingCreature())); + this.addAbility(ability); + } + + public DiveBomber(final DiveBomber card) { + super(card); + } + + @Override + public DiveBomber copy() { + return new DiveBomber(this); + } +} diff --git a/Mage.Sets/src/mage/sets/onslaught/GrasslandCrusader.java b/Mage.Sets/src/mage/sets/onslaught/GrasslandCrusader.java new file mode 100644 index 00000000000..e7d0cebe0a0 --- /dev/null +++ b/Mage.Sets/src/mage/sets/onslaught/GrasslandCrusader.java @@ -0,0 +1,81 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.sets.onslaught; + +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.continuous.BoostTargetEffect; +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; +import mage.target.common.TargetCreaturePermanent; + +/** + * + * @author LoneFox + */ +public class GrasslandCrusader extends CardImpl { + + private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("Elf or Soldier creature"); + + static { + filter.add(Predicates.or(new SubtypePredicate("Elf"), new SubtypePredicate("Soldier"))); + } + + public GrasslandCrusader(UUID ownerId) { + super(ownerId, 32, "Grassland Crusader", Rarity.COMMON, new CardType[]{CardType.CREATURE}, "{5}{W}"); + this.expansionSetCode = "ONS"; + this.subtype.add("Human"); + this.subtype.add("Cleric"); + this.subtype.add("Soldier"); + this.power = new MageInt(2); + this.toughness = new MageInt(4); + + // {tap}: Target Elf or Soldier creature gets +2/+2 until end of turn. + Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new BoostTargetEffect(2, 2, Duration.EndOfTurn), new TapSourceCost()); + ability.addTarget(new TargetCreaturePermanent(filter)); + this.addAbility(ability); + } + + public GrasslandCrusader(final GrasslandCrusader card) { + super(card); + } + + @Override + public GrasslandCrusader copy() { + return new GrasslandCrusader(this); + } +} From 89185096f1b49584043952850beb0214c6a2a9d7 Mon Sep 17 00:00:00 2001 From: LevelX2 Date: Tue, 27 Oct 2015 09:05:22 +0100 Subject: [PATCH 226/268] * Sharpened Pitchfork - Fixed wrong rarity. --- .../src/mage/sets/innistrad/SharpenedPitchfork.java | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/Mage.Sets/src/mage/sets/innistrad/SharpenedPitchfork.java b/Mage.Sets/src/mage/sets/innistrad/SharpenedPitchfork.java index 9f5743b3bda..69b5927d538 100644 --- a/Mage.Sets/src/mage/sets/innistrad/SharpenedPitchfork.java +++ b/Mage.Sets/src/mage/sets/innistrad/SharpenedPitchfork.java @@ -28,11 +28,6 @@ package mage.sets.innistrad; import java.util.UUID; - -import mage.constants.AttachmentType; -import mage.constants.CardType; -import mage.constants.Rarity; -import mage.constants.Zone; import mage.abilities.common.SimpleStaticAbility; import mage.abilities.condition.common.EquippedHasSubtypeCondition; import mage.abilities.costs.mana.GenericManaCost; @@ -42,7 +37,11 @@ import mage.abilities.effects.common.continuous.GainAbilityAttachedEffect; import mage.abilities.keyword.EquipAbility; import mage.abilities.keyword.FirstStrikeAbility; import mage.cards.CardImpl; +import mage.constants.AttachmentType; +import mage.constants.CardType; import mage.constants.Outcome; +import mage.constants.Rarity; +import mage.constants.Zone; /** * @@ -53,7 +52,7 @@ public class SharpenedPitchfork extends CardImpl { private static final String staticText = "As long as equipped creature is a Human, it gets +1/+1"; public SharpenedPitchfork(UUID ownerId) { - super(ownerId, 232, "Sharpened Pitchfork", Rarity.COMMON, new CardType[]{CardType.ARTIFACT}, "{2}"); + super(ownerId, 232, "Sharpened Pitchfork", Rarity.UNCOMMON, new CardType[]{CardType.ARTIFACT}, "{2}"); this.expansionSetCode = "ISD"; this.subtype.add("Equipment"); From fff9f18022cb9fc1961ec833e8e6995f06e659ff Mon Sep 17 00:00:00 2001 From: LevelX2 Date: Tue, 27 Oct 2015 09:24:39 +0100 Subject: [PATCH 227/268] * Spreading Seas - Fixed that not all existing land types (e.g. Urza's Mine) were removed if a land was enchanted by Spreading Seas. --- .../src/mage/sets/magicorigins/InfiniteObliteration.java | 5 +---- .../common/continuous/BecomesBasicLandEnchantedEffect.java | 3 ++- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/Mage.Sets/src/mage/sets/magicorigins/InfiniteObliteration.java b/Mage.Sets/src/mage/sets/magicorigins/InfiniteObliteration.java index 030db436a14..9b85d3cdf94 100644 --- a/Mage.Sets/src/mage/sets/magicorigins/InfiniteObliteration.java +++ b/Mage.Sets/src/mage/sets/magicorigins/InfiniteObliteration.java @@ -113,10 +113,7 @@ class InfiniteObliterationEffect extends SearchTargetGraveyardHandLibraryForCard @Override public String getText(Mode mode) { - StringBuilder sb = new StringBuilder(); - sb.append("Name a creature card. "); - sb.append(super.getText(mode)); - return sb.toString(); + return "Name a creature card. " + super.getText(mode); } } diff --git a/Mage/src/mage/abilities/effects/common/continuous/BecomesBasicLandEnchantedEffect.java b/Mage/src/mage/abilities/effects/common/continuous/BecomesBasicLandEnchantedEffect.java index 5bb693449ef..79d9c8f91d5 100644 --- a/Mage/src/mage/abilities/effects/common/continuous/BecomesBasicLandEnchantedEffect.java +++ b/Mage/src/mage/abilities/effects/common/continuous/BecomesBasicLandEnchantedEffect.java @@ -108,7 +108,8 @@ public class BecomesBasicLandEnchantedEffect extends ContinuousEffectImpl { } break; case TypeChangingEffects_4: - permanent.getSubtype().removeAll(allLandTypes); + // subtypes are all removed by changing the subtype to a land type. + permanent.getSubtype().clear(); permanent.getSubtype().addAll(landTypes); break; } From f041f22f1104e4eb3313f2ac1b1ed8e5799bfa34 Mon Sep 17 00:00:00 2001 From: LoneFox Date: Tue, 27 Oct 2015 10:54:19 +0200 Subject: [PATCH 228/268] Implement the Courier cycle from Onslaught --- .../mage/sets/onslaught/EvergloveCourier.java | 91 ++++++++++++++++++ .../sets/onslaught/FlamestickCourier.java | 91 ++++++++++++++++++ .../sets/onslaught/FrightshroudCourier.java | 91 ++++++++++++++++++ .../mage/sets/onslaught/GhosthelmCourier.java | 92 +++++++++++++++++++ .../sets/onslaught/PearlspearCourier.java | 92 +++++++++++++++++++ 5 files changed, 457 insertions(+) create mode 100644 Mage.Sets/src/mage/sets/onslaught/EvergloveCourier.java create mode 100644 Mage.Sets/src/mage/sets/onslaught/FlamestickCourier.java create mode 100644 Mage.Sets/src/mage/sets/onslaught/FrightshroudCourier.java create mode 100644 Mage.Sets/src/mage/sets/onslaught/GhosthelmCourier.java create mode 100644 Mage.Sets/src/mage/sets/onslaught/PearlspearCourier.java diff --git a/Mage.Sets/src/mage/sets/onslaught/EvergloveCourier.java b/Mage.Sets/src/mage/sets/onslaught/EvergloveCourier.java new file mode 100644 index 00000000000..3ecfc22b812 --- /dev/null +++ b/Mage.Sets/src/mage/sets/onslaught/EvergloveCourier.java @@ -0,0 +1,91 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.sets.onslaught; + +import java.util.UUID; +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.common.SkipUntapOptionalAbility; +import mage.abilities.condition.common.SourceTappedCondition; +import mage.abilities.costs.common.TapSourceCost; +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.decorator.ConditionalContinuousEffect; +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.Rarity; +import mage.constants.Zone; +import mage.filter.common.FilterCreaturePermanent; +import mage.filter.predicate.mageobject.SubtypePredicate; +import mage.target.common.TargetCreaturePermanent; + +/** + * + * @author LoneFox + */ +public class EvergloveCourier extends CardImpl { + + private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("Elf creature"); + + static { + filter.add(new SubtypePredicate("Elf")); + } + + public EvergloveCourier(UUID ownerId) { + super(ownerId, 262, "Everglove Courier", Rarity.UNCOMMON, new CardType[]{CardType.CREATURE}, "{2}{G}"); + this.expansionSetCode = "ONS"; + this.subtype.add("Elf"); + this.power = new MageInt(2); + this.toughness = new MageInt(1); + + // You may choose not to untap Everglove Courier during your untap step. + this.addAbility(new SkipUntapOptionalAbility()); + // {2}{G}, {tap}: Target Elf creature gets +2/+2 and has trample for as long as Everglove Courier remains tapped. + Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new ConditionalContinuousEffect( + new BoostTargetEffect(2, 2, Duration.Custom), SourceTappedCondition.getInstance(), + "target Elf creature gets +2/+2"), new ManaCostsImpl("{2}{G}")); + ability.addEffect(new ConditionalContinuousEffect(new GainAbilityTargetEffect(TrampleAbility.getInstance(), + Duration.Custom), SourceTappedCondition.getInstance(),"and has trample for as long as {this} remains tapped")); + ability.addCost(new TapSourceCost()); + ability.addTarget(new TargetCreaturePermanent(filter)); + this.addAbility(ability); + } + + public EvergloveCourier(final EvergloveCourier card) { + super(card); + } + + @Override + public EvergloveCourier copy() { + return new EvergloveCourier(this); + } +} diff --git a/Mage.Sets/src/mage/sets/onslaught/FlamestickCourier.java b/Mage.Sets/src/mage/sets/onslaught/FlamestickCourier.java new file mode 100644 index 00000000000..33ca61ca662 --- /dev/null +++ b/Mage.Sets/src/mage/sets/onslaught/FlamestickCourier.java @@ -0,0 +1,91 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.sets.onslaught; + +import java.util.UUID; +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.common.SkipUntapOptionalAbility; +import mage.abilities.condition.common.SourceTappedCondition; +import mage.abilities.costs.common.TapSourceCost; +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.decorator.ConditionalContinuousEffect; +import mage.abilities.effects.common.continuous.BoostTargetEffect; +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.filter.common.FilterCreaturePermanent; +import mage.filter.predicate.mageobject.SubtypePredicate; +import mage.target.common.TargetCreaturePermanent; + +/** + * + * @author LoneFox + */ +public class FlamestickCourier extends CardImpl { + + private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("Goblin creature"); + + static { + filter.add(new SubtypePredicate("Goblin")); + } + + public FlamestickCourier(UUID ownerId) { + super(ownerId, 203, "Flamestick Courier", Rarity.UNCOMMON, new CardType[]{CardType.CREATURE}, "{2}{R}"); + this.expansionSetCode = "ONS"; + this.subtype.add("Goblin"); + this.power = new MageInt(2); + this.toughness = new MageInt(1); + + // You may choose not to untap Flamestick Courier during your untap step. + this.addAbility(new SkipUntapOptionalAbility()); + // {2}{R}, {tap}: Target Goblin creature gets +2/+2 and has haste for as long as Flamestick Courier remains tapped. + Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new ConditionalContinuousEffect( + new BoostTargetEffect(2, 2, Duration.Custom), SourceTappedCondition.getInstance(), + "target Goblin creature gets +2/+2"), new ManaCostsImpl("{2}{R}")); + ability.addEffect(new ConditionalContinuousEffect(new GainAbilityTargetEffect(HasteAbility.getInstance(), + Duration.Custom), SourceTappedCondition.getInstance(),"and has haste for as long as {this} remains tapped")); + ability.addCost(new TapSourceCost()); + ability.addTarget(new TargetCreaturePermanent(filter)); + this.addAbility(ability); + } + + public FlamestickCourier(final FlamestickCourier card) { + super(card); + } + + @Override + public FlamestickCourier copy() { + return new FlamestickCourier(this); + } +} diff --git a/Mage.Sets/src/mage/sets/onslaught/FrightshroudCourier.java b/Mage.Sets/src/mage/sets/onslaught/FrightshroudCourier.java new file mode 100644 index 00000000000..71a3e443cba --- /dev/null +++ b/Mage.Sets/src/mage/sets/onslaught/FrightshroudCourier.java @@ -0,0 +1,91 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.sets.onslaught; + +import java.util.UUID; +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.common.SkipUntapOptionalAbility; +import mage.abilities.condition.common.SourceTappedCondition; +import mage.abilities.costs.common.TapSourceCost; +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.decorator.ConditionalContinuousEffect; +import mage.abilities.effects.common.continuous.BoostTargetEffect; +import mage.abilities.effects.common.continuous.GainAbilityTargetEffect; +import mage.abilities.keyword.FearAbility; +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.mageobject.SubtypePredicate; +import mage.target.common.TargetCreaturePermanent; + +/** + * + * @author LoneFox + */ +public class FrightshroudCourier extends CardImpl { + + private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("Zombie creature"); + + static { + filter.add(new SubtypePredicate("Zombie")); + } + + public FrightshroudCourier(UUID ownerId) { + super(ownerId, 149, "Frightshroud Courier", Rarity.UNCOMMON, new CardType[]{CardType.CREATURE}, "{2}{B}"); + this.expansionSetCode = "ONS"; + this.subtype.add("Zombie"); + this.power = new MageInt(2); + this.toughness = new MageInt(1); + + // You may choose not to untap Frightshroud Courier during your untap step. + this.addAbility(new SkipUntapOptionalAbility()); + // {2}{B}, {tap}: Target Zombie creature gets +2/+2 and has fear for as long as Frightshroud Courier remains tapped. + Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new ConditionalContinuousEffect( + new BoostTargetEffect(2, 2, Duration.Custom), SourceTappedCondition.getInstance(), + "target Zombie creature gets +2/+2"), new ManaCostsImpl("{2}{B}")); + ability.addEffect(new ConditionalContinuousEffect(new GainAbilityTargetEffect(FearAbility.getInstance(), + Duration.Custom), SourceTappedCondition.getInstance(),"and has fear for as long as {this} remains tapped")); + ability.addCost(new TapSourceCost()); + ability.addTarget(new TargetCreaturePermanent(filter)); + this.addAbility(ability); + } + + public FrightshroudCourier(final FrightshroudCourier card) { + super(card); + } + + @Override + public FrightshroudCourier copy() { + return new FrightshroudCourier(this); + } +} diff --git a/Mage.Sets/src/mage/sets/onslaught/GhosthelmCourier.java b/Mage.Sets/src/mage/sets/onslaught/GhosthelmCourier.java new file mode 100644 index 00000000000..415aab1d5cf --- /dev/null +++ b/Mage.Sets/src/mage/sets/onslaught/GhosthelmCourier.java @@ -0,0 +1,92 @@ +/* + * 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.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.common.SkipUntapOptionalAbility; +import mage.abilities.condition.common.SourceTappedCondition; +import mage.abilities.costs.common.TapSourceCost; +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.decorator.ConditionalContinuousEffect; +import mage.abilities.effects.common.continuous.BoostTargetEffect; +import mage.abilities.effects.common.continuous.GainAbilityTargetEffect; +import mage.abilities.keyword.ShroudAbility; +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.mageobject.SubtypePredicate; +import mage.target.common.TargetCreaturePermanent; + +/** + * + * @author LoneFox + */ +public class GhosthelmCourier extends CardImpl { + + private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("Wizard creature"); + + static { + filter.add(new SubtypePredicate("Wizard")); + } + + public GhosthelmCourier(UUID ownerId) { + super(ownerId, 85, "Ghosthelm Courier", Rarity.UNCOMMON, new CardType[]{CardType.CREATURE}, "{2}{U}"); + this.expansionSetCode = "ONS"; + this.subtype.add("Human"); + this.subtype.add("Wizard"); + this.power = new MageInt(2); + this.toughness = new MageInt(1); + + // You may choose not to untap Ghosthelm Courier during your untap step. + this.addAbility(new SkipUntapOptionalAbility()); + // {2}{U}, {tap}: Target Wizard creature gets +2/+2 and has shroud for as long as Ghosthelm Courier remains tapped. + Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new ConditionalContinuousEffect( + new BoostTargetEffect(2, 2, Duration.Custom), SourceTappedCondition.getInstance(), + "target Wizard creature gets +2/+2"), new ManaCostsImpl("{2}{U}")); + ability.addEffect(new ConditionalContinuousEffect(new GainAbilityTargetEffect(ShroudAbility.getInstance(), + Duration.Custom), SourceTappedCondition.getInstance(),"and has shroud for as long as {this} remains tapped")); + ability.addCost(new TapSourceCost()); + ability.addTarget(new TargetCreaturePermanent(filter)); + this.addAbility(ability); + } + + public GhosthelmCourier(final GhosthelmCourier card) { + super(card); + } + + @Override + public GhosthelmCourier copy() { + return new GhosthelmCourier(this); + } +} diff --git a/Mage.Sets/src/mage/sets/onslaught/PearlspearCourier.java b/Mage.Sets/src/mage/sets/onslaught/PearlspearCourier.java new file mode 100644 index 00000000000..337976c425f --- /dev/null +++ b/Mage.Sets/src/mage/sets/onslaught/PearlspearCourier.java @@ -0,0 +1,92 @@ +/* + * 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.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.common.SkipUntapOptionalAbility; +import mage.abilities.condition.common.SourceTappedCondition; +import mage.abilities.costs.common.TapSourceCost; +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.decorator.ConditionalContinuousEffect; +import mage.abilities.effects.common.continuous.BoostTargetEffect; +import mage.abilities.effects.common.continuous.GainAbilityTargetEffect; +import mage.abilities.keyword.VigilanceAbility; +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.mageobject.SubtypePredicate; +import mage.target.common.TargetCreaturePermanent; + +/** + * + * @author LoneFox + */ +public class PearlspearCourier extends CardImpl { + + private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("Soldier creature"); + + static { + filter.add(new SubtypePredicate("Soldier")); + } + + public PearlspearCourier(UUID ownerId) { + super(ownerId, 48, "Pearlspear Courier", Rarity.UNCOMMON, new CardType[]{CardType.CREATURE}, "{2}{W}"); + this.expansionSetCode = "ONS"; + this.subtype.add("Human"); + this.subtype.add("Soldier"); + this.power = new MageInt(2); + this.toughness = new MageInt(1); + + // You may choose not to untap Pearlspear Courier during your untap step. + this.addAbility(new SkipUntapOptionalAbility()); + // {2}{W}, {tap}: Target Soldier creature gets +2/+2 and has vigilance for as long as Pearlspear Courier remains tapped. + Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new ConditionalContinuousEffect( + new BoostTargetEffect(2, 2, Duration.Custom), SourceTappedCondition.getInstance(), + "target Soldier creature gets +2/+2"), new ManaCostsImpl("{2}{W}")); + ability.addEffect(new ConditionalContinuousEffect(new GainAbilityTargetEffect(VigilanceAbility.getInstance(), + Duration.Custom), SourceTappedCondition.getInstance(),"and has vigilance for as long as {this} remains tapped")); + ability.addCost(new TapSourceCost()); + ability.addTarget(new TargetCreaturePermanent(filter)); + this.addAbility(ability); + } + + public PearlspearCourier(final PearlspearCourier card) { + super(card); + } + + @Override + public PearlspearCourier copy() { + return new PearlspearCourier(this); + } +} From 6e160d78a117d2b5075c7276fe831ae76d01f51f Mon Sep 17 00:00:00 2001 From: LoneFox Date: Tue, 27 Oct 2015 11:18:40 +0200 Subject: [PATCH 229/268] Implement cards: Gravel Slinger, Improvised Armor, Pinpoint Avalanche, and Stag Beetle --- .../mage/sets/onslaught/GravelSlinger.java | 75 ++++++++++++++++++ .../mage/sets/onslaught/ImprovisedArmor.java | 78 +++++++++++++++++++ .../sets/onslaught/PinpointAvalanche.java | 60 ++++++++++++++ .../src/mage/sets/onslaught/StagBeetle.java | 75 ++++++++++++++++++ 4 files changed, 288 insertions(+) create mode 100644 Mage.Sets/src/mage/sets/onslaught/GravelSlinger.java create mode 100644 Mage.Sets/src/mage/sets/onslaught/ImprovisedArmor.java create mode 100644 Mage.Sets/src/mage/sets/onslaught/PinpointAvalanche.java create mode 100644 Mage.Sets/src/mage/sets/onslaught/StagBeetle.java diff --git a/Mage.Sets/src/mage/sets/onslaught/GravelSlinger.java b/Mage.Sets/src/mage/sets/onslaught/GravelSlinger.java new file mode 100644 index 00000000000..23b3b50eeb0 --- /dev/null +++ b/Mage.Sets/src/mage/sets/onslaught/GravelSlinger.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.onslaught; + +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.costs.mana.ManaCostsImpl; +import mage.abilities.effects.common.DamageTargetEffect; +import mage.abilities.keyword.MorphAbility; +import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.Rarity; +import mage.constants.Zone; +import mage.filter.common.FilterAttackingOrBlockingCreature; +import mage.target.common.TargetCreaturePermanent; + +/** + * + * @author LoneFox + */ +public class GravelSlinger extends CardImpl { + + public GravelSlinger(UUID ownerId) { + super(ownerId, 33, "Gravel Slinger", Rarity.COMMON, new CardType[]{CardType.CREATURE}, "{3}{W}"); + this.expansionSetCode = "ONS"; + this.subtype.add("Human"); + this.subtype.add("Soldier"); + this.power = new MageInt(1); + this.toughness = new MageInt(3); + + // {tap}: Gravel Slinger deals 1 damage to target attacking or blocking creature. + Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new DamageTargetEffect(1), new TapSourceCost()); + ability.addTarget(new TargetCreaturePermanent(new FilterAttackingOrBlockingCreature())); + this.addAbility(ability); + // Morph {1}{W} + this.addAbility(new MorphAbility(this, new ManaCostsImpl("{1}{W}"))); + } + + public GravelSlinger(final GravelSlinger card) { + super(card); + } + + @Override + public GravelSlinger copy() { + return new GravelSlinger(this); + } +} diff --git a/Mage.Sets/src/mage/sets/onslaught/ImprovisedArmor.java b/Mage.Sets/src/mage/sets/onslaught/ImprovisedArmor.java new file mode 100644 index 00000000000..f186ac5f089 --- /dev/null +++ b/Mage.Sets/src/mage/sets/onslaught/ImprovisedArmor.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.onslaught; + +import java.util.UUID; +import mage.abilities.Ability; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.effects.common.AttachEffect; +import mage.abilities.effects.common.continuous.BoostEnchantedEffect; +import mage.abilities.keyword.CyclingAbility; +import mage.abilities.keyword.EnchantAbility; +import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.Outcome; +import mage.constants.Rarity; +import mage.constants.Zone; +import mage.target.TargetPermanent; +import mage.target.common.TargetCreaturePermanent; + +/** + * + * @author LoneFox + */ +public class ImprovisedArmor extends CardImpl { + + public ImprovisedArmor(UUID ownerId) { + super(ownerId, 40, "Improvised Armor", Rarity.UNCOMMON, new CardType[]{CardType.ENCHANTMENT}, "{3}{W}"); + this.expansionSetCode = "ONS"; + this.subtype.add("Aura"); + + // Enchant creature + TargetPermanent auraTarget = new TargetCreaturePermanent(); + this.getSpellAbility().addTarget(auraTarget); + this.getSpellAbility().addEffect(new AttachEffect(Outcome.BoostCreature)); + Ability ability = new EnchantAbility(auraTarget.getTargetName()); + this.addAbility(ability); + // Enchanted creature gets +2/+5. + this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new BoostEnchantedEffect(2, 5, Duration.WhileOnBattlefield))); + // Cycling {3} + this.addAbility(new CyclingAbility(new ManaCostsImpl("{3}"))); + } + + public ImprovisedArmor(final ImprovisedArmor card) { + super(card); + } + + @Override + public ImprovisedArmor copy() { + return new ImprovisedArmor(this); + } +} diff --git a/Mage.Sets/src/mage/sets/onslaught/PinpointAvalanche.java b/Mage.Sets/src/mage/sets/onslaught/PinpointAvalanche.java new file mode 100644 index 00000000000..e92467ae501 --- /dev/null +++ b/Mage.Sets/src/mage/sets/onslaught/PinpointAvalanche.java @@ -0,0 +1,60 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.sets.onslaught; + +import java.util.UUID; +import mage.abilities.effects.common.DamageTargetEffect; +import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.Rarity; +import mage.target.common.TargetCreaturePermanent; + +/** + * + * @author LoneFox + */ +public class PinpointAvalanche extends CardImpl { + + public PinpointAvalanche(UUID ownerId) { + super(ownerId, 221, "Pinpoint Avalanche", Rarity.COMMON, new CardType[]{CardType.INSTANT}, "{3}{R}{R}"); + this.expansionSetCode = "ONS"; + + // Pinpoint Avalanche deals 4 damage to target creature. The damage can't be prevented. + this.getSpellAbility().addEffect(new DamageTargetEffect(4, false)); + this.getSpellAbility().addTarget(new TargetCreaturePermanent()); + } + + public PinpointAvalanche(final PinpointAvalanche card) { + super(card); + } + + @Override + public PinpointAvalanche copy() { + return new PinpointAvalanche(this); + } +} diff --git a/Mage.Sets/src/mage/sets/onslaught/StagBeetle.java b/Mage.Sets/src/mage/sets/onslaught/StagBeetle.java new file mode 100644 index 00000000000..665e8a1dbb3 --- /dev/null +++ b/Mage.Sets/src/mage/sets/onslaught/StagBeetle.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.onslaught; + +import java.util.UUID; +import mage.MageInt; +import mage.abilities.common.EntersBattlefieldAbility; +import mage.abilities.dynamicvalue.common.PermanentsOnBattlefieldCount; +import mage.abilities.effects.common.counter.AddCountersSourceEffect; +import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.Rarity; +import mage.counters.CounterType; +import mage.filter.common.FilterCreaturePermanent; +import mage.filter.predicate.permanent.AnotherPredicate; + +/** + * + * @author LoneFox + */ +public class StagBeetle extends CardImpl { + + private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("other creatures"); + + static { + filter.add(new AnotherPredicate()); + } + + public StagBeetle(UUID ownerId) { + super(ownerId, 285, "Stag Beetle", Rarity.RARE, new CardType[]{CardType.CREATURE}, "{3}{G}{G}"); + this.expansionSetCode = "ONS"; + this.subtype.add("Insect"); + this.power = new MageInt(0); + this.toughness = new MageInt(0); + + // Stag Beetle enters the battlefield with X +1/+1 counters on it, where X is the number of other creatures on the battlefield. + this.addAbility(new EntersBattlefieldAbility(new AddCountersSourceEffect(CounterType.P1P1.createInstance(), + new PermanentsOnBattlefieldCount(filter), false), + "with X +1/+1 counters on it, where X is the number of other creatures on the battlefield")); + } + + public StagBeetle(final StagBeetle card) { + super(card); + } + + @Override + public StagBeetle copy() { + return new StagBeetle(this); + } +} From c2f21a85b9f255ea48bab2e470b582e672597175 Mon Sep 17 00:00:00 2001 From: LoneFox Date: Tue, 27 Oct 2015 11:38:26 +0200 Subject: [PATCH 230/268] Fix Heedless One and Reckless One to include non-creature permanents of appropriate subtype to their p/t count --- Mage.Sets/src/mage/sets/onslaught/HeedlessOne.java | 4 ++-- Mage.Sets/src/mage/sets/onslaught/RecklessOne.java | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Mage.Sets/src/mage/sets/onslaught/HeedlessOne.java b/Mage.Sets/src/mage/sets/onslaught/HeedlessOne.java index 6fd87e1ddd7..d275b1ca5f3 100644 --- a/Mage.Sets/src/mage/sets/onslaught/HeedlessOne.java +++ b/Mage.Sets/src/mage/sets/onslaught/HeedlessOne.java @@ -38,7 +38,7 @@ import mage.constants.CardType; import mage.constants.Duration; import mage.constants.Rarity; import mage.constants.Zone; -import mage.filter.common.FilterCreaturePermanent; +import mage.filter.FilterPermanent; import mage.filter.predicate.mageobject.SubtypePredicate; /** @@ -47,7 +47,7 @@ import mage.filter.predicate.mageobject.SubtypePredicate; */ public class HeedlessOne extends CardImpl { - private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("Elves on the battlefield"); + private static final FilterPermanent filter = new FilterPermanent("Elves on the battlefield"); static { filter.add(new SubtypePredicate("Elf")); diff --git a/Mage.Sets/src/mage/sets/onslaught/RecklessOne.java b/Mage.Sets/src/mage/sets/onslaught/RecklessOne.java index c79f35586ee..a6808042b8f 100644 --- a/Mage.Sets/src/mage/sets/onslaught/RecklessOne.java +++ b/Mage.Sets/src/mage/sets/onslaught/RecklessOne.java @@ -38,7 +38,7 @@ import mage.constants.CardType; import mage.constants.Duration; import mage.constants.Rarity; import mage.constants.Zone; -import mage.filter.common.FilterCreaturePermanent; +import mage.filter.FilterPermanent; import mage.filter.predicate.mageobject.SubtypePredicate; /** @@ -47,7 +47,7 @@ import mage.filter.predicate.mageobject.SubtypePredicate; */ public class RecklessOne extends CardImpl { - private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("Goblins on the battlefield"); + private static final FilterPermanent filter = new FilterPermanent("Goblins on the battlefield"); static { filter.add(new SubtypePredicate("Goblin")); From ad8074a65075fe4b1cbc7cd855a3daed27f3da7b Mon Sep 17 00:00:00 2001 From: LoneFox Date: Tue, 27 Oct 2015 12:08:50 +0200 Subject: [PATCH 231/268] Implement cards: Aphetto Grifter, Aven Fateshaper, Information Dealer, and Nameless One --- .../mage/sets/onslaught/AphettoGrifter.java | 83 +++++++++++++++++++ .../mage/sets/onslaught/AvenFateshaper.java | 72 ++++++++++++++++ .../sets/onslaught/InformationDealer.java | 78 +++++++++++++++++ .../src/mage/sets/onslaught/NamelessOne.java | 79 ++++++++++++++++++ 4 files changed, 312 insertions(+) create mode 100644 Mage.Sets/src/mage/sets/onslaught/AphettoGrifter.java create mode 100644 Mage.Sets/src/mage/sets/onslaught/AvenFateshaper.java create mode 100644 Mage.Sets/src/mage/sets/onslaught/InformationDealer.java create mode 100644 Mage.Sets/src/mage/sets/onslaught/NamelessOne.java diff --git a/Mage.Sets/src/mage/sets/onslaught/AphettoGrifter.java b/Mage.Sets/src/mage/sets/onslaught/AphettoGrifter.java new file mode 100644 index 00000000000..8c5ffc0495c --- /dev/null +++ b/Mage.Sets/src/mage/sets/onslaught/AphettoGrifter.java @@ -0,0 +1,83 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.sets.onslaught; + +import java.util.UUID; +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.costs.common.TapTargetCost; +import mage.abilities.effects.common.TapTargetEffect; +import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.Rarity; +import mage.constants.Zone; +import mage.filter.common.FilterControlledPermanent; +import mage.filter.predicate.Predicates; +import mage.filter.predicate.mageobject.SubtypePredicate; +import mage.filter.predicate.permanent.TappedPredicate; +import mage.target.TargetPermanent; +import mage.target.common.TargetControlledPermanent; +import mage.target.common.TargetCreaturePermanent; + +/** + * + * @author LoneFox + */ +public class AphettoGrifter extends CardImpl { + + private static final FilterControlledPermanent filter = new FilterControlledPermanent("untapped Wizards you control"); + + static { + filter.add(Predicates.not(new TappedPredicate())); + filter.add(new SubtypePredicate("Wizard")); + } + + public AphettoGrifter(UUID ownerId) { + super(ownerId, 65, "Aphetto Grifter", Rarity.UNCOMMON, new CardType[]{CardType.CREATURE}, "{2}{U}"); + this.expansionSetCode = "ONS"; + this.subtype.add("Human"); + this.subtype.add("Wizard"); + this.power = new MageInt(1); + this.toughness = new MageInt(1); + + // Tap two untapped Wizards you control: Tap target permanent. + Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new TapTargetEffect(), new TapTargetCost(new TargetControlledPermanent(2, 2, filter, false))); + ability.addTarget(new TargetPermanent()); + this.addAbility(ability); + } + + public AphettoGrifter(final AphettoGrifter card) { + super(card); + } + + @Override + public AphettoGrifter copy() { + return new AphettoGrifter(this); + } +} diff --git a/Mage.Sets/src/mage/sets/onslaught/AvenFateshaper.java b/Mage.Sets/src/mage/sets/onslaught/AvenFateshaper.java new file mode 100644 index 00000000000..38118afecae --- /dev/null +++ b/Mage.Sets/src/mage/sets/onslaught/AvenFateshaper.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.MageInt; +import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.effects.common.LookLibraryControllerEffect; +import mage.abilities.keyword.FlyingAbility; +import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.Rarity; +import mage.constants.Zone; + +/** + * + * @author LoneFox + */ +public class AvenFateshaper extends CardImpl { + + public AvenFateshaper(UUID ownerId) { + super(ownerId, 69, "Aven Fateshaper", Rarity.UNCOMMON, new CardType[]{CardType.CREATURE}, "{6}{U}"); + this.expansionSetCode = "ONS"; + this.subtype.add("Bird"); + this.subtype.add("Wizard"); + this.power = new MageInt(4); + this.toughness = new MageInt(5); + + // Flying + this.addAbility(FlyingAbility.getInstance()); + // When Aven Fateshaper 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))); + // {4}{U}: Look at the top four cards of your library, then put them back in any order. + this.addAbility(new SimpleActivatedAbility(Zone.BATTLEFIELD, new LookLibraryControllerEffect(4), new ManaCostsImpl("{4}{U}"))); + } + + public AvenFateshaper(final AvenFateshaper card) { + super(card); + } + + @Override + public AvenFateshaper copy() { + return new AvenFateshaper(this); + } +} diff --git a/Mage.Sets/src/mage/sets/onslaught/InformationDealer.java b/Mage.Sets/src/mage/sets/onslaught/InformationDealer.java new file mode 100644 index 00000000000..e9cb8b80e36 --- /dev/null +++ b/Mage.Sets/src/mage/sets/onslaught/InformationDealer.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.onslaught; + +import java.util.UUID; +import mage.MageInt; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.costs.common.TapSourceCost; +import mage.abilities.dynamicvalue.common.PermanentsOnBattlefieldCount; +import mage.abilities.effects.Effect; +import mage.abilities.effects.common.LookLibraryControllerEffect; +import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.Rarity; +import mage.constants.Zone; +import mage.filter.FilterPermanent; +import mage.filter.predicate.mageobject.SubtypePredicate; + +/** + * + * @author LoneFox + */ +public class InformationDealer extends CardImpl { + + private static final FilterPermanent filter = new FilterPermanent("Wizards on the battlefield"); + + static { + filter.add(new SubtypePredicate("Wizard")); + } + + public InformationDealer(UUID ownerId) { + super(ownerId, 88, "Information Dealer", Rarity.COMMON, new CardType[]{CardType.CREATURE}, "{1}{U}"); + this.expansionSetCode = "ONS"; + this.subtype.add("Human"); + this.subtype.add("Wizard"); + this.power = new MageInt(1); + this.toughness = new MageInt(1); + + // {tap}: Look at the top X cards of your library, where X is the number of Wizards on the battlefield, then put them back in any order. + Effect effect = new LookLibraryControllerEffect(new PermanentsOnBattlefieldCount(filter)); + effect.setText("Look at the top X cards of your library, where X is the number of Wizards on the battlefield, then put them back in any order."); + this.addAbility(new SimpleActivatedAbility(Zone.BATTLEFIELD, effect, new TapSourceCost())); + } + + public InformationDealer(final InformationDealer card) { + super(card); + } + + @Override + public InformationDealer copy() { + return new InformationDealer(this); + } +} diff --git a/Mage.Sets/src/mage/sets/onslaught/NamelessOne.java b/Mage.Sets/src/mage/sets/onslaught/NamelessOne.java new file mode 100644 index 00000000000..76e6b6cc06e --- /dev/null +++ b/Mage.Sets/src/mage/sets/onslaught/NamelessOne.java @@ -0,0 +1,79 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.sets.onslaught; + +import java.util.UUID; +import mage.MageInt; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.dynamicvalue.common.PermanentsOnBattlefieldCount; +import mage.abilities.effects.common.continuous.SetPowerToughnessSourceEffect; +import mage.abilities.keyword.MorphAbility; +import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.Rarity; +import mage.constants.Zone; +import mage.filter.FilterPermanent; +import mage.filter.predicate.mageobject.SubtypePredicate; + +/** + * + * @author LoneFox + */ +public class NamelessOne extends CardImpl { + + private static final FilterPermanent filter = new FilterPermanent("Wizards on the battlefield"); + + static { + filter.add(new SubtypePredicate("Wizard")); + } + + public NamelessOne(UUID ownerId) { + super(ownerId, 100, "Nameless One", Rarity.UNCOMMON, new CardType[]{CardType.CREATURE}, "{3}{U}"); + this.expansionSetCode = "ONS"; + this.subtype.add("Wizard"); + this.subtype.add("Avatar"); + this.power = new MageInt(0); + this.toughness = new MageInt(0); + + // Nameless One's power and toughness are each equal to the number of Wizards on the battlefield. + this.addAbility(new SimpleStaticAbility(Zone.ALL, new SetPowerToughnessSourceEffect(new PermanentsOnBattlefieldCount(filter), Duration.EndOfGame))); + // Morph {2}{U} + this.addAbility(new MorphAbility(this, new ManaCostsImpl("{2}{U}"))); + } + + public NamelessOne(final NamelessOne card) { + super(card); + } + + @Override + public NamelessOne copy() { + return new NamelessOne(this); + } +} From 3562047beb24a79fe4d0674453eff1c8f213684a Mon Sep 17 00:00:00 2001 From: LoneFox Date: Tue, 27 Oct 2015 13:26:18 +0200 Subject: [PATCH 232/268] Fix some cards that care about subtypes to include non-creature cards of the subtype --- .../mage/sets/onslaught/BrightstoneRitual.java | 10 +++++++++- .../src/mage/sets/onslaught/CabalArchon.java | 17 ++++++++++------- .../src/mage/sets/onslaught/FeedingFrenzy.java | 16 ++++++++++++---- .../mage/sets/onslaught/RiptideLaboratory.java | 13 +++++++------ .../mage/sets/onslaught/VoiceOfTheWoods.java | 10 +++++----- .../src/mage/sets/onslaught/Wellwisher.java | 4 ++-- .../src/mage/sets/onslaught/WirewoodHerald.java | 4 ++-- .../src/mage/sets/onslaught/WirewoodLodge.java | 13 +++++++------ .../src/mage/sets/onslaught/WirewoodSavage.java | 4 ++-- 9 files changed, 56 insertions(+), 35 deletions(-) diff --git a/Mage.Sets/src/mage/sets/onslaught/BrightstoneRitual.java b/Mage.Sets/src/mage/sets/onslaught/BrightstoneRitual.java index 896507e5b5f..5ed1e6e4089 100644 --- a/Mage.Sets/src/mage/sets/onslaught/BrightstoneRitual.java +++ b/Mage.Sets/src/mage/sets/onslaught/BrightstoneRitual.java @@ -34,7 +34,9 @@ import mage.abilities.effects.common.DynamicManaEffect; import mage.cards.CardImpl; import mage.constants.CardType; import mage.constants.Rarity; +import mage.filter.FilterPermanent; import mage.filter.common.FilterCreaturePermanent; +import mage.filter.predicate.mageobject.SubtypePredicate; /** * @@ -42,12 +44,18 @@ import mage.filter.common.FilterCreaturePermanent; */ public class BrightstoneRitual extends CardImpl { + private static final FilterPermanent filter = new FilterPermanent("Goblin on the battlefield"); + + static { + filter.add(new SubtypePredicate("Goblin")); + } + public BrightstoneRitual(UUID ownerId) { super(ownerId, 191, "Brightstone Ritual", Rarity.COMMON, new CardType[]{CardType.INSTANT}, "{R}"); this.expansionSetCode = "ONS"; // Add {R} to your mana pool for each Goblin on the battlefield. - this.getSpellAbility().addEffect(new DynamicManaEffect(Mana.RedMana, new PermanentsOnBattlefieldCount(new FilterCreaturePermanent("Goblin","Goblin on the battlefield")))); + this.getSpellAbility().addEffect(new DynamicManaEffect(Mana.RedMana, new PermanentsOnBattlefieldCount(filter))); } public BrightstoneRitual(final BrightstoneRitual card) { diff --git a/Mage.Sets/src/mage/sets/onslaught/CabalArchon.java b/Mage.Sets/src/mage/sets/onslaught/CabalArchon.java index e67cd3fa843..9f666a50fe0 100644 --- a/Mage.Sets/src/mage/sets/onslaught/CabalArchon.java +++ b/Mage.Sets/src/mage/sets/onslaught/CabalArchon.java @@ -33,25 +33,26 @@ import mage.abilities.Ability; import mage.abilities.common.SimpleActivatedAbility; import mage.abilities.costs.common.SacrificeTargetCost; import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.effects.Effect; import mage.abilities.effects.common.GainLifeEffect; import mage.abilities.effects.common.LoseLifeTargetEffect; import mage.cards.CardImpl; import mage.constants.CardType; import mage.constants.Rarity; import mage.constants.Zone; -import mage.filter.common.FilterControlledCreaturePermanent; +import mage.filter.common.FilterControlledPermanent; import mage.filter.predicate.mageobject.SubtypePredicate; import mage.target.TargetPlayer; -import mage.target.common.TargetControlledCreaturePermanent; +import mage.target.common.TargetControlledPermanent; /** * * @author fireshoes */ public class CabalArchon extends CardImpl { - - private static final FilterControlledCreaturePermanent filter = new FilterControlledCreaturePermanent("Cleric"); - + + private static final FilterControlledPermanent filter = new FilterControlledPermanent("a Cleric"); + static { filter.add(new SubtypePredicate("Cleric")); } @@ -66,8 +67,10 @@ public class CabalArchon extends CardImpl { // {B}, Sacrifice a Cleric: Target player loses 2 life and you gain 2 life. Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new LoseLifeTargetEffect(2), new ManaCostsImpl("{B}")); - ability.addEffect(new GainLifeEffect(2)); - ability.addCost(new SacrificeTargetCost(new TargetControlledCreaturePermanent(1, 1, filter, false))); + Effect effect = new GainLifeEffect(2); + effect.setText("and you gain 2 life"); + ability.addEffect(effect); + ability.addCost(new SacrificeTargetCost(new TargetControlledPermanent(1, 1, filter, false))); ability.addTarget(new TargetPlayer()); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/sets/onslaught/FeedingFrenzy.java b/Mage.Sets/src/mage/sets/onslaught/FeedingFrenzy.java index ff57cf267b9..55d168c3091 100644 --- a/Mage.Sets/src/mage/sets/onslaught/FeedingFrenzy.java +++ b/Mage.Sets/src/mage/sets/onslaught/FeedingFrenzy.java @@ -28,20 +28,20 @@ package mage.sets.onslaught; import java.util.UUID; - import mage.abilities.dynamicvalue.DynamicValue; import mage.abilities.dynamicvalue.common.CountersCount; import mage.abilities.dynamicvalue.common.ManacostVariableValue; import mage.abilities.dynamicvalue.common.PermanentsOnBattlefieldCount; import mage.abilities.dynamicvalue.common.SignInversionDynamicValue; +import mage.abilities.effects.Effect; 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.counters.CounterType; +import mage.filter.FilterPermanent; import mage.filter.common.FilterControlledPermanent; -import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.mageobject.SubtypePredicate; import mage.target.common.TargetCreaturePermanent; @@ -51,13 +51,21 @@ import mage.target.common.TargetCreaturePermanent; */ public class FeedingFrenzy extends CardImpl { + private static final FilterPermanent filter = new FilterPermanent(); + + static { + filter.add(new SubtypePredicate("Zombie")); + } + public FeedingFrenzy(UUID ownerId) { super(ownerId, 147, "Feeding Frenzy", Rarity.UNCOMMON, new CardType[]{CardType.INSTANT}, "{2}{B}"); this.expansionSetCode = "ONS"; // Target creature gets -X/-X until end of turn, where X is the number of Zombies on the battlefield. - DynamicValue x = new PermanentsOnBattlefieldCount(new FilterCreaturePermanent("Zombie", "Zombie on the battlefield"), -1); - this.getSpellAbility().addEffect(new BoostTargetEffect(x, x, Duration.EndOfTurn)); + DynamicValue x = new PermanentsOnBattlefieldCount(filter, -1); + Effect effect = new BoostTargetEffect(x, x, Duration.EndOfTurn); + effect.setText("Target creature gets -X/-X until end of turn, where X is the number of Zombies on the battlefield"); + this.getSpellAbility().addEffect(effect); this.getSpellAbility().addTarget(new TargetCreaturePermanent()); } diff --git a/Mage.Sets/src/mage/sets/onslaught/RiptideLaboratory.java b/Mage.Sets/src/mage/sets/onslaught/RiptideLaboratory.java index 06b74c0ec8d..808150e100c 100644 --- a/Mage.Sets/src/mage/sets/onslaught/RiptideLaboratory.java +++ b/Mage.Sets/src/mage/sets/onslaught/RiptideLaboratory.java @@ -38,17 +38,18 @@ import mage.cards.CardImpl; import mage.constants.CardType; import mage.constants.Rarity; import mage.constants.Zone; -import mage.filter.common.FilterControlledCreaturePermanent; +import mage.filter.common.FilterControlledPermanent; import mage.filter.predicate.mageobject.SubtypePredicate; -import mage.target.common.TargetControlledCreaturePermanent; +import mage.target.common.TargetControlledPermanent; /** * * @author emerald000 */ public class RiptideLaboratory extends CardImpl { - - private final static FilterControlledCreaturePermanent filter = new FilterControlledCreaturePermanent("Wizard"); + + private final static FilterControlledPermanent filter = new FilterControlledPermanent("Wizard you control"); + static { filter.add(new SubtypePredicate("Wizard")); } @@ -59,11 +60,11 @@ public class RiptideLaboratory extends CardImpl { // {tap}: Add {1} to your mana pool. this.addAbility(new ColorlessManaAbility()); - + // {1}{U}, {tap}: Return target Wizard you control to its owner's hand. Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new ReturnToHandTargetEffect(), new ManaCostsImpl("{1}{U}")); ability.addCost(new TapSourceCost()); - ability.addTarget(new TargetControlledCreaturePermanent(filter)); + ability.addTarget(new TargetControlledPermanent(filter)); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/sets/onslaught/VoiceOfTheWoods.java b/Mage.Sets/src/mage/sets/onslaught/VoiceOfTheWoods.java index b10c2dfa800..5395bdf8339 100644 --- a/Mage.Sets/src/mage/sets/onslaught/VoiceOfTheWoods.java +++ b/Mage.Sets/src/mage/sets/onslaught/VoiceOfTheWoods.java @@ -38,12 +38,12 @@ import mage.cards.CardImpl; import mage.constants.CardType; import mage.constants.Rarity; import mage.constants.Zone; -import mage.filter.common.FilterControlledCreaturePermanent; +import mage.filter.common.FilterControlledPermanent; import mage.filter.predicate.Predicates; import mage.filter.predicate.mageobject.SubtypePredicate; import mage.filter.predicate.permanent.TappedPredicate; import mage.game.permanent.token.Token; -import mage.target.common.TargetControlledCreaturePermanent; +import mage.target.common.TargetControlledPermanent; /** * @@ -51,7 +51,7 @@ import mage.target.common.TargetControlledCreaturePermanent; */ public class VoiceOfTheWoods extends CardImpl { - private static final FilterControlledCreaturePermanent filter = new FilterControlledCreaturePermanent("untapped Elves you control"); + private static final FilterControlledPermanent filter = new FilterControlledPermanent("untapped Elves you control"); static { filter.add(Predicates.not(new TappedPredicate())); @@ -69,7 +69,7 @@ public class VoiceOfTheWoods extends CardImpl { // Tap five untapped Elves you control: Put a 7/7 green Elemental creature token with trample onto the battlefield. Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new CreateTokenEffect(new VoiceOfTheWoodsElementalToken()), - new TapTargetCost(new TargetControlledCreaturePermanent(5,5, filter, false))); + new TapTargetCost(new TargetControlledPermanent(5,5, filter, false))); this.addAbility(ability); } @@ -97,4 +97,4 @@ class VoiceOfTheWoodsElementalToken extends Token { addAbility(TrampleAbility.getInstance()); } -} \ No newline at end of file +} diff --git a/Mage.Sets/src/mage/sets/onslaught/Wellwisher.java b/Mage.Sets/src/mage/sets/onslaught/Wellwisher.java index 43851a1fd76..eb80dcfae3e 100644 --- a/Mage.Sets/src/mage/sets/onslaught/Wellwisher.java +++ b/Mage.Sets/src/mage/sets/onslaught/Wellwisher.java @@ -37,7 +37,7 @@ import mage.cards.CardImpl; import mage.constants.CardType; import mage.constants.Rarity; import mage.constants.Zone; -import mage.filter.common.FilterCreaturePermanent; +import mage.filter.FilterPermanent; import mage.filter.predicate.mageobject.SubtypePredicate; /** @@ -46,7 +46,7 @@ import mage.filter.predicate.mageobject.SubtypePredicate; */ public class Wellwisher extends CardImpl { - private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("Elf on the battlefield"); + private static final FilterPermanent filter = new FilterPermanent("Elf on the battlefield"); static { filter.add(new SubtypePredicate("Elf")); diff --git a/Mage.Sets/src/mage/sets/onslaught/WirewoodHerald.java b/Mage.Sets/src/mage/sets/onslaught/WirewoodHerald.java index 209057bb5e8..1db70103973 100644 --- a/Mage.Sets/src/mage/sets/onslaught/WirewoodHerald.java +++ b/Mage.Sets/src/mage/sets/onslaught/WirewoodHerald.java @@ -34,7 +34,7 @@ import mage.abilities.effects.common.search.SearchLibraryPutInHandEffect; import mage.cards.CardImpl; import mage.constants.CardType; import mage.constants.Rarity; -import mage.filter.common.FilterCreatureCard; +import mage.filter.FilterCard; import mage.filter.predicate.mageobject.SubtypePredicate; import mage.target.common.TargetCardInLibrary; @@ -44,7 +44,7 @@ import mage.target.common.TargetCardInLibrary; */ public class WirewoodHerald extends CardImpl { - private static final FilterCreatureCard filter = new FilterCreatureCard("Elf card"); + private static final FilterCard filter = new FilterCard("Elf card"); static { filter.add(new SubtypePredicate("Elf")); diff --git a/Mage.Sets/src/mage/sets/onslaught/WirewoodLodge.java b/Mage.Sets/src/mage/sets/onslaught/WirewoodLodge.java index be1dc8700a9..594d11f12bf 100644 --- a/Mage.Sets/src/mage/sets/onslaught/WirewoodLodge.java +++ b/Mage.Sets/src/mage/sets/onslaught/WirewoodLodge.java @@ -38,9 +38,9 @@ import mage.cards.CardImpl; import mage.constants.CardType; import mage.constants.Rarity; import mage.constants.Zone; -import mage.filter.common.FilterCreaturePermanent; +import mage.filter.FilterPermanent; import mage.filter.predicate.mageobject.SubtypePredicate; -import mage.target.common.TargetCreaturePermanent; +import mage.target.TargetPermanent; /** * @@ -48,7 +48,8 @@ import mage.target.common.TargetCreaturePermanent; */ public class WirewoodLodge extends CardImpl { - private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("Elf"); + private static final FilterPermanent filter = new FilterPermanent("Elf"); + static { filter.add(new SubtypePredicate("Elf")); } @@ -56,14 +57,14 @@ public class WirewoodLodge extends CardImpl { public WirewoodLodge(UUID ownerId) { super(ownerId, 329, "Wirewood Lodge", Rarity.RARE, new CardType[]{CardType.LAND}, ""); this.expansionSetCode = "ONS"; - + // {T}: Add {1} to your mana pool. this.addAbility(new ColorlessManaAbility()); - + // {G}, {T}: Untap target Elf. Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new UntapTargetEffect(), new ManaCostsImpl("{G}")); ability.addCost(new TapSourceCost()); - ability.addTarget(new TargetCreaturePermanent(filter)); + ability.addTarget(new TargetPermanent(filter)); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/sets/onslaught/WirewoodSavage.java b/Mage.Sets/src/mage/sets/onslaught/WirewoodSavage.java index e6935282b58..1f91cb2fb19 100644 --- a/Mage.Sets/src/mage/sets/onslaught/WirewoodSavage.java +++ b/Mage.Sets/src/mage/sets/onslaught/WirewoodSavage.java @@ -35,7 +35,7 @@ import mage.cards.CardImpl; import mage.constants.CardType; import mage.constants.Rarity; import mage.constants.Zone; -import mage.filter.common.FilterCreaturePermanent; +import mage.filter.FilterPermanent; import mage.filter.predicate.mageobject.SubtypePredicate; /** @@ -44,7 +44,7 @@ import mage.filter.predicate.mageobject.SubtypePredicate; */ public class WirewoodSavage extends CardImpl { - private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("a Beast"); + private static final FilterPermanent filter = new FilterPermanent("a Beast"); static { filter.add(new SubtypePredicate("Beast")); From 08ea70e359d6d380ac5b2cabcd8afb64b3cb05c3 Mon Sep 17 00:00:00 2001 From: LoneFox Date: Tue, 27 Oct 2015 13:26:53 +0200 Subject: [PATCH 233/268] Text fixes --- Mage.Sets/src/mage/sets/onslaught/CabalSlaver.java | 2 +- Mage.Sets/src/mage/sets/onslaught/GoblinTaskmaster.java | 6 +++--- Mage.Sets/src/mage/sets/onslaught/SeasideHaven.java | 2 +- Mage.Sets/src/mage/sets/onslaught/Standardize.java | 6 ++---- 4 files changed, 7 insertions(+), 9 deletions(-) diff --git a/Mage.Sets/src/mage/sets/onslaught/CabalSlaver.java b/Mage.Sets/src/mage/sets/onslaught/CabalSlaver.java index 93c38299370..e05a2c5ec57 100644 --- a/Mage.Sets/src/mage/sets/onslaught/CabalSlaver.java +++ b/Mage.Sets/src/mage/sets/onslaught/CabalSlaver.java @@ -44,7 +44,7 @@ import mage.filter.predicate.mageobject.SubtypePredicate; */ public class CabalSlaver extends CardImpl { - private static final FilterPermanent filter = new FilterPermanent("Goblin"); + private static final FilterPermanent filter = new FilterPermanent("a Goblin"); static { filter.add(new SubtypePredicate("Goblin")); diff --git a/Mage.Sets/src/mage/sets/onslaught/GoblinTaskmaster.java b/Mage.Sets/src/mage/sets/onslaught/GoblinTaskmaster.java index 9d27c1aa72f..e6fe04dc554 100644 --- a/Mage.Sets/src/mage/sets/onslaught/GoblinTaskmaster.java +++ b/Mage.Sets/src/mage/sets/onslaught/GoblinTaskmaster.java @@ -48,8 +48,8 @@ import mage.target.common.TargetCreaturePermanent; * @author fireshoes */ public class GoblinTaskmaster 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")); @@ -66,7 +66,7 @@ public class GoblinTaskmaster extends CardImpl { Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new BoostTargetEffect(1, 0, Duration.EndOfTurn), new ManaCostsImpl("{1}{R}")); ability.addTarget(new TargetCreaturePermanent(filter)); this.addAbility(ability); - + // Morph {R} this.addAbility(new MorphAbility(this, new ManaCostsImpl("{R}"))); } diff --git a/Mage.Sets/src/mage/sets/onslaught/SeasideHaven.java b/Mage.Sets/src/mage/sets/onslaught/SeasideHaven.java index eaccc8185cf..ab893d66547 100644 --- a/Mage.Sets/src/mage/sets/onslaught/SeasideHaven.java +++ b/Mage.Sets/src/mage/sets/onslaught/SeasideHaven.java @@ -49,7 +49,7 @@ import mage.target.common.TargetControlledPermanent; */ public class SeasideHaven extends CardImpl { - private static final FilterControlledPermanent filter = new FilterControlledPermanent("Bird"); + private static final FilterControlledPermanent filter = new FilterControlledPermanent("a Bird"); static{ filter.add(new SubtypePredicate("Bird")); diff --git a/Mage.Sets/src/mage/sets/onslaught/Standardize.java b/Mage.Sets/src/mage/sets/onslaught/Standardize.java index c2c6f8624d0..07ffd013875 100644 --- a/Mage.Sets/src/mage/sets/onslaught/Standardize.java +++ b/Mage.Sets/src/mage/sets/onslaught/Standardize.java @@ -29,7 +29,6 @@ package mage.sets.onslaught; import java.util.Set; import java.util.UUID; - import mage.abilities.Ability; import mage.abilities.effects.ContinuousEffect; import mage.abilities.effects.Effect; @@ -58,7 +57,6 @@ public class Standardize extends CardImpl { this.expansionSetCode = "ONS"; // Choose a creature type other than Wall. Each creature becomes that type until end of turn. - this.getSpellAbility().addEffect(new StandardizeEffect()); } @@ -78,7 +76,7 @@ class StandardizeEffect extends OneShotEffect { public StandardizeEffect() { super(Outcome.BoostCreature); - staticText = "choose a creature type other than wall, each creature's type becomes that type until end of turn"; + staticText = "choose a creature type other than Wall. Each creature becomes that type until end of turn"; } @@ -93,7 +91,7 @@ class StandardizeEffect extends OneShotEffect { String chosenType = ""; if (player != null && permanent != null) { Choice typeChoice = new ChoiceImpl(true); - typeChoice.setMessage("Choose creature type other than Wall"); + typeChoice.setMessage("Choose a creature type other than Wall"); Set types = CardRepository.instance.getCreatureTypes(); types.remove("Wall"); typeChoice.setChoices(types); From 9e8fab1068d0578d5e1143e40779ea4574e7e846 Mon Sep 17 00:00:00 2001 From: LevelX2 Date: Tue, 27 Oct 2015 15:16:30 +0100 Subject: [PATCH 234/268] * Fixed some dual lands from Scars of Mirrordin that did not come tapped into play with already 3 other controlled lands in play (Seachrome Coast, Blackleave Cliffs, Copperline Gorge). --- .../sets/scarsofmirrodin/BlackcleaveCliffs.java | 13 ++++++------- .../sets/scarsofmirrodin/CopperlineGorge.java | 13 ++++++------- .../sets/scarsofmirrodin/RazorvergeThicket.java | 12 ++++++------ .../sets/scarsofmirrodin/SeachromeCoast.java | 16 +++++++++------- 4 files changed, 27 insertions(+), 27 deletions(-) diff --git a/Mage.Sets/src/mage/sets/scarsofmirrodin/BlackcleaveCliffs.java b/Mage.Sets/src/mage/sets/scarsofmirrodin/BlackcleaveCliffs.java index 33beef31b35..c18638982bd 100644 --- a/Mage.Sets/src/mage/sets/scarsofmirrodin/BlackcleaveCliffs.java +++ b/Mage.Sets/src/mage/sets/scarsofmirrodin/BlackcleaveCliffs.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.scarsofmirrodin; import java.util.UUID; -import mage.constants.CardType; -import mage.constants.Rarity; import mage.abilities.common.EntersBattlefieldAbility; import mage.abilities.condition.Condition; -import mage.abilities.condition.common.PermanentsOnTheBattlefieldCondition; import mage.abilities.condition.InvertCondition; +import mage.abilities.condition.common.PermanentsOnTheBattlefieldCondition; import mage.abilities.decorator.ConditionalOneShotEffect; import mage.abilities.effects.common.TapSourceEffect; import mage.abilities.mana.BlackManaAbility; import mage.abilities.mana.RedManaAbility; import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.Rarity; import mage.filter.common.FilterLandPermanent; /** @@ -50,18 +49,18 @@ public class BlackcleaveCliffs extends CardImpl { private static final FilterLandPermanent filter = new FilterLandPermanent(); - public BlackcleaveCliffs (UUID ownerId) { + public BlackcleaveCliffs(UUID ownerId) { super(ownerId, 224, "Blackcleave Cliffs", Rarity.RARE, new CardType[]{CardType.LAND}, null); this.expansionSetCode = "SOM"; - Condition controls = new InvertCondition(new PermanentsOnTheBattlefieldCondition(filter, PermanentsOnTheBattlefieldCondition.CountType.FEWER_THAN, 4)); + Condition controls = new InvertCondition(new PermanentsOnTheBattlefieldCondition(filter, PermanentsOnTheBattlefieldCondition.CountType.FEWER_THAN, 3)); String abilityText = "tapped unless you control fewer than 3 lands"; this.addAbility(new EntersBattlefieldAbility(new ConditionalOneShotEffect(new TapSourceEffect(), controls, abilityText), abilityText)); this.addAbility(new BlackManaAbility()); this.addAbility(new RedManaAbility()); } - public BlackcleaveCliffs (final BlackcleaveCliffs card) { + public BlackcleaveCliffs(final BlackcleaveCliffs card) { super(card); } diff --git a/Mage.Sets/src/mage/sets/scarsofmirrodin/CopperlineGorge.java b/Mage.Sets/src/mage/sets/scarsofmirrodin/CopperlineGorge.java index 7a0f5ed0907..6c5a7eb2f84 100644 --- a/Mage.Sets/src/mage/sets/scarsofmirrodin/CopperlineGorge.java +++ b/Mage.Sets/src/mage/sets/scarsofmirrodin/CopperlineGorge.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.scarsofmirrodin; import java.util.UUID; -import mage.constants.CardType; -import mage.constants.Rarity; import mage.abilities.common.EntersBattlefieldAbility; import mage.abilities.condition.Condition; -import mage.abilities.condition.common.PermanentsOnTheBattlefieldCondition; import mage.abilities.condition.InvertCondition; +import mage.abilities.condition.common.PermanentsOnTheBattlefieldCondition; import mage.abilities.decorator.ConditionalOneShotEffect; import mage.abilities.effects.common.TapSourceEffect; import mage.abilities.mana.GreenManaAbility; import mage.abilities.mana.RedManaAbility; import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.Rarity; import mage.filter.common.FilterLandPermanent; /** @@ -50,19 +49,19 @@ public class CopperlineGorge extends CardImpl { private static FilterLandPermanent filter = new FilterLandPermanent(); - public CopperlineGorge (UUID ownerId) { + public CopperlineGorge(UUID ownerId) { super(ownerId, 225, "Copperline Gorge", Rarity.RARE, new CardType[]{CardType.LAND}, null); this.expansionSetCode = "SOM"; // Copperline Gorge enters the battlefield tapped unless you control two or fewer other lands. - Condition controls = new InvertCondition(new PermanentsOnTheBattlefieldCondition(filter, PermanentsOnTheBattlefieldCondition.CountType.FEWER_THAN, 4)); + Condition controls = new InvertCondition(new PermanentsOnTheBattlefieldCondition(filter, PermanentsOnTheBattlefieldCondition.CountType.FEWER_THAN, 3)); String abilityText = "tapped unless you control two or fewer other lands"; this.addAbility(new EntersBattlefieldAbility(new ConditionalOneShotEffect(new TapSourceEffect(), controls, abilityText), abilityText)); this.addAbility(new RedManaAbility()); this.addAbility(new GreenManaAbility()); } - public CopperlineGorge (final CopperlineGorge card) { + public CopperlineGorge(final CopperlineGorge card) { super(card); } diff --git a/Mage.Sets/src/mage/sets/scarsofmirrodin/RazorvergeThicket.java b/Mage.Sets/src/mage/sets/scarsofmirrodin/RazorvergeThicket.java index dc1ac788117..0cf9a06debf 100644 --- a/Mage.Sets/src/mage/sets/scarsofmirrodin/RazorvergeThicket.java +++ b/Mage.Sets/src/mage/sets/scarsofmirrodin/RazorvergeThicket.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.scarsofmirrodin; import java.util.UUID; -import mage.constants.CardType; -import mage.constants.Rarity; import mage.abilities.common.EntersBattlefieldAbility; import mage.abilities.condition.Condition; -import mage.abilities.condition.common.PermanentsOnTheBattlefieldCondition; import mage.abilities.condition.InvertCondition; +import mage.abilities.condition.common.PermanentsOnTheBattlefieldCondition; import mage.abilities.decorator.ConditionalOneShotEffect; import mage.abilities.effects.common.TapSourceEffect; import mage.abilities.mana.GreenManaAbility; import mage.abilities.mana.WhiteManaAbility; import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.Rarity; import mage.filter.common.FilterLandPermanent; /** @@ -50,18 +49,19 @@ public class RazorvergeThicket extends CardImpl { private static FilterLandPermanent filter = new FilterLandPermanent(); - public RazorvergeThicket (UUID ownerId) { + public RazorvergeThicket(UUID ownerId) { super(ownerId, 228, "Razorverge Thicket", Rarity.RARE, new CardType[]{CardType.LAND}, null); this.expansionSetCode = "SOM"; Condition controls = new InvertCondition(new PermanentsOnTheBattlefieldCondition(filter, PermanentsOnTheBattlefieldCondition.CountType.FEWER_THAN, 3)); String abilityText = "tap it unless you control fewer than 3 lands"; this.addAbility(new EntersBattlefieldAbility(new ConditionalOneShotEffect(new TapSourceEffect(), controls, abilityText), abilityText)); + this.addAbility(new GreenManaAbility()); this.addAbility(new WhiteManaAbility()); } - public RazorvergeThicket (final RazorvergeThicket card) { + public RazorvergeThicket(final RazorvergeThicket card) { super(card); } diff --git a/Mage.Sets/src/mage/sets/scarsofmirrodin/SeachromeCoast.java b/Mage.Sets/src/mage/sets/scarsofmirrodin/SeachromeCoast.java index 2aca41fbcf8..6f98e8a9366 100644 --- a/Mage.Sets/src/mage/sets/scarsofmirrodin/SeachromeCoast.java +++ b/Mage.Sets/src/mage/sets/scarsofmirrodin/SeachromeCoast.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.scarsofmirrodin; import java.util.UUID; -import mage.constants.CardType; -import mage.constants.Rarity; import mage.abilities.common.EntersBattlefieldAbility; import mage.abilities.condition.Condition; -import mage.abilities.condition.common.PermanentsOnTheBattlefieldCondition; import mage.abilities.condition.InvertCondition; +import mage.abilities.condition.common.PermanentsOnTheBattlefieldCondition; import mage.abilities.decorator.ConditionalOneShotEffect; import mage.abilities.effects.common.TapSourceEffect; import mage.abilities.mana.BlueManaAbility; import mage.abilities.mana.WhiteManaAbility; import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.Rarity; import mage.filter.common.FilterLandPermanent; /** @@ -50,18 +49,21 @@ public class SeachromeCoast extends CardImpl { private static FilterLandPermanent filter = new FilterLandPermanent(); - public SeachromeCoast (UUID ownerId) { + public SeachromeCoast(UUID ownerId) { super(ownerId, 229, "Seachrome Coast", Rarity.RARE, new CardType[]{CardType.LAND}, null); this.expansionSetCode = "SOM"; - Condition controls = new InvertCondition(new PermanentsOnTheBattlefieldCondition(filter, PermanentsOnTheBattlefieldCondition.CountType.FEWER_THAN, 4)); + // Seachrome Coast enters the battlefield tapped unless you control two or fewer other lands. + Condition controls = new InvertCondition(new PermanentsOnTheBattlefieldCondition(filter, PermanentsOnTheBattlefieldCondition.CountType.FEWER_THAN, 3)); String abilityText = "tap it unless you control fewer than 3 lands"; this.addAbility(new EntersBattlefieldAbility(new ConditionalOneShotEffect(new TapSourceEffect(), controls, abilityText), abilityText)); + + // {T}: Add {W} or {U} to your mana pool. this.addAbility(new WhiteManaAbility()); this.addAbility(new BlueManaAbility()); } - public SeachromeCoast (final SeachromeCoast card) { + public SeachromeCoast(final SeachromeCoast card) { super(card); } From 5c31b03c004d444b2373054af1cfba09f471ca76 Mon Sep 17 00:00:00 2001 From: LevelX2 Date: Tue, 27 Oct 2015 17:55:38 +0100 Subject: [PATCH 235/268] * Fixed a problem that ability controller of replacement effects for cards entering the battlefield were not changed early enough (e.g. causing problem if putting Canopy Vista of opponent with Oblivion Sower onto th ebattlefield). --- .../sets/battleforzendikar/CanopyVista.java | 4 +- .../sets/battleforzendikar/OblivionSower.java | 2 +- .../oneshot/exile/OblivionSowerTest.java | 74 +++++++++++++++++++ .../java/org/mage/test/player/TestPlayer.java | 2 +- .../mage/cards/repository/CardRepository.java | 2 +- Mage/src/mage/players/PlayerImpl.java | 6 +- 6 files changed, 83 insertions(+), 7 deletions(-) create mode 100644 Mage.Tests/src/test/java/org/mage/test/cards/abilities/oneshot/exile/OblivionSowerTest.java diff --git a/Mage.Sets/src/mage/sets/battleforzendikar/CanopyVista.java b/Mage.Sets/src/mage/sets/battleforzendikar/CanopyVista.java index d6fc7f74027..97dcdb7afae 100644 --- a/Mage.Sets/src/mage/sets/battleforzendikar/CanopyVista.java +++ b/Mage.Sets/src/mage/sets/battleforzendikar/CanopyVista.java @@ -47,9 +47,9 @@ import mage.filter.predicate.mageobject.SupertypePredicate; * @author fireshoes */ public class CanopyVista extends CardImpl { - + private static final FilterLandPermanent filter = new FilterLandPermanent(); - + static { filter.add(new SupertypePredicate("Basic")); } diff --git a/Mage.Sets/src/mage/sets/battleforzendikar/OblivionSower.java b/Mage.Sets/src/mage/sets/battleforzendikar/OblivionSower.java index 80518ad1c23..533a88f299a 100644 --- a/Mage.Sets/src/mage/sets/battleforzendikar/OblivionSower.java +++ b/Mage.Sets/src/mage/sets/battleforzendikar/OblivionSower.java @@ -111,7 +111,7 @@ class OblivionSowerEffect extends OneShotEffect { + targetPlayer.getName() + " to put into play under your control"); TargetCard targetCards = new TargetCard(0, exiledLands.size(), Zone.EXILED, filterToPlay); if (controller.chooseTarget(outcome, exiledLands, targetCards, source, game)) { - controller.moveCards(new CardsImpl(targetCards.getTargets()), null, Zone.BATTLEFIELD, source, game); + controller.moveCards(new CardsImpl(targetCards.getTargets()), Zone.BATTLEFIELD, source, game); } } return true; diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/abilities/oneshot/exile/OblivionSowerTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/abilities/oneshot/exile/OblivionSowerTest.java new file mode 100644 index 00000000000..ae9c4982beb --- /dev/null +++ b/Mage.Tests/src/test/java/org/mage/test/cards/abilities/oneshot/exile/OblivionSowerTest.java @@ -0,0 +1,74 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package org.mage.test.cards.abilities.oneshot.exile; + +import mage.constants.PhaseStep; +import mage.constants.Zone; +import org.junit.Test; +import org.mage.test.serverside.base.CardTestPlayerBase; + +/** + * + * @author LevelX2 + */ +public class OblivionSowerTest extends CardTestPlayerBase { + + /** + * When putting lands into play from an opponent's exile zone using Oblivion + * Sower, the BFZ dual lands behave exactly the opposite way of how they + * should: if you control less than two basics, they enter the battlefield + * untapped, and if you control more, they enter tapped. + */ + @Test + public void testPlayLandsFromExile() { + addCard(Zone.BATTLEFIELD, playerA, "Plains", 6); + // When you cast Oblivion Sower, target opponent exiles the top four cards of his or her library, then you may put any number of land cards that player owns from exile onto the battlefield under your control. + addCard(Zone.HAND, playerA, "Oblivion Sower"); // Creature - 5/8 + + // Canopy Vista enters the battlefield tapped unless you control two or more basic lands. + addCard(Zone.LIBRARY, playerB, "Canopy Vista", 3); + addCard(Zone.LIBRARY, playerB, "Silvercoat Lion", 1); + skipInitShuffling(); + + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Oblivion Sower"); + + addTarget(playerA, "Canopy Vista^Canopy Vista^Canopy Vista"); + + setStopAt(1, PhaseStep.BEGIN_COMBAT); + execute(); + + assertHandCount(playerA, "Oblivion Sower", 0); + assertPermanentCount(playerA, "Oblivion Sower", 1); + + assertExileCount("Silvercoat Lion", 1); + assertPermanentCount(playerA, "Canopy Vista", 3); + + assertTappedCount("Canopy Vista", false, 3); + + } +} diff --git a/Mage.Tests/src/test/java/org/mage/test/player/TestPlayer.java b/Mage.Tests/src/test/java/org/mage/test/player/TestPlayer.java index 2f80da8fa0d..795e12ae9bc 100644 --- a/Mage.Tests/src/test/java/org/mage/test/player/TestPlayer.java +++ b/Mage.Tests/src/test/java/org/mage/test/player/TestPlayer.java @@ -821,7 +821,7 @@ public class TestPlayer implements Player { boolean targetFound = false; for (String targetName : targetList) { for (Card card : cards.getCards(game)) { - if (card.getName().equals(targetName)) { + if (card.getName().equals(targetName) && !target.getTargets().contains(card.getId())) { target.add(card.getId(), game); targetFound = true; break; diff --git a/Mage/src/mage/cards/repository/CardRepository.java b/Mage/src/mage/cards/repository/CardRepository.java index ab5ff527376..48fb69dcf39 100644 --- a/Mage/src/mage/cards/repository/CardRepository.java +++ b/Mage/src/mage/cards/repository/CardRepository.java @@ -63,7 +63,7 @@ public enum CardRepository { // raise this if db structure was changed private static final long CARD_DB_VERSION = 42; // raise this if new cards were added to the server - private static final long CARD_CONTENT_VERSION = 40; + private static final long CARD_CONTENT_VERSION = 41; private final Random random = new Random(); private Dao cardDao; diff --git a/Mage/src/mage/players/PlayerImpl.java b/Mage/src/mage/players/PlayerImpl.java index 20b7bfafe96..80d529136d5 100644 --- a/Mage/src/mage/players/PlayerImpl.java +++ b/Mage/src/mage/players/PlayerImpl.java @@ -3076,9 +3076,13 @@ public abstract class PlayerImpl implements Player, Serializable { game.setScopeRelevant(true); for (Permanent permanent : permanents) { fromZone = game.getState().getZone(permanent.getId()); + // make sure the controller of all continuous effects of this card are switched to the current controller + game.getContinuousEffects().setController(permanent.getId(), permanent.getControllerId()); if (permanent.entersBattlefield(source.getSourceId(), game, fromZone, true)) { permanentsEntered.add(permanent); } else { + // revert controller to owner if permanent does not enter + game.getContinuousEffects().setController(permanent.getId(), permanent.getOwnerId()); game.getPermanentsEntering().remove(permanent.getId()); } } @@ -3087,8 +3091,6 @@ public abstract class PlayerImpl implements Player, Serializable { fromZone = game.getState().getZone(permanent.getId()); if (((Card) permanent).removeFromZone(game, fromZone, source.getSourceId())) { permanent.updateZoneChangeCounter(game); - // make sure the controller of all continuous effects of this card are switched to the current controller - game.getContinuousEffects().setController(permanent.getId(), permanent.getControllerId()); game.addPermanent(permanent); permanent.setZone(Zone.BATTLEFIELD, game); game.getPermanentsEntering().remove(permanent.getId()); From 0c988de9fb8db8c0daac815baef919792be5b743 Mon Sep 17 00:00:00 2001 From: Neil Gentleman Date: Tue, 27 Oct 2015 00:59:24 -0700 Subject: [PATCH 236/268] fix Impelled Giant --- .../src/mage/sets/eventide/ImpelledGiant.java | 7 +-- .../abilities/other/ImpelledGiantTest.java | 50 +++++++++++++++++++ 2 files changed, 52 insertions(+), 5 deletions(-) create mode 100644 Mage.Tests/src/test/java/org/mage/test/cards/abilities/other/ImpelledGiantTest.java diff --git a/Mage.Sets/src/mage/sets/eventide/ImpelledGiant.java b/Mage.Sets/src/mage/sets/eventide/ImpelledGiant.java index 7c10d02f4d6..ceb04da2360 100644 --- a/Mage.Sets/src/mage/sets/eventide/ImpelledGiant.java +++ b/Mage.Sets/src/mage/sets/eventide/ImpelledGiant.java @@ -154,13 +154,10 @@ class ImpelledGiantBoostEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { Permanent impelledGiant = game.getPermanent(source.getSourceId()); - Permanent tappedCreature = game.getPermanent(this.targetPointer.getFirst(game, source)); - if (tappedCreature == null) { - tappedCreature = (Permanent) game.getLastKnownInformation(this.targetPointer.getFirst(game, source), Zone.BATTLEFIELD); - } + Permanent tappedCreature = game.getPermanentOrLKIBattlefield(this.targetPointer.getFirst(game, source)); if (tappedCreature != null && impelledGiant != null) { int amount = tappedCreature.getPower().getValue(); - impelledGiant.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new BoostSourceEffect(amount, 0, Duration.EndOfTurn)), source.getSourceId(), game); + game.addEffect(new BoostSourceEffect(amount, 0, Duration.EndOfTurn), source); } return true; } diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/abilities/other/ImpelledGiantTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/abilities/other/ImpelledGiantTest.java new file mode 100644 index 00000000000..907175c0693 --- /dev/null +++ b/Mage.Tests/src/test/java/org/mage/test/cards/abilities/other/ImpelledGiantTest.java @@ -0,0 +1,50 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package org.mage.test.cards.abilities.other; + +import mage.constants.PhaseStep; +import mage.constants.Zone; +import org.junit.Test; +import org.mage.test.serverside.base.CardTestPlayerBase; + +public class ImpelledGiantTest extends CardTestPlayerBase { + + @Test + public void testGainsPower() { + addCard(Zone.BATTLEFIELD, playerA, "Impelled Giant"); + addCard(Zone.BATTLEFIELD, playerA, "Hurloon Minotaur"); + + activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Tap an untapped red creature you control other than Impelled Giant"); + + setStopAt(1, PhaseStep.BEGIN_COMBAT); + execute(); + + assertTapped("Hurloon Minotaur", true); + assertPowerToughness(playerA, "Impelled Giant", 5, 3); + } +} From a84a56032737e3d572851610734ccfc434e79468 Mon Sep 17 00:00:00 2001 From: LevelX2 Date: Wed, 28 Oct 2015 10:54:59 +0100 Subject: [PATCH 237/268] * Spreading Seas - Fixed that not all existing land subtypes (e.g. Urza's Mine) were removed if a land was enchanted by Spreading Seas --- .../continuous/BecomesBasicLandEnchantedEffect.java | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/Mage/src/mage/abilities/effects/common/continuous/BecomesBasicLandEnchantedEffect.java b/Mage/src/mage/abilities/effects/common/continuous/BecomesBasicLandEnchantedEffect.java index 79d9c8f91d5..536b87db161 100644 --- a/Mage/src/mage/abilities/effects/common/continuous/BecomesBasicLandEnchantedEffect.java +++ b/Mage/src/mage/abilities/effects/common/continuous/BecomesBasicLandEnchantedEffect.java @@ -47,12 +47,20 @@ public class BecomesBasicLandEnchantedEffect extends ContinuousEffectImpl { protected final static ArrayList allLandTypes = new ArrayList<>(); - static { + static { // 205.3i allLandTypes.add("Forest"); allLandTypes.add("Swamp"); allLandTypes.add("Plains"); allLandTypes.add("Mountains"); allLandTypes.add("Island"); + allLandTypes.add("Urza's"); + allLandTypes.add("Mine"); + allLandTypes.add("Power-Plant"); + allLandTypes.add("Tower"); + allLandTypes.add("Desert"); + allLandTypes.add("Gate"); + allLandTypes.add("Lair"); + allLandTypes.add("Locus"); } protected ArrayList landTypes = new ArrayList<>(); @@ -109,7 +117,7 @@ public class BecomesBasicLandEnchantedEffect extends ContinuousEffectImpl { break; case TypeChangingEffects_4: // subtypes are all removed by changing the subtype to a land type. - permanent.getSubtype().clear(); + permanent.getSubtype().removeAll(allLandTypes); permanent.getSubtype().addAll(landTypes); break; } From f47a2d93844f873836b3681fcc26131534bee696 Mon Sep 17 00:00:00 2001 From: LevelX2 Date: Wed, 28 Oct 2015 17:02:46 +0100 Subject: [PATCH 238/268] * Scrap Mastery - Fixed a bug that card movement caused an exception. --- .../src/mage/sets/commander2014/ScrapMastery.java | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/Mage.Sets/src/mage/sets/commander2014/ScrapMastery.java b/Mage.Sets/src/mage/sets/commander2014/ScrapMastery.java index f2512b5b703..badafeb966f 100644 --- a/Mage.Sets/src/mage/sets/commander2014/ScrapMastery.java +++ b/Mage.Sets/src/mage/sets/commander2014/ScrapMastery.java @@ -33,9 +33,8 @@ import java.util.Set; import java.util.UUID; import mage.abilities.Ability; import mage.abilities.effects.OneShotEffect; +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; @@ -90,12 +89,12 @@ class ScrapMasteryEffect extends OneShotEffect { public boolean apply(Game game, Ability source) { Player controller = game.getPlayer(source.getControllerId()); if (controller != null) { - Map> exiledCards = new HashMap<>(); + Map> exiledCards = new HashMap<>(); // exile artifacts from graveyard for (UUID playerId : game.getState().getPlayersInRange(controller.getId(), game)) { Player player = game.getPlayer(playerId); if (player != null) { - Set cards = player.getGraveyard().getCards(new FilterArtifactCard(), game); + Set cards = player.getGraveyard().getCards(new FilterArtifactCard(), game); controller.moveCards(cards, Zone.EXILED, source, game); exiledCards.put(player.getId(), cards); } @@ -113,8 +112,7 @@ class ScrapMasteryEffect extends OneShotEffect { for (UUID playerId : game.getState().getPlayersInRange(controller.getId(), game)) { Player player = game.getPlayer(playerId); if (player != null) { - Cards playersExiledCards = new CardsImpl(exiledCards.get(playerId)); - controller.moveCards(playersExiledCards, Zone.BATTLEFIELD, source, game); + controller.moveCards(exiledCards.get(playerId), Zone.BATTLEFIELD, source, game); } } return true; From 1ef99e775fed0b5b2d28429fff5fbac547654a1a Mon Sep 17 00:00:00 2001 From: LevelX2 Date: Wed, 28 Oct 2015 17:04:57 +0100 Subject: [PATCH 239/268] * Fixed a bug with DiscardTargetCost causing problems for cards with discard costs (e.g. Solitary Confinement). --- .../sets/judgment/SolitaryConfinement.java | 7 ++--- .../costs/common/DiscardTargetCost.java | 8 ++--- .../SacrificeSourceUnlessPaysEffect.java | 29 ++++++++----------- 3 files changed, 18 insertions(+), 26 deletions(-) diff --git a/Mage.Sets/src/mage/sets/judgment/SolitaryConfinement.java b/Mage.Sets/src/mage/sets/judgment/SolitaryConfinement.java index c7435e2543d..893686b35e9 100644 --- a/Mage.Sets/src/mage/sets/judgment/SolitaryConfinement.java +++ b/Mage.Sets/src/mage/sets/judgment/SolitaryConfinement.java @@ -54,16 +54,15 @@ public class SolitaryConfinement extends CardImpl { super(ownerId, 24, "Solitary Confinement", Rarity.RARE, new CardType[]{CardType.ENCHANTMENT}, "{2}{W}"); this.expansionSetCode = "JUD"; - // At the beginning of your upkeep, sacrifice Solitary Confinement unless you discard a card. this.addAbility(new BeginningOfUpkeepTriggeredAbility(Zone.BATTLEFIELD, new SacrificeSourceUnlessPaysEffect(new DiscardTargetCost(new TargetCardInHand())), TargetController.YOU, false)); - + // Skip your draw step. this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new SkipDrawStepEffect())); - + // You have shroud. this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new GainAbilityControllerEffect(ShroudAbility.getInstance()))); - + // Prevent all damage that would be dealt to you. this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new PreventAllDamageToControllerEffect(Duration.WhileOnBattlefield))); } diff --git a/Mage/src/mage/abilities/costs/common/DiscardTargetCost.java b/Mage/src/mage/abilities/costs/common/DiscardTargetCost.java index c62ecfc3953..da388060961 100644 --- a/Mage/src/mage/abilities/costs/common/DiscardTargetCost.java +++ b/Mage/src/mage/abilities/costs/common/DiscardTargetCost.java @@ -59,9 +59,7 @@ public class DiscardTargetCost extends CostImpl { public DiscardTargetCost(DiscardTargetCost cost) { super(cost); - for (Card card : cost.cards) { - this.cards.add(card.copy()); - } + this.cards.addAll(cost.cards); this.randomDiscard = cost.randomDiscard; } @@ -84,7 +82,7 @@ public class DiscardTargetCost extends CostImpl { return false; } player.discard(card, ability, game); - this.cards.add(card.copy()); + this.cards.add(card); } } } @@ -96,7 +94,7 @@ public class DiscardTargetCost extends CostImpl { public void clearPaid() { super.clearPaid(); this.cards.clear(); - this.targets.clear(); + this.targets.clearChosen(); } @Override diff --git a/Mage/src/mage/abilities/effects/common/SacrificeSourceUnlessPaysEffect.java b/Mage/src/mage/abilities/effects/common/SacrificeSourceUnlessPaysEffect.java index b36191ecbc3..f0904271903 100644 --- a/Mage/src/mage/abilities/effects/common/SacrificeSourceUnlessPaysEffect.java +++ b/Mage/src/mage/abilities/effects/common/SacrificeSourceUnlessPaysEffect.java @@ -1,29 +1,26 @@ package mage.abilities.effects.common; -import mage.MageObject; -import mage.constants.Outcome; import mage.abilities.Ability; import mage.abilities.Mode; import mage.abilities.costs.Cost; import mage.abilities.effects.OneShotEffect; +import mage.constants.Outcome; import mage.game.Game; import mage.game.permanent.Permanent; import mage.players.Player; import mage.util.CardUtil; /** - * Created by IntelliJ IDEA. - * User: Loki - * Date: 21.12.10 - * Time: 9:21 + * Created by IntelliJ IDEA. User: Loki Date: 21.12.10 Time: 9:21 */ public class SacrificeSourceUnlessPaysEffect extends OneShotEffect { + protected Cost cost; public SacrificeSourceUnlessPaysEffect(Cost cost) { super(Outcome.Sacrifice); this.cost = cost; - } + } public SacrificeSourceUnlessPaysEffect(final SacrificeSourceUnlessPaysEffect effect) { super(effect); @@ -33,14 +30,13 @@ public class SacrificeSourceUnlessPaysEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { Player player = game.getPlayer(source.getControllerId()); - Permanent permanent = game.getPermanentOrLKIBattlefield(source.getSourceId()); - MageObject sourceObject = source.getSourceObject(game); - if (sourceObject != null && player != null && permanent != null) { + Permanent sourcePermanent = game.getPermanentOrLKIBattlefield(source.getSourceId()); + if (player != null && sourcePermanent != null) { StringBuilder sb = new StringBuilder(cost.getText()).append("?"); - if (!sb.toString().toLowerCase().startsWith("exile ") && !sb.toString().toLowerCase().startsWith("return ") ) { + if (!sb.toString().toLowerCase().startsWith("exile ") && !sb.toString().toLowerCase().startsWith("return ")) { sb.insert(0, "Pay "); } - String message = CardUtil.replaceSourceName(sb.toString(), sourceObject.getLogName()); + String message = CardUtil.replaceSourceName(sb.toString(), sourcePermanent.getLogName()); message = Character.toUpperCase(message.charAt(0)) + message.substring(1); if (player.chooseUse(Outcome.Benefit, message, source, game)) { cost.clearPaid(); @@ -48,7 +44,7 @@ public class SacrificeSourceUnlessPaysEffect extends OneShotEffect { return true; } } - permanent.sacrifice(source.getSourceId(), game); + sourcePermanent.sacrifice(source.getSourceId(), game); return true; } return false; @@ -61,7 +57,7 @@ public class SacrificeSourceUnlessPaysEffect extends OneShotEffect { @Override public String getText(Mode mode) { - if(staticText != null && !staticText.isEmpty()) { + if (staticText != null && !staticText.isEmpty()) { return staticText; } @@ -74,11 +70,10 @@ public class SacrificeSourceUnlessPaysEffect extends OneShotEffect { || costText.toLowerCase().startsWith("sacrifice")) { sb.append(costText.substring(0, 1).toLowerCase()); sb.append(costText.substring(1)); - } - else { + } else { sb.append("pay ").append(costText); } return sb.toString(); } - } +} From d79776e5897caacbdb2c6cde54409f9ca18e188c Mon Sep 17 00:00:00 2001 From: LevelX2 Date: Wed, 28 Oct 2015 17:05:58 +0100 Subject: [PATCH 240/268] * Added some tests. --- .../src/mage/sets/magic2013/TradingPost.java | 25 ++---- .../oneshot/sacrifice/TradingPostTest.java | 77 +++++++++++++++++++ .../entersBattlefield/LivingLoreTest.java | 59 ++++++++++++++ .../base/impl/CardTestPlayerAPIImpl.java | 8 +- 4 files changed, 149 insertions(+), 20 deletions(-) create mode 100644 Mage.Tests/src/test/java/org/mage/test/cards/abilities/oneshot/sacrifice/TradingPostTest.java create mode 100644 Mage.Tests/src/test/java/org/mage/test/cards/replacement/entersBattlefield/LivingLoreTest.java diff --git a/Mage.Sets/src/mage/sets/magic2013/TradingPost.java b/Mage.Sets/src/mage/sets/magic2013/TradingPost.java index f6370a6d285..07f0f0fab5a 100644 --- a/Mage.Sets/src/mage/sets/magic2013/TradingPost.java +++ b/Mage.Sets/src/mage/sets/magic2013/TradingPost.java @@ -28,11 +28,6 @@ package mage.sets.magic2013; import java.util.UUID; - -import mage.constants.CardType; -import mage.constants.Rarity; -import mage.MageInt; -import mage.ObjectColor; import mage.abilities.Ability; import mage.abilities.common.SimpleActivatedAbility; import mage.abilities.costs.common.DiscardTargetCost; @@ -45,10 +40,12 @@ import mage.abilities.effects.common.DrawCardSourceControllerEffect; import mage.abilities.effects.common.GainLifeEffect; import mage.abilities.effects.common.ReturnFromGraveyardToHandTargetEffect; import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.Rarity; import mage.constants.Zone; import mage.filter.common.FilterArtifactCard; -import mage.filter.common.FilterControlledPermanent; -import mage.filter.predicate.mageobject.CardTypePredicate; +import mage.filter.common.FilterControlledArtifactPermanent; +import mage.filter.common.FilterControlledCreaturePermanent; import mage.game.permanent.token.GoatToken; import mage.target.common.TargetCardInGraveyard; import mage.target.common.TargetCardInHand; @@ -60,14 +57,6 @@ import mage.target.common.TargetControlledPermanent; */ public class TradingPost extends CardImpl { - final static FilterControlledPermanent filter = new FilterControlledPermanent("creature"); - final static FilterControlledPermanent filter2 = new FilterControlledPermanent("artifact"); - - static { - filter.add(new CardTypePredicate(CardType.CREATURE)); - filter2.add(new CardTypePredicate(CardType.ARTIFACT)); - } - public TradingPost(UUID ownerId) { super(ownerId, 220, "Trading Post", Rarity.RARE, new CardType[]{CardType.ARTIFACT}, "{4}"); this.expansionSetCode = "M13"; @@ -86,15 +75,15 @@ public class TradingPost extends CardImpl { // {1}, {tap}, Sacrifice a creature: Return target artifact card from your graveyard to your hand. Ability ability3 = new SimpleActivatedAbility(Zone.BATTLEFIELD, new ReturnFromGraveyardToHandTargetEffect(), new GenericManaCost(1)); - ability3.addTarget(new TargetCardInGraveyard(new FilterArtifactCard("artifact card in your graveyard"))); + ability3.addTarget(new TargetCardInGraveyard(new FilterArtifactCard("an artifact card in your graveyard"))); ability3.addCost(new TapSourceCost()); - ability3.addCost(new SacrificeTargetCost(new TargetControlledPermanent(filter))); + ability3.addCost(new SacrificeTargetCost(new TargetControlledPermanent(new FilterControlledCreaturePermanent("a creature")))); this.addAbility(ability3); // {1}, {tap}, Sacrifice an artifact: Draw a card. Ability ability4 = new SimpleActivatedAbility(Zone.BATTLEFIELD, new DrawCardSourceControllerEffect(1), new GenericManaCost(1)); ability4.addCost(new TapSourceCost()); - ability4.addCost(new SacrificeTargetCost(new TargetControlledPermanent(filter2))); + ability4.addCost(new SacrificeTargetCost(new TargetControlledPermanent(new FilterControlledArtifactPermanent("an artifact")))); this.addAbility(ability4); } diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/abilities/oneshot/sacrifice/TradingPostTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/abilities/oneshot/sacrifice/TradingPostTest.java new file mode 100644 index 00000000000..242c0358eb7 --- /dev/null +++ b/Mage.Tests/src/test/java/org/mage/test/cards/abilities/oneshot/sacrifice/TradingPostTest.java @@ -0,0 +1,77 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package org.mage.test.cards.abilities.oneshot.sacrifice; + +import mage.constants.PhaseStep; +import mage.constants.Zone; +import org.junit.Test; +import org.mage.test.serverside.base.CardTestPlayerBase; + +/** + * + * @author LevelX2 + */ +public class TradingPostTest extends CardTestPlayerBase { + + /** + * Trading Post doesn't let me sacrifice a creature owned by my opponent, + * but controlled by me. I get an error message saying You cannot sacrifice + * this creature. + */ + @Test + public void testSacrifice() { + addCard(Zone.BATTLEFIELD, playerA, "Mountain", 4); + // {1}, {T}, Discard a card: You gain 4 life. + // {1}, {T}, Pay 1 life: Put a 0/1 white Goat creature token onto the battlefield. + // {1}, {T}, Sacrifice a creature: Return target artifact card from your graveyard to your hand. + // {1}, {T}, Sacrifice an artifact: Draw a card. + addCard(Zone.BATTLEFIELD, playerA, "Trading Post", 1); + // Gain control of target creature until end of turn. Untap that creature. It gains haste until end of turn. (It can attack and this turn.) + addCard(Zone.HAND, playerA, "Act of Treason"); // Sorcery {2}{R} + addCard(Zone.GRAVEYARD, playerA, "Helm of Possession"); + + addCard(Zone.BATTLEFIELD, playerB, "Savannah Lions"); + + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Act of Treason", "Savannah Lions"); + + activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "{1},{T}, Sacrifice a creature", "Helm of Possession", "Act of Treason", StackClause.WHILE_NOT_ON_STACK); + setChoice(playerA, "Savannah Lions"); + + setStopAt(1, PhaseStep.BEGIN_COMBAT); + execute(); + + assertGraveyardCount(playerA, "Act of Treason", 1); + + assertPermanentCount(playerB, "Savannah Lions", 0); + assertGraveyardCount(playerB, "Savannah Lions", 1); + + assertTapped("Trading Post", true); + assertHandCount(playerA, 1); + + } +} diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/replacement/entersBattlefield/LivingLoreTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/replacement/entersBattlefield/LivingLoreTest.java new file mode 100644 index 00000000000..217636f7e2a --- /dev/null +++ b/Mage.Tests/src/test/java/org/mage/test/cards/replacement/entersBattlefield/LivingLoreTest.java @@ -0,0 +1,59 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package org.mage.test.cards.replacement.entersBattlefield; + +import mage.constants.PhaseStep; +import mage.constants.Zone; +import org.junit.Test; +import org.mage.test.serverside.base.CardTestPlayerBase; + +/** + * + * @author LevelX2 + */ +public class LivingLoreTest extends CardTestPlayerBase { + + /** + * That the +1/+1 counters are added to Living Lore before state based + * actions take place + */ + @Test + public void testCountersAdded() { + addCard(Zone.BATTLEFIELD, playerA, "Island", 4); + addCard(Zone.HAND, playerA, "Living Lore"); //{3}{U} + addCard(Zone.GRAVEYARD, playerA, "Natural Connection", 1); // {2}{G} + + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Living Lore"); + setStopAt(1, PhaseStep.BEGIN_COMBAT); + execute(); + + assertPermanentCount(playerA, "Living Lore", 1); + assertPowerToughness(playerA, "Living Lore", 3, 3); + } + +} diff --git a/Mage.Tests/src/test/java/org/mage/test/serverside/base/impl/CardTestPlayerAPIImpl.java b/Mage.Tests/src/test/java/org/mage/test/serverside/base/impl/CardTestPlayerAPIImpl.java index 4b9cc8f0eb5..e5978b008f0 100644 --- a/Mage.Tests/src/test/java/org/mage/test/serverside/base/impl/CardTestPlayerAPIImpl.java +++ b/Mage.Tests/src/test/java/org/mage/test/serverside/base/impl/CardTestPlayerAPIImpl.java @@ -994,6 +994,10 @@ public abstract class CardTestPlayerAPIImpl extends MageTestPlayerBase implement player.addAction(turnNum, step, "activate:" + ability + "$target=" + targetName); } + public void activateAbility(int turnNum, PhaseStep step, TestPlayer player, String ability, String targetName, String spellOnStack) { + this.activateAbility(turnNum, step, player, ability, targetName, spellOnStack, StackClause.WHILE_ON_STACK); + } + /** * * @param turnNum @@ -1004,13 +1008,13 @@ public abstract class CardTestPlayerAPIImpl extends MageTestPlayerBase implement * NO_TARGET * @param spellOnStack */ - public void activateAbility(int turnNum, PhaseStep step, TestPlayer player, String ability, String targetName, String spellOnStack) { + public void activateAbility(int turnNum, PhaseStep step, TestPlayer player, String ability, String targetName, String spellOnStack, StackClause clause) { StringBuilder sb = new StringBuilder("activate:").append(ability); if (targetName != null && !targetName.isEmpty()) { sb.append("$target=").append(targetName); } if (spellOnStack != null && !spellOnStack.isEmpty()) { - sb.append("$spellOnStack=").append(spellOnStack); + sb.append("$").append(StackClause.WHILE_ON_STACK.equals(clause) ? "" : "!").append("spellOnStack=").append(spellOnStack); } player.addAction(turnNum, step, sb.toString()); } From 024f13ce9a7da07122d3935f1edb35ee78908d94 Mon Sep 17 00:00:00 2001 From: LevelX2 Date: Wed, 28 Oct 2015 23:55:34 +0100 Subject: [PATCH 241/268] * The Rack - Fixed that it did no damage to the chosen opponent. --- Mage.Sets/src/mage/sets/fourthedition/TheRack.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Mage.Sets/src/mage/sets/fourthedition/TheRack.java b/Mage.Sets/src/mage/sets/fourthedition/TheRack.java index bbbed87b4d3..1f22f23cfad 100644 --- a/Mage.Sets/src/mage/sets/fourthedition/TheRack.java +++ b/Mage.Sets/src/mage/sets/fourthedition/TheRack.java @@ -119,7 +119,7 @@ class TheRackEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { - UUID playerId = (UUID) game.getState().getValue(source.getSourceId().toString() + "_player"); + UUID playerId = (UUID) game.getState().getValue(source.getSourceId().toString() + ChooseOpponentEffect.VALUE_KEY); Player chosenPlayer = game.getPlayer(playerId); if (chosenPlayer != null) { int damage = 3 - chosenPlayer.getHand().size(); From 80ed40f6e8acb44809d104b455f452bb287ce703 Mon Sep 17 00:00:00 2001 From: Neil Gentleman Date: Tue, 27 Oct 2015 20:36:07 -0700 Subject: [PATCH 242/268] use correct mana symbol order matching the printed cards --- Mage.Sets/src/mage/sets/conflux/KnotvineMystic.java | 2 +- Mage.Sets/src/mage/sets/gatecrash/UrbanEvolution.java | 2 +- Mage.Sets/src/mage/sets/khansoftarkir/Duneblast.java | 2 +- Mage.Sets/src/mage/sets/khansoftarkir/SultaiAscendancy.java | 2 +- .../src/mage/sets/prereleaseevents/QuestingPhelddagrif.java | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/Mage.Sets/src/mage/sets/conflux/KnotvineMystic.java b/Mage.Sets/src/mage/sets/conflux/KnotvineMystic.java index 608418d7828..afe5461a9fa 100644 --- a/Mage.Sets/src/mage/sets/conflux/KnotvineMystic.java +++ b/Mage.Sets/src/mage/sets/conflux/KnotvineMystic.java @@ -46,7 +46,7 @@ import mage.constants.Rarity; public class KnotvineMystic extends CardImpl{ public KnotvineMystic(UUID ownerId) { - super(ownerId, 114, "Knotvine Mystic", Rarity.UNCOMMON, new CardType[]{CardType.CREATURE}, "{W}{R}{G}"); + super(ownerId, 114, "Knotvine Mystic", Rarity.UNCOMMON, new CardType[]{CardType.CREATURE}, "{R}{G}{W}"); this.expansionSetCode = "CON"; diff --git a/Mage.Sets/src/mage/sets/gatecrash/UrbanEvolution.java b/Mage.Sets/src/mage/sets/gatecrash/UrbanEvolution.java index 53128276399..087c376526c 100644 --- a/Mage.Sets/src/mage/sets/gatecrash/UrbanEvolution.java +++ b/Mage.Sets/src/mage/sets/gatecrash/UrbanEvolution.java @@ -44,7 +44,7 @@ import mage.constants.Duration; public class UrbanEvolution extends CardImpl { public UrbanEvolution(UUID ownerId) { - super(ownerId, 204, "Urban Evolution", Rarity.UNCOMMON, new CardType[]{CardType.SORCERY}, "{3}{U}{G}"); + super(ownerId, 204, "Urban Evolution", Rarity.UNCOMMON, new CardType[]{CardType.SORCERY}, "{3}{G}{U}"); this.expansionSetCode = "GTC"; //Draw three cards. diff --git a/Mage.Sets/src/mage/sets/khansoftarkir/Duneblast.java b/Mage.Sets/src/mage/sets/khansoftarkir/Duneblast.java index 34d4495c712..c0424b1594c 100644 --- a/Mage.Sets/src/mage/sets/khansoftarkir/Duneblast.java +++ b/Mage.Sets/src/mage/sets/khansoftarkir/Duneblast.java @@ -48,7 +48,7 @@ import mage.target.common.TargetCreaturePermanent; public class Duneblast extends CardImpl { public Duneblast(UUID ownerId) { - super(ownerId, 174, "Duneblast", Rarity.RARE, new CardType[]{CardType.SORCERY}, "{4}{W}{G}{B}"); + super(ownerId, 174, "Duneblast", Rarity.RARE, new CardType[]{CardType.SORCERY}, "{4}{W}{B}{G}"); this.expansionSetCode = "KTK"; diff --git a/Mage.Sets/src/mage/sets/khansoftarkir/SultaiAscendancy.java b/Mage.Sets/src/mage/sets/khansoftarkir/SultaiAscendancy.java index ab1050c0e4b..b0cf690da77 100644 --- a/Mage.Sets/src/mage/sets/khansoftarkir/SultaiAscendancy.java +++ b/Mage.Sets/src/mage/sets/khansoftarkir/SultaiAscendancy.java @@ -46,7 +46,7 @@ import mage.filter.FilterCard; public class SultaiAscendancy extends CardImpl { public SultaiAscendancy(UUID ownerId) { - super(ownerId, 203, "Sultai Ascendancy", Rarity.RARE, new CardType[]{CardType.ENCHANTMENT}, "{G}{B}{U}"); + super(ownerId, 203, "Sultai Ascendancy", Rarity.RARE, new CardType[]{CardType.ENCHANTMENT}, "{B}{G}{U}"); this.expansionSetCode = "KTK"; diff --git a/Mage.Sets/src/mage/sets/prereleaseevents/QuestingPhelddagrif.java b/Mage.Sets/src/mage/sets/prereleaseevents/QuestingPhelddagrif.java index 1aee4f8fb02..30f15d65b72 100644 --- a/Mage.Sets/src/mage/sets/prereleaseevents/QuestingPhelddagrif.java +++ b/Mage.Sets/src/mage/sets/prereleaseevents/QuestingPhelddagrif.java @@ -65,7 +65,7 @@ public class QuestingPhelddagrif extends CardImpl { } public QuestingPhelddagrif(UUID ownerId) { - super(ownerId, 13, "Questing Phelddagrif", Rarity.SPECIAL, new CardType[]{CardType.CREATURE}, "{1}{W}{U}{G}"); + super(ownerId, 13, "Questing Phelddagrif", Rarity.SPECIAL, new CardType[]{CardType.CREATURE}, "{1}{G}{W}{U}"); this.expansionSetCode = "PTC"; this.subtype.add("Phelddagrif"); this.power = new MageInt(4); From 3c24b9fe4740b94d77dd72c30afa147fc91dfbbb Mon Sep 17 00:00:00 2001 From: Neil Gentleman Date: Wed, 28 Oct 2015 21:42:05 -0700 Subject: [PATCH 243/268] fix Gempalm Polluter card name --- Mage.Sets/src/mage/sets/legions/GempalmPolluter.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Mage.Sets/src/mage/sets/legions/GempalmPolluter.java b/Mage.Sets/src/mage/sets/legions/GempalmPolluter.java index 1bf3c4306e7..65f53df4512 100644 --- a/Mage.Sets/src/mage/sets/legions/GempalmPolluter.java +++ b/Mage.Sets/src/mage/sets/legions/GempalmPolluter.java @@ -56,7 +56,7 @@ public class GempalmPolluter extends CardImpl { } public GempalmPolluter(UUID ownerId) { - super(ownerId, 70, "Gempalm Avenger", Rarity.COMMON, new CardType[]{CardType.CREATURE}, "{5}{B}"); + super(ownerId, 70, "Gempalm Polluter", Rarity.COMMON, new CardType[]{CardType.CREATURE}, "{5}{B}"); this.expansionSetCode = "LGN"; this.subtype.add("Zombie"); this.power = new MageInt(4); From 35052f806dfc07f5e307ea913b8c8a76c60582a8 Mon Sep 17 00:00:00 2001 From: Neil Gentleman Date: Wed, 28 Oct 2015 21:47:14 -0700 Subject: [PATCH 244/268] fix Skeletonize token type ... but the card is currently broken and doesn't create the token --- Mage.Sets/src/mage/sets/shardsofalara/Skeletonize.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Mage.Sets/src/mage/sets/shardsofalara/Skeletonize.java b/Mage.Sets/src/mage/sets/shardsofalara/Skeletonize.java index f9000f459ea..18cf0faca35 100644 --- a/Mage.Sets/src/mage/sets/shardsofalara/Skeletonize.java +++ b/Mage.Sets/src/mage/sets/shardsofalara/Skeletonize.java @@ -152,7 +152,7 @@ class SkeletonToken extends Token { super("Skeleton", "1/1 black Skeleton creature token with \"{B}: Regenerate this creature.\""); this.cardType.add(CardType.CREATURE); this.color = ObjectColor.BLACK; - this.subtype.add("Bat"); + this.subtype.add("Skeleton"); this.power = new MageInt(1); this.toughness = new MageInt(1); From 81de9eb5c85c2854ea79e6f6ac5fe1d82f4a2d1a Mon Sep 17 00:00:00 2001 From: Neil Gentleman Date: Tue, 27 Oct 2015 22:25:24 -0700 Subject: [PATCH 245/268] DealtDamageToCreatureBySourceDies replaces per-card effect --- .../sets/avacynrestored/PillarOfFlame.java | 48 ------------------- .../championsofkamigawa/YamabushisStorm.java | 42 ---------------- 2 files changed, 90 deletions(-) diff --git a/Mage.Sets/src/mage/sets/avacynrestored/PillarOfFlame.java b/Mage.Sets/src/mage/sets/avacynrestored/PillarOfFlame.java index 014284bd8e5..ed8b8b3b02c 100644 --- a/Mage.Sets/src/mage/sets/avacynrestored/PillarOfFlame.java +++ b/Mage.Sets/src/mage/sets/avacynrestored/PillarOfFlame.java @@ -74,51 +74,3 @@ public class PillarOfFlame extends CardImpl { return new PillarOfFlame(this); } } - -class PillarOfFlameEffect extends ReplacementEffectImpl { - - public PillarOfFlameEffect() { - super(Duration.EndOfTurn, Outcome.Exile); - staticText = "If a creature dealt damage this way would die this turn, exile it instead"; - } - - public PillarOfFlameEffect(final PillarOfFlameEffect effect) { - super(effect); - } - - @Override - public PillarOfFlameEffect copy() { - return new PillarOfFlameEffect(this); - } - - @Override - public boolean apply(Game game, Ability source) { - return true; - } - - @Override - public boolean replaceEvent(GameEvent event, Ability source, Game game) { - Player controller = game.getPlayer(source.getControllerId()); - Permanent permanent = ((ZoneChangeEvent) event).getTarget(); - if (controller != null && permanent != null) { - return controller.moveCards(permanent, Zone.BATTLEFIELD, Zone.EXILED, source, game); - } - return false; - } - - @Override - public boolean checksEventType(GameEvent event, Game game) { - return event.getType() == EventType.ZONE_CHANGE; - } - - @Override - public boolean applies(GameEvent event, Ability source, Game game) { - if (((ZoneChangeEvent) event).isDiesEvent()) { - DamagedByWatcher watcher = (DamagedByWatcher) game.getState().getWatchers().get("DamagedByWatcher", source.getSourceId()); - if (watcher != null) { - return watcher.wasDamaged(event.getTargetId(), game); - } - } - return false; - } -} diff --git a/Mage.Sets/src/mage/sets/championsofkamigawa/YamabushisStorm.java b/Mage.Sets/src/mage/sets/championsofkamigawa/YamabushisStorm.java index 9ec4a27bccf..ad1ceef375e 100644 --- a/Mage.Sets/src/mage/sets/championsofkamigawa/YamabushisStorm.java +++ b/Mage.Sets/src/mage/sets/championsofkamigawa/YamabushisStorm.java @@ -77,45 +77,3 @@ public class YamabushisStorm extends CardImpl { } } - -class YamabushisStormEffect extends ReplacementEffectImpl { - - public YamabushisStormEffect() { - super(Duration.EndOfTurn, Outcome.Exile); - staticText = "If a creature dealt damage this way would die this turn, exile it instead"; - } - - public YamabushisStormEffect(final YamabushisStormEffect effect) { - super(effect); - } - - @Override - public YamabushisStormEffect copy() { - return new YamabushisStormEffect(this); - } - - @Override - public boolean replaceEvent(GameEvent event, Ability source, Game game) { - Player controller = game.getPlayer(source.getControllerId()); - Permanent permanent = ((ZoneChangeEvent) event).getTarget(); - if (controller != null && permanent != null) { - return controller.moveCardToExileWithInfo(permanent, null, "", source.getSourceId(), game, Zone.BATTLEFIELD, true); - } - return false; - } - - @Override - public boolean checksEventType(GameEvent event, Game game) { - return event.getType() == EventType.ZONE_CHANGE; - } - - @Override - public boolean applies(GameEvent event, Ability source, Game game) { - if (((ZoneChangeEvent) event).isDiesEvent()) { - DamagedByWatcher watcher = (DamagedByWatcher) game.getState().getWatchers().get("DamagedByWatcher", source.getSourceId()); - return watcher != null && watcher.wasDamaged(event.getTargetId(), game); - } - return false; - } - -} From ff1b424cafeae523ebd004ab30e3333b8afc50bb Mon Sep 17 00:00:00 2001 From: Neil Gentleman Date: Tue, 27 Oct 2015 21:02:32 -0700 Subject: [PATCH 246/268] options passed to JOptionPane were backwards they're both -1, so this doesn't change anything --- .../java/org/mage/plugins/card/images/DownloadPictures.java | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/Mage.Client/src/main/java/org/mage/plugins/card/images/DownloadPictures.java b/Mage.Client/src/main/java/org/mage/plugins/card/images/DownloadPictures.java index 4467e0ab2af..2423f215207 100644 --- a/Mage.Client/src/main/java/org/mage/plugins/card/images/DownloadPictures.java +++ b/Mage.Client/src/main/java/org/mage/plugins/card/images/DownloadPictures.java @@ -49,8 +49,6 @@ import mage.client.constants.Constants; import mage.client.dialog.PreferencesDialog; import mage.client.util.sets.ConstructedFormats; import mage.remote.Connection; -import static mage.remote.Connection.ProxyType.HTTP; -import static mage.remote.Connection.ProxyType.SOCKS; import net.java.truevfs.access.TFile; import net.java.truevfs.access.TFileOutputStream; import net.java.truevfs.access.TVFS; @@ -221,7 +219,7 @@ public class DownloadPictures extends DefaultBoundedRangeModel implements Runnab // JOptionPane Object[] options = { startDownloadButton, closeButton = new JButton("Cancel") }; - dlg = new JOptionPane(p0, JOptionPane.DEFAULT_OPTION, JOptionPane.PLAIN_MESSAGE, null, options, options[1]); + dlg = new JOptionPane(p0, JOptionPane.PLAIN_MESSAGE, JOptionPane.DEFAULT_OPTION, null, options, options[1]); } public static boolean checkForNewCards(List allCards) { From 0af814f3d0665890788b4edf72827b748257c6ed Mon Sep 17 00:00:00 2001 From: Winston Huang Date: Wed, 28 Oct 2015 09:33:41 -0700 Subject: [PATCH 247/268] Fix MageFrame title --- Mage.Client/src/main/java/mage/client/MageFrame.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Mage.Client/src/main/java/mage/client/MageFrame.java b/Mage.Client/src/main/java/mage/client/MageFrame.java index a6aef412905..83e70321aa2 100644 --- a/Mage.Client/src/main/java/mage/client/MageFrame.java +++ b/Mage.Client/src/main/java/mage/client/MageFrame.java @@ -372,7 +372,7 @@ public class MageFrame extends javax.swing.JFrame implements MageClient { private void setWindowTitle() { setTitle(TITLE_NAME + " Client: " - + version == null ? "" : version.toString() + " Server: " + + (version == null ? "" : version.toString()) + " Server: " + ((session != null && session.isConnected()) ? session.getVersionInfo() : "")); } From b23bd0cf1ffa02e3bc349d96015d1272d56f9b42 Mon Sep 17 00:00:00 2001 From: Neil Gentleman Date: Wed, 28 Oct 2015 22:51:24 -0700 Subject: [PATCH 248/268] some Fallen Empires cards had the wrong package --- Mage.Sets/src/mage/sets/fallenempires/IcatianJavelineers3.java | 2 +- Mage.Sets/src/mage/sets/fallenempires/NightSoil2.java | 2 +- Mage.Sets/src/mage/sets/fallenempires/NightSoil3.java | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Mage.Sets/src/mage/sets/fallenempires/IcatianJavelineers3.java b/Mage.Sets/src/mage/sets/fallenempires/IcatianJavelineers3.java index 85649357295..bd805f28bfe 100644 --- a/Mage.Sets/src/mage/sets/fallenempires/IcatianJavelineers3.java +++ b/Mage.Sets/src/mage/sets/fallenempires/IcatianJavelineers3.java @@ -25,7 +25,7 @@ * authors and should not be interpreted as representing official policies, either expressed * or implied, of BetaSteward_at_googlemail.com. */ -package mage.sets.timeshifted; +package mage.sets.fallenempires; import java.util.UUID; import mage.constants.Rarity; diff --git a/Mage.Sets/src/mage/sets/fallenempires/NightSoil2.java b/Mage.Sets/src/mage/sets/fallenempires/NightSoil2.java index 09706ba97b5..b691888fe0a 100644 --- a/Mage.Sets/src/mage/sets/fallenempires/NightSoil2.java +++ b/Mage.Sets/src/mage/sets/fallenempires/NightSoil2.java @@ -25,7 +25,7 @@ * authors and should not be interpreted as representing official policies, either expressed * or implied, of BetaSteward_at_googlemail.com. */ -package mage.sets.masterseditionii; +package mage.sets.fallenempires; import java.util.UUID; import mage.constants.Rarity; diff --git a/Mage.Sets/src/mage/sets/fallenempires/NightSoil3.java b/Mage.Sets/src/mage/sets/fallenempires/NightSoil3.java index 7289331f5f6..0acc86c5305 100644 --- a/Mage.Sets/src/mage/sets/fallenempires/NightSoil3.java +++ b/Mage.Sets/src/mage/sets/fallenempires/NightSoil3.java @@ -25,7 +25,7 @@ * authors and should not be interpreted as representing official policies, either expressed * or implied, of BetaSteward_at_googlemail.com. */ -package mage.sets.masterseditionii; +package mage.sets.fallenempires; import java.util.UUID; import mage.constants.Rarity; From 995063039da37d20f0cb8b6f91af51e03a71e63f Mon Sep 17 00:00:00 2001 From: Neil Gentleman Date: Wed, 28 Oct 2015 23:25:17 -0700 Subject: [PATCH 249/268] fix wrong-typed tokens and abilities --- .../sets/betrayersofkamigawa/KitsunePalliator.java | 8 -------- .../src/mage/sets/commander2013/LeafdrakeRoost.java | 10 +++++----- .../mage/sets/morningtide/BrighthearthBanneret.java | 2 +- Mage.Sets/src/mage/sets/prophecy/LivingTerrain.java | 2 +- Mage.Sets/src/mage/sets/timespiral/GriffinGuide.java | 2 +- Mage.Sets/src/mage/sets/timespiral/OpalGuardian.java | 2 +- 6 files changed, 9 insertions(+), 17 deletions(-) diff --git a/Mage.Sets/src/mage/sets/betrayersofkamigawa/KitsunePalliator.java b/Mage.Sets/src/mage/sets/betrayersofkamigawa/KitsunePalliator.java index 4940e8ce24f..9af055fbbd3 100644 --- a/Mage.Sets/src/mage/sets/betrayersofkamigawa/KitsunePalliator.java +++ b/Mage.Sets/src/mage/sets/betrayersofkamigawa/KitsunePalliator.java @@ -39,8 +39,6 @@ import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.PreventDamageToTargetEffect; import mage.cards.CardImpl; import mage.filter.common.FilterCreaturePermanent; -import mage.filter.predicate.mageobject.SubtypePredicate; -import mage.filter.predicate.permanent.ControllerPredicate; import mage.game.Game; import mage.game.permanent.Permanent; import mage.players.Player; @@ -52,12 +50,6 @@ import mage.target.targetpointer.FixedTarget; */ public class KitsunePalliator extends CardImpl { - private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("Samurai you control"); - static { - filter.add(new ControllerPredicate(TargetController.YOU)); - filter.add(new SubtypePredicate("Samurai")); - } - public KitsunePalliator(UUID ownerId) { super(ownerId, 14, "Kitsune Palliator", Rarity.UNCOMMON, new CardType[]{CardType.CREATURE}, "{2}{W}"); this.expansionSetCode = "BOK"; diff --git a/Mage.Sets/src/mage/sets/commander2013/LeafdrakeRoost.java b/Mage.Sets/src/mage/sets/commander2013/LeafdrakeRoost.java index 97101a89d01..b8ee63186e4 100644 --- a/Mage.Sets/src/mage/sets/commander2013/LeafdrakeRoost.java +++ b/Mage.Sets/src/mage/sets/commander2013/LeafdrakeRoost.java @@ -70,7 +70,7 @@ public class LeafdrakeRoost extends CardImpl { this.addAbility(ability); // Enchanted land has "{G}{U}, {tap}: Put a 2/2 green and blue Drake creature token with flying onto the battlefield." - Ability abilityToGain = new SimpleActivatedAbility(Zone.BATTLEFIELD, new CreateTokenEffect(new LeafdrakeRoostDragonToken()), new ManaCostsImpl("{G}{U}")); + Ability abilityToGain = new SimpleActivatedAbility(Zone.BATTLEFIELD, new CreateTokenEffect(new LeafdrakeRoostDrakeToken()), new ManaCostsImpl("{G}{U}")); abilityToGain.addCost(new TapSourceCost()); this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new GainAbilityAttachedEffect(abilityToGain, AttachmentType.AURA, Duration.WhileOnBattlefield, "Enchanted land has \"{G}{U}, {t}: Put a 2/2 green and blue Drake creature token with flying onto the battlefield.\""))); @@ -87,14 +87,14 @@ public class LeafdrakeRoost extends CardImpl { } } -class LeafdrakeRoostDragonToken extends Token { +class LeafdrakeRoostDrakeToken extends Token { - public LeafdrakeRoostDragonToken() { - super("Dragon", "2/2 green and blue Drake creature token with flying"); + public LeafdrakeRoostDrakeToken() { + super("Drake", "2/2 green and blue Drake creature token with flying"); cardType.add(CardType.CREATURE); color.setGreen(true); color.setBlue(true); - subtype.add("Dragon"); + subtype.add("Drake"); power = new MageInt(2); toughness = new MageInt(2); this.addAbility(FlyingAbility.getInstance()); diff --git a/Mage.Sets/src/mage/sets/morningtide/BrighthearthBanneret.java b/Mage.Sets/src/mage/sets/morningtide/BrighthearthBanneret.java index e404891c77d..521d13e03fa 100644 --- a/Mage.Sets/src/mage/sets/morningtide/BrighthearthBanneret.java +++ b/Mage.Sets/src/mage/sets/morningtide/BrighthearthBanneret.java @@ -52,7 +52,7 @@ public class BrighthearthBanneret extends CardImpl { static { filter.add(Predicates.or( new SubtypePredicate("Elemental"), - new SubtypePredicate("Shaman"))); + new SubtypePredicate("Warrior"))); } public BrighthearthBanneret(UUID ownerId) { diff --git a/Mage.Sets/src/mage/sets/prophecy/LivingTerrain.java b/Mage.Sets/src/mage/sets/prophecy/LivingTerrain.java index 2430cec8be6..1e2a615e112 100644 --- a/Mage.Sets/src/mage/sets/prophecy/LivingTerrain.java +++ b/Mage.Sets/src/mage/sets/prophecy/LivingTerrain.java @@ -80,7 +80,7 @@ class TreefolkToken extends Token { super("Treefolk", "5/6 green Treefolk creature"); cardType.add(CardType.CREATURE); this.color.setGreen(true); - subtype.add("Spirit"); + subtype.add("Treefolk"); power = new MageInt(5); toughness = new MageInt(6); } diff --git a/Mage.Sets/src/mage/sets/timespiral/GriffinGuide.java b/Mage.Sets/src/mage/sets/timespiral/GriffinGuide.java index c086c8bf41e..b94762aca65 100644 --- a/Mage.Sets/src/mage/sets/timespiral/GriffinGuide.java +++ b/Mage.Sets/src/mage/sets/timespiral/GriffinGuide.java @@ -93,7 +93,7 @@ class GriffinToken extends Token { cardType.add(CardType.CREATURE); color.setWhite(true); - subtype.add("Soldier"); + subtype.add("Griffin"); power = new MageInt(2); toughness = new MageInt(2); this.addAbility(FlyingAbility.getInstance()); diff --git a/Mage.Sets/src/mage/sets/timespiral/OpalGuardian.java b/Mage.Sets/src/mage/sets/timespiral/OpalGuardian.java index 04e6861f177..56c436d813c 100644 --- a/Mage.Sets/src/mage/sets/timespiral/OpalGuardian.java +++ b/Mage.Sets/src/mage/sets/timespiral/OpalGuardian.java @@ -86,7 +86,7 @@ class OpalGuardianGargoyle extends Token { public OpalGuardianGargoyle() { super("Gargoyle", "a 3/4 Gargoyle creature with flying and protection from red"); cardType.add(CardType.CREATURE); - subtype.add("Knight"); + subtype.add("Gargoyle"); power = new MageInt(3); toughness = new MageInt(4); this.addAbility(FlyingAbility.getInstance()); From 5c5e64fcce12c114f4aaa0a4a4e7afff6adc6ca8 Mon Sep 17 00:00:00 2001 From: Neil Gentleman Date: Thu, 29 Oct 2015 00:18:51 -0700 Subject: [PATCH 250/268] Krovikan Fetish is a slow cantrip --- Mage.Sets/src/mage/sets/fifthedition/KrovikanFetish.java | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/Mage.Sets/src/mage/sets/fifthedition/KrovikanFetish.java b/Mage.Sets/src/mage/sets/fifthedition/KrovikanFetish.java index b0737e4e546..ecf2cda9de2 100644 --- a/Mage.Sets/src/mage/sets/fifthedition/KrovikanFetish.java +++ b/Mage.Sets/src/mage/sets/fifthedition/KrovikanFetish.java @@ -31,7 +31,9 @@ import java.util.UUID; import mage.abilities.Ability; import mage.abilities.common.EntersBattlefieldTriggeredAbility; import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.common.delayed.AtTheBeginOfNextUpkeepDelayedTriggeredAbility; import mage.abilities.effects.common.AttachEffect; +import mage.abilities.effects.common.CreateDelayedTriggeredAbilityEffect; import mage.abilities.effects.common.DrawCardSourceControllerEffect; import mage.abilities.effects.common.continuous.BoostEnchantedEffect; import mage.abilities.keyword.EnchantAbility; @@ -63,7 +65,8 @@ public class KrovikanFetish extends CardImpl { this.addAbility(ability); // When Krovikan Fetish enters the battlefield, draw a card at the beginning of the next turn's upkeep. - this.addAbility(new EntersBattlefieldTriggeredAbility(new DrawCardSourceControllerEffect(1), false)); + this.addAbility(new EntersBattlefieldTriggeredAbility(new CreateDelayedTriggeredAbilityEffect( + new AtTheBeginOfNextUpkeepDelayedTriggeredAbility(new DrawCardSourceControllerEffect(1), Duration.OneUse)), false)); // Enchanted creature gets +1/+1. this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new BoostEnchantedEffect(1, 1, Duration.WhileOnBattlefield))); From 2153d5ccf5330c3978ad8428dabe25a1d7828bfc Mon Sep 17 00:00:00 2001 From: LevelX2 Date: Fri, 30 Oct 2015 00:30:53 +0100 Subject: [PATCH 251/268] * Fixed that for spells cast with flashback values calculated from the paid mana (e.g. Converge) did not work correctly. --- .../abilities/keywords/FlashbackTest.java | 65 +++++++++++----- .../abilities/keyword/FlashbackAbility.java | 76 +++++++------------ 2 files changed, 72 insertions(+), 69 deletions(-) diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/abilities/keywords/FlashbackTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/abilities/keywords/FlashbackTest.java index 52dff9e173a..fe11b32bf84 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/abilities/keywords/FlashbackTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/abilities/keywords/FlashbackTest.java @@ -49,76 +49,103 @@ public class FlashbackTest extends CardTestPlayerBase { addCard(Zone.BATTLEFIELD, playerA, "Island", 2); addCard(Zone.BATTLEFIELD, playerA, "Forest", 5); addCard(Zone.HAND, playerA, "Snapcaster Mage", 1); - + // Destroy all artifacts and enchantments. You gain 2 life for each permanent destroyed this way. addCard(Zone.GRAVEYARD, playerA, "Fracturing Gust"); addCard(Zone.BATTLEFIELD, playerA, "Berserkers' Onslaught", 1); addCard(Zone.BATTLEFIELD, playerB, "Darksteel Citadel", 1); - // When Snapcaster Mage enters the battlefield, target instant or sorcery card in your graveyard gains flashback until end of turn. The flashback cost is equal to its mana cost. castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Snapcaster Mage"); setChoice(playerA, "Fracturing Gust"); activateAbility(1, PhaseStep.POSTCOMBAT_MAIN, playerA, "Flashback {2}{G/W}{G/W}{G/W}"); // now snapcaster mage is died so -13/-13 - setStopAt(1, PhaseStep.END_TURN); execute(); assertPermanentCount(playerA, "Snapcaster Mage", 1); assertGraveyardCount(playerA, "Berserkers' Onslaught", 1); - + assertPermanentCount(playerB, "Darksteel Citadel", 1); - + assertExileCount("Fracturing Gust", 1); } /** * My opponent put Iona on the battlefield using Unburial Rites, but my game * log didn't show me the color he has chosen. - * + * */ @Test public void testUnburialRites() { addCard(Zone.BATTLEFIELD, playerA, "Swamp", 1); addCard(Zone.BATTLEFIELD, playerA, "Plains", 8); // Return target creature card from your graveyard to the battlefield. - // Flashback {3}{W} + // Flashback {3}{W} addCard(Zone.HAND, playerA, "Unburial Rites", 1); // Sorcery - {4}{B} - + // Flying // As Iona, Shield of Emeria enters the battlefield, choose a color. // Your opponents can't cast spells of the chosen color. addCard(Zone.GRAVEYARD, playerA, "Iona, Shield of Emeria"); - + // As Lurebound Scarecrow enters the battlefield, choose a color. - // When you control no permanents of the chosen color, sacrifice Lurebound Scarecrow. + // When you control no permanents of the chosen color, sacrifice Lurebound Scarecrow. addCard(Zone.GRAVEYARD, playerA, "Lurebound Scarecrow"); // Enchantment - {2}{U} addCard(Zone.BATTLEFIELD, playerB, "Mountain", 1); - addCard(Zone.HAND, playerB, "Lightning Bolt", 1); + addCard(Zone.HAND, playerB, "Lightning Bolt", 1); - - castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Unburial Rites", "Iona, Shield of Emeria"); + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Unburial Rites", "Iona, Shield of Emeria"); setChoice(playerA, "Red"); - activateAbility(1, PhaseStep.POSTCOMBAT_MAIN, playerA, "Flashback {3}{W}"); + activateAbility(1, PhaseStep.POSTCOMBAT_MAIN, playerA, "Flashback {3}{W}"); addTarget(playerA, "Lurebound Scarecrow"); setChoice(playerA, "White"); - - castSpell(1, PhaseStep.POSTCOMBAT_MAIN, playerB, "Lightning Bolt", playerA); + + castSpell(1, PhaseStep.POSTCOMBAT_MAIN, playerB, "Lightning Bolt", playerA); setStopAt(1, PhaseStep.END_TURN); execute(); assertPermanentCount(playerA, "Iona, Shield of Emeria", 1); assertPermanentCount(playerA, "Lurebound Scarecrow", 1); - + assertHandCount(playerB, "Lightning Bolt", 1); - + assertExileCount("Unburial Rites", 1); } - + + /** + * + */ + @Test + public void testFlashbackWithConverge() { + addCard(Zone.BATTLEFIELD, playerA, "Island", 1); + addCard(Zone.BATTLEFIELD, playerA, "Mountain", 1); + addCard(Zone.BATTLEFIELD, playerA, "Plains", 2); + addCard(Zone.BATTLEFIELD, playerA, "Swamp", 1); + addCard(Zone.BATTLEFIELD, playerA, "Forest", 1); + addCard(Zone.HAND, playerA, "Snapcaster Mage", 1); + + // Converge - Put a 1/1 white Kor Ally creature token onto the battlefield for each color of mana spent to cast Unified Front. + addCard(Zone.GRAVEYARD, playerA, "Unified Front"); // {3}{W} + + activateManaAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Add {W}"); + // When Snapcaster Mage enters the battlefield, target instant or sorcery card in your graveyard gains flashback until end of turn. The flashback cost is equal to its mana cost. + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Snapcaster Mage"); + setChoice(playerA, "Unified Front"); + + activateAbility(1, PhaseStep.POSTCOMBAT_MAIN, playerA, "Flashback {3}{W}"); + + setStopAt(1, PhaseStep.END_TURN); + execute(); + + assertPermanentCount(playerA, "Snapcaster Mage", 1); + assertPermanentCount(playerA, "Kor Ally", 4); + assertExileCount("Unified Front", 1); + + } } diff --git a/Mage/src/mage/abilities/keyword/FlashbackAbility.java b/Mage/src/mage/abilities/keyword/FlashbackAbility.java index d1f23c4dbd1..b8631af4523 100644 --- a/Mage/src/mage/abilities/keyword/FlashbackAbility.java +++ b/Mage/src/mage/abilities/keyword/FlashbackAbility.java @@ -29,18 +29,12 @@ package mage.abilities.keyword; import java.util.UUID; import mage.abilities.Ability; -import mage.abilities.DelayedTriggeredAbility; import mage.abilities.SpellAbility; import mage.abilities.costs.Cost; -import mage.abilities.costs.VariableCost; -import mage.abilities.costs.mana.VariableManaCost; import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.ReplacementEffectImpl; -import mage.abilities.effects.common.CreateDelayedTriggeredAbilityEffect; -import mage.abilities.effects.common.ExileSourceEffect; import mage.cards.Card; import mage.cards.SplitCard; -import mage.constants.CardType; import mage.constants.Duration; import mage.constants.Outcome; import mage.constants.SpellAbilityType; @@ -54,13 +48,14 @@ import mage.players.Player; /** * 702.32. Flashback * - * 702.32a. Flashback appears on some instants and sorceries. It represents two static abilities: - * one that functions while the card is in a player‘s graveyard and the other that functions - * while the card is on the stack. Flashback [cost] means, "You may cast this card from your - * graveyard by paying [cost] rather than paying its mana cost" and, "If the flashback cost - * was paid, exile this card instead of putting it anywhere else any time it would leave the - * stack." Casting a spell using its flashback ability follows the rules for paying alternative - * costs in rules 601.2b and 601.2e–g. + * 702.32a. Flashback appears on some instants and sorceries. It represents two + * static abilities: one that functions while the card is in a player‘s + * graveyard and the other that functions while the card is on the stack. + * Flashback [cost] means, "You may cast this card from your graveyard by paying + * [cost] rather than paying its mana cost" and, "If the flashback cost was + * paid, exile this card instead of putting it anywhere else any time it would + * leave the stack." Casting a spell using its flashback ability follows the + * rules for paying alternative costs in rules 601.2b and 601.2e–g. * * @author nantuko */ @@ -92,10 +87,10 @@ public class FlashbackAbility extends SpellAbility { if (card != null) { // Flashback can never cast a split card by Fuse, because Fuse only works from hand if (card.isSplitCard()) { - if (((SplitCard)card).getLeftHalfCard().getName().equals(abilityName)) { - return ((SplitCard)card).getLeftHalfCard().getSpellAbility().canActivate(playerId, game); - } else if (((SplitCard)card).getRightHalfCard().getName().equals(abilityName)) { - return ((SplitCard)card).getRightHalfCard().getSpellAbility().canActivate(playerId, game); + if (((SplitCard) card).getLeftHalfCard().getName().equals(abilityName)) { + return ((SplitCard) card).getLeftHalfCard().getSpellAbility().canActivate(playerId, game); + } else if (((SplitCard) card).getRightHalfCard().getName().equals(abilityName)) { + return ((SplitCard) card).getRightHalfCard().getSpellAbility().canActivate(playerId, game); } } return card.getSpellAbility().canActivate(playerId, game); @@ -108,7 +103,7 @@ public class FlashbackAbility extends SpellAbility { public FlashbackAbility copy() { return new FlashbackAbility(this); } - + @Override public String getRule(boolean all) { return this.getRule(); @@ -176,45 +171,26 @@ class FlashbackEffect extends OneShotEffect { Player controller = game.getPlayer(source.getControllerId()); if (controller != null) { SpellAbility spellAbility; - switch(((FlashbackAbility) source).getSpellAbilityType()) { + switch (((FlashbackAbility) source).getSpellAbilityType()) { case SPLIT_LEFT: - spellAbility = ((SplitCard)card).getLeftHalfCard().getSpellAbility(); + spellAbility = ((SplitCard) card).getLeftHalfCard().getSpellAbility(); break; case SPLIT_RIGHT: - spellAbility = ((SplitCard)card).getRightHalfCard().getSpellAbility(); + spellAbility = ((SplitCard) card).getRightHalfCard().getSpellAbility(); break; default: spellAbility = card.getSpellAbility(); } spellAbility.clear(); - // used if flashbacked spell has a {X} cost - int amount = source.getManaCostsToPay().getX(); - if (amount == 0) { - // add variable cost like Discard X cards to get the X value to the spell - // because there is currently no way to set the x value in anotehr way, it's set for the - // x mana value to be known by the spell - for (Cost cost:source.getCosts()) { - if (cost instanceof VariableCost && cost.isPaid()) { - amount = ((VariableCost) cost).getAmount(); - break; - } - } + // set the payed flashback costs to the spell ability so abilities like Converge or calculation of {X} values work + spellAbility.getManaCostsToPay().clear(); + spellAbility.getManaCostsToPay().addAll(source.getManaCostsToPay()); + if (!game.isSimulation()) { + game.informPlayers(controller.getLogName() + " flashbacks " + card.getLogName()); } - if (amount > 0) { - // multiplier must be taken into account because if the base spell has {X}{X} the x value would be wrongly halfed - for (VariableCost variableCost: spellAbility.getManaCostsToPay().getVariableCosts()) { - if (variableCost instanceof VariableManaCost) { - amount = amount * ((VariableManaCost)variableCost).getMultiplier(); - break; - } - } - spellAbility.getManaCostsToPay().setX(amount); - } - if (!game.isSimulation()) - game.informPlayers(new StringBuilder(controller.getLogName()).append(" flashbacks ").append(card.getName()).toString()); spellAbility.setCostModificationActive(false); // prevents to apply cost modification twice for flashbacked spells - if (controller.cast(spellAbility, game, true)) { + if (controller.cast(spellAbility, game, false)) { game.addEffect(new FlashbackReplacementEffect(), source); return true; } @@ -252,7 +228,7 @@ class FlashbackReplacementEffect extends ReplacementEffectImpl { if (controller != null) { Card card = game.getCard(event.getTargetId()); if (card != null) { - return controller.moveCardToExileWithInfo(card, null, "", source.getSourceId(), game, game.getState().getZone(card.getId()), true); + return controller.moveCards(card, Zone.EXILED, source, game); } } return false; @@ -265,8 +241,8 @@ class FlashbackReplacementEffect extends ReplacementEffectImpl { @Override public boolean applies(GameEvent event, Ability source, Game game) { - return event.getTargetId().equals(source.getSourceId()) - && ((ZoneChangeEvent)event).getFromZone() == Zone.STACK - && ((ZoneChangeEvent)event).getToZone() != Zone.EXILED; + return event.getTargetId().equals(source.getSourceId()) + && ((ZoneChangeEvent) event).getFromZone() == Zone.STACK + && ((ZoneChangeEvent) event).getToZone() != Zone.EXILED; } } From 66733ba2606706652faf89418f2d0e1bfcf362a5 Mon Sep 17 00:00:00 2001 From: Plopman <> Date: Fri, 30 Oct 2015 20:03:22 +0100 Subject: [PATCH 252/268] Fixed MWSDeckImporter to import deck when other setCode is used. (e.g. R instead of 3ED) --- Mage/src/mage/cards/decks/importer/MWSDeckImporter.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Mage/src/mage/cards/decks/importer/MWSDeckImporter.java b/Mage/src/mage/cards/decks/importer/MWSDeckImporter.java index f8bb97629ae..7ee643ff02a 100644 --- a/Mage/src/mage/cards/decks/importer/MWSDeckImporter.java +++ b/Mage/src/mage/cards/decks/importer/MWSDeckImporter.java @@ -73,7 +73,8 @@ public class MWSDeckImporter extends DeckImporter { if (!cards.isEmpty()) { cardInfo = cards.get(new Random().nextInt(cards.size())); } - } else { + } + if (cardInfo == null) { cardInfo = CardRepository.instance.findPreferedCoreExpansionCard(lineName, true); } From e0c1492f884a76c4288e6003c602e63fdab57ab3 Mon Sep 17 00:00:00 2001 From: LevelX2 Date: Fri, 30 Oct 2015 22:34:42 +0100 Subject: [PATCH 253/268] * Fixed a problem that the AI was locked if a attack fee has to be paid but the AI was not able to pay the costs. --- .../src/mage/player/ai/ComputerPlayer6.java | 3 ++- .../src/mage/sets/conspiracy/GrenzoDungeonWarden.java | 4 ++-- .../src/mage/sets/divinevsdemonic/FaithsFetters.java | 2 +- .../test/AI/basic/PreventRepeatedActionsTest.java | 11 ++++++++--- Mage/src/mage/players/Library.java | 11 +++++++++++ 5 files changed, 24 insertions(+), 7 deletions(-) diff --git a/Mage.Server.Plugins/Mage.Player.AI.MA/src/mage/player/ai/ComputerPlayer6.java b/Mage.Server.Plugins/Mage.Player.AI.MA/src/mage/player/ai/ComputerPlayer6.java index 022e7f9ee30..128c502cc63 100644 --- a/Mage.Server.Plugins/Mage.Player.AI.MA/src/mage/player/ai/ComputerPlayer6.java +++ b/Mage.Server.Plugins/Mage.Player.AI.MA/src/mage/player/ai/ComputerPlayer6.java @@ -1193,7 +1193,8 @@ public class ComputerPlayer6 extends ComputerPlayer /*implements Player*/ { safeToAttack = false; } if (safeToAttack) { - attackingPlayer.declareAttacker(attacker.getId(), defenderId, game, false); + // undo has to be possible e.g. if not able to pay a attack fee (e.g. Ghostly Prison) + attackingPlayer.declareAttacker(attacker.getId(), defenderId, game, true); } } } diff --git a/Mage.Sets/src/mage/sets/conspiracy/GrenzoDungeonWarden.java b/Mage.Sets/src/mage/sets/conspiracy/GrenzoDungeonWarden.java index 855d62758c7..ddc3e84d5a7 100644 --- a/Mage.Sets/src/mage/sets/conspiracy/GrenzoDungeonWarden.java +++ b/Mage.Sets/src/mage/sets/conspiracy/GrenzoDungeonWarden.java @@ -100,9 +100,9 @@ class GrenzoDungeonWardenEffect extends OneShotEffect { Player controller = game.getPlayer(source.getControllerId()); if (controller != null) { if (controller.getLibrary().size() > 0) { - Card card = controller.getLibrary().removeFromBottom(game); + Card card = controller.getLibrary().getFromBottom(game); if (card != null) { - controller.moveCards(card, Zone.LIBRARY, Zone.GRAVEYARD, source, game); + controller.moveCards(card, Zone.GRAVEYARD, source, game); if (card.getCardType().contains(CardType.CREATURE)) { Permanent sourcePermanent = game.getPermanentOrLKIBattlefield(source.getSourceId()); if (sourcePermanent != null && card.getPower().getValue() <= sourcePermanent.getPower().getValue()) { diff --git a/Mage.Sets/src/mage/sets/divinevsdemonic/FaithsFetters.java b/Mage.Sets/src/mage/sets/divinevsdemonic/FaithsFetters.java index e586bbed0c7..d386108be97 100644 --- a/Mage.Sets/src/mage/sets/divinevsdemonic/FaithsFetters.java +++ b/Mage.Sets/src/mage/sets/divinevsdemonic/FaithsFetters.java @@ -71,7 +71,7 @@ public class FaithsFetters extends CardImpl { // When Faith's Fetters enters the battlefield, you gain 4 life. this.addAbility(new EntersBattlefieldTriggeredAbility(new GainLifeEffect(4))); - // Enchanted permanent can't attack or block, and its activated abilities can't be activated unless they're mana abilities. + // Enchanted permanent's activated abilities can't be activated unless they're mana abilities. If enchanted permanent is a creature, it can't attack or block. Effect effect = new CantAttackBlockAttachedEffect(AttachmentType.AURA); effect.setText("Enchanted permanent can't attack or block,"); ability = new SimpleStaticAbility(Zone.BATTLEFIELD, effect); diff --git a/Mage.Tests/src/test/java/org/mage/test/AI/basic/PreventRepeatedActionsTest.java b/Mage.Tests/src/test/java/org/mage/test/AI/basic/PreventRepeatedActionsTest.java index 1a6259d8e10..45e99f0806b 100644 --- a/Mage.Tests/src/test/java/org/mage/test/AI/basic/PreventRepeatedActionsTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/AI/basic/PreventRepeatedActionsTest.java @@ -73,15 +73,20 @@ public class PreventRepeatedActionsTest extends CardTestPlayerBaseAI { */ @Test public void testBasaltMonolith() { + addCard(Zone.HAND, playerA, "Phyrexian Vault", 1); + addCard(Zone.BATTLEFIELD, playerA, "Plains", 3); // Basalt Monolith doesn't untap during your untap step. // {T}: Add {3} to your mana pool. // {3}: Untap Basalt Monolith. - addCard(Zone.BATTLEFIELD, playerA, "Basalt Monolith", 1); + addCard(Zone.BATTLEFIELD, playerA, "Basalt Monolith", 1, true); - setStopAt(1, PhaseStep.END_TURN); + setStopAt(5, PhaseStep.END_TURN); execute(); - assertTapped("Basalt Monolith", false); + // {2}, {T}, Sacrifice a creature: Draw a card. + assertPermanentCount(playerA, "Phyrexian Vault", 1); + assertTapped("Basalt Monolith", true); + assertTappedCount("Plains", false, 3); } /** diff --git a/Mage/src/mage/players/Library.java b/Mage/src/mage/players/Library.java index ec7cfc1942a..1b72dd544a3 100644 --- a/Mage/src/mage/players/Library.java +++ b/Mage/src/mage/players/Library.java @@ -128,6 +128,17 @@ public class Library implements Serializable { return game.getCard(library.peekFirst()); } + /** + * Returns the bottommost card of the Library without removing it + * + * @param game + * @return Card + * @see Card + */ + public Card getFromBottom(Game game) { + return game.getCard(library.pollLast()); + } + public void putOnTop(Card card, Game game) { if (card.getOwnerId().equals(playerId)) { card.setZone(Zone.LIBRARY, game); From 03ad44a0e31b8924fbae14694733d07368859c70 Mon Sep 17 00:00:00 2001 From: LevelX2 Date: Fri, 30 Oct 2015 22:47:26 +0100 Subject: [PATCH 254/268] * Shifting Sliver - Fixed that the "Can't be blocked" ability was applied to non slivers instead of Slivers. --- Mage.Sets/src/mage/sets/legions/ShiftingSliver.java | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/Mage.Sets/src/mage/sets/legions/ShiftingSliver.java b/Mage.Sets/src/mage/sets/legions/ShiftingSliver.java index 656caafaa53..98d27b84b80 100644 --- a/Mage.Sets/src/mage/sets/legions/ShiftingSliver.java +++ b/Mage.Sets/src/mage/sets/legions/ShiftingSliver.java @@ -29,10 +29,8 @@ package mage.sets.legions; import java.util.UUID; import mage.MageInt; -import mage.abilities.Ability; import mage.abilities.common.SimpleStaticAbility; import mage.abilities.effects.common.combat.CantBeBlockedByCreaturesAllEffect; -import mage.abilities.effects.common.continuous.GainAbilityAllEffect; import mage.cards.CardImpl; import mage.constants.CardType; import mage.constants.Duration; @@ -47,12 +45,12 @@ import mage.filter.predicate.mageobject.SubtypePredicate; * @author cbt33 */ public class ShiftingSliver extends CardImpl { - + private static final FilterCreaturePermanent filterCreatures = new FilterCreaturePermanent("Slivers"); private static final FilterCreaturePermanent filterBlockedBy = new FilterCreaturePermanent("except by Slivers"); - + static { - filterCreatures.add(Predicates.not(new SubtypePredicate("Sliver"))); + filterCreatures.add(new SubtypePredicate("Sliver")); filterBlockedBy.add(Predicates.not(new SubtypePredicate("Sliver"))); } From f3184bb6c837dc66bdfbbf9706139eba3e6dbae0 Mon Sep 17 00:00:00 2001 From: LevelX2 Date: Fri, 30 Oct 2015 23:24:33 +0100 Subject: [PATCH 255/268] * Fixed that for a manifested morph creature of the opponent the tooltip for a morph creature instead a manifested creature was shown. --- Mage.Common/src/mage/view/PermanentView.java | 85 ++++++++++---------- 1 file changed, 43 insertions(+), 42 deletions(-) diff --git a/Mage.Common/src/mage/view/PermanentView.java b/Mage.Common/src/mage/view/PermanentView.java index 2b7fe476f00..9ec311a269d 100644 --- a/Mage.Common/src/mage/view/PermanentView.java +++ b/Mage.Common/src/mage/view/PermanentView.java @@ -1,31 +1,30 @@ /* -* Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. -* -* Redistribution and use in source and binary forms, with or without modification, are -* permitted provided that the following conditions are met: -* -* 1. Redistributions of source code must retain the above copyright notice, this list of -* conditions and the following disclaimer. -* -* 2. Redistributions in binary form must reproduce the above copyright notice, this list -* of conditions and the following disclaimer in the documentation and/or other materials -* provided with the distribution. -* -* THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED -* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND -* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR -* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR -* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON -* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING -* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF -* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -* -* The views and conclusions contained in the software and documentation are those of the -* authors and should not be interpreted as representing official policies, either expressed -* or implied, of BetaSteward_at_googlemail.com. -*/ - + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ package mage.view; import java.util.ArrayList; @@ -44,6 +43,7 @@ import mage.players.Player; * @author BetaSteward_at_googlemail.com */ public class PermanentView extends CardView { + private static final long serialVersionUID = 1L; private boolean tapped; @@ -78,7 +78,7 @@ public class PermanentView extends CardView { } this.attachedTo = permanent.getAttachedTo(); if (isToken()) { - original = new CardView(((PermanentToken)permanent).getToken()); + original = new CardView(((PermanentToken) permanent).getToken()); original.expansionSetCode = permanent.getExpansionSetCode(); tokenSetCode = original.getTokenSetCode(); } else { @@ -98,7 +98,7 @@ public class PermanentView extends CardView { this.alternateName = permanent.getFlipCardName(); this.originalName = this.getName(); } else { - if (controlled // controller may always know + if (controlled // controller may always know || (!morphed && !manifested)) { // others don't know for morph or transformed cards this.alternateName = original.getName(); this.originalName = this.getName(); @@ -113,11 +113,11 @@ public class PermanentView extends CardView { this.nameOwner = ""; } } else { - this.nameOwner = ""; + this.nameOwner = ""; } - + if (permanent.isFaceDown(game) && card != null) { - if (controlled){ + if (controlled) { // must be a morphed or manifested card for (Ability permanentAbility : permanent.getAbilities()) { if (permanentAbility instanceof TurnFaceUpAbility && !permanentAbility.getRuleVisible()) { @@ -131,17 +131,17 @@ public class PermanentView extends CardView { this.displayName = card.getName(); this.expansionSetCode = card.getExpansionSetCode(); this.cardNumber = card.getCardNumber(); - } else{ - if (permanent.isMorphed()) { - this.rules.add("If the controller has priority, he or she may turn this permanent face up." + - " This is a special action; it doesn’t use the stack. To do this he or she pays the morph costs," + - " then turns this permanent face up."); - }else if (permanent.isManifested()) { - this.rules.add("A manifested creature card can be turned face up any time for it's mana cost." + - " A face-down card can also be turned face up for its morph cost."); + } else { + if (permanent.isManifested()) { + this.rules.add("A manifested creature card can be turned face up any time for it's mana cost." + + " A face-down card can also be turned face up for its morph cost."); + } else if (permanent.isMorphed()) { + this.rules.add("If the controller has priority, he or she may turn this permanent face up." + + " This is a special action; it doesn’t use the stack. To do this he or she pays the morph costs," + + " then turns this permanent face up."); } } - } + } // determines if shown in it's own column if (permanent.getAttachedTo() != null) { attachedToPermanent = game.getPermanent(permanent.getAttachedTo()) != null; @@ -170,7 +170,7 @@ public class PermanentView extends CardView { return phasedIn; } - public boolean hasSummoningSickness(){ + public boolean hasSummoningSickness() { return summoningSickness; } @@ -209,6 +209,7 @@ public class PermanentView extends CardView { public boolean isMorphed() { return morphed; } + public boolean isManifested() { return manifested; } From b3deb7bedd8550a0af29b7b86b632ce3786d4f4e Mon Sep 17 00:00:00 2001 From: LevelX2 Date: Fri, 30 Oct 2015 23:33:20 +0100 Subject: [PATCH 256/268] * Void Winnower - Fixed that {X} costs of spells were not taken into account for the can't cast spells ability. --- Mage.Sets/src/mage/sets/battleforzendikar/VoidWinnower.java | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/Mage.Sets/src/mage/sets/battleforzendikar/VoidWinnower.java b/Mage.Sets/src/mage/sets/battleforzendikar/VoidWinnower.java index f76974193ac..0a15ab9ecf8 100644 --- a/Mage.Sets/src/mage/sets/battleforzendikar/VoidWinnower.java +++ b/Mage.Sets/src/mage/sets/battleforzendikar/VoidWinnower.java @@ -44,6 +44,7 @@ import mage.game.Game; import mage.game.events.GameEvent; import mage.game.events.GameEvent.EventType; import mage.game.permanent.Permanent; +import mage.game.stack.Spell; /** * @@ -115,9 +116,9 @@ class VoidWinnowerCantCastEffect extends ContinuousRuleModifyingEffectImpl { public boolean applies(GameEvent event, Ability source, Game game) { if (game.getOpponents(source.getControllerId()).contains(event.getPlayerId())) { MageObject object = game.getObject(event.getSourceId()); - if (object != null) { + if (object != null && (object instanceof Spell)) { // the low bit will always be set on an odd number. - return (object.getManaCost().convertedManaCost() & 1) == 0; + return (((Spell) object).getConvertedManaCost() & 1) == 0; } } return false; From 3beb5568c4a195b7357a2013e5716c53ef4555ab Mon Sep 17 00:00:00 2001 From: LevelX2 Date: Sat, 31 Oct 2015 00:55:12 +0100 Subject: [PATCH 257/268] * Karn Liberated - Fixed that commanders were not returned to command zone after game reset. --- .../mage/sets/newphyrexia/KarnLiberated.java | 30 ++++++++++++------- .../commander/duel/CastBRGCommanderTest.java | 27 +++++++++++++++++ .../common/ExileFromZoneTargetEffect.java | 13 +++----- Mage/src/mage/game/GameImpl.java | 3 +- 4 files changed, 53 insertions(+), 20 deletions(-) diff --git a/Mage.Sets/src/mage/sets/newphyrexia/KarnLiberated.java b/Mage.Sets/src/mage/sets/newphyrexia/KarnLiberated.java index e51d4c7d16e..468537a4201 100644 --- a/Mage.Sets/src/mage/sets/newphyrexia/KarnLiberated.java +++ b/Mage.Sets/src/mage/sets/newphyrexia/KarnLiberated.java @@ -139,12 +139,17 @@ class KarnLiberatedEffect extends OneShotEffect { if (card.getOwnerId().equals(player.getId()) && !card.isCopy() // no copies && !player.getSideboard().contains(card.getId()) && !cards.contains(card)) { // not the exiled cards - player.getLibrary().putOnTop(card, game); + if (card.getId().equals(player.getCommanderId())) { + card.moveToZone(Zone.COMMAND, null, game, true); + } else { + player.getLibrary().putOnTop(card, game); + } } } player.init(game); } for (Card card : cards) { + game.getState().setZone(card.getId(), Zone.EXILED); if (CardUtil.isPermanentCard(card) && !card.getSubtype().contains("Aura")) { game.getExile().add(exileId, sourceObject.getIdName(), card); } @@ -209,16 +214,21 @@ class KarnLiberatedDelayedEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { - ExileZone exile = game.getExile().getExileZone(exileId); - if (exile != null) { - Cards cards = new CardsImpl(); // needed because putOntoTheBattlefield removes from exile - cards.addAll(exile); - for (Card card : cards.getCards(game)) { - card.putOntoBattlefield(game, Zone.EXILED, source.getSourceId(), source.getControllerId()); - Permanent permanent = game.getPermanent(card.getId()); - ((PermanentImpl) permanent).removeSummoningSickness(); + Player controller = game.getPlayer(source.getControllerId()); + if (controller != null) { + ExileZone exile = game.getExile().getExileZone(exileId); + if (exile != null) { + // Creatures put onto the battlefield due to Karn's ability will have been under their controller's control continuously + // since the beginning of the first turn. They can attack and their activated abilities with {T} in the cost can be activated. + Cards cards = new CardsImpl(); // needed because putOntoTheBattlefield removes from exile + cards.addAll(exile); + controller.moveCards(cards, Zone.BATTLEFIELD, source, game); + for (Card card : cards.getCards(game)) { + Permanent permanent = game.getPermanent(card.getId()); + ((PermanentImpl) permanent).removeSummoningSickness(); + } + return true; } - return true; } return false; } diff --git a/Mage.Tests/src/test/java/org/mage/test/commander/duel/CastBRGCommanderTest.java b/Mage.Tests/src/test/java/org/mage/test/commander/duel/CastBRGCommanderTest.java index b7732e593b4..12dc632f2f3 100644 --- a/Mage.Tests/src/test/java/org/mage/test/commander/duel/CastBRGCommanderTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/commander/duel/CastBRGCommanderTest.java @@ -69,4 +69,31 @@ public class CastBRGCommanderTest extends CardTestCommanderDuelBase { } + /** + * Activating Karn Liberated 's ultimate in an edh game (human OR ai) causes + * all the command zones to lose their generals upon the new game restart + */ + @Test + public void castCommanderAfterKarnUltimate() { + // +4: Target player exiles a card from his or her hand. + // -3: Exile target permanent. + // -14: Restart the game, leaving in exile all non-Aura permanent cards exiled with Karn Liberated. Then put those cards onto the battlefield under your control. + addCard(Zone.BATTLEFIELD, playerA, "Karn Liberated", 1); + addCard(Zone.HAND, playerA, "Silvercoat Lion", 2); + + activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "+4: Target player", playerA); + addTarget(playerA, "Silvercoat Lion"); + activateAbility(3, PhaseStep.PRECOMBAT_MAIN, playerA, "+4: Target player", playerA); + addTarget(playerA, "Silvercoat Lion"); + activateAbility(5, PhaseStep.PRECOMBAT_MAIN, playerA, "-14: Restart"); + + setStopAt(5, PhaseStep.BEGIN_COMBAT); + execute(); + + assertGraveyardCount(playerA, "Karn Liberated", 0); + assertPermanentCount(playerA, "Silvercoat Lion", 2); + assertCommandZoneCount(playerA, "Prossh, Skyraider of Kher", 1); + assertCommandZoneCount(playerB, "Ob Nixilis of the Black Oath", 1); + + } } diff --git a/Mage/src/mage/abilities/effects/common/ExileFromZoneTargetEffect.java b/Mage/src/mage/abilities/effects/common/ExileFromZoneTargetEffect.java index 654c49ea41e..97ecc487a04 100644 --- a/Mage/src/mage/abilities/effects/common/ExileFromZoneTargetEffect.java +++ b/Mage/src/mage/abilities/effects/common/ExileFromZoneTargetEffect.java @@ -30,7 +30,7 @@ package mage.abilities.effects.common; import java.util.UUID; import mage.abilities.Ability; import mage.abilities.effects.OneShotEffect; -import mage.cards.Card; +import mage.cards.CardsImpl; import mage.constants.Outcome; import mage.constants.Zone; import mage.filter.FilterCard; @@ -91,16 +91,11 @@ public class ExileFromZoneTargetEffect extends OneShotEffect { default: } if (target != null && target.canChoose(source.getSourceId(), player.getId(), game)) { - if (target.choose(Outcome.Exile, player.getId(), source.getSourceId(), game)) { - for (UUID cardId : target.getTargets()) { - Card card = game.getCard(cardId); - if (card != null) { - card.moveToExile(exileId, exileName, source.getSourceId(), game); - } - } - return true; + if (target.chooseTarget(Outcome.Exile, player.getId(), source, game)) { + player.moveCardsToExile(new CardsImpl(target.getTargets()).getCards(game), source, game, true, exileId, exileName); } } + return true; } return false; } diff --git a/Mage/src/mage/game/GameImpl.java b/Mage/src/mage/game/GameImpl.java index ba89c05297f..6edfd87c44b 100644 --- a/Mage/src/mage/game/GameImpl.java +++ b/Mage/src/mage/game/GameImpl.java @@ -671,7 +671,8 @@ public abstract class GameImpl implements Game, Serializable { } @Override - public void removeBookmark(int bookmark) { + public void removeBookmark(int bookmark + ) { if (!simulation) { if (bookmark != 0) { while (savedStates.size() > bookmark) { From 452fd481b4a0653466eba1c06edc75183871f861 Mon Sep 17 00:00:00 2001 From: LevelX2 Date: Sat, 31 Oct 2015 10:23:48 +0100 Subject: [PATCH 258/268] * Sapling of Colfenor - Fixed that the card did not stay on top of library if it was no creature card. --- .../mage/sets/eventide/SaplingOfColfenor.java | 29 ++++++++++--------- 1 file changed, 16 insertions(+), 13 deletions(-) diff --git a/Mage.Sets/src/mage/sets/eventide/SaplingOfColfenor.java b/Mage.Sets/src/mage/sets/eventide/SaplingOfColfenor.java index d91784affe7..1d7f50f456c 100644 --- a/Mage.Sets/src/mage/sets/eventide/SaplingOfColfenor.java +++ b/Mage.Sets/src/mage/sets/eventide/SaplingOfColfenor.java @@ -29,6 +29,7 @@ package mage.sets.eventide; import java.util.UUID; import mage.MageInt; +import mage.MageObject; import mage.abilities.Ability; import mage.abilities.common.AttacksTriggeredAbility; import mage.abilities.effects.OneShotEffect; @@ -80,11 +81,9 @@ public class SaplingOfColfenor extends CardImpl { } class SaplingOfColfenorEffect extends OneShotEffect { - - Cards cards = new CardsImpl(); public SaplingOfColfenorEffect() { - super(Outcome.GainLife); + super(Outcome.Benefit); this.staticText = "reveal the top card of your library. If it's a creature card, you gain life equal to that card's toughness, lose life equal to its power, then put it into your hand"; } @@ -99,17 +98,21 @@ class SaplingOfColfenorEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { - Player you = game.getPlayer(source.getControllerId()); - if (you != null && you.getLibrary().size() > 0) { - Card card = you.getLibrary().removeFromTop(game); - cards.add(card); - you.revealCards("Sapling of Colfenor", cards, game); - if (card.getCardType().contains(CardType.CREATURE)) { - you.gainLife(card.getToughness().getValue(), game); - you.loseLife(card.getPower().getValue(), game); - return card.moveToZone(Zone.HAND, source.getSourceId(), game, false); + Player controller = game.getPlayer(source.getControllerId()); + MageObject sourceObject = source.getSourceObject(game); + if (controller != null && sourceObject != null) { + if (controller.getLibrary().size() > 0) { + Card card = controller.getLibrary().getFromTop(game); + Cards cards = new CardsImpl(card); + controller.revealCards(sourceObject.getIdName(), cards, game); + if (card.getCardType().contains(CardType.CREATURE)) { + controller.gainLife(card.getToughness().getValue(), game); + controller.loseLife(card.getPower().getValue(), game); + return controller.moveCards(cards.getCards(game), Zone.HAND, source, game); + } } + return true; } return false; } -} \ No newline at end of file +} From 2e49a74aab68119735ef747335b854d2ba4d7522 Mon Sep 17 00:00:00 2001 From: LevelX2 Date: Sat, 31 Oct 2015 10:32:45 +0100 Subject: [PATCH 259/268] * Fixed test with Flashback and converge. --- .../org/mage/test/cards/abilities/keywords/FlashbackTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/abilities/keywords/FlashbackTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/abilities/keywords/FlashbackTest.java index fe11b32bf84..33e68b79c9b 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/abilities/keywords/FlashbackTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/abilities/keywords/FlashbackTest.java @@ -133,7 +133,7 @@ public class FlashbackTest extends CardTestPlayerBase { // Converge - Put a 1/1 white Kor Ally creature token onto the battlefield for each color of mana spent to cast Unified Front. addCard(Zone.GRAVEYARD, playerA, "Unified Front"); // {3}{W} - activateManaAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Add {W}"); + activateManaAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "{T}: Add {W}"); // When Snapcaster Mage enters the battlefield, target instant or sorcery card in your graveyard gains flashback until end of turn. The flashback cost is equal to its mana cost. castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Snapcaster Mage"); setChoice(playerA, "Unified Front"); From e88c60eb85ee1f8ee71be65dd8ca164299f12619 Mon Sep 17 00:00:00 2001 From: LevelX2 Date: Sat, 31 Oct 2015 10:33:37 +0100 Subject: [PATCH 260/268] * Scroll Rack - Fixed that the cards were shown face down if setting the order they go to library. --- Mage.Common/src/mage/remote/SessionImpl.java | 4 +--- Mage.Common/src/mage/view/CardView.java | 2 +- .../src/main/java/mage/server/game/GameController.java | 7 +++++-- Mage.Sets/src/mage/sets/tempest/ScrollRack.java | 7 +------ 4 files changed, 8 insertions(+), 12 deletions(-) diff --git a/Mage.Common/src/mage/remote/SessionImpl.java b/Mage.Common/src/mage/remote/SessionImpl.java index 8017868ba74..3b4036d4c26 100644 --- a/Mage.Common/src/mage/remote/SessionImpl.java +++ b/Mage.Common/src/mage/remote/SessionImpl.java @@ -468,9 +468,7 @@ public class SessionImpl implements Session { @Override public void handleConnectionException(Throwable throwable, Client client) { - logger.info("connection to server lost - " + throwable.getMessage()); - throwable.printStackTrace(); - + logger.info("connection to server lost - " + throwable.getMessage(), throwable); reconnect(throwable); } } diff --git a/Mage.Common/src/mage/view/CardView.java b/Mage.Common/src/mage/view/CardView.java index 008f6cd0b46..7216ba5c499 100644 --- a/Mage.Common/src/mage/view/CardView.java +++ b/Mage.Common/src/mage/view/CardView.java @@ -153,7 +153,7 @@ public class CardView extends SimpleCardView { * for morph / face down cards to know which player may see information for * the card * @param showFaceDownCard if true and the card is not on the battelfield, - * also a face down card is shown in the view down cards will be shown + * also a face down card is shown in the view, face down cards will be shown */ public CardView(Card card, Game game, boolean controlled, boolean showFaceDownCard) { super(card.getId(), card.getExpansionSetCode(), card.getCardNumber(), card.getUsesVariousArt(), card.getTokenSetCode(), game != null); diff --git a/Mage.Server/src/main/java/mage/server/game/GameController.java b/Mage.Server/src/main/java/mage/server/game/GameController.java index eec4ea0dfe7..07a5763a51a 100644 --- a/Mage.Server/src/main/java/mage/server/game/GameController.java +++ b/Mage.Server/src/main/java/mage/server/game/GameController.java @@ -825,8 +825,11 @@ public class GameController implements GameCallback { @Override public void execute(UUID playerId) { if (cards != null) { - Zone targetZone = (Zone) options.get("targetZone"); - boolean showFaceDown = targetZone != null && targetZone.equals(Zone.PICK); + // Zone targetZone = (Zone) options.get("targetZone"); + // Are there really situations where a player selects from a list of face down cards? + // So always show face up for selection + // boolean showFaceDown = targetZone != null && targetZone.equals(Zone.PICK); + boolean showFaceDown = true; getGameSession(playerId).target(question, new CardsView(game, cards.getCards(game), showFaceDown), targets, required, options); } else if (perms != null) { CardsView permsView = new CardsView(); diff --git a/Mage.Sets/src/mage/sets/tempest/ScrollRack.java b/Mage.Sets/src/mage/sets/tempest/ScrollRack.java index db4100fe0e7..6e792063af6 100644 --- a/Mage.Sets/src/mage/sets/tempest/ScrollRack.java +++ b/Mage.Sets/src/mage/sets/tempest/ScrollRack.java @@ -27,7 +27,6 @@ */ package mage.sets.tempest; -import java.util.Set; import java.util.UUID; import mage.MageObject; import mage.abilities.Ability; @@ -111,11 +110,7 @@ class ScrollRackEffect extends OneShotEffect { } // Put that many cards from the top of your library into your hand. if (amountExiled > 0) { - Set cards = controller.getLibrary().getTopCards(game, amountExiled); - for (Card card : cards) { - card.setFaceDown(true, game); - } - controller.moveCards(cards, null, Zone.HAND, source, game); + controller.moveCards(controller.getLibrary().getTopCards(game, amountExiled), Zone.HAND, source, game); } // Then look at the exiled cards and put them on top of your library in any order controller.putCardsOnTopOfLibrary(game.getExile().getExileZone(source.getSourceId()), game, source, true); From c1d6703e71a714ae91d60a0336ca6308014547f5 Mon Sep 17 00:00:00 2001 From: LevelX2 Date: Sat, 31 Oct 2015 11:34:58 +0100 Subject: [PATCH 261/268] * Howling Mine - Fixed that it did throw an exception if Howling Mine has left the battlefield before its triggered ability resolved. --- .../src/mage/sets/magic2010/HowlingMine.java | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/Mage.Sets/src/mage/sets/magic2010/HowlingMine.java b/Mage.Sets/src/mage/sets/magic2010/HowlingMine.java index 5ec15b0a5a3..2499010036b 100644 --- a/Mage.Sets/src/mage/sets/magic2010/HowlingMine.java +++ b/Mage.Sets/src/mage/sets/magic2010/HowlingMine.java @@ -1,16 +1,16 @@ /* * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. - * + * * Redistribution and use in source and binary forms, with or without modification, are * permitted provided that the following conditions are met: - * + * * 1. Redistributions of source code must retain the above copyright notice, this list of * conditions and the following disclaimer. - * + * * 2. Redistributions in binary form must reproduce the above copyright notice, this list * of conditions and the following disclaimer in the documentation and/or other materials * provided with the distribution. - * + * * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR @@ -20,12 +20,11 @@ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * + * * The views and conclusions contained in the software and documentation are those of the * authors and should not be interpreted as representing official policies, either expressed * or implied, of BetaSteward_at_googlemail.com. */ - package mage.sets.magic2010; import java.util.UUID; @@ -38,6 +37,7 @@ import mage.constants.Zone; import mage.game.Game; import mage.game.events.GameEvent; import mage.game.events.GameEvent.EventType; +import mage.game.permanent.Permanent; import mage.target.targetpointer.FixedTarget; /** @@ -90,7 +90,8 @@ class HowlingMineAbility extends TriggeredAbilityImpl { @Override public boolean checkInterveningIfClause(Game game) { - return !game.getPermanent(this.sourceId).isTapped(); + Permanent source = game.getPermanentOrLKIBattlefield(this.sourceId); + return source != null && !source.isTapped(); } @Override From a5d7ca83d7ac5e13805bff58f2838384a97beed6 Mon Sep 17 00:00:00 2001 From: LevelX2 Date: Sat, 31 Oct 2015 11:55:20 +0100 Subject: [PATCH 262/268] Checked objects possible to cause null pointer exceptions. Added some logging. --- Mage.Common/src/mage/view/SeatView.java | 7 ++- .../java/mage/server/game/GamesRoomImpl.java | 16 ++--- .../sets/battleforzendikar/BringToLight.java | 11 +++- .../mage/sets/lorwyn/RingsOfBrighthearth.java | 2 +- .../mage/sets/mirrodin/IsochronScepter.java | 25 +++++--- .../QuicksilverGargantuan.java | 63 ++++++++++--------- .../mage/sets/tenthedition/DoublingCube.java | 12 ++-- Mage/src/mage/Mana.java | 2 +- ...tureEntersBattlefieldTriggeredAbility.java | 7 ++- .../predicate/mageobject/ColorPredicate.java | 2 +- Mage/src/mage/game/GameCommanderImpl.java | 8 ++- Mage/src/mage/players/net/UserData.java | 5 +- 12 files changed, 94 insertions(+), 66 deletions(-) diff --git a/Mage.Common/src/mage/view/SeatView.java b/Mage.Common/src/mage/view/SeatView.java index f8f79a397e2..d812dadebd6 100644 --- a/Mage.Common/src/mage/view/SeatView.java +++ b/Mage.Common/src/mage/view/SeatView.java @@ -30,6 +30,7 @@ package mage.view; import java.io.Serializable; import java.util.UUID; import mage.game.Seat; +import mage.players.net.UserData; /** * @@ -48,7 +49,11 @@ public class SeatView implements Serializable { if (seat.getPlayer() != null) { this.playerId = seat.getPlayer().getId(); this.playerName = seat.getPlayer().getName(); - this.flagName = seat.getPlayer().getUserData().getFlagName(); + if (seat.getPlayer().getUserData() == null) { + this.flagName = UserData.getDefaultFlagName(); + } else { + this.flagName = seat.getPlayer().getUserData().getFlagName(); + } } else { // Empty seat this.playerName = ""; diff --git a/Mage.Server/src/main/java/mage/server/game/GamesRoomImpl.java b/Mage.Server/src/main/java/mage/server/game/GamesRoomImpl.java index 63edac13488..9afcea78466 100644 --- a/Mage.Server/src/main/java/mage/server/game/GamesRoomImpl.java +++ b/Mage.Server/src/main/java/mage/server/game/GamesRoomImpl.java @@ -228,13 +228,15 @@ class TableListSorter implements Comparator { @Override public int compare(Table one, Table two) { - if (!one.getState().equals(TableState.SIDEBOARDING) && !one.getState().equals(TableState.DUELING)) { - if (one.getState().compareTo(two.getState()) != 0) { - return one.getState().compareTo(two.getState()); - } - } else if (!two.getState().equals(TableState.SIDEBOARDING) && !two.getState().equals(TableState.DUELING)) { - if (one.getState().compareTo(two.getState()) != 0) { - return one.getState().compareTo(two.getState()); + if (one.getState() != null && two.getState() != null) { + if (!TableState.SIDEBOARDING.equals(one.getState()) && !TableState.DUELING.equals(one.getState())) { + if (one.getState().compareTo(two.getState()) != 0) { + return one.getState().compareTo(two.getState()); + } + } else if (!TableState.SIDEBOARDING.equals(two.getState()) && !TableState.DUELING.equals(two.getState())) { + if (one.getState().compareTo(two.getState()) != 0) { + return one.getState().compareTo(two.getState()); + } } } if (two.getEndTime() != null) { diff --git a/Mage.Sets/src/mage/sets/battleforzendikar/BringToLight.java b/Mage.Sets/src/mage/sets/battleforzendikar/BringToLight.java index 21f64d21c7e..5419dc82641 100644 --- a/Mage.Sets/src/mage/sets/battleforzendikar/BringToLight.java +++ b/Mage.Sets/src/mage/sets/battleforzendikar/BringToLight.java @@ -45,6 +45,7 @@ import mage.filter.predicate.mageobject.ConvertedManaCostPredicate; import mage.game.Game; import mage.players.Player; import mage.target.common.TargetCardInLibrary; +import org.apache.log4j.Logger; /** * @@ -77,7 +78,7 @@ class BringToLightEffect extends OneShotEffect { public BringToLightEffect() { super(Outcome.PlayForFree); this.staticText = "Converge — Search your library for a creature, instant, or sorcery card with converted mana " - + "cost less than or equal to the number of colors of mana spent to cast Bring to Light, exile that card, " + + "cost less than or equal to the number of colors of mana spent to cast {this}, exile that card, " + "then shuffle your library. You may cast that card without paying its mana cost"; } @@ -102,12 +103,16 @@ class BringToLightEffect extends OneShotEffect { controller.searchLibrary(target, game); Card card = controller.getLibrary().getCard(target.getFirstTarget(), game); if (card != null) { - controller.moveCards(card, null, Zone.EXILED, source, game); + controller.moveCards(card, Zone.EXILED, source, game); } controller.shuffleLibrary(game); if (card != null) { if (controller.chooseUse(outcome, "Cast " + card.getName() + " without paying its mana cost?", source, game)) { - controller.cast(card.getSpellAbility(), game, true); + if (card.getSpellAbility() != null) { + controller.cast(card.getSpellAbility(), game, true); + } else { + Logger.getLogger(BringToLightEffect.class).error("Bring to Light: spellAbility == null " + card.getName()); + } } } return true; diff --git a/Mage.Sets/src/mage/sets/lorwyn/RingsOfBrighthearth.java b/Mage.Sets/src/mage/sets/lorwyn/RingsOfBrighthearth.java index 4bf012e1bbb..8793c91e928 100644 --- a/Mage.Sets/src/mage/sets/lorwyn/RingsOfBrighthearth.java +++ b/Mage.Sets/src/mage/sets/lorwyn/RingsOfBrighthearth.java @@ -94,7 +94,7 @@ class RingsOfBrighthearthTriggeredAbility extends TriggeredAbilityImpl { public boolean checkTrigger(GameEvent event, Game game) { if (event.getPlayerId().equals(getControllerId())) { StackAbility stackAbility = (StackAbility) game.getStack().getStackObject(event.getSourceId()); - if (!(stackAbility.getStackAbility() instanceof ManaAbility)) { + if (stackAbility != null && !(stackAbility.getStackAbility() instanceof ManaAbility)) { Effect effect = this.getEffects().get(0); effect.setValue("stackAbility", stackAbility.getStackAbility()); return true; diff --git a/Mage.Sets/src/mage/sets/mirrodin/IsochronScepter.java b/Mage.Sets/src/mage/sets/mirrodin/IsochronScepter.java index 182669babf1..e4eb8d30835 100644 --- a/Mage.Sets/src/mage/sets/mirrodin/IsochronScepter.java +++ b/Mage.Sets/src/mage/sets/mirrodin/IsochronScepter.java @@ -28,11 +28,6 @@ package mage.sets.mirrodin; import java.util.UUID; - -import mage.constants.CardType; -import mage.constants.Outcome; -import mage.constants.Rarity; -import mage.constants.Zone; import mage.abilities.Ability; import mage.abilities.common.EntersBattlefieldTriggeredAbility; import mage.abilities.common.SimpleActivatedAbility; @@ -41,6 +36,10 @@ import mage.abilities.costs.mana.GenericManaCost; import mage.abilities.effects.OneShotEffect; import mage.cards.Card; import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.Outcome; +import mage.constants.Rarity; +import mage.constants.Zone; import mage.filter.Filter; import mage.filter.FilterCard; import mage.filter.predicate.mageobject.CardTypePredicate; @@ -50,6 +49,7 @@ import mage.game.permanent.Permanent; import mage.players.Player; import mage.target.TargetCard; import mage.util.CardUtil; +import org.apache.log4j.Logger; /** * @@ -84,7 +84,8 @@ public class IsochronScepter extends CardImpl { class IsochronScepterImprintEffect extends OneShotEffect { private static final FilterCard filter = new FilterCard("instant card with converted mana cost 2 or less from your hand"); - static { + + static { filter.add(new CardTypePredicate(CardType.INSTANT)); filter.add(new ConvertedManaCostPredicate(Filter.ComparisonType.LessThan, 3)); } @@ -109,7 +110,7 @@ class IsochronScepterImprintEffect extends OneShotEffect { && controller.choose(Outcome.Benefit, controller.getHand(), target, game)) { Card card = controller.getHand().get(target.getFirstTarget(), game); if (card != null) { - controller.moveCardToExileWithInfo(card, source.getSourceId(), sourcePermanent.getIdName() +" (Imprint)", source.getSourceId(), game, Zone.HAND, true); + controller.moveCardToExileWithInfo(card, source.getSourceId(), sourcePermanent.getIdName() + " (Imprint)", source.getSourceId(), game, Zone.HAND, true); Permanent permanent = game.getPermanent(source.getSourceId()); if (permanent != null) { permanent.imprint(card.getId(), game); @@ -121,7 +122,7 @@ class IsochronScepterImprintEffect extends OneShotEffect { return true; } return false; - + } @java.lang.Override @@ -158,10 +159,14 @@ class IsochronScepterCopyEffect extends OneShotEffect { if (controller.chooseUse(outcome, new StringBuilder("Create a copy of ").append(imprintedInstant.getName()).append("?").toString(), source, game)) { Card copiedCard = game.copyCard(imprintedInstant, source, source.getControllerId()); if (copiedCard != null) { - game.getExile().add(source.getSourceId(), "",copiedCard); + game.getExile().add(source.getSourceId(), "", copiedCard); game.getState().setZone(copiedCard.getId(), Zone.EXILED); if (controller.chooseUse(outcome, "Cast the copied card without paying mana cost?", source, game)) { - controller.cast(copiedCard.getSpellAbility(), game, true); + if (copiedCard.getSpellAbility() != null) { + controller.cast(copiedCard.getSpellAbility(), game, true); + } else { + Logger.getLogger(IsochronScepterCopyEffect.class).error("Isochron Scepter: spell ability == null " + copiedCard.getName()); + } } } } diff --git a/Mage.Sets/src/mage/sets/scarsofmirrodin/QuicksilverGargantuan.java b/Mage.Sets/src/mage/sets/scarsofmirrodin/QuicksilverGargantuan.java index a02bb9ccda7..2b9c6fb19c1 100644 --- a/Mage.Sets/src/mage/sets/scarsofmirrodin/QuicksilverGargantuan.java +++ b/Mage.Sets/src/mage/sets/scarsofmirrodin/QuicksilverGargantuan.java @@ -25,27 +25,25 @@ * authors and should not be interpreted as representing official policies, either expressed * or implied, of BetaSteward_at_googlemail.com. */ - package mage.sets.scarsofmirrodin; -import mage.constants.CardType; -import mage.constants.Rarity; +import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.EntersBattlefieldAbility; import mage.abilities.effects.ContinuousEffectImpl; import mage.cards.Card; import mage.cards.CardImpl; +import mage.constants.CardType; import mage.constants.Duration; import mage.constants.Layer; import mage.constants.Outcome; +import mage.constants.Rarity; import mage.constants.SubLayer; import mage.game.Game; import mage.game.permanent.Permanent; -import mage.target.common.TargetCreaturePermanent; - -import java.util.UUID; import mage.target.Target; +import mage.target.common.TargetCreaturePermanent; /** * @author ayratn @@ -60,7 +58,7 @@ public class QuicksilverGargantuan extends CardImpl { this.power = new MageInt(7); this.toughness = new MageInt(7); - Ability ability = new EntersBattlefieldAbility(new QuicksilverGargantuanCopyEffect(), + Ability ability = new EntersBattlefieldAbility(new QuicksilverGargantuanCopyEffect(), "You may have {this} enter the battlefield as a copy of any creature on the battlefield, except it's still 7/7"); Target target = new TargetCreaturePermanent(); target.setNotTarget(true); @@ -81,7 +79,7 @@ public class QuicksilverGargantuan extends CardImpl { public QuicksilverGargantuanCopyEffect() { super(Duration.WhileOnBattlefield, Layer.CopyEffects_1, SubLayer.NA, Outcome.BecomeCreature); - staticText = "You may have {this} enter the battlefield as a copy of any creature on the battlefield, except it's still 7/7"; + staticText = "You may have {this} enter the battlefield as a copy of any creature on the battlefield, except it's still 7/7"; } public QuicksilverGargantuanCopyEffect(final QuicksilverGargantuanCopyEffect effect) { @@ -91,30 +89,35 @@ public class QuicksilverGargantuan extends CardImpl { @Override public boolean apply(Game game, Ability source) { Card card = game.getCard(source.getFirstTarget()); - Permanent permanent = game.getPermanent(source.getSourceId()); - permanent.setName(card.getName()); - permanent.getColor(game).setColor(card.getColor(game)); - permanent.getManaCost().clear(); - permanent.getManaCost().add(card.getManaCost()); - permanent.getCardType().clear(); - for (CardType type : card.getCardType()) { - permanent.getCardType().add(type); + Permanent permanent = game.getPermanentEntering(source.getSourceId()); + if (permanent == null) { + permanent = game.getPermanent(source.getSourceId()); } - permanent.getSubtype().clear(); - for (String type : card.getSubtype()) { - permanent.getSubtype().add(type); + if (permanent != null) { + permanent.setName(card.getName()); + permanent.getColor(game).setColor(card.getColor(game)); + permanent.getManaCost().clear(); + permanent.getManaCost().add(card.getManaCost()); + permanent.getCardType().clear(); + for (CardType type : card.getCardType()) { + permanent.getCardType().add(type); + } + permanent.getSubtype().clear(); + for (String type : card.getSubtype()) { + permanent.getSubtype().add(type); + } + permanent.getSupertype().clear(); + for (String type : card.getSupertype()) { + permanent.getSupertype().add(type); + } + permanent.setExpansionSetCode(card.getExpansionSetCode()); + permanent.getAbilities().clear(); + for (Ability ability : card.getAbilities()) { + permanent.addAbility(ability, game); + } + return true; } - permanent.getSupertype().clear(); - for (String type : card.getSupertype()) { - permanent.getSupertype().add(type); - } - permanent.setExpansionSetCode(card.getExpansionSetCode()); - permanent.getAbilities().clear(); - for (Ability ability : card.getAbilities()) { - permanent.addAbility(ability, game); - } - - return true; + return false; } @Override diff --git a/Mage.Sets/src/mage/sets/tenthedition/DoublingCube.java b/Mage.Sets/src/mage/sets/tenthedition/DoublingCube.java index 86c0ba07ee5..99ea557b4ee 100644 --- a/Mage.Sets/src/mage/sets/tenthedition/DoublingCube.java +++ b/Mage.Sets/src/mage/sets/tenthedition/DoublingCube.java @@ -36,7 +36,6 @@ import mage.abilities.effects.common.ManaEffect; import mage.abilities.mana.SimpleManaAbility; import mage.cards.CardImpl; import mage.constants.CardType; -import mage.constants.Outcome; import mage.constants.Rarity; import mage.constants.Zone; import mage.game.Game; @@ -57,7 +56,7 @@ public class DoublingCube extends CardImpl { Ability ability = new SimpleManaAbility(Zone.BATTLEFIELD, new DoublingCubeEffect(), new ManaCostsImpl("{3}")); ability.addCost(new TapSourceCost()); this.addAbility(ability); - + } public DoublingCube(final DoublingCube card) { @@ -83,11 +82,11 @@ class DoublingCubeEffect extends ManaEffect { @Override public boolean apply(Game game, Ability source) { - Player you = game.getPlayer(source.getControllerId()); - if (you == null) { + Player controller = game.getPlayer(source.getControllerId()); + if (controller == null) { return false; } - ManaPool pool = you.getManaPool(); + ManaPool pool = controller.getManaPool(); int blackMana = pool.getBlack(); int whiteMana = pool.getWhite(); int blueMana = pool.getBlue(); @@ -105,10 +104,9 @@ class DoublingCubeEffect extends ManaEffect { return null; } - @Override public DoublingCubeEffect copy() { return new DoublingCubeEffect(this); } - } +} diff --git a/Mage/src/mage/Mana.java b/Mage/src/mage/Mana.java index b9b3e04c8fa..e5dace32df1 100644 --- a/Mage/src/mage/Mana.java +++ b/Mage/src/mage/Mana.java @@ -259,7 +259,7 @@ public class Mana implements Comparable, Serializable, Copyable { @Override public String toString() { - StringBuilder sbMana = threadLocalBuilder.get(); + StringBuilder sbMana = new StringBuilder(); if (colorless > 0) { sbMana.append("{").append(Integer.toString(colorless)).append("}"); } diff --git a/Mage/src/mage/abilities/common/AnotherCreatureEntersBattlefieldTriggeredAbility.java b/Mage/src/mage/abilities/common/AnotherCreatureEntersBattlefieldTriggeredAbility.java index cb67ac5ca14..accd6b22057 100644 --- a/Mage/src/mage/abilities/common/AnotherCreatureEntersBattlefieldTriggeredAbility.java +++ b/Mage/src/mage/abilities/common/AnotherCreatureEntersBattlefieldTriggeredAbility.java @@ -30,8 +30,11 @@ public class AnotherCreatureEntersBattlefieldTriggeredAbility extends TriggeredA @Override public boolean checkTrigger(GameEvent event, Game game) { if (event.getTargetId() != this.getSourceId()) { - Permanent permanent = game.getPermanent(event.getTargetId()); - if (permanent.getCardType().contains(CardType.CREATURE)) { + Permanent permanent = game.getPermanentEntering(event.getTargetId()); + if (permanent == null) { + permanent = game.getPermanent(event.getTargetId()); + } + if (permanent != null && permanent.getCardType().contains(CardType.CREATURE)) { return true; } } diff --git a/Mage/src/mage/filter/predicate/mageobject/ColorPredicate.java b/Mage/src/mage/filter/predicate/mageobject/ColorPredicate.java index 74e5164049d..d6f3ad0a97d 100644 --- a/Mage/src/mage/filter/predicate/mageobject/ColorPredicate.java +++ b/Mage/src/mage/filter/predicate/mageobject/ColorPredicate.java @@ -46,7 +46,7 @@ public class ColorPredicate implements Predicate { @Override public boolean apply(MageObject input, Game game) { - return input.getColor(game).contains(color); + return color != null && input.getColor(game).contains(color); } @Override diff --git a/Mage/src/mage/game/GameCommanderImpl.java b/Mage/src/mage/game/GameCommanderImpl.java index 4181efc3e4c..2d9602d02ac 100644 --- a/Mage/src/mage/game/GameCommanderImpl.java +++ b/Mage/src/mage/game/GameCommanderImpl.java @@ -129,7 +129,9 @@ public abstract class GameCommanderImpl extends GameImpl { if (!mulliganedCards.containsKey(playerId)) { mulliganedCards.put(playerId, new CardsImpl()); } - card.moveToExile(null, "", null, this); + player.getHand().remove(card); + getExile().add(card); + getState().setZone(card.getId(), Zone.EXILED); card.setFaceDown(true, this); mulliganedCards.get(playerId).add(card); } @@ -168,7 +170,9 @@ public abstract class GameCommanderImpl extends GameImpl { if (player != null && mulliganedCards.containsKey(playerId)) { for (Card card : mulliganedCards.get(playerId).getCards(this)) { if (card != null) { - card.moveToZone(Zone.LIBRARY, null, this, false); + getExile().removeCard(card, this); + player.getLibrary().putOnTop(card, this); + getState().setZone(card.getId(), Zone.LIBRARY); card.setFaceDown(false, this); } } diff --git a/Mage/src/mage/players/net/UserData.java b/Mage/src/mage/players/net/UserData.java index 0e6e4017334..c2c3b2a3bb4 100644 --- a/Mage/src/mage/players/net/UserData.java +++ b/Mage/src/mage/players/net/UserData.java @@ -59,7 +59,7 @@ public class UserData implements Serializable { } public static UserData getDefaultUserDataView() { - return new UserData(UserGroup.DEFAULT, 0, false, false, true, null, "world.png", false, true, true, false, false, false); + return new UserData(UserGroup.DEFAULT, 0, false, false, true, null, getDefaultFlagName(), false, true, true, false, false, false); } public void setGroupId(int groupId) { @@ -166,4 +166,7 @@ public class UserData implements Serializable { this.autoOrderTrigger = autoOrderTrigger; } + public static String getDefaultFlagName() { + return "world.png"; + } } From 46ae07be232ca3931bb01b8dc301a20fa1cedd39 Mon Sep 17 00:00:00 2001 From: LevelX2 Date: Sat, 31 Oct 2015 12:30:55 +0100 Subject: [PATCH 263/268] Xmage 1.4.4v12 --- Mage.Common/src/mage/utils/MageVersion.java | 2 +- Mage/src/mage/cards/repository/CardRepository.java | 2 +- Utils/release/getting_implemented_cards.txt | 3 +++ 3 files changed, 5 insertions(+), 2 deletions(-) diff --git a/Mage.Common/src/mage/utils/MageVersion.java b/Mage.Common/src/mage/utils/MageVersion.java index 560f6c74042..35f5462039e 100644 --- a/Mage.Common/src/mage/utils/MageVersion.java +++ b/Mage.Common/src/mage/utils/MageVersion.java @@ -41,7 +41,7 @@ public class MageVersion implements Serializable, Comparable { public final static int MAGE_VERSION_MAJOR = 1; public final static int MAGE_VERSION_MINOR = 4; public final static int MAGE_VERSION_PATCH = 4; - public final static String MAGE_VERSION_MINOR_PATCH = "v11"; + public final static String MAGE_VERSION_MINOR_PATCH = "v12"; public final static String MAGE_VERSION_INFO = ""; private final int major; diff --git a/Mage/src/mage/cards/repository/CardRepository.java b/Mage/src/mage/cards/repository/CardRepository.java index 48fb69dcf39..6e96be70a8d 100644 --- a/Mage/src/mage/cards/repository/CardRepository.java +++ b/Mage/src/mage/cards/repository/CardRepository.java @@ -63,7 +63,7 @@ public enum CardRepository { // raise this if db structure was changed private static final long CARD_DB_VERSION = 42; // raise this if new cards were added to the server - private static final long CARD_CONTENT_VERSION = 41; + private static final long CARD_CONTENT_VERSION = 42; private final Random random = new Random(); private Dao cardDao; diff --git a/Utils/release/getting_implemented_cards.txt b/Utils/release/getting_implemented_cards.txt index bd7cacbd8a5..7be6e490eb5 100644 --- a/Utils/release/getting_implemented_cards.txt +++ b/Utils/release/getting_implemented_cards.txt @@ -39,6 +39,9 @@ git log 8c7dc7b2da3630b6dfec1390854fa2be11631c79..head --diff-filter=A --name-st since 1.4.4.v9 git log 1b71f505064b82893003207fc29954de533fbed5..head --diff-filter=A --name-status | sed -ne "s/^A[^u]Mage.Sets\/src\/mage\/sets\///p" | sort > added_cards.txt +since 1.4.4.v12 +git log a5d7ca83d7ac5e13805bff58f2838384a97beed6..head --diff-filter=A --name-status | sed -ne "s/^A[^u]Mage.Sets\/src\/mage\/sets\///p" | sort > added_cards.txt + 3. Copy added_cards.txt to trunk\Utils folder 4. Run script: > perl extract_in_wiki_format.perl From 93964407d805881fb836440a958ff2f984bf738c Mon Sep 17 00:00:00 2001 From: LevelX2 Date: Sat, 31 Oct 2015 18:00:13 +0100 Subject: [PATCH 264/268] * Annihilating Fire - Added missing watcher for exile ability. --- .../returntoravnica/AnnihilatingFire.java | 23 ++++++++++--------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/Mage.Sets/src/mage/sets/returntoravnica/AnnihilatingFire.java b/Mage.Sets/src/mage/sets/returntoravnica/AnnihilatingFire.java index 9ec377e67ea..402a1df1aa6 100644 --- a/Mage.Sets/src/mage/sets/returntoravnica/AnnihilatingFire.java +++ b/Mage.Sets/src/mage/sets/returntoravnica/AnnihilatingFire.java @@ -37,6 +37,7 @@ import mage.constants.CardType; import mage.constants.Duration; import mage.constants.Rarity; import mage.target.common.TargetCreatureOrPlayer; +import mage.watchers.common.DamagedByWatcher; /** * @@ -45,20 +46,20 @@ import mage.target.common.TargetCreatureOrPlayer; public class AnnihilatingFire extends CardImpl { public AnnihilatingFire(UUID ownerId) { - super(ownerId, 85, "Annihilating Fire", Rarity.COMMON, new CardType[]{CardType.INSTANT}, "{1}{R}{R}"); - this.expansionSetCode = "RTR"; + super(ownerId, 85, "Annihilating Fire", Rarity.COMMON, new CardType[]{CardType.INSTANT}, "{1}{R}{R}"); + this.expansionSetCode = "RTR"; + // Annihilating Fire deals 3 damage to target creature or player. + this.getSpellAbility().addEffect(new DamageTargetEffect(3)); + this.getSpellAbility().addTarget(new TargetCreatureOrPlayer()); - // Annihilating Fire deals 3 damage to target creature or player. - this.getSpellAbility().addEffect(new DamageTargetEffect(3)); - this.getSpellAbility().addTarget(new TargetCreatureOrPlayer()); + // If a creature dealt damage this way would die this turn, exile it instead. + this.getSpellAbility().addEffect(new DealtDamageToCreatureBySourceDies(this, Duration.EndOfTurn)); + this.getSpellAbility().addWatcher(new DamagedByWatcher()); + } - // If a creature dealt damage this way would die this turn, exile it instead. - this.getSpellAbility().addEffect(new DealtDamageToCreatureBySourceDies(this, Duration.EndOfTurn)); - } - - public AnnihilatingFire(final AnnihilatingFire card) { - super(card); + public AnnihilatingFire(final AnnihilatingFire card) { + super(card); } @Override From bc409eccdcd4c4c1a2c5b13fe6de24c8d3a89ca9 Mon Sep 17 00:00:00 2001 From: LevelX2 Date: Sat, 31 Oct 2015 18:00:55 +0100 Subject: [PATCH 265/268] * Nine-Ringed Bo - Added missing watcher for exile ability. --- .../sets/championsofkamigawa/NineRingedBo.java | 18 +++++------------- 1 file changed, 5 insertions(+), 13 deletions(-) diff --git a/Mage.Sets/src/mage/sets/championsofkamigawa/NineRingedBo.java b/Mage.Sets/src/mage/sets/championsofkamigawa/NineRingedBo.java index 6914d9ff5bb..8f5ac8aaffa 100644 --- a/Mage.Sets/src/mage/sets/championsofkamigawa/NineRingedBo.java +++ b/Mage.Sets/src/mage/sets/championsofkamigawa/NineRingedBo.java @@ -28,27 +28,19 @@ package mage.sets.championsofkamigawa; 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.common.ActivateAsSorceryActivatedAbility; import mage.abilities.costs.common.TapSourceCost; import mage.abilities.effects.Effect; -import mage.abilities.effects.ReplacementEffectImpl; import mage.abilities.effects.common.DamageTargetEffect; import mage.abilities.effects.common.replacement.DealtDamageToCreatureBySourceDies; 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.mageobject.SubtypePredicate; -import mage.game.Game; -import mage.game.events.GameEvent; -import mage.game.events.GameEvent.EventType; -import mage.game.events.ZoneChangeEvent; -import mage.game.permanent.Permanent; -import mage.players.Player; import mage.target.common.TargetCreaturePermanent; import mage.watchers.common.DamagedByWatcher; @@ -74,7 +66,7 @@ public class NineRingedBo extends CardImpl { Effect effect = new DealtDamageToCreatureBySourceDies(this, Duration.EndOfTurn); effect.setText("If that creature would die this turn, exile it instead"); ability.addEffect(effect); - this.addAbility(ability); + this.addAbility(ability, new DamagedByWatcher()); } public NineRingedBo(final NineRingedBo card) { From a5730d83596d0b1485bcfbd6c2be6b81eaf233b3 Mon Sep 17 00:00:00 2001 From: LevelX2 Date: Sat, 31 Oct 2015 18:01:18 +0100 Subject: [PATCH 266/268] * Demonfire - Added missing watcher for exile ability. --- .../src/mage/sets/dissension/Demonfire.java | 22 +++++++++---------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/Mage.Sets/src/mage/sets/dissension/Demonfire.java b/Mage.Sets/src/mage/sets/dissension/Demonfire.java index 02484480095..b71edacc19e 100644 --- a/Mage.Sets/src/mage/sets/dissension/Demonfire.java +++ b/Mage.Sets/src/mage/sets/dissension/Demonfire.java @@ -44,6 +44,7 @@ import mage.constants.Duration; import mage.constants.Rarity; import mage.constants.Zone; import mage.target.common.TargetCreatureOrPlayer; +import mage.watchers.common.DamagedByWatcher; /** * @@ -54,30 +55,29 @@ public class Demonfire extends CardImpl { public Demonfire(UUID ownerId) { super(ownerId, 60, "Demonfire", Rarity.RARE, new CardType[]{CardType.SORCERY}, "{X}{R}"); this.expansionSetCode = "DIS"; - - - // Demonfire deals X damage to target creature or player. + // Demonfire deals X damage to target creature or player. this.getSpellAbility().addEffect(new ConditionalOneShotEffect( new DamageTargetEffect(new ManacostVariableValue()), new InvertCondition(HellbentCondition.getInstance()), - "{this} deals X damage to target creature or player")); + "{this} deals X damage to target creature or player")); // If a creature dealt damage this way would die this turn, exile it instead. - this.getSpellAbility().addEffect(new DealtDamageToCreatureBySourceDies(this, Duration.EndOfTurn)); - + this.getSpellAbility().addEffect(new DealtDamageToCreatureBySourceDies(this, Duration.EndOfTurn)); + this.getSpellAbility().addWatcher(new DamagedByWatcher()); + // Hellbent - If you have no cards in hand, Demonfire can't be countered by spells or abilities and the damage can't be prevented. this.getSpellAbility().addEffect(new ConditionalOneShotEffect( new DamageTargetEffect(new ManacostVariableValue(), false), HellbentCondition.getInstance(), - "
Hellbent - If you have no cards in hand, {this} can't be countered by spells or abilities and the damage can't be prevented.")); + "
Hellbent - If you have no cards in hand, {this} can't be countered by spells or abilities and the damage can't be prevented.")); // can't be countered - Effect effect = new CantBeCounteredSourceEffect(); - effect.setText(""); + Effect effect = new CantBeCounteredSourceEffect(); + effect.setText(""); this.addAbility(new SimpleStaticAbility(Zone.STACK, new ConditionalContinuousRuleModifyingEffect( - (CantBeCounteredSourceEffect)effect, + (CantBeCounteredSourceEffect) effect, HellbentCondition.getInstance()))); - + this.getSpellAbility().addTarget(new TargetCreatureOrPlayer()); } From df04cc72292650f01a260326244061a7c9eb3891 Mon Sep 17 00:00:00 2001 From: LevelX2 Date: Sat, 31 Oct 2015 18:35:53 +0100 Subject: [PATCH 267/268] * Quicksilver Gargantuan - Fixed bug/exception of copy ability. --- .../QuicksilverGargantuan.java | 77 ++++--------------- 1 file changed, 17 insertions(+), 60 deletions(-) diff --git a/Mage.Sets/src/mage/sets/scarsofmirrodin/QuicksilverGargantuan.java b/Mage.Sets/src/mage/sets/scarsofmirrodin/QuicksilverGargantuan.java index 2b9c6fb19c1..c7c1f7b3bcb 100644 --- a/Mage.Sets/src/mage/sets/scarsofmirrodin/QuicksilverGargantuan.java +++ b/Mage.Sets/src/mage/sets/scarsofmirrodin/QuicksilverGargantuan.java @@ -29,21 +29,16 @@ package mage.sets.scarsofmirrodin; import java.util.UUID; import mage.MageInt; +import mage.MageObject; import mage.abilities.Ability; import mage.abilities.common.EntersBattlefieldAbility; -import mage.abilities.effects.ContinuousEffectImpl; -import mage.cards.Card; +import mage.abilities.effects.common.CopyPermanentEffect; import mage.cards.CardImpl; import mage.constants.CardType; -import mage.constants.Duration; -import mage.constants.Layer; -import mage.constants.Outcome; import mage.constants.Rarity; -import mage.constants.SubLayer; import mage.game.Game; import mage.game.permanent.Permanent; -import mage.target.Target; -import mage.target.common.TargetCreaturePermanent; +import mage.util.functions.ApplyToPermanent; /** * @author ayratn @@ -58,11 +53,8 @@ public class QuicksilverGargantuan extends CardImpl { this.power = new MageInt(7); this.toughness = new MageInt(7); - Ability ability = new EntersBattlefieldAbility(new QuicksilverGargantuanCopyEffect(), + Ability ability = new EntersBattlefieldAbility(new CopyPermanentEffect(new QuicksilverGargantuanApplyToPermanent()), "You may have {this} enter the battlefield as a copy of any creature on the battlefield, except it's still 7/7"); - Target target = new TargetCreaturePermanent(); - target.setNotTarget(true); - ability.addTarget(target); this.addAbility(ability); } @@ -74,57 +66,22 @@ public class QuicksilverGargantuan extends CardImpl { public QuicksilverGargantuan copy() { return new QuicksilverGargantuan(this); } +} - private class QuicksilverGargantuanCopyEffect extends ContinuousEffectImpl { +class QuicksilverGargantuanApplyToPermanent extends ApplyToPermanent { - public QuicksilverGargantuanCopyEffect() { - super(Duration.WhileOnBattlefield, Layer.CopyEffects_1, SubLayer.NA, Outcome.BecomeCreature); - staticText = "You may have {this} enter the battlefield as a copy of any creature on the battlefield, except it's still 7/7"; - } - - public QuicksilverGargantuanCopyEffect(final QuicksilverGargantuanCopyEffect effect) { - super(effect); - } - - @Override - public boolean apply(Game game, Ability source) { - Card card = game.getCard(source.getFirstTarget()); - Permanent permanent = game.getPermanentEntering(source.getSourceId()); - if (permanent == null) { - permanent = game.getPermanent(source.getSourceId()); - } - if (permanent != null) { - permanent.setName(card.getName()); - permanent.getColor(game).setColor(card.getColor(game)); - permanent.getManaCost().clear(); - permanent.getManaCost().add(card.getManaCost()); - permanent.getCardType().clear(); - for (CardType type : card.getCardType()) { - permanent.getCardType().add(type); - } - permanent.getSubtype().clear(); - for (String type : card.getSubtype()) { - permanent.getSubtype().add(type); - } - permanent.getSupertype().clear(); - for (String type : card.getSupertype()) { - permanent.getSupertype().add(type); - } - permanent.setExpansionSetCode(card.getExpansionSetCode()); - permanent.getAbilities().clear(); - for (Ability ability : card.getAbilities()) { - permanent.addAbility(ability, game); - } - return true; - } - return false; - } - - @Override - public QuicksilverGargantuanCopyEffect copy() { - return new QuicksilverGargantuanCopyEffect(this); - } + @Override + public Boolean apply(Game game, Permanent permanent) { + permanent.getPower().initValue(7); + permanent.getToughness().initValue(7); + return true; + } + @Override + public Boolean apply(Game game, MageObject mageObject) { + mageObject.getPower().initValue(7); + mageObject.getToughness().initValue(7); + return true; } } From 4af5368fc2b9874f0bb5b9d3b4ec37f2f77c0417 Mon Sep 17 00:00:00 2001 From: LevelX2 Date: Sun, 1 Nov 2015 09:18:36 +0100 Subject: [PATCH 268/268] * Zameck Guildmage - Fixed that the first ability could be activated in all zones instead of only on the battlefield. --- Mage.Sets/src/mage/sets/gatecrash/ZameckGuildmage.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Mage.Sets/src/mage/sets/gatecrash/ZameckGuildmage.java b/Mage.Sets/src/mage/sets/gatecrash/ZameckGuildmage.java index 41bc52a2399..ba0208320ff 100644 --- a/Mage.Sets/src/mage/sets/gatecrash/ZameckGuildmage.java +++ b/Mage.Sets/src/mage/sets/gatecrash/ZameckGuildmage.java @@ -64,7 +64,7 @@ public class ZameckGuildmage extends CardImpl { this.toughness = new MageInt(2); // {G}{U}: This turn, each creature you control enters the battlefield with an additional +1/+1 counter on it. - this.addAbility(new SimpleActivatedAbility(Zone.ALL, new ZameckGuildmageEntersBattlefieldEffect(), new ManaCostsImpl("{G}{U}"))); + this.addAbility(new SimpleActivatedAbility(Zone.BATTLEFIELD, new ZameckGuildmageEntersBattlefieldEffect(), new ManaCostsImpl("{G}{U}"))); // {G}{U}, Remove a +1/+1 counter from a creature you control: Draw a card. Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new DrawCardSourceControllerEffect(1), new ManaCostsImpl("{G}{U}"));