mirror of
https://github.com/correl/mage.git
synced 2025-01-12 11:08:01 +00:00
Added some tests for rollback (#2072). Could not reproduce any problems yet.
This commit is contained in:
parent
baeaaa3eb7
commit
316b1848c4
8 changed files with 253 additions and 24 deletions
|
@ -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());
|
||||
}
|
||||
|
|
|
@ -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());
|
||||
}
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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);
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -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);
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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<UUID, Integer> amountOfLifeGainedThisTurn = new HashMap<UUID, Integer>();
|
||||
|
||||
private final Map<UUID, Integer> 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;
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue