From 5ce105e6995b54475c99a98c47182122834a0b25 Mon Sep 17 00:00:00 2001 From: LevelX2 Date: Sat, 16 Aug 2014 16:55:27 +0200 Subject: [PATCH] * Voice of Resurgence - Fixed a bug that the triggered ability did not work if a token copy of Voice of Resurgence died. --- .../sets/dragonsmaze/VoiceOfResurgence.java | 32 +++--- .../cards/copy/KikiJikiMirrorBreakerTest.java | 103 ++++++++++++++++++ .../common/DamageEverythingEffect.java | 5 +- 3 files changed, 124 insertions(+), 16 deletions(-) create mode 100644 Mage.Tests/src/test/java/org/mage/test/cards/copy/KikiJikiMirrorBreakerTest.java diff --git a/Mage.Sets/src/mage/sets/dragonsmaze/VoiceOfResurgence.java b/Mage.Sets/src/mage/sets/dragonsmaze/VoiceOfResurgence.java index 2b2db95ab0d..d687cdb4e39 100644 --- a/Mage.Sets/src/mage/sets/dragonsmaze/VoiceOfResurgence.java +++ b/Mage.Sets/src/mage/sets/dragonsmaze/VoiceOfResurgence.java @@ -28,9 +28,6 @@ package mage.sets.dragonsmaze; import java.util.UUID; - -import mage.constants.CardType; -import mage.constants.Rarity; import mage.MageInt; import mage.MageObject; import mage.abilities.TriggeredAbilityImpl; @@ -40,12 +37,15 @@ import mage.abilities.dynamicvalue.common.PermanentsOnBattlefieldCount; import mage.abilities.effects.common.CreateTokenEffect; import mage.abilities.effects.common.continious.SetPowerToughnessSourceEffect; import mage.cards.CardImpl; +import mage.constants.CardType; import mage.constants.Duration; +import mage.constants.Rarity; import mage.constants.Zone; import mage.filter.common.FilterControlledPermanent; import mage.filter.predicate.mageobject.CardTypePredicate; import mage.game.Game; import mage.game.events.GameEvent; +import mage.game.events.ZoneChangeEvent; import mage.game.permanent.token.Token; import mage.game.stack.Spell; @@ -102,19 +102,16 @@ class VoiceOfResurgenceTriggeredAbility extends TriggeredAbilityImpl { } } // Voice Of Resurgence Dies - if (event.getType() == GameEvent.EventType.ZONE_CHANGE) { - if (super.getSourceId().equals(event.getTargetId())) { - MageObject before = game.getLastKnownInformation(event.getTargetId(), Zone.BATTLEFIELD); - Zone after = game.getState().getZone(event.getTargetId()); - return before != null && after != null && Zone.GRAVEYARD.match(after); - } + if (event.getType() == GameEvent.EventType.ZONE_CHANGE && getSourceId().equals(event.getTargetId())) { + ZoneChangeEvent zce = (ZoneChangeEvent) event; + return zce.getFromZone().equals(Zone.BATTLEFIELD) && zce.getToZone().equals(Zone.GRAVEYARD); } return false; } @Override public String getRule() { - return "Whenever an opponent casts a spell during your turn or when Voice of Resurgence dies, put a green and white Elemental creature token onto the battlefield with \"This creature's power and toughness are each equal to the number of creatures you control."; + return "Whenever an opponent casts a spell during your turn or when {this} dies, put a green and white Elemental creature token onto the battlefield with \"This creature's power and toughness are each equal to the number of creatures you control."; } @Override @@ -125,17 +122,24 @@ class VoiceOfResurgenceTriggeredAbility extends TriggeredAbilityImpl { class VoiceOfResurgenceToken extends Token { + private static final FilterControlledPermanent filter = new FilterControlledPermanent("creatures you control"); + private static final DynamicValue creaturesControlled = new PermanentsOnBattlefieldCount(filter); + + static { + filter.add(new CardTypePredicate(CardType.CREATURE)); + } + public VoiceOfResurgenceToken() { super("Elemental", "X/X green and white Elemental creature with with \"This creature's power and toughness are each equal to the number of creatures you control."); + setOriginalExpansionSetCode("DGM"); cardType.add(CardType.CREATURE); color.setGreen(true); color.setWhite(true); subtype.add("Elemental"); - power = new MageInt(0); + + power = new MageInt(0); toughness = new MageInt(0); - FilterControlledPermanent filter = new FilterControlledPermanent("creatures you control"); - filter.add(new CardTypePredicate(CardType.CREATURE)); - DynamicValue creaturesControlled = new PermanentsOnBattlefieldCount(filter); + this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new SetPowerToughnessSourceEffect(creaturesControlled, Duration.EndOfGame))); } } diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/copy/KikiJikiMirrorBreakerTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/copy/KikiJikiMirrorBreakerTest.java new file mode 100644 index 00000000000..6fad9673f1b --- /dev/null +++ b/Mage.Tests/src/test/java/org/mage/test/cards/copy/KikiJikiMirrorBreakerTest.java @@ -0,0 +1,103 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ + +package 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 KikiJikiMirrorBreakerTest extends CardTestPlayerBase { + + @Test + public void testSimpleCopy() { + addCard(Zone.BATTLEFIELD, playerA, "Mountain", 5); + addCard(Zone.BATTLEFIELD, playerA, "Kiki-Jiki, Mirror Breaker", 1); + addCard(Zone.BATTLEFIELD, playerA, "Voice of Resurgence", 1); + + activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "{T}: Put a token that's a copy of target nonlegendary creature you control onto the battlefield. That token has haste. Sacrifice it at the beginning of the next end step."); + + setStopAt(1, PhaseStep.BEGIN_COMBAT); + execute(); + + assertLife(playerA, 20); + assertLife(playerB, 20); + assertPermanentCount(playerA, "Voice of Resurgence", 2); + } + + @Test + public void testSimpleCopyExiledAtEnd() { + addCard(Zone.BATTLEFIELD, playerA, "Mountain", 5); + addCard(Zone.BATTLEFIELD, playerA, "Kiki-Jiki, Mirror Breaker", 1); + addCard(Zone.BATTLEFIELD, playerA, "Voice of Resurgence", 1); + + activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "{T}: Put a token that's a copy of target nonlegendary creature you control onto the battlefield. That token has haste. Sacrifice it at the beginning of the next end step."); + + setStopAt(1, PhaseStep.END_TURN); + execute(); + + assertLife(playerA, 20); + assertLife(playerB, 20); + assertPermanentCount(playerA, "Elemental", 0); // because the copy was exiled + assertPermanentCount(playerA, "Voice of Resurgence", 1); + } + + @Test + public void testCopyAndCopiedTokenDies() { + addCard(Zone.BATTLEFIELD, playerA, "Mountain", 5); + addCard(Zone.BATTLEFIELD, playerA, "Kiki-Jiki, Mirror Breaker", 1); + addCard(Zone.BATTLEFIELD, playerA, "Voice of Resurgence", 1); + + addCard(Zone.BATTLEFIELD, playerB, "Mountain", 3); + addCard(Zone.HAND, playerB, "Flamebreak"); + + activateAbility(2, PhaseStep.PRECOMBAT_MAIN, playerA, "{T}: Put a token that's a copy of target nonlegendary creature you control onto the battlefield. That token has haste. Sacrifice it at the beginning of the next end step."); + + castSpell(2, PhaseStep.POSTCOMBAT_MAIN, playerB, "Flamebreak"); + setStopAt(2, PhaseStep.END_TURN); + execute(); + + assertLife(playerA, 17); + assertLife(playerB, 17); + + assertGraveyardCount(playerB, "Flamebreak", 1); + + assertPermanentCount(playerA, "Voice of Resurgence", 0); + assertGraveyardCount(playerA, "Voice of Resurgence", 1); + + assertPermanentCount(playerA, "Elemental", 2); + + + } + +} \ No newline at end of file diff --git a/Mage/src/mage/abilities/effects/common/DamageEverythingEffect.java b/Mage/src/mage/abilities/effects/common/DamageEverythingEffect.java index dfa0633f439..e45f227091e 100644 --- a/Mage/src/mage/abilities/effects/common/DamageEverythingEffect.java +++ b/Mage/src/mage/abilities/effects/common/DamageEverythingEffect.java @@ -78,14 +78,15 @@ public class DamageEverythingEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { + int damage = amount.calculate(game, source, this); List permanents = game.getBattlefield().getActivePermanents(filter, source.getControllerId(), game); for (Permanent permanent: permanents) { - permanent.damage(amount.calculate(game, source, this), source.getSourceId(), game, false, true); + permanent.damage(damage, source.getSourceId(), game, false, true); } for (UUID playerId: game.getPlayer(source.getControllerId()).getInRange()) { Player player = game.getPlayer(playerId); if (player != null) { - player.damage(amount.calculate(game, source, this), source.getSourceId(), game, false, true); + player.damage(damage, source.getSourceId(), game, false, true); } } return true;