From 9ba29218ba761b6da26e505619e542cf93d00f28 Mon Sep 17 00:00:00 2001 From: LoneFox Date: Tue, 13 Oct 2015 10:02:42 +0300 Subject: [PATCH 01/12] 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 02/12] 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 03/12] 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 04/12] 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 03542fbc92a70780550fa0719eaad1cd8b4cc67d Mon Sep 17 00:00:00 2001 From: LoneFox Date: Wed, 14 Oct 2015 21:00:55 +0300 Subject: [PATCH 05/12] 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 06/12] 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 64017caa1b4b1eb23f91b0ec3c557eb724709e1a Mon Sep 17 00:00:00 2001 From: Plopman Date: Wed, 14 Oct 2015 21:19:44 +0200 Subject: [PATCH 07/12] 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 08/12] 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 09/12] 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 10/12] * 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 11/12] 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 12/12] 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