Skip to content

Commit

Permalink
* No more continuous effects stay on battlefield after player leave t…
Browse files Browse the repository at this point in the history
…he game;

Test framework: added real time check for player in game or not;
  • Loading branch information
JayDi85 committed Apr 28, 2019
1 parent 00633ce commit 9ef2e0b
Show file tree
Hide file tree
Showing 5 changed files with 244 additions and 25 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,132 @@
package org.mage.test.cards.continuous;

import mage.abilities.common.SimpleStaticAbility;
import mage.abilities.effects.common.continuous.BoostAllEffect;
import mage.constants.Duration;
import mage.constants.PhaseStep;
import mage.constants.Zone;
import org.junit.Test;
import org.mage.test.serverside.base.CardTestMultiPlayerBaseWithRangeAll;

/**
* @author JayDi85
*/
public class PlayerLeavesGameTest extends CardTestMultiPlayerBaseWithRangeAll {

/*
800.4a When a player leaves the game, all objects (see rule 109) owned by that player leave the game and any effects
which give that player control of any objects or players end. Then, if that player controlled any objects on the stack
not represented by cards, those objects cease to exist. Then, if there are any objects still controlled by that player,
those objects are exiled. This is not a state-based action. It happens as soon as the player leaves the game.
If the player who left the game had priority at the time he or she left, priority passes to the next player in turn
order who’s still in the game.
*/

String cardBear2 = "Balduvian Bears"; // 2/2

@Test
public void test_PlayerLeaveGame() {
// Player order: A -> D -> C -> B

// B must checks A for online status
checkPlayerInGame("turn 1", 1, PhaseStep.PRECOMBAT_MAIN, playerD, playerA, true);
checkPlayerInGame("turn 2", 2, PhaseStep.PRECOMBAT_MAIN, playerD, playerA, true);
checkPlayerInGame("turn 3 before", 3, PhaseStep.PRECOMBAT_MAIN, playerD, playerA, true);

concede(3, PhaseStep.POSTCOMBAT_MAIN, playerA);

checkPlayerInGame("turn 3 after", 3, PhaseStep.END_TURN, playerD, playerA, false);
checkPlayerInGame("turn 4", 4, PhaseStep.PRECOMBAT_MAIN, playerD, playerA, false);

setStopAt(4, PhaseStep.CLEANUP);
setStrictChooseMode(true);
execute();
assertAllCommandsUsed();
}

@Test
public void test_PlayerLeaveGameWithOwnPermanent() {
// Player order: A -> D -> C -> B

addCard(Zone.BATTLEFIELD, playerA, cardBear2, 1);

// B must checks A for online status
checkPlayerInGame("turn 1", 1, PhaseStep.PRECOMBAT_MAIN, playerD, playerA, true);
checkPermanentCount("turn 1", 1, PhaseStep.PRECOMBAT_MAIN, playerD, playerA, cardBear2, 1);
checkPlayerInGame("turn 2", 2, PhaseStep.PRECOMBAT_MAIN, playerD, playerA, true);
checkPermanentCount("turn 2", 2, PhaseStep.PRECOMBAT_MAIN, playerD, playerA, cardBear2, 1);
checkPlayerInGame("turn 3 before", 3, PhaseStep.PRECOMBAT_MAIN, playerD, playerA, true);
checkPermanentCount("turn 3 before", 3, PhaseStep.PRECOMBAT_MAIN, playerD, playerA, cardBear2, 1);

concede(3, PhaseStep.POSTCOMBAT_MAIN, playerA);

checkPlayerInGame("turn 3 after", 3, PhaseStep.END_TURN, playerD, playerA, false);
checkPermanentCount("turn 3 after", 3, PhaseStep.END_TURN, playerD, playerA, cardBear2, 0);
checkPlayerInGame("turn 4", 4, PhaseStep.PRECOMBAT_MAIN, playerD, playerA, false);
checkPermanentCount("turn 4", 4, PhaseStep.PRECOMBAT_MAIN, playerD, playerA, cardBear2, 0);

setStopAt(4, PhaseStep.CLEANUP);
setStrictChooseMode(true);
execute();
assertAllCommandsUsed();
}

private void prepareAndRunLeaveGameWithEffectTest(Duration duration) {
// Player order: A -> D -> C -> B
addCard(Zone.BATTLEFIELD, playerA, cardBear2, 1);
addCard(Zone.BATTLEFIELD, playerD, cardBear2, 1);
addCustomCardWithAbility("effect", playerA, new SimpleStaticAbility(new BoostAllEffect(1, 1, duration)));

// B must checks A for online status
checkPlayerInGame(duration.toString() + " - turn 1", 1, PhaseStep.PRECOMBAT_MAIN, playerD, playerA, true);
checkPermanentCount(duration.name() + " - turn 1", 1, PhaseStep.PRECOMBAT_MAIN, playerD, playerA, cardBear2, 1);
checkPT(duration.name() + " - turn 1", 1, PhaseStep.PRECOMBAT_MAIN, playerD, cardBear2, 3, 3);
//
checkPlayerInGame(duration.name() + " - turn 2", 2, PhaseStep.PRECOMBAT_MAIN, playerD, playerA, true);
checkPermanentCount(duration.name() + " - turn 2", 2, PhaseStep.PRECOMBAT_MAIN, playerD, playerA, cardBear2, 1);
checkPT(duration.name() + " - turn 2", 2, PhaseStep.PRECOMBAT_MAIN, playerD, cardBear2, 3, 3);
//
checkPlayerInGame(duration.name() + " - turn 3 before", 3, PhaseStep.PRECOMBAT_MAIN, playerD, playerA, true);
checkPermanentCount(duration.name() + " - turn 3 before", 3, PhaseStep.PRECOMBAT_MAIN, playerD, playerA, cardBear2, 1);
checkPT(duration.name() + " - turn 3 before", 3, PhaseStep.PRECOMBAT_MAIN, playerD, cardBear2, 3, 3);
//
concede(3, PhaseStep.POSTCOMBAT_MAIN, playerA);
//
checkPlayerInGame(duration.name() + " - turn 3 after", 3, PhaseStep.END_TURN, playerD, playerA, false);
checkPermanentCount(duration.name() + " - turn 3 after", 3, PhaseStep.END_TURN, playerD, playerA, cardBear2, 0);
checkPT(duration.name() + " - turn 3 after", 3, PhaseStep.END_TURN, playerD, cardBear2, 2, 2);
//
checkPlayerInGame(duration.name() + " - turn 4", 4, PhaseStep.PRECOMBAT_MAIN, playerD, playerA, false);
checkPermanentCount(duration.name() + " - turn 4", 4, PhaseStep.PRECOMBAT_MAIN, playerD, playerA, cardBear2, 0);
checkPT(duration.name() + " - turn 4", 4, PhaseStep.PRECOMBAT_MAIN, playerD, cardBear2, 2, 2);

setStopAt(4, PhaseStep.CLEANUP);
setStrictChooseMode(true);
execute();
assertAllCommandsUsed();
}

@Test
public void test_PlayerLeaveGameWithOwnPermanentAndCustomEffect() {
prepareAndRunLeaveGameWithEffectTest(Duration.Custom);
}

@Test
public void test_PlayerLeaveGameWithOwnPermanentAndWhileOnBattlefieldEffect() {
prepareAndRunLeaveGameWithEffectTest(Duration.WhileOnBattlefield);
}

@Test
public void test_PlayerLeaveGameWithOwnPermanentAndEndOfGameEffect() {
prepareAndRunLeaveGameWithEffectTest(Duration.EndOfGame);
}

@Test
public void test_PlayerLeaveGameWithOwnPermanentAndUntilSourceLeavesBattlefielEffect() {
prepareAndRunLeaveGameWithEffectTest(Duration.UntilSourceLeavesBattlefield);
}

// TODO: add leave tests for end of step
// TODO: add leave tests for end of turn
// TODO: add leave tests for end of your turn
}
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@

package org.mage.test.commander.duel;


import java.io.FileNotFoundException;
import mage.constants.PhaseStep;
import mage.constants.Zone;
import mage.game.Game;
Expand All @@ -11,8 +9,9 @@
import org.junit.Test;
import org.mage.test.serverside.base.CardTestCommanderDuelBase;

import java.io.FileNotFoundException;

/**
*
* @author LevelX2
*/

Expand All @@ -21,11 +20,11 @@ public class TeferiMageOfZhalfirTest extends CardTestCommanderDuelBase {
@Override
protected Game createNewGameAndPlayers() throws GameException, FileNotFoundException {
setDecknamePlayerA("CommanderDuel_UW.dck"); // Commander = Daxos of Meletis
return super.createNewGameAndPlayers();
return super.createNewGameAndPlayers();
}

@Test
public void castCommanderWithFlash() {
public void castCommanderWithFlash() {
addCard(Zone.BATTLEFIELD, playerA, "Plains", 2);
addCard(Zone.BATTLEFIELD, playerA, "Island", 1);

Expand All @@ -36,11 +35,13 @@ public void castCommanderWithFlash() {
execute();

assertPermanentCount(playerA, "Daxos of Meletis", 1);

assertAllCommandsUsed();
}

@Test
public void testCommanderDamage() {
setLife(playerA, 20);
setLife(playerB, 20);
addCard(Zone.BATTLEFIELD, playerA, "Plains", 6);
addCard(Zone.BATTLEFIELD, playerA, "Island", 1);
// Enchant creature
Expand All @@ -49,24 +50,30 @@ public void testCommanderDamage() {
addCard(Zone.HAND, playerA, "Angelic Destiny");

addCard(Zone.BATTLEFIELD, playerA, "Teferi, Mage of Zhalfir");

// Daxos of Meletis can't be blocked by creatures with power 3 or greater.
// Whenever Daxos of Meletis deals combat damage to a player, exile the top card of that player's library. You gain life equal to that card's converted mana cost. Until end of turn, you may cast that card and you may spend mana as though it were mana of any color to cast it.
// Whenever Daxos of Meletis deals combat damage to a player, exile the top card of that player's library.
// You gain life equal to that card's converted mana cost. Until end of turn, you may cast that card
// and you may spend mana as though it were mana of any color to cast it.
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Daxos of Meletis");
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Angelic Destiny","Daxos of Meletis");

waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN);
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Angelic Destiny", "Daxos of Meletis");

attack(3, playerA, "Daxos of Meletis");
attack(5, playerA, "Daxos of Meletis");
attack(7, playerA, "Daxos of Meletis");
attack(9, playerA, "Daxos of Meletis");

checkPT("before lost", 9, PhaseStep.PRECOMBAT_MAIN, playerA, "Daxos of Meletis", 6, 6);

setStrictChooseMode(true);
setStopAt(9, PhaseStep.POSTCOMBAT_MAIN);
execute();
assertAllCommandsUsed();

assertPermanentCount(playerA, "Daxos of Meletis", 1);
assertPowerToughness(playerA, "Daxos of Meletis", 6, 6);
assertPowerToughness(playerA, "Daxos of Meletis", 6, 6); // no effects removes after game over -- users and tests can get last game state with all affected effects

Assert.assertEquals("Player A has won because of commander damage", true, playerA.hasWon());
Assert.assertEquals("Player A has lost because of commander damage", true, playerB.hasLost());
}
Assert.assertEquals("Player B has lost because of commander damage", true, playerB.hasLost());
}
}
25 changes: 22 additions & 3 deletions Mage.Tests/src/test/java/org/mage/test/player/TestPlayer.java
Original file line number Diff line number Diff line change
Expand Up @@ -626,16 +626,23 @@ public boolean priority(Game game) {
wasProccessed = true;
}

// check player in game: target player, must be in game
if (params[0].equals(CHECK_COMMAND_PLAYER_IN_GAME) && params.length == 3) {
assertPlayerInGame(action, game, game.getPlayer(UUID.fromString(params[1])), Boolean.parseBoolean(params[2]));
actions.remove(action);
wasProccessed = true;
}

// check ability: card name, ability class, must have
if (params[0].equals(CHECK_COMMAND_ABILITY) && params.length == 4) {
assertAbility(action, game, computerPlayer, params[1], params[2], Boolean.parseBoolean(params[3]));
actions.remove(action);
wasProccessed = true;
}

// check battlefield count: card name, count
if (params[0].equals(CHECK_COMMAND_PERMANENT_COUNT) && params.length == 3) {
assertPermanentCount(action, game, computerPlayer, params[1], Integer.parseInt(params[2]));
// check battlefield count: target player, card name, count
if (params[0].equals(CHECK_COMMAND_PERMANENT_COUNT) && params.length == 4) {
assertPermanentCount(action, game, game.getPlayer(UUID.fromString(params[1])), params[2], Integer.parseInt(params[3]));
actions.remove(action);
wasProccessed = true;
}
Expand Down Expand Up @@ -928,6 +935,18 @@ private void assertLife(PlayerAction action, Game game, Player player, int Life)
Life, player.getLife());
}

private void assertPlayerInGame(PlayerAction action, Game game, Player targetPlayer, boolean mustBeInGame) {
Assert.assertNotNull("Can't find target player", targetPlayer);

if (targetPlayer.isInGame() && !mustBeInGame) {
Assert.fail(action.getActionName() + " - player " + targetPlayer.getName() + " must NOT be in game");
}

if (!targetPlayer.isInGame() && mustBeInGame) {
Assert.fail(action.getActionName() + " - player " + targetPlayer.getName() + " must be in game");
}
}

private void assertAbility(PlayerAction action, Game game, Player player, String permanentName, String abilityClass, boolean mustHave) {
Permanent perm = findPermanentWithAssert(action, game, player, permanentName);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@ public abstract class CardTestPlayerAPIImpl extends MageTestPlayerBase implement
public static final String CHECK_COMMAND_SUBTYPE = "SUBTYPE";
public static final String CHECK_COMMAND_MANA_POOL = "MANA_POOL";
public static final String CHECK_COMMAND_ALIAS_ZONE = "ALIAS_ZONE";
public static final String CHECK_COMMAND_PLAYER_IN_GAME = "PLAYER_IN_GAME";

// TODO: add target player param to commands
public static final String SHOW_COMMAND_LIBRARY = "LIBRARY";
Expand Down Expand Up @@ -300,14 +301,23 @@ public void checkLife(String checkName, int turnNum, PhaseStep step, TestPlayer
check(checkName, turnNum, step, player, CHECK_COMMAND_LIFE, life.toString());
}

public void checkPlayerInGame(String checkName, int turnNum, PhaseStep step, TestPlayer player, TestPlayer targetPlayer, Boolean mustBeInGame) {
check(checkName, turnNum, step, player, CHECK_COMMAND_PLAYER_IN_GAME, targetPlayer.getId().toString(), mustBeInGame.toString());
}

public void checkAbility(String checkName, int turnNum, PhaseStep step, TestPlayer player, String permanentName, Class<?> abilityClass, Boolean mustHave) {
//Assert.assertNotEquals("", permanentName);
check(checkName, turnNum, step, player, CHECK_COMMAND_ABILITY, permanentName, abilityClass.getName(), mustHave.toString());
}

public void checkPermanentCount(String checkName, int turnNum, PhaseStep step, TestPlayer player, String permanentName, Integer count) {
//Assert.assertNotEquals("", permanentName);
check(checkName, turnNum, step, player, CHECK_COMMAND_PERMANENT_COUNT, permanentName, count.toString());
checkPermanentCount(checkName, turnNum, step, player, player, permanentName, count);
}

public void checkPermanentCount(String checkName, int turnNum, PhaseStep step, TestPlayer player, TestPlayer targetPlayer, String permanentName, Integer count) {
//Assert.assertNotEquals("", permanentName);
check(checkName, turnNum, step, player, CHECK_COMMAND_PERMANENT_COUNT, targetPlayer.getId().toString(), permanentName, count.toString());
}

public void checkPermanentCounters(String checkName, int turnNum, PhaseStep step, TestPlayer player, String permanentName, CounterType counterType, Integer count) {
Expand Down
Loading

0 comments on commit 9ef2e0b

Please sign in to comment.