* Karn Liberated - Fixed that a with Karn's ability exiled commander was not put to battlefield after game restart.

This commit is contained in:
LevelX2 2020-01-19 16:48:58 +01:00
parent 217517feee
commit d87a4e4c9b
5 changed files with 122 additions and 65 deletions

View file

@ -1,5 +1,8 @@
package mage.cards.k; package mage.cards.k;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
import mage.MageObject; import mage.MageObject;
import mage.abilities.Ability; import mage.abilities.Ability;
import mage.abilities.DelayedTriggeredAbility; import mage.abilities.DelayedTriggeredAbility;
@ -23,10 +26,6 @@ import mage.target.TargetPlayer;
import mage.target.common.TargetCardInHand; import mage.target.common.TargetCardInHand;
import mage.util.CardUtil; import mage.util.CardUtil;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
/** /**
* @author bunchOfDevs * @author bunchOfDevs
*/ */
@ -111,7 +110,7 @@ class KarnLiberatedEffect extends OneShotEffect {
&& !cards.contains(card)) { // not the exiled cards && !cards.contains(card)) { // not the exiled cards
if (game.getCommandersIds(player).contains(card.getId())) { if (game.getCommandersIds(player).contains(card.getId())) {
game.addCommander(new Commander(card)); // TODO: check restart and init 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); game.setZone(card.getId(), Zone.COMMAND);
} else { } else {
player.getLibrary().putOnTop(card, game); player.getLibrary().putOnTop(card, game);
@ -124,10 +123,7 @@ class KarnLiberatedEffect extends OneShotEffect {
} }
for (Card card : cards) { for (Card card : cards) {
game.getState().setZone(card.getId(), Zone.EXILED); game.getState().setZone(card.getId(), Zone.EXILED);
if (card.isPermanent() game.getExile().add(exileId, sourceObject.getIdName(), card);
&& !card.hasSubtype(SubType.AURA, game)) {
game.getExile().add(exileId, sourceObject.getIdName(), card);
}
} }
game.addDelayedTriggeredAbility(new KarnLiberatedDelayedTriggeredAbility(exileId), source); game.addDelayedTriggeredAbility(new KarnLiberatedDelayedTriggeredAbility(exileId), source);
game.setStartingPlayerId(source.getControllerId()); game.setStartingPlayerId(source.getControllerId());

View file

@ -1,4 +1,3 @@
package org.mage.test.commander.duel; package org.mage.test.commander.duel;
import java.io.FileNotFoundException; import java.io.FileNotFoundException;
@ -6,6 +5,8 @@ import mage.constants.PhaseStep;
import mage.constants.Zone; import mage.constants.Zone;
import mage.game.Game; import mage.game.Game;
import mage.game.GameException; import mage.game.GameException;
import mage.watchers.common.CommanderInfoWatcher;
import org.junit.Assert;
import org.junit.Test; import org.junit.Test;
import org.mage.test.serverside.base.CardTestCommanderDuelBase; 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. // 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. // Sacrifice another creature: Prossh gets +1/+0 until end of turn.
setDecknamePlayerA("Power Hungry.dck"); // Commander = Prosssh, Skyrider of Kher {3}{B}{R}{G} 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(); return super.createNewGameAndPlayers();
} }
@ -38,7 +39,10 @@ public class CastBRGCommanderTest extends CardTestCommanderDuelBase {
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Savage Summoning"); castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Savage Summoning");
castSpell(1, PhaseStep.BEGIN_COMBAT, playerA, "Prossh, Skyraider of Kher"); // 5/5 castSpell(1, PhaseStep.BEGIN_COMBAT, playerA, "Prossh, Skyraider of Kher"); // 5/5
setStopAt(1, PhaseStep.END_COMBAT); setStopAt(1, PhaseStep.END_COMBAT);
setStrictChooseMode(true);
execute(); execute();
assertAllCommandsUsed();
assertGraveyardCount(playerA, "Savage Summoning", 1); assertGraveyardCount(playerA, "Savage Summoning", 1);
assertPermanentCount(playerA, "Prossh, Skyraider of Kher", 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"); activateAbility(5, PhaseStep.PRECOMBAT_MAIN, playerA, "-14: Restart");
setStopAt(5, PhaseStep.BEGIN_COMBAT); setStopAt(5, PhaseStep.BEGIN_COMBAT);
setStrictChooseMode(true);
execute(); execute();
assertAllCommandsUsed();
assertGraveyardCount(playerA, "Karn Liberated", 0); assertGraveyardCount(playerA, "Karn Liberated", 0);
assertPermanentCount(playerA, "Silvercoat Lion", 2); 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". * 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 * 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(2, PhaseStep.PRECOMBAT_MAIN, playerB, "Daxos of Meletis");
castSpell(3, PhaseStep.PRECOMBAT_MAIN, playerA, "Mogg Infestation"); castSpell(3, PhaseStep.PRECOMBAT_MAIN, playerA, "Mogg Infestation");
addTarget(playerA, playerB);
setChoice(playerB, "Yes"); // Move commander to command zone
setStopAt(3, PhaseStep.BEGIN_COMBAT); setStopAt(3, PhaseStep.BEGIN_COMBAT);
setStrictChooseMode(true);
execute(); execute();
assertAllCommandsUsed();
assertGraveyardCount(playerA, "Mogg Infestation", 1); assertGraveyardCount(playerA, "Mogg Infestation", 1);
assertCommandZoneCount(playerB, "Daxos of Meletis", 1); assertCommandZoneCount(playerB, "Daxos of Meletis", 1);

View file

@ -1,5 +1,10 @@
package org.mage.test.player; 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.MageItem;
import mage.MageObject; import mage.MageObject;
import mage.MageObjectReference; import mage.MageObjectReference;
@ -56,13 +61,6 @@ import mage.util.CardUtil;
import org.apache.log4j.Logger; import org.apache.log4j.Logger;
import org.junit.Assert; import org.junit.Assert;
import org.junit.Ignore; 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.*; 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 ATTACK_SKIP = "[attack_skip]";
public static final String NO_TARGET = "NO_TARGET"; // cast spell or activate ability without target defines 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 int foundNoAction = 0;
private boolean AIPlayer; private boolean AIPlayer;
private final List<PlayerAction> actions = new ArrayList<>(); private final List<PlayerAction> actions = new ArrayList<>();
@ -179,7 +177,7 @@ public class TestPlayer implements Player {
/** /**
* @param maxCallsWithoutAction max number of priority passes a player may * @param maxCallsWithoutAction max number of priority passes a player may
* have for this test (default = 100) * have for this test (default = 100)
*/ */
public void setMaxCallsWithoutAction(int maxCallsWithoutAction) { public void setMaxCallsWithoutAction(int maxCallsWithoutAction) {
this.maxCallsWithoutAction = maxCallsWithoutAction; this.maxCallsWithoutAction = maxCallsWithoutAction;
@ -518,6 +516,7 @@ public class TestPlayer implements Player {
if (computerPlayer.activateAbility((ActivatedAbility) newAbility, game)) { if (computerPlayer.activateAbility((ActivatedAbility) newAbility, game)) {
actions.remove(action); actions.remove(action);
groupsForTargetHandling = null; groupsForTargetHandling = null;
foundNoAction = 0; // Reset enless loop check because of no action
return true; return true;
} else { } else {
game.restoreState(bookmark, ability.getRule()); game.restoreState(bookmark, ability.getRule());
@ -854,7 +853,8 @@ public class TestPlayer implements Player {
if (numberOfActions == actions.size()) { if (numberOfActions == actions.size()) {
foundNoAction++; foundNoAction++;
if (foundNoAction > maxCallsWithoutAction) { 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 { } else {
foundNoAction = 0; foundNoAction = 0;
@ -903,12 +903,12 @@ public class TestPlayer implements Player {
List<String> data = cards.stream() List<String> data = cards.stream()
.map(c -> (((c instanceof PermanentToken) ? "[T] " : "[C] ") .map(c -> (((c instanceof PermanentToken) ? "[T] " : "[C] ")
+ c.getIdName() + c.getIdName()
+ (c.isCopy() ? " [copy of " + c.getCopyFrom().getId().toString().substring(0, 3) + "]" : "") + (c.isCopy() ? " [copy of " + c.getCopyFrom().getId().toString().substring(0, 3) + "]" : "")
+ " - " + c.getPower().getValue() + "/" + c.getToughness().getValue() + " - " + c.getPower().getValue() + "/" + c.getToughness().getValue()
+ (c.isPlaneswalker() ? " - L" + c.getCounters(game).getCount(CounterType.LOYALTY) : "") + (c.isPlaneswalker() ? " - L" + c.getCounters(game).getCount(CounterType.LOYALTY) : "")
+ ", " + (c.isTapped() ? "Tapped" : "Untapped") + ", " + (c.isTapped() ? "Tapped" : "Untapped")
+ (c.getAttachedTo() == null ? "" : ", attached to " + game.getPermanent(c.getAttachedTo()).getIdName()))) + (c.getAttachedTo() == null ? "" : ", attached to " + game.getPermanent(c.getAttachedTo()).getIdName())))
.sorted() .sorted()
.collect(Collectors.toList()); .collect(Collectors.toList());
@ -932,11 +932,11 @@ public class TestPlayer implements Player {
List<String> data = abilities.stream() List<String> data = abilities.stream()
.map(a -> (a.getZone() + " -> " .map(a -> (a.getZone() + " -> "
+ a.getSourceObject(game).getIdName() + " -> " + a.getSourceObject(game).getIdName() + " -> "
+ (a.toString().length() > 0 + (a.toString().length() > 0
? a.toString().substring(0, Math.min(20, a.toString().length()) - 1) ? a.toString().substring(0, Math.min(20, a.toString().length()) - 1)
: a.getClass().getSimpleName()) : a.getClass().getSimpleName())
+ "...")) + "..."))
.sorted() .sorted()
.collect(Collectors.toList()); .collect(Collectors.toList());
@ -1290,7 +1290,7 @@ public class TestPlayer implements Player {
UUID defenderId = null; UUID defenderId = null;
boolean mustAttackByAction = false; boolean mustAttackByAction = false;
boolean madeAttackByAction = 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(); PlayerAction action = it.next();
if (action.getTurnNum() == game.getTurnNum() && action.getAction().startsWith("attack:")) { if (action.getTurnNum() == game.getTurnNum() && action.getAction().startsWith("attack:")) {
mustAttackByAction = true; mustAttackByAction = true;
@ -1779,7 +1779,7 @@ public class TestPlayer implements Player {
// skip targets // skip targets
if (targets.get(0).equals(TARGET_SKIP)) { if (targets.get(0).equals(TARGET_SKIP)) {
Assert.assertTrue("found skip target, but it require more targets, needs " Assert.assertTrue("found skip target, but it require more targets, needs "
+ (target.getMinNumberOfTargets() - target.getTargets().size()) + " more", + (target.getMinNumberOfTargets() - target.getTargets().size()) + " more",
target.getTargets().size() >= target.getMinNumberOfTargets()); target.getTargets().size() >= target.getMinNumberOfTargets());
targets.remove(0); targets.remove(0);
return true; return true;
@ -2082,7 +2082,7 @@ public class TestPlayer implements Player {
this.chooseStrictModeFailed("choice", game, this.chooseStrictModeFailed("choice", game,
"Triggered list (total " + abilities.size() + "):\n" "Triggered list (total " + abilities.size() + "):\n"
+ abilities.stream().map(a -> getInfo(a, game)).collect(Collectors.joining("\n"))); + abilities.stream().map(a -> getInfo(a, game)).collect(Collectors.joining("\n")));
return computerPlayer.chooseTriggeredAbility(abilities, game); return computerPlayer.chooseTriggeredAbility(abilities, game);
} }
@ -3258,7 +3258,7 @@ public class TestPlayer implements Player {
@Override @Override
public boolean choose(Outcome outcome, Target target, public boolean choose(Outcome outcome, Target target,
UUID sourceId, Game game UUID sourceId, Game game
) { ) {
// needed to call here the TestPlayer because it's overwitten // needed to call here the TestPlayer because it's overwitten
return choose(outcome, target, sourceId, game, null); return choose(outcome, target, sourceId, game, null);
@ -3266,7 +3266,7 @@ public class TestPlayer implements Player {
@Override @Override
public boolean choose(Outcome outcome, Cards cards, public boolean choose(Outcome outcome, Cards cards,
TargetCard target, Game game TargetCard target, Game game
) { ) {
if (!choices.isEmpty()) { if (!choices.isEmpty()) {
for (String choose2 : choices) { for (String choose2 : choices) {
@ -3302,7 +3302,7 @@ public class TestPlayer implements Player {
@Override @Override
public boolean chooseTargetAmount(Outcome outcome, TargetAmount target, public boolean chooseTargetAmount(Outcome outcome, TargetAmount target,
Ability source, Game game Ability source, Game game
) { ) {
// chooseTargetAmount calls for EACH target cycle (e.g. one target per click, see TargetAmount) // chooseTargetAmount calls for EACH target cycle (e.g. one target per click, see TargetAmount)
// if use want to stop choosing then chooseTargetAmount must return false (example: up to xxx) // if use want to stop choosing then chooseTargetAmount must return false (example: up to xxx)
@ -3314,7 +3314,7 @@ public class TestPlayer implements Player {
// skip targets // skip targets
if (targets.get(0).equals(TARGET_SKIP)) { if (targets.get(0).equals(TARGET_SKIP)) {
Assert.assertTrue("found skip target, but it require more targets, needs " Assert.assertTrue("found skip target, but it require more targets, needs "
+ (target.getMinNumberOfTargets() - target.getTargets().size()) + " more", + (target.getMinNumberOfTargets() - target.getTargets().size()) + " more",
target.getTargets().size() >= target.getMinNumberOfTargets()); target.getTargets().size() >= target.getMinNumberOfTargets());
targets.remove(0); targets.remove(0);
return false; // false in chooseTargetAmount = stop to choose return false; // false in chooseTargetAmount = stop to choose
@ -3367,15 +3367,15 @@ public class TestPlayer implements Player {
@Override @Override
public boolean choosePile(Outcome outcome, String message, public boolean choosePile(Outcome outcome, String message,
List<? extends Card> pile1, List<? extends Card> pile2, List<? extends Card> pile1, List<? extends Card> pile2,
Game game Game game
) { ) {
return computerPlayer.choosePile(outcome, message, pile1, pile2, game); return computerPlayer.choosePile(outcome, message, pile1, pile2, game);
} }
@Override @Override
public boolean playMana(Ability ability, ManaCost unpaid, public boolean playMana(Ability ability, ManaCost unpaid,
String promptText, Game game String promptText, Game game
) { ) {
groupsForTargetHandling = null; groupsForTargetHandling = null;
return computerPlayer.playMana(ability, unpaid, promptText, game); return computerPlayer.playMana(ability, unpaid, promptText, game);
@ -3389,15 +3389,15 @@ public class TestPlayer implements Player {
@Override @Override
public UUID chooseBlockerOrder(List<Permanent> blockers, CombatGroup combatGroup, public UUID chooseBlockerOrder(List<Permanent> blockers, CombatGroup combatGroup,
List<UUID> blockerOrder, Game game List<UUID> blockerOrder, Game game
) { ) {
return computerPlayer.chooseBlockerOrder(blockers, combatGroup, blockerOrder, game); return computerPlayer.chooseBlockerOrder(blockers, combatGroup, blockerOrder, game);
} }
@Override @Override
public void assignDamage(int damage, List<UUID> targets, public void assignDamage(int damage, List<UUID> targets,
String singleTargetName, UUID sourceId, String singleTargetName, UUID sourceId,
Game game Game game
) { ) {
computerPlayer.assignDamage(damage, targets, singleTargetName, sourceId, game); computerPlayer.assignDamage(damage, targets, singleTargetName, sourceId, game);
} }
@ -3416,14 +3416,14 @@ public class TestPlayer implements Player {
@Override @Override
public void pickCard(List<Card> cards, Deck deck, public void pickCard(List<Card> cards, Deck deck,
Draft draft Draft draft
) { ) {
computerPlayer.pickCard(cards, deck, draft); computerPlayer.pickCard(cards, deck, draft);
} }
@Override @Override
public boolean scry(int value, Ability source, public boolean scry(int value, Ability source,
Game game Game game
) { ) {
// Don't scry at the start of the game. // Don't scry at the start of the game.
if (game.getTurnNum() == 1 && game.getStep() == null) { if (game.getTurnNum() == 1 && game.getStep() == null) {
@ -3434,44 +3434,44 @@ public class TestPlayer implements Player {
@Override @Override
public boolean surveil(int value, Ability source, public boolean surveil(int value, Ability source,
Game game Game game
) { ) {
return computerPlayer.surveil(value, source, game); return computerPlayer.surveil(value, source, game);
} }
@Override @Override
public boolean moveCards(Card card, Zone toZone, public boolean moveCards(Card card, Zone toZone,
Ability source, Game game Ability source, Game game
) { ) {
return computerPlayer.moveCards(card, toZone, source, game); return computerPlayer.moveCards(card, toZone, source, game);
} }
@Override @Override
public boolean moveCards(Card card, Zone toZone, public boolean moveCards(Card card, Zone toZone,
Ability source, Game game, Ability source, Game game,
boolean tapped, boolean faceDown, boolean byOwner, List<UUID> appliedEffects boolean tapped, boolean faceDown, boolean byOwner, List<UUID> appliedEffects
) { ) {
return computerPlayer.moveCards(card, toZone, source, game, tapped, faceDown, byOwner, appliedEffects); return computerPlayer.moveCards(card, toZone, source, game, tapped, faceDown, byOwner, appliedEffects);
} }
@Override @Override
public boolean moveCards(Cards cards, Zone toZone, public boolean moveCards(Cards cards, Zone toZone,
Ability source, Game game Ability source, Game game
) { ) {
return computerPlayer.moveCards(cards, toZone, source, game); return computerPlayer.moveCards(cards, toZone, source, game);
} }
@Override @Override
public boolean moveCards(Set<Card> cards, Zone toZone, public boolean moveCards(Set<Card> cards, Zone toZone,
Ability source, Game game Ability source, Game game
) { ) {
return computerPlayer.moveCards(cards, toZone, source, game); return computerPlayer.moveCards(cards, toZone, source, game);
} }
@Override @Override
public boolean moveCards(Set<Card> cards, Zone toZone, public boolean moveCards(Set<Card> cards, Zone toZone,
Ability source, Game game, Ability source, Game game,
boolean tapped, boolean faceDown, boolean byOwner, List<UUID> appliedEffects boolean tapped, boolean faceDown, boolean byOwner, List<UUID> appliedEffects
) { ) {
return computerPlayer.moveCards(cards, toZone, source, game, tapped, faceDown, byOwner, appliedEffects); return computerPlayer.moveCards(cards, toZone, source, game, tapped, faceDown, byOwner, appliedEffects);
} }

View file

@ -1,5 +1,7 @@
package mage.game; package mage.game;
import java.util.Map;
import java.util.UUID;
import mage.abilities.Ability; import mage.abilities.Ability;
import mage.abilities.common.SimpleStaticAbility; import mage.abilities.common.SimpleStaticAbility;
import mage.abilities.effects.common.InfoEffect; import mage.abilities.effects.common.InfoEffect;
@ -16,9 +18,6 @@ import mage.players.Player;
import mage.watchers.common.CommanderInfoWatcher; import mage.watchers.common.CommanderInfoWatcher;
import mage.watchers.common.CommanderPlaysCountWatcher; import mage.watchers.common.CommanderPlaysCountWatcher;
import java.util.Map;
import java.util.UUID;
public abstract class GameCommanderImpl extends GameImpl { public abstract class GameCommanderImpl extends GameImpl {
// private final Map<UUID, Cards> mulliganedCards = new HashMap<>(); // 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) { public void initCommander(Card commander, Player player) {
commander.moveToZone(Zone.COMMAND, null, this, true); 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()); commander.getAbilities().setControllerId(player.getId());
Ability ability = new SimpleStaticAbility(Zone.COMMAND, new InfoEffect("Commander effects")); Ability ability = new SimpleStaticAbility(Zone.COMMAND, new InfoEffect("Commander effects"));

View file

@ -1,5 +1,8 @@
package mage.watchers.common; package mage.watchers.common;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
import mage.MageObject; import mage.MageObject;
import mage.cards.Card; import mage.cards.Card;
import mage.constants.WatcherScope; import mage.constants.WatcherScope;
@ -11,10 +14,6 @@ import mage.game.permanent.Permanent;
import mage.players.Player; import mage.players.Player;
import mage.watchers.Watcher; import mage.watchers.Watcher;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
/* 20130711 /* 20130711
*903.14a A player that's been dealt 21 or more combat damage by the same commander *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.) * 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) { if (object != null) {
StringBuilder sb = new StringBuilder(); StringBuilder sb = new StringBuilder();
sb.append("<b>" + commanderTypeName + "</b>"); sb.append("<b>").append(commanderTypeName).append("</b>");
CommanderPlaysCountWatcher watcher = game.getState().getWatcher(CommanderPlaysCountWatcher.class); CommanderPlaysCountWatcher watcher = game.getState().getWatcher(CommanderPlaysCountWatcher.class);
int playsCount = watcher.getPlaysCount(sourceId); int playsCount = watcher.getPlaysCount(sourceId);
if (playsCount > 0) { if (playsCount > 0) {
@ -80,7 +79,7 @@ public class CommanderInfoWatcher extends Watcher {
if (checkCommanderDamage) { if (checkCommanderDamage) {
for (Map.Entry<UUID, Integer> entry : damageToPlayer.entrySet()) { for (Map.Entry<UUID, Integer> entry : damageToPlayer.entrySet()) {
Player damagedPlayer = game.getPlayer(entry.getKey()); 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(), this.addInfo(object, "Commander" + entry.getKey(),
"<b>" + commanderTypeName + "</b> did " + entry.getValue() + " combat damage to player " + damagedPlayer.getLogName() + '.', game); "<b>" + commanderTypeName + "</b> did " + entry.getValue() + " combat damage to player " + damagedPlayer.getLogName() + '.', game);
} }