diff --git a/Mage.Sets/src/mage/sets/darkascension/Gravecrawler.java b/Mage.Sets/src/mage/sets/darkascension/Gravecrawler.java new file mode 100644 index 00000000000..c4e99ce104d --- /dev/null +++ b/Mage.Sets/src/mage/sets/darkascension/Gravecrawler.java @@ -0,0 +1,119 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.sets.darkascension; + +import java.util.UUID; +import mage.Constants; +import mage.Constants.CardType; +import mage.Constants.Rarity; +import mage.Constants.Zone; +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.CantBlockAbility; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.effects.AsThoughEffectImpl; +import mage.cards.Card; +import mage.cards.CardImpl; +import mage.filter.Filter; +import mage.filter.common.FilterCreaturePermanent; +import mage.game.Game; + +/** + * + * @author BetaSteward + */ +public class Gravecrawler extends CardImpl { + + public Gravecrawler(UUID ownerId) { + super(ownerId, 64, "Gravecrawler", Rarity.RARE, new CardType[]{CardType.CREATURE}, "{B}"); + this.expansionSetCode = "DKA"; + this.subtype.add("Zombie"); + + this.color.setBlack(true); + this.power = new MageInt(2); + this.toughness = new MageInt(1); + + // Gravecrawler can't block. + this.addAbility(CantBlockAbility.getInstance()); + + // You may cast Gravecrawler from your graveyard as long as you control a Zombie. + this.addAbility(new SimpleStaticAbility(Zone.GRAVEYARD, new GravecrawlerPlayEffect())); + + } + + public Gravecrawler(final Gravecrawler card) { + super(card); + } + + @Override + public Gravecrawler copy() { + return new Gravecrawler(this); + } +} + +class GravecrawlerPlayEffect extends AsThoughEffectImpl { + + private final static FilterCreaturePermanent filter = new FilterCreaturePermanent("zombie"); + + static { + filter.getSubtype().add("Zombie"); + filter.setScopeSubtype(Filter.ComparisonScope.Any); + } + + public GravecrawlerPlayEffect() { + super(Constants.AsThoughEffectType.CAST, Constants.Duration.EndOfGame, Constants.Outcome.Benefit); + staticText = "You may cast Gravecrawler from your graveyard as long as you control a Zombie"; + } + + public GravecrawlerPlayEffect(final GravecrawlerPlayEffect effect) { + super(effect); + } + + @Override + public boolean apply(Game game, Ability source) { + return true; + } + + @Override + public GravecrawlerPlayEffect copy() { + return new GravecrawlerPlayEffect(this); + } + + @Override + public boolean applies(UUID sourceId, Ability source, Game game) { + if (sourceId.equals(source.getSourceId())) { + Card card = game.getCard(source.getSourceId()); + if (card != null && game.getState().getZone(source.getSourceId()) == Constants.Zone.GRAVEYARD) { + if (game.getBattlefield().countAll(filter, source.getControllerId()) > 0) + return true; + } + } + return false; + } + +} \ No newline at end of file diff --git a/Mage.Sets/src/mage/sets/darkascension/HavengulLich.java b/Mage.Sets/src/mage/sets/darkascension/HavengulLich.java new file mode 100644 index 00000000000..7423f596798 --- /dev/null +++ b/Mage.Sets/src/mage/sets/darkascension/HavengulLich.java @@ -0,0 +1,218 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.sets.darkascension; + +import java.util.UUID; +import mage.Constants; +import mage.Constants.CardType; +import mage.Constants.Duration; +import mage.Constants.Outcome; +import mage.Constants.Rarity; +import mage.Constants.Zone; +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.ActivatedAbility; +import mage.abilities.DelayedTriggeredAbility; +import mage.abilities.TriggeredAbilityImpl; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.costs.mana.GenericManaCost; +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.effects.AsThoughEffectImpl; +import mage.abilities.effects.ContinuousEffectImpl; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.CounterUnlessPaysEffect; +import mage.cards.Card; +import mage.cards.CardImpl; +import mage.filter.FilterCard; +import mage.filter.common.FilterCreatureCard; +import mage.game.Game; +import mage.game.events.GameEvent; +import mage.game.permanent.Permanent; +import mage.game.stack.Spell; +import mage.target.common.TargetCardInGraveyard; +import mage.target.targetpointer.FixedTarget; + +/** + * + * @author BetaSteward + */ +public class HavengulLich extends CardImpl { + + private static final FilterCard filter = new FilterCreatureCard("creature card in a graveyard"); + + public HavengulLich(UUID ownerId) { + super(ownerId, 139, "Havengul Lich", Rarity.MYTHIC, new CardType[]{CardType.CREATURE}, "{3}{U}{B}"); + this.expansionSetCode = "DKA"; + this.subtype.add("Zombie"); + this.subtype.add("Wizard"); + + this.color.setBlue(true); + this.color.setBlack(true); + this.power = new MageInt(4); + this.toughness = new MageInt(4); + + // {1}: You may cast target creature card in a graveyard this turn. When you cast that card this turn, Havengul Lich gains all activated abilities of that card until end of turn. + Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new HavengulLichPlayEffect(), new ManaCostsImpl("{1}")); + ability.addEffect(new HavengulLichPlayedEffect()); + ability.addTarget(new TargetCardInGraveyard(filter)); + this.addAbility(ability); + + } + + public HavengulLich(final HavengulLich card) { + super(card); + } + + @Override + public HavengulLich copy() { + return new HavengulLich(this); + } +} + +//allow card in graveyard to be played +class HavengulLichPlayEffect extends AsThoughEffectImpl { + + public HavengulLichPlayEffect() { + super(Constants.AsThoughEffectType.CAST, Constants.Duration.EndOfTurn, Constants.Outcome.Benefit); + staticText = "You may cast target creature card in a graveyard this turn"; + } + + public HavengulLichPlayEffect(final HavengulLichPlayEffect effect) { + super(effect); + } + + @Override + public boolean apply(Game game, Ability source) { + return true; + } + + @Override + public HavengulLichPlayEffect copy() { + return new HavengulLichPlayEffect(this); + } + + @Override + public boolean applies(UUID sourceId, Ability source, Game game) { + Card card = game.getCard(sourceId); + if (card != null && game.getState().getZone(card.getId()) == Constants.Zone.GRAVEYARD) { + if (targetPointer.getFirst(source).equals(card.getId())) + return true; + } + return false; + } + +} + +//create delayed triggered ability to watch for card being played +class HavengulLichPlayedEffect extends OneShotEffect { + + public HavengulLichPlayedEffect() { + super(Outcome.PutCreatureInPlay); + } + + public HavengulLichPlayedEffect(final HavengulLichPlayedEffect effect) { + super(effect); + } + + @Override + public boolean apply(Game game, Ability source) { + DelayedTriggeredAbility ability = new HavengulLichDelayedTriggeredAbility(targetPointer.getFirst(source)); + ability.setSourceId(source.getSourceId()); + ability.setControllerId(source.getControllerId()); + game.addDelayedTriggeredAbility(ability); + return true; + } + + @Override + public HavengulLichPlayedEffect copy() { + return new HavengulLichPlayedEffect(this); + } + +} + +// when card is played create continuous effect +class HavengulLichDelayedTriggeredAbility extends DelayedTriggeredAbility { + + private UUID cardId; + + public HavengulLichDelayedTriggeredAbility (UUID cardId) { + super(new HavengulLichEffect(cardId), Duration.EndOfTurn); + this.cardId = cardId; + } + + public HavengulLichDelayedTriggeredAbility(HavengulLichDelayedTriggeredAbility ability) { + super(ability); + this.cardId = ability.cardId; + } + + @Override + public boolean checkTrigger(GameEvent event, Game game) { + if (event.getType() == GameEvent.EventType.SPELL_CAST && event.getSourceId().equals(cardId)) { + return true; + } + return false; + } + + @Override + public HavengulLichDelayedTriggeredAbility copy() { + return new HavengulLichDelayedTriggeredAbility(this); + } +} + +// copy activated abilities of card +class HavengulLichEffect extends ContinuousEffectImpl { + + private UUID cardId; + + public HavengulLichEffect(UUID cardId) { + super(Duration.EndOfTurn, Constants.Layer.AbilityAddingRemovingEffects_6, Constants.SubLayer.NA, Constants.Outcome.AddAbility); + this.cardId = cardId; + } + + public HavengulLichEffect(final HavengulLichEffect effect) { + super(effect); + this.cardId = effect.cardId; + } + + @Override + public HavengulLichEffect copy() { + return new HavengulLichEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Permanent permanent = game.getPermanent(source.getSourceId()); + Card card = game.getCard(cardId); + if (permanent != null && card != null) { + for (ActivatedAbility ability: card.getAbilities().getActivatedAbilities(Zone.BATTLEFIELD)) { + permanent.addAbility(ability, game); + } + } + return false; + } +} \ No newline at end of file diff --git a/Mage.Sets/src/mage/sets/darkascension/Immerwolf.java b/Mage.Sets/src/mage/sets/darkascension/Immerwolf.java new file mode 100644 index 00000000000..98fcf6c3810 --- /dev/null +++ b/Mage.Sets/src/mage/sets/darkascension/Immerwolf.java @@ -0,0 +1,138 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.sets.darkascension; + +import java.util.UUID; +import mage.Constants; +import mage.Constants.CardType; +import mage.Constants.Rarity; +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.effects.ReplacementEffectImpl; +import mage.abilities.effects.common.continious.BoostControlledEffect; +import mage.abilities.keyword.IntimidateAbility; +import mage.cards.CardImpl; +import mage.filter.Filter; +import mage.filter.common.FilterCreaturePermanent; +import mage.game.Game; +import mage.game.events.GameEvent; +import mage.game.permanent.Permanent; + +/** + * + * @author BetaSteward + */ +public class Immerwolf extends CardImpl { + + private final static FilterCreaturePermanent filter = new FilterCreaturePermanent("Wolf and Werewolf creatures"); + + static { + filter.getSubtype().add("Wolf"); + filter.getSubtype().add("Werewolf"); + filter.setScopeSubtype(Filter.ComparisonScope.Any); + } + + public Immerwolf(UUID ownerId) { + super(ownerId, 141, "Immerwolf", Rarity.UNCOMMON, new CardType[]{CardType.CREATURE}, "{1}{R}{G}"); + this.expansionSetCode = "DKA"; + this.subtype.add("Wolf"); + + this.color.setRed(true); + this.color.setGreen(true); + this.power = new MageInt(2); + this.toughness = new MageInt(2); + + this.addAbility(IntimidateAbility.getInstance()); + + // Other Wolf and Werewolf creatures you control get +1/+1. + this.addAbility(new SimpleStaticAbility(Constants.Zone.BATTLEFIELD, new BoostControlledEffect(1, 1, Constants.Duration.WhileOnBattlefield, filter, true))); + + // Non-Human Werewolves you control can't transform. + this.addAbility(new SimpleStaticAbility(Constants.Zone.BATTLEFIELD, new ImmerwolfEffect())); + + } + + public Immerwolf(final Immerwolf card) { + super(card); + } + + @Override + public Immerwolf copy() { + return new Immerwolf(this); + } +} + +class ImmerwolfEffect extends ReplacementEffectImpl { + + private final static FilterCreaturePermanent filterWerewolf = new FilterCreaturePermanent("Werewolf creature"); + private final static FilterCreaturePermanent filterNonhuman = new FilterCreaturePermanent("Non-human creature"); + + static { + filterWerewolf.getSubtype().add("Werewolf"); + filterWerewolf.setScopeSubtype(Filter.ComparisonScope.Any); + filterNonhuman.getSubtype().add("Human"); + filterNonhuman.setScopeSubtype(Filter.ComparisonScope.Any); + filterNonhuman.setNotFilter(true); + } + + public ImmerwolfEffect() { + super(Constants.Duration.WhileOnBattlefield, Constants.Outcome.Detriment); + staticText = "Non-Human Werewolves you control can't transform"; + } + + public ImmerwolfEffect(final ImmerwolfEffect effect) { + super(effect); + } + + @Override + public ImmerwolfEffect copy() { + return new ImmerwolfEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + return true; + } + + @Override + public boolean replaceEvent(GameEvent event, Ability source, Game game) { + return true; + } + + @Override + public boolean applies(GameEvent event, Ability source, Game game) { + if (event.getType() == GameEvent.EventType.TRANSFORM) { + Permanent permanent = game.getPermanent(event.getTargetId()); + if (permanent != null && permanent.getControllerId().equals(source.getControllerId()) && filterWerewolf.match(permanent) && filterNonhuman.match(permanent)) { + return true; + } + } + return false; + } +} diff --git a/Mage.Tests/src/test/java/org/mage/test/ai/bugs/TestHavengulLich.java b/Mage.Tests/src/test/java/org/mage/test/ai/bugs/TestHavengulLich.java new file mode 100644 index 00000000000..6fd30da4845 --- /dev/null +++ b/Mage.Tests/src/test/java/org/mage/test/ai/bugs/TestHavengulLich.java @@ -0,0 +1,47 @@ +package org.mage.test.ai.bugs; + +import org.mage.test.cards.*; +import mage.Constants; +import mage.Constants.PhaseStep; +import org.junit.Ignore; +import org.junit.Test; +import org.mage.test.serverside.base.CardTestPlayerBase; + +/** + * + * @author BetaSteward + */ +public class TestHavengulLich extends CardTestPlayerBase { + + @Test + public void testCard() { + addCard(Constants.Zone.GRAVEYARD, playerA, "Gravecrawler"); + addCard(Constants.Zone.BATTLEFIELD, playerA, "Black Cat"); + addCard(Constants.Zone.BATTLEFIELD, playerA, "Swamp"); + + castSpell(1, Constants.PhaseStep.PRECOMBAT_MAIN, playerA, "Gravecrawler"); + setStopAt(1, Constants.PhaseStep.BEGIN_COMBAT); + execute(); + + assertLife(playerA, 20); + assertLife(playerB, 20); + assertPermanentCount(playerA, "Gravecrawler", 1); + assertGraveyardCount(playerA, 0); + } + + @Test + public void testCard1() { + addCard(Constants.Zone.GRAVEYARD, playerA, "Gravecrawler"); + addCard(Constants.Zone.BATTLEFIELD, playerA, "Swamp"); + + castSpell(1, Constants.PhaseStep.PRECOMBAT_MAIN, playerA, "Gravecrawler"); + setStopAt(1, Constants.PhaseStep.BEGIN_COMBAT); + execute(); + + assertLife(playerA, 20); + assertLife(playerB, 20); + assertPermanentCount(playerA, "Gravecrawler", 0); + assertGraveyardCount(playerA, 1); + } + +} diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/TestGravecrawler.java b/Mage.Tests/src/test/java/org/mage/test/cards/TestGravecrawler.java new file mode 100644 index 00000000000..4c63dd00e3e --- /dev/null +++ b/Mage.Tests/src/test/java/org/mage/test/cards/TestGravecrawler.java @@ -0,0 +1,46 @@ +package org.mage.test.cards; + +import mage.Constants; +import mage.Constants.PhaseStep; +import org.junit.Ignore; +import org.junit.Test; +import org.mage.test.serverside.base.CardTestPlayerBase; + +/** + * + * @author BetaSteward + */ +public class TestGravecrawler extends CardTestPlayerBase { + + @Test + public void testCard() { + addCard(Constants.Zone.GRAVEYARD, playerA, "Gravecrawler"); + addCard(Constants.Zone.BATTLEFIELD, playerA, "Black Cat"); + addCard(Constants.Zone.BATTLEFIELD, playerA, "Swamp"); + + castSpell(1, Constants.PhaseStep.PRECOMBAT_MAIN, playerA, "Gravecrawler"); + setStopAt(1, Constants.PhaseStep.BEGIN_COMBAT); + execute(); + + assertLife(playerA, 20); + assertLife(playerB, 20); + assertPermanentCount(playerA, "Gravecrawler", 1); + assertGraveyardCount(playerA, 0); + } + + @Test + public void testCard1() { + addCard(Constants.Zone.GRAVEYARD, playerA, "Gravecrawler"); + addCard(Constants.Zone.BATTLEFIELD, playerA, "Swamp"); + + castSpell(1, Constants.PhaseStep.PRECOMBAT_MAIN, playerA, "Gravecrawler"); + setStopAt(1, Constants.PhaseStep.BEGIN_COMBAT); + execute(); + + assertLife(playerA, 20); + assertLife(playerB, 20); + assertPermanentCount(playerA, "Gravecrawler", 0); + assertGraveyardCount(playerA, 1); + } + +} diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/TestHavengulLich.java b/Mage.Tests/src/test/java/org/mage/test/cards/TestHavengulLich.java new file mode 100644 index 00000000000..06ac53c34bc --- /dev/null +++ b/Mage.Tests/src/test/java/org/mage/test/cards/TestHavengulLich.java @@ -0,0 +1,83 @@ +package org.mage.test.cards; + +import java.util.ArrayList; +import java.util.List; +import mage.Constants; +import mage.Constants.PhaseStep; +import mage.abilities.Ability; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.costs.common.TapSourceCost; +import mage.abilities.effects.common.DamageTargetEffect; +import mage.target.common.TargetCreatureOrPlayer; +import org.junit.Ignore; +import org.junit.Test; +import org.mage.test.serverside.base.CardTestPlayerBase; + +/** + * + * @author BetaSteward + */ +public class TestHavengulLich extends CardTestPlayerBase { + + @Test + public void testCard() { + addCard(Constants.Zone.BATTLEFIELD, playerA, "Mountain", 4); + addCard(Constants.Zone.BATTLEFIELD, playerA, "Havengul Lich"); + addCard(Constants.Zone.GRAVEYARD, playerA, "Prodigal Pyromancer"); + + activateAbility(1, Constants.PhaseStep.PRECOMBAT_MAIN, playerA, "{1}", "Prodigal Pyromancer"); + castSpell(1, Constants.PhaseStep.PRECOMBAT_MAIN, playerA, "Prodigal Pyromancer"); + activateAbility(1, Constants.PhaseStep.POSTCOMBAT_MAIN, playerA, "{T}", playerB); + setStopAt(1, Constants.PhaseStep.END_TURN); + execute(); + + assertLife(playerA, 20); + assertLife(playerB, 19); + assertPermanentCount(playerA, "Havengul Lich", 1); + assertPermanentCount(playerA, "Prodigal Pyromancer", 1); + assertTapped("Havengul Lich", true); + assertTapped("Prodigal Pyromancer", false); + assertGraveyardCount(playerA, 0); + } + + @Test + public void testCard1() { + addCard(Constants.Zone.BATTLEFIELD, playerA, "Swamp", 3); + addCard(Constants.Zone.BATTLEFIELD, playerA, "Havengul Lich"); + addCard(Constants.Zone.GRAVEYARD, playerA, "Black Cat"); + + activateAbility(1, Constants.PhaseStep.PRECOMBAT_MAIN, playerA, "{1}", "Black Cat"); + castSpell(3, Constants.PhaseStep.PRECOMBAT_MAIN, playerA, "Black Cat"); + setStopAt(3, Constants.PhaseStep.BEGIN_COMBAT); + execute(); + + assertLife(playerA, 20); + assertLife(playerB, 20); + assertPermanentCount(playerA, "Havengul Lich", 1); + assertPermanentCount(playerA, "Black Cat", 0); + assertGraveyardCount(playerA, 1); + } + + @Test + public void testCard2() { + addCard(Constants.Zone.BATTLEFIELD, playerA, "Mountain", 4); + addCard(Constants.Zone.BATTLEFIELD, playerA, "Havengul Lich"); + addCard(Constants.Zone.GRAVEYARD, playerA, "Prodigal Pyromancer"); + + activateAbility(1, Constants.PhaseStep.PRECOMBAT_MAIN, playerA, "{1}", "Prodigal Pyromancer"); + castSpell(1, Constants.PhaseStep.PRECOMBAT_MAIN, playerA, "Prodigal Pyromancer"); + activateAbility(3, Constants.PhaseStep.PRECOMBAT_MAIN, playerA, "{T}", playerB); + activateAbility(3, Constants.PhaseStep.PRECOMBAT_MAIN, playerA, "{T}", playerB); + setStopAt(3, Constants.PhaseStep.BEGIN_COMBAT); + execute(); + + assertLife(playerA, 20); + assertLife(playerB, 19); + assertPermanentCount(playerA, "Havengul Lich", 1); + assertPermanentCount(playerA, "Prodigal Pyromancer", 1); + assertTapped("Prodigal Pyromancer", true); + assertTapped("Havengul Lich", false); + assertGraveyardCount(playerA, 0); + } + +} diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/TestImmerwolf.java b/Mage.Tests/src/test/java/org/mage/test/cards/TestImmerwolf.java new file mode 100644 index 00000000000..ff7247a39ab --- /dev/null +++ b/Mage.Tests/src/test/java/org/mage/test/cards/TestImmerwolf.java @@ -0,0 +1,51 @@ +package org.mage.test.cards; + +import mage.Constants; +import mage.Constants.PhaseStep; +import org.junit.Ignore; +import org.junit.Test; +import org.mage.test.serverside.base.CardTestPlayerBase; + +/** + * + * @author BetaSteward + */ +public class TestImmerwolf extends CardTestPlayerBase { + + @Test + public void testCard() { + addCard(Constants.Zone.BATTLEFIELD, playerA, "Afflicted Deserter"); + addCard(Constants.Zone.BATTLEFIELD, playerA, "Immerwolf"); + addCard(Constants.Zone.BATTLEFIELD, playerB, "Ornithopter"); + + setStopAt(2, Constants.PhaseStep.BEGIN_COMBAT); + execute(); + + assertLife(playerA, 20); + assertLife(playerB, 17); + assertPermanentCount(playerB, "Ornithopter", 0); + assertPermanentCount(playerA, "Afflicted Deserter", 0); + assertPermanentCount(playerA, "Werewolf Ransacker", 1); + } + + @Test + public void testCard1() { + addCard(Constants.Zone.BATTLEFIELD, playerA, "Afflicted Deserter"); + addCard(Constants.Zone.BATTLEFIELD, playerA, "Immerwolf"); + addCard(Constants.Zone.BATTLEFIELD, playerB, "Ornithopter"); + addCard(Constants.Zone.BATTLEFIELD, playerB, "Mountain", 2); + addCard(Constants.Zone.HAND, playerB, "Lightning Bolt", 2); + + castSpell(2, Constants.PhaseStep.PRECOMBAT_MAIN, playerB, "Lightning Bolt", playerA); + castSpell(2, Constants.PhaseStep.PRECOMBAT_MAIN, playerB, "Lightning Bolt", playerA); + setStopAt(3, Constants.PhaseStep.DRAW); + execute(); + + assertLife(playerA, 14); + assertLife(playerB, 17); + assertPermanentCount(playerB, "Ornithopter", 0); + assertPermanentCount(playerA, "Afflicted Deserter", 0); + assertPermanentCount(playerA, "Werewolf Ransacker", 1); + } + +} diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/TestWerewolfRansacker.java b/Mage.Tests/src/test/java/org/mage/test/cards/TestWerewolfRansacker.java index cf3b72ec31c..c4a2eb7c4c4 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/TestWerewolfRansacker.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/TestWerewolfRansacker.java @@ -45,5 +45,23 @@ public class TestWerewolfRansacker extends CardTestPlayerBase { assertPermanentCount(playerA, "Blade Splicer", 1); assertPermanentCount(playerA, "Golem", 0); } - + + @Test + public void testCard2() { + addCard(Constants.Zone.BATTLEFIELD, playerA, "Afflicted Deserter"); + addCard(Constants.Zone.BATTLEFIELD, playerB, "Ornithopter"); + addCard(Constants.Zone.BATTLEFIELD, playerB, "Mountain", 2); + addCard(Constants.Zone.HAND, playerB, "Lightning Bolt", 2); + + castSpell(2, Constants.PhaseStep.PRECOMBAT_MAIN, playerB, "Lightning Bolt", playerA); + castSpell(2, Constants.PhaseStep.PRECOMBAT_MAIN, playerB, "Lightning Bolt", playerA); + setStopAt(3, Constants.PhaseStep.DRAW); + execute(); + + assertLife(playerA, 14); + assertLife(playerB, 17); + assertPermanentCount(playerB, "Ornithopter", 0); + assertPermanentCount(playerA, "Afflicted Deserter", 1); + assertPermanentCount(playerA, "Werewolf Ransacker", 0); + } } 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 f5bca1055e2..95886a372a6 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 @@ -34,8 +34,10 @@ import java.util.List; import java.util.UUID; import mage.Constants; import mage.Constants.PhaseStep; +import mage.MageObject; import mage.abilities.Ability; import mage.abilities.ActivatedAbility; +import mage.cards.Card; import mage.counters.Counter; import mage.filter.FilterPermanent; import mage.filter.common.FilterAttackingCreature; @@ -175,17 +177,10 @@ public class TestPlayer extends ComputerPlayer { target = group.substring(group.indexOf("target=") + 7); String[] targets = target.split("\\^"); for (String t: targets) { - for (Permanent permanent: game.getBattlefield().getAllActivePermanents()) { - if (permanent.getName().equals(t)) { - ability.getTargets().get(0).addTarget(permanent.getId(), ability, game); - break; - } - } - Iterator it = game.getStack().iterator(); - while (it.hasNext()) { - StackObject object = it.next(); - if (object.getName().equals(t)) { - ability.getTargets().get(0).addTarget(object.getId(), ability, game); + for (UUID id: ability.getTargets().get(0).possibleTargets(ability.getSourceId(), ability.getControllerId(), game)) { + MageObject object = game.getObject(id); + if (object != null && object.getName().equals(t)) { + ability.getTargets().get(0).addTarget(id, ability, game); break; } } diff --git a/Mage.Tests/src/test/java/org/mage/test/serverside/base/impl/CardTestPlayerAPIImpl.java b/Mage.Tests/src/test/java/org/mage/test/serverside/base/impl/CardTestPlayerAPIImpl.java index 832e5e9b81c..89404d8a7ae 100644 --- a/Mage.Tests/src/test/java/org/mage/test/serverside/base/impl/CardTestPlayerAPIImpl.java +++ b/Mage.Tests/src/test/java/org/mage/test/serverside/base/impl/CardTestPlayerAPIImpl.java @@ -504,7 +504,7 @@ public abstract class CardTestPlayerAPIImpl extends MageTestPlayerBase implement } public void activateAbility(int turnNum, PhaseStep step, TestPlayer player, String ability, Player target) { - player.addAction(turnNum, step, "activate:" + ability + ";target=" + target.getName()); + player.addAction(turnNum, step, "activate:" + ability + ";targetPlayer=" + target.getName()); } public void activateAbility(int turnNum, PhaseStep step, TestPlayer player, String ability, String targetName) { diff --git a/Mage/src/mage/abilities/DelayedTriggeredAbilities.java b/Mage/src/mage/abilities/DelayedTriggeredAbilities.java index 1a56a44694a..fedc8c2f37a 100644 --- a/Mage/src/mage/abilities/DelayedTriggeredAbilities.java +++ b/Mage/src/mage/abilities/DelayedTriggeredAbilities.java @@ -29,6 +29,8 @@ package mage.abilities; import java.util.Iterator; +import mage.Constants; +import mage.Constants.Duration; import mage.game.Game; import mage.game.events.GameEvent; @@ -51,8 +53,7 @@ import mage.game.events.GameEvent; public void checkTriggers(GameEvent event, Game game) { if (this.size() > 0) { - Iterator it = this.iterator(); - while (it.hasNext()) { + for (Iterator it = this.iterator();it.hasNext();) { DelayedTriggeredAbility ability = it.next(); if (ability.checkTrigger(event, game)) { ability.trigger(game, ability.controllerId); @@ -62,5 +63,13 @@ import mage.game.events.GameEvent; } } + public void removeEndOfTurnAbilities() { + for (Iterator it = this.iterator();it.hasNext();) { + DelayedTriggeredAbility ability = it.next(); + if (ability.getDuration() == Duration.EndOfTurn) + it.remove(); + } + } + } diff --git a/Mage/src/mage/abilities/DelayedTriggeredAbility.java b/Mage/src/mage/abilities/DelayedTriggeredAbility.java index 68d6e55766e..af26f4e6c2b 100644 --- a/Mage/src/mage/abilities/DelayedTriggeredAbility.java +++ b/Mage/src/mage/abilities/DelayedTriggeredAbility.java @@ -28,6 +28,7 @@ package mage.abilities; +import mage.Constants.Duration; import mage.Constants.Zone; import mage.abilities.effects.Effect; @@ -37,14 +38,26 @@ import mage.abilities.effects.Effect; */ public abstract class DelayedTriggeredAbility> extends TriggeredAbilityImpl { - public DelayedTriggeredAbility(Effect effect) { - super(Zone.ALL, effect); + private Duration duration; + + public DelayedTriggeredAbility(Effect effect) { + this(effect, Duration.EndOfGame); } - public DelayedTriggeredAbility(final DelayedTriggeredAbility ability) { + public DelayedTriggeredAbility(Effect effect, Duration duration) { + super(Zone.ALL, effect); + this.duration = duration; + } + + public DelayedTriggeredAbility(final DelayedTriggeredAbility ability) { super(ability); + this.duration = ability.duration; } @Override public abstract T copy(); + + public Duration getDuration() { + return duration; + } } diff --git a/Mage/src/mage/game/GameState.java b/Mage/src/mage/game/GameState.java index 3f5f7784b74..a3e18526e5f 100644 --- a/Mage/src/mage/game/GameState.java +++ b/Mage/src/mage/game/GameState.java @@ -362,6 +362,7 @@ public class GameState implements Serializable, Copyable { public void removeEotEffects(Game game) { effects.removeEndOfTurnEffects(); + delayed.removeEndOfTurnAbilities(); applyEffects(game); } diff --git a/Mage/src/mage/players/PlayerImpl.java b/Mage/src/mage/players/PlayerImpl.java index 36a0b517c16..8ee10589b5c 100644 --- a/Mage/src/mage/players/PlayerImpl.java +++ b/Mage/src/mage/players/PlayerImpl.java @@ -1242,12 +1242,19 @@ public abstract class PlayerImpl> implements Player, Ser if (canPlay(ability, available, game)) playable.add(ability); } + if (game.getContinuousEffects().asThough(card.getId(), AsThoughEffectType.CAST, game)) { + for (ActivatedAbility ability: card.getAbilities().getActivatedAbilities(Zone.HAND)) { + if (ability instanceof SpellAbility || ability instanceof PlayLandAbility) + playable.add(ability); + } + } } for (ExileZone exile: game.getExile().getExileZones()) { for (Card card: exile.getCards(game)) { if (game.getContinuousEffects().asThough(card.getId(), AsThoughEffectType.CAST, game)) { for (ActivatedAbility ability: card.getAbilities().getActivatedAbilities(Zone.HAND)) { - playable.add(ability); + if (ability instanceof SpellAbility || ability instanceof PlayLandAbility) + playable.add(ability); } } } @@ -1256,7 +1263,8 @@ public abstract class PlayerImpl> implements Player, Ser for (Card card: cards.getCards(game)) { if (game.getContinuousEffects().asThough(card.getId(), AsThoughEffectType.CAST, game)) { for (ActivatedAbility ability: card.getAbilities().getActivatedAbilities(Zone.HAND)) { - playable.add(ability); + if (ability instanceof SpellAbility || ability instanceof PlayLandAbility) + playable.add(ability); } } }