mirror of
https://github.com/correl/mage.git
synced 2024-11-28 19:19:55 +00:00
* Karn Liberated - Fixed that a with Karn's ability exiled commander was not put to battlefield after game restart.
This commit is contained in:
parent
217517feee
commit
d87a4e4c9b
5 changed files with 122 additions and 65 deletions
|
@ -1,5 +1,8 @@
|
|||
package mage.cards.k;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
import mage.MageObject;
|
||||
import mage.abilities.Ability;
|
||||
import mage.abilities.DelayedTriggeredAbility;
|
||||
|
@ -23,10 +26,6 @@ import mage.target.TargetPlayer;
|
|||
import mage.target.common.TargetCardInHand;
|
||||
import mage.util.CardUtil;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
|
||||
/**
|
||||
* @author bunchOfDevs
|
||||
*/
|
||||
|
@ -111,7 +110,7 @@ class KarnLiberatedEffect extends OneShotEffect {
|
|||
&& !cards.contains(card)) { // not the exiled cards
|
||||
if (game.getCommandersIds(player).contains(card.getId())) {
|
||||
game.addCommander(new Commander(card)); // TODO: check restart and init
|
||||
// no needs in initCommander call -- it's uses on game startup (init)
|
||||
// no needs in initCommander call -- it's used on game startup (init)
|
||||
game.setZone(card.getId(), Zone.COMMAND);
|
||||
} else {
|
||||
player.getLibrary().putOnTop(card, game);
|
||||
|
@ -124,11 +123,8 @@ class KarnLiberatedEffect extends OneShotEffect {
|
|||
}
|
||||
for (Card card : cards) {
|
||||
game.getState().setZone(card.getId(), Zone.EXILED);
|
||||
if (card.isPermanent()
|
||||
&& !card.hasSubtype(SubType.AURA, game)) {
|
||||
game.getExile().add(exileId, sourceObject.getIdName(), card);
|
||||
}
|
||||
}
|
||||
game.addDelayedTriggeredAbility(new KarnLiberatedDelayedTriggeredAbility(exileId), source);
|
||||
game.setStartingPlayerId(source.getControllerId());
|
||||
game.start(null);
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
|
||||
package org.mage.test.commander.duel;
|
||||
|
||||
import java.io.FileNotFoundException;
|
||||
|
@ -6,6 +5,8 @@ import mage.constants.PhaseStep;
|
|||
import mage.constants.Zone;
|
||||
import mage.game.Game;
|
||||
import mage.game.GameException;
|
||||
import mage.watchers.common.CommanderInfoWatcher;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
import org.mage.test.serverside.base.CardTestCommanderDuelBase;
|
||||
|
||||
|
@ -21,7 +22,7 @@ public class CastBRGCommanderTest extends CardTestCommanderDuelBase {
|
|||
// When you cast Prossh, Skyraider of Kher, put X 0/1 red Kobold creature tokens named Kobolds of Kher Keep onto the battlefield, where X is the amount of mana spent to cast Prossh.
|
||||
// Sacrifice another creature: Prossh gets +1/+0 until end of turn.
|
||||
setDecknamePlayerA("Power Hungry.dck"); // Commander = Prosssh, Skyrider of Kher {3}{B}{R}{G}
|
||||
setDecknamePlayerB("CommanderDuel_UW.dck"); // Daxos of Meletis {1}{W}{U}
|
||||
setDecknamePlayerB("CommanderDuel_UW.dck"); // Commander = Daxos of Meletis {1}{W}{U}
|
||||
return super.createNewGameAndPlayers();
|
||||
}
|
||||
|
||||
|
@ -38,7 +39,10 @@ public class CastBRGCommanderTest extends CardTestCommanderDuelBase {
|
|||
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Savage Summoning");
|
||||
castSpell(1, PhaseStep.BEGIN_COMBAT, playerA, "Prossh, Skyraider of Kher"); // 5/5
|
||||
setStopAt(1, PhaseStep.END_COMBAT);
|
||||
|
||||
setStrictChooseMode(true);
|
||||
execute();
|
||||
assertAllCommandsUsed();
|
||||
|
||||
assertGraveyardCount(playerA, "Savage Summoning", 1);
|
||||
assertPermanentCount(playerA, "Prossh, Skyraider of Kher", 1);
|
||||
|
@ -66,7 +70,10 @@ public class CastBRGCommanderTest extends CardTestCommanderDuelBase {
|
|||
activateAbility(5, PhaseStep.PRECOMBAT_MAIN, playerA, "-14: Restart");
|
||||
|
||||
setStopAt(5, PhaseStep.BEGIN_COMBAT);
|
||||
|
||||
setStrictChooseMode(true);
|
||||
execute();
|
||||
assertAllCommandsUsed();
|
||||
|
||||
assertGraveyardCount(playerA, "Karn Liberated", 0);
|
||||
assertPermanentCount(playerA, "Silvercoat Lion", 2);
|
||||
|
@ -75,6 +82,55 @@ public class CastBRGCommanderTest extends CardTestCommanderDuelBase {
|
|||
|
||||
}
|
||||
|
||||
/**
|
||||
* If the commander is exiled by Karn (and not returned to the command
|
||||
* zone), it needs to restart the game in play and not the command zone.
|
||||
*/
|
||||
@Test
|
||||
public void testCommanderRestoredToBattlefieldAfterKarnUltimate() {
|
||||
// +4: Target player exiles a card from their hand.
|
||||
// -3: Exile target permanent.
|
||||
// -14: Restart the game, leaving in exile all non-Aura permanent cards exiled with Karn Liberated. Then put those cards onto the battlefield under your control.
|
||||
addCard(Zone.BATTLEFIELD, playerA, "Karn Liberated", 1); // Planeswalker (6)
|
||||
addCard(Zone.HAND, playerA, "Silvercoat Lion", 3);
|
||||
|
||||
addCard(Zone.BATTLEFIELD, playerB, "Plains", 2);
|
||||
addCard(Zone.BATTLEFIELD, playerB, "Island", 1);
|
||||
|
||||
activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "+4: Target player", playerA);
|
||||
addTarget(playerA, "Silvercoat Lion");
|
||||
|
||||
castSpell(2, PhaseStep.PRECOMBAT_MAIN, playerB, "Daxos of Meletis");
|
||||
|
||||
activateAbility(3, PhaseStep.PRECOMBAT_MAIN, playerA, "+4: Target player", playerA);
|
||||
addTarget(playerA, "Silvercoat Lion");
|
||||
|
||||
attack(4, playerB, "Daxos of Meletis");
|
||||
|
||||
activateAbility(5, PhaseStep.PRECOMBAT_MAIN, playerA, "-3: Exile target permanent", "Daxos of Meletis");
|
||||
setChoice(playerB, "No"); // Move commander NOT to command zone
|
||||
|
||||
activateAbility(7, PhaseStep.PRECOMBAT_MAIN, playerA, "+4: Target player", playerA);
|
||||
addTarget(playerA, "Silvercoat Lion");
|
||||
activateAbility(9, PhaseStep.PRECOMBAT_MAIN, playerA, "-14: Restart");
|
||||
|
||||
setStopAt(9, PhaseStep.BEGIN_COMBAT);
|
||||
|
||||
setStrictChooseMode(true);
|
||||
execute();
|
||||
assertAllCommandsUsed();
|
||||
|
||||
assertGraveyardCount(playerA, "Karn Liberated", 0);
|
||||
assertPermanentCount(playerA, "Silvercoat Lion", 3);
|
||||
assertCommandZoneCount(playerA, "Prossh, Skyraider of Kher", 1);
|
||||
assertCommandZoneCount(playerB, "Daxos of Meletis", 0);
|
||||
assertPermanentCount(playerA, "Daxos of Meletis", 1); // Karn brings back the cards under the control of Karn's controller
|
||||
|
||||
CommanderInfoWatcher watcher = currentGame.getState().getWatcher(CommanderInfoWatcher.class, playerB.getCommandersIds().iterator().next());
|
||||
Assert.assertEquals("Watcher is reset to 0 commander damage", 0, (int) watcher.getDamageToPlayer().size());
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Mogg infestation creates tokens "for each creature that died this way".
|
||||
* When a commander is moved to a command zone, it doesn't "die", and thus
|
||||
|
@ -92,9 +148,14 @@ public class CastBRGCommanderTest extends CardTestCommanderDuelBase {
|
|||
|
||||
castSpell(2, PhaseStep.PRECOMBAT_MAIN, playerB, "Daxos of Meletis");
|
||||
castSpell(3, PhaseStep.PRECOMBAT_MAIN, playerA, "Mogg Infestation");
|
||||
addTarget(playerA, playerB);
|
||||
setChoice(playerB, "Yes"); // Move commander to command zone
|
||||
|
||||
setStopAt(3, PhaseStep.BEGIN_COMBAT);
|
||||
|
||||
setStrictChooseMode(true);
|
||||
execute();
|
||||
assertAllCommandsUsed();
|
||||
|
||||
assertGraveyardCount(playerA, "Mogg Infestation", 1);
|
||||
assertCommandZoneCount(playerB, "Daxos of Meletis", 1);
|
||||
|
|
|
@ -1,5 +1,10 @@
|
|||
package org.mage.test.player;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.*;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
import java.util.stream.Collectors;
|
||||
import mage.MageItem;
|
||||
import mage.MageObject;
|
||||
import mage.MageObjectReference;
|
||||
|
@ -56,13 +61,6 @@ import mage.util.CardUtil;
|
|||
import org.apache.log4j.Logger;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Ignore;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.*;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import static org.mage.test.serverside.base.impl.CardTestPlayerAPIImpl.*;
|
||||
|
||||
/**
|
||||
|
@ -80,7 +78,7 @@ public class TestPlayer implements Player {
|
|||
public static final String ATTACK_SKIP = "[attack_skip]";
|
||||
public static final String NO_TARGET = "NO_TARGET"; // cast spell or activate ability without target defines
|
||||
|
||||
private int maxCallsWithoutAction = 100;
|
||||
private int maxCallsWithoutAction = 400;
|
||||
private int foundNoAction = 0;
|
||||
private boolean AIPlayer;
|
||||
private final List<PlayerAction> actions = new ArrayList<>();
|
||||
|
@ -518,6 +516,7 @@ public class TestPlayer implements Player {
|
|||
if (computerPlayer.activateAbility((ActivatedAbility) newAbility, game)) {
|
||||
actions.remove(action);
|
||||
groupsForTargetHandling = null;
|
||||
foundNoAction = 0; // Reset enless loop check because of no action
|
||||
return true;
|
||||
} else {
|
||||
game.restoreState(bookmark, ability.getRule());
|
||||
|
@ -854,7 +853,8 @@ public class TestPlayer implements Player {
|
|||
if (numberOfActions == actions.size()) {
|
||||
foundNoAction++;
|
||||
if (foundNoAction > maxCallsWithoutAction) {
|
||||
throw new AssertionError("More priority calls to " + getName() + " and doing no action than allowed (" + maxCallsWithoutAction + ')');
|
||||
throw new AssertionError("More priority calls to " + getName()
|
||||
+ " without taking any action than allowed (" + maxCallsWithoutAction + ") on turn " + game.getTurnNum());
|
||||
}
|
||||
} else {
|
||||
foundNoAction = 0;
|
||||
|
@ -1290,7 +1290,7 @@ public class TestPlayer implements Player {
|
|||
UUID defenderId = null;
|
||||
boolean mustAttackByAction = false;
|
||||
boolean madeAttackByAction = false;
|
||||
for (Iterator<org.mage.test.player.PlayerAction> it = actions.iterator(); it.hasNext(); ) {
|
||||
for (Iterator<org.mage.test.player.PlayerAction> it = actions.iterator(); it.hasNext();) {
|
||||
PlayerAction action = it.next();
|
||||
if (action.getTurnNum() == game.getTurnNum() && action.getAction().startsWith("attack:")) {
|
||||
mustAttackByAction = true;
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
package mage.game;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.UUID;
|
||||
import mage.abilities.Ability;
|
||||
import mage.abilities.common.SimpleStaticAbility;
|
||||
import mage.abilities.effects.common.InfoEffect;
|
||||
|
@ -16,9 +18,6 @@ import mage.players.Player;
|
|||
import mage.watchers.common.CommanderInfoWatcher;
|
||||
import mage.watchers.common.CommanderPlaysCountWatcher;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.UUID;
|
||||
|
||||
public abstract class GameCommanderImpl extends GameImpl {
|
||||
|
||||
// private final Map<UUID, Cards> mulliganedCards = new HashMap<>();
|
||||
|
@ -78,7 +77,9 @@ public abstract class GameCommanderImpl extends GameImpl {
|
|||
}
|
||||
|
||||
public void initCommander(Card commander, Player player) {
|
||||
if (!Zone.EXILED.equals(getState().getZone(commander.getId()))) { // Exile check needed for Karn Liberated restart
|
||||
commander.moveToZone(Zone.COMMAND, null, this, true);
|
||||
}
|
||||
commander.getAbilities().setControllerId(player.getId());
|
||||
|
||||
Ability ability = new SimpleStaticAbility(Zone.COMMAND, new InfoEffect("Commander effects"));
|
||||
|
|
|
@ -1,5 +1,8 @@
|
|||
package mage.watchers.common;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.UUID;
|
||||
import mage.MageObject;
|
||||
import mage.cards.Card;
|
||||
import mage.constants.WatcherScope;
|
||||
|
@ -11,10 +14,6 @@ import mage.game.permanent.Permanent;
|
|||
import mage.players.Player;
|
||||
import mage.watchers.Watcher;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.UUID;
|
||||
|
||||
/* 20130711
|
||||
*903.14a A player that's been dealt 21 or more combat damage by the same commander
|
||||
* over the course of the game loses the game. (This is a state-based action. See rule 704.)
|
||||
|
@ -69,7 +68,7 @@ public class CommanderInfoWatcher extends Watcher {
|
|||
}
|
||||
if (object != null) {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append("<b>" + commanderTypeName + "</b>");
|
||||
sb.append("<b>").append(commanderTypeName).append("</b>");
|
||||
CommanderPlaysCountWatcher watcher = game.getState().getWatcher(CommanderPlaysCountWatcher.class);
|
||||
int playsCount = watcher.getPlaysCount(sourceId);
|
||||
if (playsCount > 0) {
|
||||
|
@ -80,7 +79,7 @@ public class CommanderInfoWatcher extends Watcher {
|
|||
if (checkCommanderDamage) {
|
||||
for (Map.Entry<UUID, Integer> entry : damageToPlayer.entrySet()) {
|
||||
Player damagedPlayer = game.getPlayer(entry.getKey());
|
||||
sb.append("<b>" + commanderTypeName + "</b> did ").append(entry.getValue()).append(" combat damage to player ").append(damagedPlayer.getLogName()).append('.');
|
||||
sb.append("<b>").append(commanderTypeName).append("</b> did ").append(entry.getValue()).append(" combat damage to player ").append(damagedPlayer.getLogName()).append('.');
|
||||
this.addInfo(object, "Commander" + entry.getKey(),
|
||||
"<b>" + commanderTypeName + "</b> did " + entry.getValue() + " combat damage to player " + damagedPlayer.getLogName() + '.', game);
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue