diff --git a/Mage.Sets/src/mage/cards/a/AngelicAccord.java b/Mage.Sets/src/mage/cards/a/AngelicAccord.java index 91446af496e..b8922cdf652 100644 --- a/Mage.Sets/src/mage/cards/a/AngelicAccord.java +++ b/Mage.Sets/src/mage/cards/a/AngelicAccord.java @@ -49,8 +49,7 @@ import mage.watchers.common.PlayerGainedLifeWatcher; public class AngelicAccord extends CardImpl { public AngelicAccord(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.ENCHANTMENT},"{3}{W}"); - + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{3}{W}"); // At the beginning of each end step, if you gained 4 or more life this turn, put a 4/4 white Angel creature token with flying onto the battlefield. this.addAbility(new BeginningOfEndStepTriggeredAbility(Zone.BATTLEFIELD, new CreateTokenEffect(new AngelToken()), TargetController.ANY, @@ -76,7 +75,7 @@ class YouGainedLifeCondition extends IntCompareCondition { @Override protected int getInputValue(Game game, Ability source) { int gainedLife = 0; - PlayerGainedLifeWatcher watcher = (PlayerGainedLifeWatcher) game.getState().getWatchers().get("PlayerGainedLifeWatcher"); + PlayerGainedLifeWatcher watcher = (PlayerGainedLifeWatcher) game.getState().getWatchers().get(PlayerGainedLifeWatcher.class.getName()); if (watcher != null) { gainedLife = watcher.getLiveGained(source.getControllerId()); } diff --git a/Mage.Sets/src/mage/cards/l/LoneRider.java b/Mage.Sets/src/mage/cards/l/LoneRider.java index 6aa798d32ad..e490bb46048 100644 --- a/Mage.Sets/src/mage/cards/l/LoneRider.java +++ b/Mage.Sets/src/mage/cards/l/LoneRider.java @@ -39,9 +39,9 @@ import mage.abilities.effects.common.TransformSourceEffect; import mage.abilities.keyword.FirstStrikeAbility; import mage.abilities.keyword.LifelinkAbility; import mage.abilities.keyword.TransformAbility; -import mage.cards.i.ItThatRidesAsOne; import mage.cards.CardImpl; import mage.cards.CardSetInfo; +import mage.cards.i.ItThatRidesAsOne; import mage.constants.CardType; import mage.game.Game; import mage.game.events.GameEvent; @@ -56,7 +56,7 @@ public class LoneRider extends CardImpl { private static final String ruleText = "At the beginning of the end step, if you gained 3 or more life this turn, transform {this}"; public LoneRider(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{1}{W}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{W}"); this.subtype.add("Human"); this.subtype.add("Knight"); this.power = new MageInt(1); @@ -96,7 +96,7 @@ class YouGainedLifeCondition extends IntCompareCondition { @Override protected int getInputValue(Game game, Ability source) { int gainedLife = 0; - PlayerGainedLifeWatcher watcher = (PlayerGainedLifeWatcher) game.getState().getWatchers().get("PlayerGainedLifeWatcher"); + PlayerGainedLifeWatcher watcher = (PlayerGainedLifeWatcher) game.getState().getWatchers().get(PlayerGainedLifeWatcher.class.getName()); if (watcher != null) { gainedLife = watcher.getLiveGained(source.getControllerId()); } diff --git a/Mage.Sets/src/mage/cards/n/NeedlebiteTrap.java b/Mage.Sets/src/mage/cards/n/NeedlebiteTrap.java index da2b5068dc6..fa69a3bd4fc 100644 --- a/Mage.Sets/src/mage/cards/n/NeedlebiteTrap.java +++ b/Mage.Sets/src/mage/cards/n/NeedlebiteTrap.java @@ -28,8 +28,6 @@ package mage.cards.n; import java.util.UUID; - -import mage.constants.CardType; import mage.abilities.Ability; import mage.abilities.condition.Condition; import mage.abilities.costs.AlternativeCostSourceAbility; @@ -38,6 +36,7 @@ import mage.abilities.effects.common.GainLifeEffect; import mage.abilities.effects.common.LoseLifeTargetEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; +import mage.constants.CardType; import mage.game.Game; import mage.target.TargetPlayer; import mage.watchers.common.PlayerGainedLifeWatcher; @@ -49,7 +48,7 @@ import mage.watchers.common.PlayerGainedLifeWatcher; public class NeedlebiteTrap extends CardImpl { public NeedlebiteTrap(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.INSTANT},"{5}{B}{B}"); + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{5}{B}{B}"); this.subtype.add("Trap"); // If an opponent gained life this turn, you may pay {B} rather than pay Needlebite Trap's mana cost. @@ -81,7 +80,7 @@ class NeedlebiteTrapCondition implements Condition { @Override public boolean apply(Game game, Ability source) { - PlayerGainedLifeWatcher watcher = (PlayerGainedLifeWatcher) game.getState().getWatchers().get("PlayerGainedLifeWatcher"); + PlayerGainedLifeWatcher watcher = (PlayerGainedLifeWatcher) game.getState().getWatchers().get(PlayerGainedLifeWatcher.class.getName()); if (watcher != null) { for (UUID opponentId : game.getOpponents(source.getControllerId())) { if (watcher.getLiveGained(opponentId) > 0) { diff --git a/Mage.Sets/src/mage/cards/t/TamiyosJournal.java b/Mage.Sets/src/mage/cards/t/TamiyosJournal.java index ed83d0d5467..e56cc2ba74f 100644 --- a/Mage.Sets/src/mage/cards/t/TamiyosJournal.java +++ b/Mage.Sets/src/mage/cards/t/TamiyosJournal.java @@ -50,18 +50,18 @@ import mage.target.common.TargetControlledPermanent; * @author fireshoes */ public class TamiyosJournal extends CardImpl { - + private static final FilterControlledPermanent filter = new FilterControlledPermanent("three Clues"); - + static { filter.add(new SubtypePredicate("Clue")); } public TamiyosJournal(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.ARTIFACT},"{5}"); + super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{5}"); this.supertype.add("Legendary"); - // At the beginning of your upkeep, investigate. + // At the beginning of your upkeep, investigate (Put a colorless Clue artifact token onto the battlefield with \"{2}, Sacrifice this artifact: Draw a card.\"). this.addAbility(new BeginningOfUpkeepTriggeredAbility(Zone.BATTLEFIELD, new InvestigateEffect(), TargetController.YOU, false)); // {T}, Sacrifice three Clues: Search your library for a card and put that card into your hand. Then shuffle your library. diff --git a/Mage.Tests/src/test/java/org/mage/test/rollback/NewCreaturesAreRemovedTest.java b/Mage.Tests/src/test/java/org/mage/test/rollback/NewCreaturesAreRemovedTest.java new file mode 100644 index 00000000000..bab2478981d --- /dev/null +++ b/Mage.Tests/src/test/java/org/mage/test/rollback/NewCreaturesAreRemovedTest.java @@ -0,0 +1,136 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation 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.rollback; + +import mage.constants.PhaseStep; +import mage.constants.Zone; +import org.junit.Test; +import org.mage.test.serverside.base.CardTestPlayerBase; + +/** + * + * @author LevelX2 + */ +public class NewCreaturesAreRemovedTest extends CardTestPlayerBase { + + /** + * I was playing with a Tamiyo's Journal in the battlefield. + * + * During my turn I rollbacked. The clue generated by Tamiyo's Journal + * stayed on battlefield and when my turn started again, it re-investigated + * for another one. + * + */ + @Test + public void testTamiyosJournal() { + addCard(Zone.BATTLEFIELD, playerA, "Swamp", 5); + // At the beginning of your upkeep, investigate (Put a colorless Clue artifact token onto the battlefield with \"{2}, Sacrifice this artifact: Draw a card.\"). + // {T}, Sacrifice three Clues: Search your library for a card and put that card into your hand. Then shuffle your library. + addCard(Zone.HAND, playerA, "Tamiyo's Journal"); // Artifact {5} + addCard(Zone.BATTLEFIELD, playerA, "Silvercoat Lion", 3); + addCard(Zone.BATTLEFIELD, playerB, "Pillarfield Ox", 3); + + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Tamiyo's Journal"); + + // As Port Town enters the battlefield, you may reveal a Plains or Island card from your hand. If you don't, Port Town enters the battlefield tapped. + // {T}: Add {W} or {U} to your mana pool. + addCard(Zone.HAND, playerA, "Port Town"); // Land + addCard(Zone.HAND, playerA, "Island"); // Land + + attack(2, playerB, "Pillarfield Ox"); + + attack(3, playerA, "Silvercoat Lion"); + + attack(4, playerB, "Pillarfield Ox"); + + attack(5, playerA, "Silvercoat Lion"); + + attack(6, playerB, "Pillarfield Ox"); + + playLand(7, PhaseStep.PRECOMBAT_MAIN, playerA, "Port Town"); + attack(7, playerA, "Silvercoat Lion"); + + setStopAt(7, PhaseStep.POSTCOMBAT_MAIN); + execute(); + + assertLife(playerA, 14); + assertLife(playerB, 14); + assertPermanentCount(playerA, "Port Town", 1); + assertTapped("Port Town", false); + assertPermanentCount(playerA, "Clue", 3); + + } + + @Test + public void testTamiyosJournalAndRollback() { + addCard(Zone.BATTLEFIELD, playerA, "Swamp", 5); + // At the beginning of your upkeep, investigate (Put a colorless Clue artifact token onto the battlefield with \"{2}, Sacrifice this artifact: Draw a card.\"). + // {T}, Sacrifice three Clues: Search your library for a card and put that card into your hand. Then shuffle your library. + addCard(Zone.HAND, playerA, "Tamiyo's Journal"); // Artifact {5} + + // As Port Town enters the battlefield, you may reveal a Plains or Island card from your hand. If you don't, Port Town enters the battlefield tapped. + // {T}: Add {W} or {U} to your mana pool. + addCard(Zone.HAND, playerA, "Port Town"); // Land + addCard(Zone.HAND, playerA, "Island"); // Land + + addCard(Zone.BATTLEFIELD, playerA, "Silvercoat Lion", 3); + addCard(Zone.BATTLEFIELD, playerB, "Pillarfield Ox", 3); + + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Tamiyo's Journal"); + + attack(2, playerB, "Pillarfield Ox"); + + attack(3, playerA, "Silvercoat Lion"); + rollbackTurns(3, PhaseStep.END_TURN, playerA, 0); + + attack(4, playerB, "Pillarfield Ox"); + + attack(5, playerA, "Silvercoat Lion"); + + rollbackTurns(5, PhaseStep.END_TURN, playerA, 0); + + attack(6, playerB, "Pillarfield Ox"); + + playLand(7, PhaseStep.PRECOMBAT_MAIN, playerA, "Port Town"); + attack(7, playerA, "Silvercoat Lion"); + + rollbackTurns(7, PhaseStep.END_TURN, playerA, 0); + + setStopAt(7, PhaseStep.POSTCOMBAT_MAIN); + execute(); + + assertPermanentCount(playerA, "Port Town", 1); + assertTapped("Port Town", false); + assertPermanentCount(playerA, "Clue", 3); + + assertLife(playerA, 14); + assertLife(playerB, 14); + + } + +} diff --git a/Mage.Tests/src/test/java/org/mage/test/rollback/TransformTest.java b/Mage.Tests/src/test/java/org/mage/test/rollback/TransformTest.java new file mode 100644 index 00000000000..ca6c01584d5 --- /dev/null +++ b/Mage.Tests/src/test/java/org/mage/test/rollback/TransformTest.java @@ -0,0 +1,99 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation 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.rollback; + +import mage.constants.PhaseStep; +import mage.constants.Zone; +import org.junit.Test; +import org.mage.test.serverside.base.CardTestPlayerBase; + +/** + * + * @author LevelX2 + */ +public class TransformTest extends CardTestPlayerBase { + + /** + * + */ + @Test + public void testTransform() { + addCard(Zone.BATTLEFIELD, playerA, "Plains", 5); + // First strike, lifelink + // At the beginning of the end step, if you gained 3 or more life this turn, transform Lone Rider. + // BACK: It That Rides as One + // Creature 4/4 First strike, lifelink + addCard(Zone.HAND, playerA, "Lone Rider"); // Creature {1}{W} 1/1 + // When Venerable Monk enters the battlefield, you gain 2 life. + addCard(Zone.HAND, playerA, "Venerable Monk"); // Creature {2}{W} 2/2 + + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Lone Rider"); + castSpell(3, PhaseStep.POSTCOMBAT_MAIN, playerA, "Venerable Monk"); + + attack(3, playerA, "Lone Rider"); + + setStopAt(4, PhaseStep.PRECOMBAT_MAIN); + execute(); + + assertLife(playerA, 23); + assertLife(playerB, 19); + + assertPermanentCount(playerA, "Venerable Monk", 1); + assertPermanentCount(playerA, "It That Rides as One", 1); + + } + + @Test + public void testRollbackWithTransform() { + addCard(Zone.BATTLEFIELD, playerA, "Plains", 5); + // First strike, lifelink + // At the beginning of the end step, if you gained 3 or more life this turn, transform Lone Rider. + // BACK: It That Rides as One + // Creature 4/4 First strike, lifelink + addCard(Zone.HAND, playerA, "Lone Rider"); // Creature {1}{W} 1/1 + // When Venerable Monk enters the battlefield, you gain 2 life. + addCard(Zone.HAND, playerA, "Venerable Monk"); // Creature {2}{W} 2/2 + + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Lone Rider"); + castSpell(3, PhaseStep.POSTCOMBAT_MAIN, playerA, "Venerable Monk"); + + attack(3, playerA, "Lone Rider"); + + rollbackTurns(3, PhaseStep.END_TURN, playerA, 0); + setStopAt(4, PhaseStep.PRECOMBAT_MAIN); + execute(); + + assertLife(playerA, 23); + assertLife(playerB, 19); + + assertPermanentCount(playerA, "Venerable Monk", 1); + assertPermanentCount(playerA, "It That Rides as One", 1); + + } + +} diff --git a/Mage/src/main/java/mage/abilities/dynamicvalue/common/ControllerGotLifeCount.java b/Mage/src/main/java/mage/abilities/dynamicvalue/common/ControllerGotLifeCount.java index 4884eb2c457..37bf1032449 100644 --- a/Mage/src/main/java/mage/abilities/dynamicvalue/common/ControllerGotLifeCount.java +++ b/Mage/src/main/java/mage/abilities/dynamicvalue/common/ControllerGotLifeCount.java @@ -59,7 +59,7 @@ public class ControllerGotLifeCount implements DynamicValue, MageSingleton { } public int calculate(Game game, UUID controllerId) { - PlayerGainedLifeWatcher watcher = (PlayerGainedLifeWatcher) game.getState().getWatchers().get("PlayerGainedLifeWatcher"); + PlayerGainedLifeWatcher watcher = (PlayerGainedLifeWatcher) game.getState().getWatchers().get(PlayerGainedLifeWatcher.class.getName()); if (watcher != null) { return watcher.getLiveGained(controllerId); } diff --git a/Mage/src/main/java/mage/watchers/common/PlayerGainedLifeWatcher.java b/Mage/src/main/java/mage/watchers/common/PlayerGainedLifeWatcher.java index 95e6fea3548..cc26a60ab89 100644 --- a/Mage/src/main/java/mage/watchers/common/PlayerGainedLifeWatcher.java +++ b/Mage/src/main/java/mage/watchers/common/PlayerGainedLifeWatcher.java @@ -25,7 +25,6 @@ * authors and should not be interpreted as representing official policies, either expressed * or implied, of BetaSteward_at_googlemail.com. */ - package mage.watchers.common; import java.util.HashMap; @@ -37,8 +36,6 @@ import mage.game.Game; import mage.game.events.GameEvent; import mage.watchers.Watcher; - - /** * Counts amount of life gained during the current turn by players. * @@ -47,11 +44,10 @@ import mage.watchers.Watcher; */ public class PlayerGainedLifeWatcher extends Watcher { - private Map amountOfLifeGainedThisTurn = new HashMap(); - + private final Map amountOfLifeGainedThisTurn = new HashMap<>(); public PlayerGainedLifeWatcher() { - super("PlayerGainedLifeWatcher", WatcherScope.GAME); + super(PlayerGainedLifeWatcher.class.getName(), WatcherScope.GAME); } public PlayerGainedLifeWatcher(final PlayerGainedLifeWatcher watcher) { @@ -71,9 +67,9 @@ public class PlayerGainedLifeWatcher extends Watcher { if (playerId != null) { Integer amount = amountOfLifeGainedThisTurn.get(playerId); if (amount == null) { - amount = Integer.valueOf(event.getAmount()); + amount = event.getAmount(); } else { - amount = Integer.valueOf(amount + event.getAmount()); + amount = amount + event.getAmount(); } amountOfLifeGainedThisTurn.put(playerId, amount); } @@ -83,7 +79,7 @@ public class PlayerGainedLifeWatcher extends Watcher { public int getLiveGained(UUID playerId) { Integer amount = amountOfLifeGainedThisTurn.get(playerId); if (amount != null) { - return amount.intValue(); + return amount; } return 0; }