diff --git a/Mage.Sets/src/mage/sets/darkascension/CurseOfBloodletting.java b/Mage.Sets/src/mage/sets/darkascension/CurseOfBloodletting.java new file mode 100644 index 00000000000..f129e7c0138 --- /dev/null +++ b/Mage.Sets/src/mage/sets/darkascension/CurseOfBloodletting.java @@ -0,0 +1,125 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those 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.abilities.Ability; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.effects.ReplacementEffectImpl; +import mage.abilities.effects.common.AttachEffect; +import mage.abilities.keyword.EnchantAbility; +import mage.cards.CardImpl; +import mage.game.Game; +import mage.game.events.GameEvent; +import mage.game.permanent.Permanent; +import mage.game.stack.StackObject; +import mage.players.Player; +import mage.target.TargetPlayer; + +/** + * + * @author BetaSteward + */ +public class CurseOfBloodletting extends CardImpl { + + public CurseOfBloodletting(UUID ownerId) { + super(ownerId, 85, "Curse of Bloodletting", Rarity.RARE, new CardType[]{CardType.ENCHANTMENT}, "{3}{R}{R}"); + this.expansionSetCode = "DKA"; + this.subtype.add("Aura"); + this.subtype.add("Curse"); + + this.color.setRed(true); + + // Enchant player + TargetPlayer auraTarget = new TargetPlayer(); + this.getSpellAbility().addTarget(auraTarget); + this.getSpellAbility().addEffect(new AttachEffect(Constants.Outcome.Damage)); + this.addAbility(new EnchantAbility(auraTarget.getTargetName())); + + // If a source would deal damage to enchanted player, it deals double that damage to that player instead. + this.addAbility(new SimpleStaticAbility(Constants.Zone.BATTLEFIELD, new CurseOfBloodlettingEffect())); + } + + public CurseOfBloodletting(final CurseOfBloodletting card) { + super(card); + } + + @Override + public CurseOfBloodletting copy() { + return new CurseOfBloodletting(this); + } +} + +class CurseOfBloodlettingEffect extends ReplacementEffectImpl { + + public CurseOfBloodlettingEffect() { + super(Constants.Duration.WhileOnBattlefield, Constants.Outcome.Damage); + staticText = "If a source would deal damage to enchanted player, it deals double that damage to that player instead"; + } + + public CurseOfBloodlettingEffect(final CurseOfBloodlettingEffect effect) { + super(effect); + } + + @Override + public CurseOfBloodlettingEffect copy() { + return new CurseOfBloodlettingEffect(this); + } + + @Override + public boolean applies(GameEvent event, Ability source, Game game) { + switch (event.getType()) { + case DAMAGE_PLAYER: + StackObject spell = game.getStack().getStackObject(event.getSourceId()); + if (spell != null) { + Permanent enchantment = game.getPermanent(source.getSourceId()); + if (enchantment != null && enchantment.getAttachedTo() != null) { + Player player = game.getPlayer(enchantment.getAttachedTo()); + if (player != null && event.getTargetId().equals(player.getId())) { + event.setAmount(event.getAmount() * 2); + } + } + } + } + return false; + } + + @Override + public boolean apply(Game game, Ability source) { + return true; + } + + @Override + public boolean replaceEvent(GameEvent event, Ability source, Game game) { + return apply(game, source); + } + +} \ No newline at end of file diff --git a/Mage.Sets/src/mage/sets/darkascension/CurseOfEchoes.java b/Mage.Sets/src/mage/sets/darkascension/CurseOfEchoes.java new file mode 100644 index 00000000000..73e1c3ebb71 --- /dev/null +++ b/Mage.Sets/src/mage/sets/darkascension/CurseOfEchoes.java @@ -0,0 +1,176 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those 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.abilities.Ability; +import mage.abilities.Mode; +import mage.abilities.TriggeredAbilityImpl; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.AttachEffect; +import mage.abilities.keyword.EnchantAbility; +import mage.cards.CardImpl; +import mage.filter.Filter; +import mage.filter.FilterSpell; +import mage.game.Game; +import mage.game.events.GameEvent; +import mage.game.permanent.Permanent; +import mage.game.stack.Spell; +import mage.players.Player; +import mage.target.TargetPlayer; +import mage.target.TargetSpell; + +/** + * + * @author BetaSteward + */ +public class CurseOfEchoes extends CardImpl { + + public CurseOfEchoes(UUID ownerId) { + super(ownerId, 34, "Curse of Echoes", Rarity.RARE, new CardType[]{CardType.ENCHANTMENT}, "{4}{U}"); + this.expansionSetCode = "DKA"; + this.subtype.add("Aura"); + this.subtype.add("Curse"); + + this.color.setBlue(true); + + // Enchant player + TargetPlayer auraTarget = new TargetPlayer(); + this.getSpellAbility().addTarget(auraTarget); + this.getSpellAbility().addEffect(new AttachEffect(Constants.Outcome.Damage)); + this.addAbility(new EnchantAbility(auraTarget.getTargetName())); + + // Whenever enchanted player casts an instant or sorcery spell, each other player may copy that spell and may choose new targets for the copy he or she controls. + this.addAbility(new CurseOfEchoesCopyTriggeredAbility()); + } + + public CurseOfEchoes(final CurseOfEchoes card) { + super(card); + } + + @Override + public CurseOfEchoes copy() { + return new CurseOfEchoes(this); + } +} + +class CurseOfEchoesCopyTriggeredAbility extends TriggeredAbilityImpl { + + private static final FilterSpell filter = new FilterSpell(); + + static { + filter.getCardType().add(CardType.INSTANT); + filter.getCardType().add(CardType.SORCERY); + filter.setScopeCardType(Filter.ComparisonScope.Any); + } + + public CurseOfEchoesCopyTriggeredAbility() { + super(Constants.Zone.BATTLEFIELD, new CurseOfEchoesEffect(), false); + this.addTarget(new TargetSpell(filter)); + } + + public CurseOfEchoesCopyTriggeredAbility(final CurseOfEchoesCopyTriggeredAbility ability) { + super(ability); + } + + @Override + public CurseOfEchoesCopyTriggeredAbility copy() { + return new CurseOfEchoesCopyTriggeredAbility(this); + } + + @Override + public boolean checkTrigger(GameEvent event, Game game) { + if (event.getType() == GameEvent.EventType.SPELL_CAST) { + Spell spell = game.getStack().getSpell(event.getTargetId()); + if (spell != null && spell.getCardType().contains(CardType.INSTANT) || spell.getCardType().contains(CardType.SORCERY)) { + Permanent enchantment = game.getPermanent(sourceId); + if (enchantment != null && enchantment.getAttachedTo() != null) { + Player player = game.getPlayer(enchantment.getAttachedTo()); + if (player != null && spell.getControllerId().equals(player.getId())) { + this.getTargets().get(0).add(spell.getId(), game); + return true; + } + } + } + } + return false; + } + + @Override + public String getRule() { + return "Whenever enchanted player casts an instant or sorcery spell, each other player may copy that spell and may choose new targets for the copy he or she controls."; + } +} + +class CurseOfEchoesEffect extends OneShotEffect { + + public CurseOfEchoesEffect() { + super(Constants.Outcome.Copy); + } + + public CurseOfEchoesEffect(final CurseOfEchoesEffect effect) { + super(effect); + } + + @Override + public boolean apply(Game game, Ability source) { + Spell spell = game.getStack().getSpell(targetPointer.getFirst(source)); + if (spell != null) { + String chooseMessage = "Copy target spell? You may choose new targets for the copy."; + for (UUID playerId: game.getPlayerList()) { + if (!playerId.equals(spell.getControllerId())) { + Player player = game.getPlayer(playerId); + if (player.chooseUse(Constants.Outcome.Copy, chooseMessage, game)) { + Spell copy = spell.copySpell(); + copy.setControllerId(playerId); + copy.setCopiedSpell(true); + game.getStack().push(copy); + copy.chooseNewTargets(game, playerId); + } + } + } + return true; + } + return false; + } + + @Override + public CurseOfEchoesEffect copy() { + return new CurseOfEchoesEffect(this); + } + + @Override + public String getText(Mode mode) { + StringBuilder sb = new StringBuilder(); + sb.append("Copy target ").append(mode.getTargets().get(0).getTargetName()).append(". You may choose new targets for the copy"); + return sb.toString(); + } +} diff --git a/Mage.Sets/src/mage/sets/darkascension/CurseOfExhaustion.java b/Mage.Sets/src/mage/sets/darkascension/CurseOfExhaustion.java new file mode 100644 index 00000000000..10a2ee22bb0 --- /dev/null +++ b/Mage.Sets/src/mage/sets/darkascension/CurseOfExhaustion.java @@ -0,0 +1,157 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those 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.abilities.Ability; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.effects.ReplacementEffectImpl; +import mage.abilities.effects.common.AttachEffect; +import mage.abilities.keyword.EnchantAbility; +import mage.cards.CardImpl; +import mage.game.Game; +import mage.game.events.GameEvent; +import mage.game.permanent.Permanent; +import mage.players.Player; +import mage.target.TargetPlayer; +import mage.watchers.Watcher; +import mage.watchers.WatcherImpl; + +/** + * + * @author BetaSteward + */ +public class CurseOfExhaustion extends CardImpl { + + public CurseOfExhaustion(UUID ownerId) { + super(ownerId, 5, "Curse of Exhaustion", Rarity.UNCOMMON, new CardType[]{CardType.ENCHANTMENT}, "{2}{W}{W}"); + this.expansionSetCode = "DKA"; + this.subtype.add("Aura"); + this.subtype.add("Curse"); + + this.color.setWhite(true); + this.addWatcher(new CurseOfExhaustionWatcher()); + + // Enchant player + TargetPlayer auraTarget = new TargetPlayer(); + this.getSpellAbility().addTarget(auraTarget); + this.getSpellAbility().addEffect(new AttachEffect(Constants.Outcome.Detriment)); + this.addAbility(new EnchantAbility(auraTarget.getTargetName())); + + // Enchanted player can't cast more than one spell each turn. + this.addAbility(new SimpleStaticAbility(Constants.Zone.BATTLEFIELD, new CurseOfExhaustionEffect())); + } + + public CurseOfExhaustion(final CurseOfExhaustion card) { + super(card); + } + + @Override + public CurseOfExhaustion copy() { + return new CurseOfExhaustion(this); + } +} + +class CurseOfExhaustionWatcher extends WatcherImpl { + + public CurseOfExhaustionWatcher() { + super("SpellCast", Constants.WatcherScope.PLAYER); + } + + public CurseOfExhaustionWatcher(final CurseOfExhaustionWatcher watcher) { + super(watcher); + } + + @Override + public CurseOfExhaustionWatcher copy() { + return new CurseOfExhaustionWatcher(this); + } + + @Override + public void watch(GameEvent event, Game game) { + if (condition == true) //no need to check - condition has already occured + return; + if (event.getType() == GameEvent.EventType.SPELL_CAST ) { + Permanent enchantment = game.getPermanent(this.sourceId); + if (enchantment != null && enchantment.getAttachedTo() != null) { + Player player = game.getPlayer(enchantment.getAttachedTo()); + if (player != null && event.getPlayerId().equals(player.getId())) { + condition = true; + } + } + } + } + +} + +class CurseOfExhaustionEffect extends ReplacementEffectImpl { + + public CurseOfExhaustionEffect() { + super(Constants.Duration.WhileOnBattlefield, Constants.Outcome.Benefit); + staticText = "Enchanted player can't cast more than one spell each turn."; + } + + public CurseOfExhaustionEffect(final CurseOfExhaustionEffect effect) { + super(effect); + } + + @Override + public CurseOfExhaustionEffect copy() { + return new CurseOfExhaustionEffect(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.CAST_SPELL) { + Permanent enchantment = game.getPermanent(source.getSourceId()); + if (enchantment != null && enchantment.getAttachedTo() != null) { + Player player = game.getPlayer(enchantment.getAttachedTo()); + if (player != null && event.getPlayerId().equals(player.getId())) { + Watcher watcher = game.getState().getWatchers().get("SpellCast", source.getControllerId()); + if (watcher != null && watcher.conditionMet()) + return true; + } + } + } + return false; + } + +} diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/TestCurseOfBloodletting.java b/Mage.Tests/src/test/java/org/mage/test/cards/TestCurseOfBloodletting.java new file mode 100644 index 00000000000..1482d0e04fc --- /dev/null +++ b/Mage.Tests/src/test/java/org/mage/test/cards/TestCurseOfBloodletting.java @@ -0,0 +1,31 @@ +package org.mage.test.cards; + +import mage.Constants; +import org.junit.Test; +import org.mage.test.serverside.base.CardTestPlayerBase; + +/** + * + * @author BetaSteward + */ +public class TestCurseOfBloodletting extends CardTestPlayerBase { + + @Test + public void testCard1() { + addCard(Constants.Zone.BATTLEFIELD, playerA, "Mountain", 7); + addCard(Constants.Zone.HAND, playerA, "Curse of Bloodletting"); + addCard(Constants.Zone.HAND, playerA, "Lightning Bolt", 2); + + castSpell(1, Constants.PhaseStep.PRECOMBAT_MAIN, playerA, "Curse of Bloodletting", playerB); + castSpell(1, Constants.PhaseStep.POSTCOMBAT_MAIN, playerA, "Lightning Bolt", playerB); + castSpell(1, Constants.PhaseStep.POSTCOMBAT_MAIN, playerA, "Lightning Bolt", playerA); + + + setStopAt(1, Constants.PhaseStep.END_TURN); + execute(); + + assertLife(playerA, 17); + assertLife(playerB, 14); + } + +} diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/TestCurseOfEchoes.java b/Mage.Tests/src/test/java/org/mage/test/cards/TestCurseOfEchoes.java new file mode 100644 index 00000000000..ef0f2d08688 --- /dev/null +++ b/Mage.Tests/src/test/java/org/mage/test/cards/TestCurseOfEchoes.java @@ -0,0 +1,30 @@ +package org.mage.test.cards; + +import mage.Constants; +import org.junit.Test; +import org.mage.test.serverside.base.CardTestPlayerBase; + +/** + * + * @author BetaSteward + */ +public class TestCurseOfEchoes extends CardTestPlayerBase { + + @Test + public void testCard1() { + addCard(Constants.Zone.BATTLEFIELD, playerA, "Island", 5); + addCard(Constants.Zone.BATTLEFIELD, playerB, "Island", 5); + addCard(Constants.Zone.HAND, playerA, "Curse of Echoes"); + addCard(Constants.Zone.HAND, playerB, "Jace's Ingenuity"); + + castSpell(1, Constants.PhaseStep.PRECOMBAT_MAIN, playerA, "Curse of Echoes", playerB); + castSpell(1, Constants.PhaseStep.POSTCOMBAT_MAIN, playerB, "Jace's Ingenuity"); + + setStopAt(1, Constants.PhaseStep.END_TURN); + execute(); + + assertHandCount(playerA, 3); + assertHandCount(playerB, 3); + } + +} diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/TestCurseOfExhaustion.java b/Mage.Tests/src/test/java/org/mage/test/cards/TestCurseOfExhaustion.java new file mode 100644 index 00000000000..e4a26340364 --- /dev/null +++ b/Mage.Tests/src/test/java/org/mage/test/cards/TestCurseOfExhaustion.java @@ -0,0 +1,51 @@ +package org.mage.test.cards; + +import mage.Constants; +import org.junit.Ignore; +import org.junit.Test; +import org.mage.test.serverside.base.CardTestPlayerBase; + +/** + * + * @author BetaSteward + */ +public class TestCurseOfExhaustion extends CardTestPlayerBase { + + @Test + public void testCard1() { + addCard(Constants.Zone.BATTLEFIELD, playerA, "Plains", 4); + addCard(Constants.Zone.HAND, playerA, "Curse of Exhaustion"); + addCard(Constants.Zone.BATTLEFIELD, playerB, "Mountain", 2); + addCard(Constants.Zone.HAND, playerB, "Lightning Bolt", 2); + + castSpell(1, Constants.PhaseStep.PRECOMBAT_MAIN, playerA, "Curse of Exhaustion", playerB); + castSpell(1, Constants.PhaseStep.POSTCOMBAT_MAIN, playerB, "Lightning Bolt", playerA); + castSpell(1, Constants.PhaseStep.POSTCOMBAT_MAIN, playerB, "Lightning Bolt", playerA); + + + setStopAt(1, Constants.PhaseStep.END_TURN); + execute(); + + assertLife(playerB, 20); + assertLife(playerA, 17); + } + + @Test + public void testCard2() { + addCard(Constants.Zone.BATTLEFIELD, playerA, "Mountain", 4); + addCard(Constants.Zone.BATTLEFIELD, playerA, "Plains", 2); + addCard(Constants.Zone.HAND, playerA, "Curse of Exhaustion"); + addCard(Constants.Zone.HAND, playerA, "Lightning Bolt", 2); + + castSpell(1, Constants.PhaseStep.PRECOMBAT_MAIN, playerA, "Curse of Exhaustion", playerB); + castSpell(1, Constants.PhaseStep.POSTCOMBAT_MAIN, playerA, "Lightning Bolt", playerB); + castSpell(1, Constants.PhaseStep.POSTCOMBAT_MAIN, playerA, "Lightning Bolt", playerB); + + + setStopAt(1, Constants.PhaseStep.END_TURN); + execute(); + + assertLife(playerA, 20); + assertLife(playerB, 14); + } +} 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 4f82609d785..1a467a7c681 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 @@ -352,6 +352,17 @@ public abstract class CardTestPlayerAPIImpl extends MageTestPlayerBase implement Assert.assertEquals("(Battlefield) Card counts are not equal (" + cardName + ")", count, actualCount); } + /** + * Assert card count in player's hand. + * + * @param player {@link Player} who's hand should be counted. + * @param count Expected count. + */ + public void assertHandCount(Player player, int count) throws AssertionError { + int actual = currentGame.getPlayer(player.getId()).getHand().size(); + Assert.assertEquals("(Hand) Card counts are not equal ", count, actual); + } + /** * Assert card count in player's graveyard. * diff --git a/Mage/src/mage/game/stack/Spell.java b/Mage/src/mage/game/stack/Spell.java index 9b34d840a73..fbe15d83ee6 100644 --- a/Mage/src/mage/game/stack/Spell.java +++ b/Mage/src/mage/game/stack/Spell.java @@ -303,6 +303,7 @@ public class Spell> implements StackObject, Card { @Override public void setControllerId(UUID controllerId) { + this.ability.setControllerId(controllerId); this.controllerId = controllerId; }