Merge branch 'master' into master

This commit is contained in:
LevelX2 2017-11-02 11:29:47 +01:00 committed by GitHub
commit 9700445fae
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
75 changed files with 3013 additions and 654 deletions

1
.gitignore vendored
View file

@ -44,6 +44,7 @@ Mage.Server.Plugins/Mage.Game.CommanderDuel/target
Mage.Server.Plugins/Mage.Game.CommanderFreeForAll/target/ Mage.Server.Plugins/Mage.Game.CommanderFreeForAll/target/
Mage.Server.Plugins/Mage.Game.FreeForAll/target Mage.Server.Plugins/Mage.Game.FreeForAll/target
Mage.Server.Plugins/Mage.Game.MomirDuel/target Mage.Server.Plugins/Mage.Game.MomirDuel/target
Mage.Server.Plugins/Mage.Game.MomirGame/target/
Mage.Server.Plugins/Mage.Game.PennyDreadfulCommanderFreeForAll/target Mage.Server.Plugins/Mage.Game.PennyDreadfulCommanderFreeForAll/target
Mage.Server.Plugins/Mage.Game.TinyLeadersDuel/target Mage.Server.Plugins/Mage.Game.TinyLeadersDuel/target
Mage.Server.Plugins/Mage.Game.TwoPlayerDuel/target Mage.Server.Plugins/Mage.Game.TwoPlayerDuel/target

View file

@ -519,7 +519,7 @@ public class ComputerPlayer6 extends ComputerPlayer /*implements Player*/ {
logger.trace("interrupted - " + val); logger.trace("interrupted - " + val);
return val; return val;
} }
if (depth <= 0 || SimulationNode2.nodeCount > maxNodes || game.gameOver(null)) { if (depth <= 0 || SimulationNode2.nodeCount > maxNodes || game.checkIfGameIsOver()) {
logger.trace("Add actions -- reached end state, node count=" + SimulationNode2.nodeCount + ", depth=" + depth); logger.trace("Add actions -- reached end state, node count=" + SimulationNode2.nodeCount + ", depth=" + depth);
val = GameStateEvaluator2.evaluate(playerId, game); val = GameStateEvaluator2.evaluate(playerId, game);
UUID currentPlayerId = node.getGame().getPlayerList().get(); UUID currentPlayerId = node.getGame().getPlayerList().get();
@ -540,7 +540,7 @@ public class ComputerPlayer6 extends ComputerPlayer /*implements Player*/ {
} }
} }
if (game.gameOver(null)) { if (game.checkIfGameIsOver()) {
val = GameStateEvaluator2.evaluate(playerId, game); val = GameStateEvaluator2.evaluate(playerId, game);
} else if (!node.getChildren().isEmpty()) { } else if (!node.getChildren().isEmpty()) {
//declared attackers or blockers or triggered abilities //declared attackers or blockers or triggered abilities
@ -588,7 +588,7 @@ public class ComputerPlayer6 extends ComputerPlayer /*implements Player*/ {
logger.debug("Sim Prio [" + depth + "] -- repeated action: " + action.toString()); logger.debug("Sim Prio [" + depth + "] -- repeated action: " + action.toString());
continue; continue;
} }
if (!sim.gameOver(null) && action.isUsesStack()) { if (!sim.checkIfGameIsOver() && action.isUsesStack()) {
// only pass if the last action uses the stack // only pass if the last action uses the stack
UUID nextPlayerId = sim.getPlayerList().get(); UUID nextPlayerId = sim.getPlayerList().get();
do { do {
@ -864,7 +864,7 @@ public class ComputerPlayer6 extends ComputerPlayer /*implements Player*/ {
break; break;
case CLEANUP: case CLEANUP:
game.getPhase().getStep().beginStep(game, activePlayerId); game.getPhase().getStep().beginStep(game, activePlayerId);
if (!game.checkStateAndTriggered() && !game.gameOver(null)) { if (!game.checkStateAndTriggered() && !game.checkIfGameIsOver()) {
game.getState().setActivePlayerId(game.getState().getPlayerList(game.getActivePlayerId()).getNext()); game.getState().setActivePlayerId(game.getState().getPlayerList(game.getActivePlayerId()).getNext());
game.getTurn().setPhase(new BeginningPhase()); game.getTurn().setPhase(new BeginningPhase());
game.getPhase().setStep(new UntapStep()); game.getPhase().setStep(new UntapStep());

View file

@ -233,7 +233,7 @@ public class ComputerPlayer7 extends ComputerPlayer6 {
return GameStateEvaluator2.evaluate(playerId, game); return GameStateEvaluator2.evaluate(playerId, game);
} }
// Condition to stop deeper simulation // Condition to stop deeper simulation
if (depth <= 0 || SimulationNode2.nodeCount > maxNodes || game.gameOver(null)) { if (depth <= 0 || SimulationNode2.nodeCount > maxNodes || game.checkIfGameIsOver()) {
val = GameStateEvaluator2.evaluate(playerId, game); val = GameStateEvaluator2.evaluate(playerId, game);
if (logger.isTraceEnabled()) { if (logger.isTraceEnabled()) {
StringBuilder sb = new StringBuilder("Add Actions -- reached end state <").append(val).append('>'); StringBuilder sb = new StringBuilder("Add Actions -- reached end state <").append(val).append('>');
@ -267,7 +267,7 @@ public class ComputerPlayer7 extends ComputerPlayer6 {
} }
} }
if (game.gameOver(null)) { if (game.checkIfGameIsOver()) {
val = GameStateEvaluator2.evaluate(playerId, game); val = GameStateEvaluator2.evaluate(playerId, game);
} else if (stepFinished) { } else if (stepFinished) {
logger.debug("Step finished"); logger.debug("Step finished");
@ -481,7 +481,7 @@ public class ComputerPlayer7 extends ComputerPlayer6 {
sim.fireEvent(GameEvent.getEvent(GameEvent.EventType.DECLARE_BLOCKERS_STEP_POST, sim.getActivePlayerId(), sim.getActivePlayerId())); sim.fireEvent(GameEvent.getEvent(GameEvent.EventType.DECLARE_BLOCKERS_STEP_POST, sim.getActivePlayerId(), sim.getActivePlayerId()));
Combat simCombat = sim.getCombat().copy(); Combat simCombat = sim.getCombat().copy();
finishCombat(sim); finishCombat(sim);
if (sim.gameOver(null)) { if (sim.checkIfGameIsOver()) {
val = GameStateEvaluator2.evaluate(playerId, sim); val = GameStateEvaluator2.evaluate(playerId, sim);
} else if (!counter) { } else if (!counter) {
val = simulatePostCombatMain(sim, newNode, depth - 1, alpha, beta); val = simulatePostCombatMain(sim, newNode, depth - 1, alpha, beta);
@ -549,7 +549,7 @@ public class ComputerPlayer7 extends ComputerPlayer6 {
logger.debug("interrupted"); logger.debug("interrupted");
return; return;
} }
if (!game.gameOver(null)) { if (!game.checkIfGameIsOver()) {
game.getPhase().setStep(step); game.getPhase().setStep(step);
if (!step.skipStep(game, game.getActivePlayerId())) { if (!step.skipStep(game, game.getActivePlayerId())) {
step.beginStep(game, game.getActivePlayerId()); step.beginStep(game, game.getActivePlayerId());
@ -598,7 +598,7 @@ public class ComputerPlayer7 extends ComputerPlayer6 {
logger.debug("interrupted"); logger.debug("interrupted");
return; return;
} }
if (!game.gameOver(null)) { if (!game.checkIfGameIsOver()) {
game.getTurn().getPhase().endPhase(game, game.getActivePlayerId()); game.getTurn().getPhase().endPhase(game, game.getActivePlayerId());
game.getTurn().setPhase(new EndPhase()); game.getTurn().setPhase(new EndPhase());
if (game.getTurn().getPhase().beginPhase(game, game.getActivePlayerId())) { if (game.getTurn().getPhase().beginPhase(game, game.getActivePlayerId())) {

View file

@ -33,7 +33,7 @@ public final class GameStateEvaluator2 {
public static int evaluate(UUID playerId, Game game) { public static int evaluate(UUID playerId, Game game) {
Player player = game.getPlayer(playerId); Player player = game.getPlayer(playerId);
Player opponent = game.getPlayer(game.getOpponents(playerId).iterator().next()); Player opponent = game.getPlayer(game.getOpponents(playerId).iterator().next());
if (game.gameOver(null)) { if (game.checkIfGameIsOver()) {
if (player.hasLost() || opponent.hasWon()) { if (player.hasLost() || opponent.hasWon()) {
return LOSE_GAME_SCORE; return LOSE_GAME_SCORE;
} }

View file

@ -61,7 +61,7 @@ public class ActionSimulator {
public int evaluateState() { public int evaluateState() {
Player opponent = game.getPlayer(game.getOpponents(player.getId()).iterator().next()); Player opponent = game.getPlayer(game.getOpponents(player.getId()).iterator().next());
if (game.gameOver(null)) { if (game.checkIfGameIsOver()) {
if (player.hasLost() || opponent.hasWon()) { if (player.hasLost() || opponent.hasWon()) {
return Integer.MIN_VALUE; return Integer.MIN_VALUE;
} }

View file

@ -79,7 +79,7 @@ public class MCTSNode {
this.game = game; this.game = game;
this.stateValue = game.getState().getValue(game, targetPlayer); this.stateValue = game.getState().getValue(game, targetPlayer);
this.fullStateValue = game.getState().getValue(true, game); this.fullStateValue = game.getState().getValue(true, game);
this.terminal = game.gameOver(null); this.terminal = game.checkIfGameIsOver();
setPlayer(); setPlayer();
nodeCount = 1; nodeCount = 1;
// logger.info(this.stateValue); // logger.info(this.stateValue);
@ -90,7 +90,7 @@ public class MCTSNode {
this.game = game; this.game = game;
this.stateValue = game.getState().getValue(game, targetPlayer); this.stateValue = game.getState().getValue(game, targetPlayer);
this.fullStateValue = game.getState().getValue(true, game); this.fullStateValue = game.getState().getValue(true, game);
this.terminal = game.gameOver(null); this.terminal = game.checkIfGameIsOver();
this.parent = parent; this.parent = parent;
this.action = action; this.action = action;
setPlayer(); setPlayer();
@ -104,7 +104,7 @@ public class MCTSNode {
this.combat = combat; this.combat = combat;
this.stateValue = game.getState().getValue(game, targetPlayer); this.stateValue = game.getState().getValue(game, targetPlayer);
this.fullStateValue = game.getState().getValue(true, game); this.fullStateValue = game.getState().getValue(true, game);
this.terminal = game.gameOver(null); this.terminal = game.checkIfGameIsOver();
this.parent = parent; this.parent = parent;
setPlayer(); setPlayer();
nodeCount++; nodeCount++;

View file

@ -330,7 +330,7 @@ public class ComputerPlayer2 extends ComputerPlayer implements Player {
return GameStateEvaluator.evaluate(playerId, game); return GameStateEvaluator.evaluate(playerId, game);
} }
int val; int val;
if (node.depth > maxDepth || game.gameOver(null)) { if (node.depth > maxDepth || game.checkIfGameIsOver()) {
logger.debug(indent(node.depth) + "simulating -- reached end state"); logger.debug(indent(node.depth) + "simulating -- reached end state");
val = GameStateEvaluator.evaluate(playerId, game); val = GameStateEvaluator.evaluate(playerId, game);
} }
@ -357,7 +357,7 @@ public class ComputerPlayer2 extends ComputerPlayer implements Player {
} }
} }
if (game.gameOver(null)) { if (game.checkIfGameIsOver()) {
val = GameStateEvaluator.evaluate(playerId, game); val = GameStateEvaluator.evaluate(playerId, game);
} }
else if (!node.getChildren().isEmpty()) { else if (!node.getChildren().isEmpty()) {
@ -403,7 +403,7 @@ public class ComputerPlayer2 extends ComputerPlayer implements Player {
logger.debug(indent(node.depth) + "found useless action: " + action); logger.debug(indent(node.depth) + "found useless action: " + action);
continue; continue;
} }
if (!sim.gameOver(null) && action.isUsesStack()) { if (!sim.checkIfGameIsOver() && action.isUsesStack()) {
// only pass if the last action uses the stack // only pass if the last action uses the stack
sim.getPlayer(currentPlayer.getId()).pass(game); sim.getPlayer(currentPlayer.getId()).pass(game);
sim.getPlayerList().getNext(); sim.getPlayerList().getNext();
@ -588,7 +588,7 @@ public class ComputerPlayer2 extends ComputerPlayer implements Player {
break; break;
case CLEANUP: case CLEANUP:
game.getPhase().getStep().beginStep(game, activePlayerId); game.getPhase().getStep().beginStep(game, activePlayerId);
if (!game.checkStateAndTriggered() && !game.gameOver(null)) { if (!game.checkStateAndTriggered() && !game.checkIfGameIsOver()) {
game.getState().setActivePlayerId(game.getState().getPlayerList(game.getActivePlayerId()).getNext()); game.getState().setActivePlayerId(game.getState().getPlayerList(game.getActivePlayerId()).getNext());
game.getTurn().setPhase(new BeginningPhase()); game.getTurn().setPhase(new BeginningPhase());
game.getPhase().setStep(new UntapStep()); game.getPhase().setStep(new UntapStep());

View file

@ -184,7 +184,7 @@ public class ComputerPlayer3 extends ComputerPlayer2 implements Player {
logger.debug(indent(node.depth) + "interrupted"); logger.debug(indent(node.depth) + "interrupted");
return GameStateEvaluator.evaluate(playerId, game); return GameStateEvaluator.evaluate(playerId, game);
} }
if (node.depth > maxDepth || game.gameOver(null)) { if (node.depth > maxDepth || game.checkIfGameIsOver()) {
logger.debug(indent(node.depth) + "simulating -- reached end state"); logger.debug(indent(node.depth) + "simulating -- reached end state");
val = GameStateEvaluator.evaluate(playerId, game); val = GameStateEvaluator.evaluate(playerId, game);
} }
@ -204,7 +204,7 @@ public class ComputerPlayer3 extends ComputerPlayer2 implements Player {
} }
} }
if (game.gameOver(null)) { if (game.checkIfGameIsOver()) {
val = GameStateEvaluator.evaluate(playerId, game); val = GameStateEvaluator.evaluate(playerId, game);
} }
else if (stepFinished) { else if (stepFinished) {
@ -408,7 +408,7 @@ public class ComputerPlayer3 extends ComputerPlayer2 implements Player {
sim.fireEvent(GameEvent.getEvent(GameEvent.EventType.DECLARE_BLOCKERS_STEP_POST, sim.getActivePlayerId(), sim.getActivePlayerId())); sim.fireEvent(GameEvent.getEvent(GameEvent.EventType.DECLARE_BLOCKERS_STEP_POST, sim.getActivePlayerId(), sim.getActivePlayerId()));
Combat simCombat = sim.getCombat().copy(); Combat simCombat = sim.getCombat().copy();
finishCombat(sim); finishCombat(sim);
if (sim.gameOver(null)) { if (sim.checkIfGameIsOver()) {
val = GameStateEvaluator.evaluate(playerId, sim); val = GameStateEvaluator.evaluate(playerId, sim);
} }
else if (!counter) { else if (!counter) {
@ -450,7 +450,7 @@ public class ComputerPlayer3 extends ComputerPlayer2 implements Player {
return GameStateEvaluator.evaluate(playerId, game); return GameStateEvaluator.evaluate(playerId, game);
} }
Integer val = null; Integer val = null;
if (!game.gameOver(null)) { if (!game.checkIfGameIsOver()) {
logger.debug(indent(node.depth) + "simulating -- ending turn"); logger.debug(indent(node.depth) + "simulating -- ending turn");
simulateToEnd(game); simulateToEnd(game);
game.getState().setActivePlayerId(game.getState().getPlayerList(game.getActivePlayerId()).getNext()); game.getState().setActivePlayerId(game.getState().getPlayerList(game.getActivePlayerId()).getNext());
@ -478,7 +478,7 @@ public class ComputerPlayer3 extends ComputerPlayer2 implements Player {
logger.debug("interrupted"); logger.debug("interrupted");
return; return;
} }
if (!game.gameOver(null)) { if (!game.checkIfGameIsOver()) {
game.getPhase().setStep(step); game.getPhase().setStep(step);
if (!step.skipStep(game, game.getActivePlayerId())) { if (!step.skipStep(game, game.getActivePlayerId())) {
step.beginStep(game, game.getActivePlayerId()); step.beginStep(game, game.getActivePlayerId());
@ -526,7 +526,7 @@ public class ComputerPlayer3 extends ComputerPlayer2 implements Player {
logger.debug("interrupted"); logger.debug("interrupted");
return; return;
} }
if (!game.gameOver(null)) { if (!game.checkIfGameIsOver()) {
game.getTurn().getPhase().endPhase(game, game.getActivePlayerId()); game.getTurn().getPhase().endPhase(game, game.getActivePlayerId());
game.getTurn().setPhase(new EndPhase()); game.getTurn().setPhase(new EndPhase());
if (game.getTurn().getPhase().beginPhase(game, game.getActivePlayerId())) { if (game.getTurn().getPhase().beginPhase(game, game.getActivePlayerId())) {

View file

@ -70,7 +70,7 @@ public final class GameStateEvaluator {
public static int evaluate(UUID playerId, Game game, boolean ignoreTapped) { public static int evaluate(UUID playerId, Game game, boolean ignoreTapped) {
Player player = game.getPlayer(playerId); Player player = game.getPlayer(playerId);
Player opponent = game.getPlayer(game.getOpponents(playerId).iterator().next()); Player opponent = game.getPlayer(game.getOpponents(playerId).iterator().next());
if (game.gameOver(null)) { if (game.checkIfGameIsOver()) {
if (player.hasLost() || opponent.hasWon()) if (player.hasLost() || opponent.hasWon())
return LOSE_SCORE; return LOSE_SCORE;
if (opponent.hasLost() || player.hasWon()) if (opponent.hasLost() || player.hasWon())

View file

@ -53,6 +53,7 @@ import mage.filter.common.FilterCreatureForCombat;
import mage.filter.common.FilterCreatureForCombatBlock; import mage.filter.common.FilterCreatureForCombatBlock;
import mage.filter.predicate.permanent.ControllerIdPredicate; import mage.filter.predicate.permanent.ControllerIdPredicate;
import mage.game.Game; import mage.game.Game;
import mage.game.GameImpl;
import mage.game.combat.CombatGroup; import mage.game.combat.CombatGroup;
import mage.game.draft.Draft; import mage.game.draft.Draft;
import mage.game.events.GameEvent; import mage.game.events.GameEvent;
@ -186,13 +187,25 @@ public class HumanPlayer extends PlayerImpl {
response.clear(); response.clear();
logger.debug("Waiting response from player: " + getId()); logger.debug("Waiting response from player: " + getId());
game.resumeTimer(getTurnControlledBy()); game.resumeTimer(getTurnControlledBy());
synchronized (response) { boolean loop = true;
try { while (loop) {
response.wait(); loop = false;
} catch (InterruptedException ex) { synchronized (response) {
logger.error("Response error for player " + getName() + " gameId: " + game.getId(), ex); try {
} finally { response.wait();
game.pauseTimer(getTurnControlledBy()); } catch (InterruptedException ex) {
logger.error("Response error for player " + getName() + " gameId: " + game.getId(), ex);
} finally {
game.pauseTimer(getTurnControlledBy());
}
}
if (response.getResponseConcedeCheck()) {
((GameImpl) game).checkConcede();
if (game.hasEnded()) {
return;
}
response.clear();
loop = true;
} }
} }
if (recordingMacro && !macroTriggeredSelectionFlag) { if (recordingMacro && !macroTriggeredSelectionFlag) {
@ -1706,6 +1719,15 @@ public class HumanPlayer extends PlayerImpl {
} }
} }
@Override
public void signalPlayerConcede() {
synchronized (response) {
response.setResponseConcedeCheck();
response.notifyAll();
logger.debug("Set check concede for waiting player: " + getId());
}
}
@Override @Override
public void skip() { public void skip() {
synchronized (response) { synchronized (response) {

View file

@ -43,6 +43,7 @@ public class PlayerResponse implements Serializable {
private Integer responseInteger; private Integer responseInteger;
private ManaType responseManaType; private ManaType responseManaType;
private UUID responseManaTypePlayerId; private UUID responseManaTypePlayerId;
private Boolean responseConcedeCheck;
public PlayerResponse() { public PlayerResponse() {
clear(); clear();
@ -55,7 +56,8 @@ public class PlayerResponse implements Serializable {
+ ',' + responseBoolean + ',' + responseBoolean
+ ',' + responseInteger + ',' + responseInteger
+ ',' + responseManaType + ',' + responseManaType
+ ',' + responseManaTypePlayerId; + ',' + responseManaTypePlayerId
+ ',' + responseConcedeCheck;
} }
public PlayerResponse(PlayerResponse other) { public PlayerResponse(PlayerResponse other) {
@ -69,6 +71,7 @@ public class PlayerResponse implements Serializable {
responseInteger = other.responseInteger; responseInteger = other.responseInteger;
responseManaType = other.responseManaType; responseManaType = other.responseManaType;
responseManaTypePlayerId = other.responseManaTypePlayerId; responseManaTypePlayerId = other.responseManaTypePlayerId;
responseConcedeCheck = other.responseConcedeCheck;
} }
public void clear() { public void clear() {
@ -78,6 +81,7 @@ public class PlayerResponse implements Serializable {
responseInteger = null; responseInteger = null;
responseManaType = null; responseManaType = null;
responseManaTypePlayerId = null; responseManaTypePlayerId = null;
responseConcedeCheck = null;
} }
public String getString() { public String getString() {
@ -104,6 +108,17 @@ public class PlayerResponse implements Serializable {
this.responseBoolean = responseBoolean; this.responseBoolean = responseBoolean;
} }
public Boolean getResponseConcedeCheck() {
if (responseConcedeCheck == null) {
return false;
}
return responseConcedeCheck;
}
public void setResponseConcedeCheck() {
this.responseConcedeCheck = true;
}
public Integer getInteger() { public Integer getInteger() {
return responseInteger; return responseInteger;
} }

View file

@ -34,6 +34,7 @@ import mage.abilities.TriggeredAbilityImpl;
import mage.abilities.common.SimpleActivatedAbility; import mage.abilities.common.SimpleActivatedAbility;
import mage.abilities.costs.mana.ManaCostsImpl; import mage.abilities.costs.mana.ManaCostsImpl;
import mage.abilities.effects.ContinuousRuleModifyingEffectImpl; import mage.abilities.effects.ContinuousRuleModifyingEffectImpl;
import mage.abilities.effects.OneShotEffect;
import mage.abilities.effects.common.GainLifeEffect; import mage.abilities.effects.common.GainLifeEffect;
import mage.abilities.effects.common.LoseLifeTargetEffect; import mage.abilities.effects.common.LoseLifeTargetEffect;
import mage.abilities.effects.common.combat.BlocksIfAbleAllEffect; import mage.abilities.effects.common.combat.BlocksIfAbleAllEffect;
@ -47,6 +48,7 @@ import mage.game.events.GameEvent;
import mage.game.permanent.Permanent; import mage.game.permanent.Permanent;
import mage.players.Player; import mage.players.Player;
import mage.target.targetpointer.FixedTarget; import mage.target.targetpointer.FixedTarget;
import mage.watchers.common.ChooseBlockersRedundancyWatcher;
/** /**
* *
@ -72,6 +74,8 @@ public class BrutalHordechief extends CardImpl {
// {3}{R/W}{R/W}: Creatures your opponents control block this turn if able, and you choose how those creatures block. // {3}{R/W}{R/W}: Creatures your opponents control block this turn if able, and you choose how those creatures block.
Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new BlocksIfAbleAllEffect(filter, Duration.EndOfTurn), new ManaCostsImpl("{3}{R/W}{R/W}")); Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new BlocksIfAbleAllEffect(filter, Duration.EndOfTurn), new ManaCostsImpl("{3}{R/W}{R/W}"));
ability.addEffect(new BrutalHordechiefChooseBlockersEffect()); ability.addEffect(new BrutalHordechiefChooseBlockersEffect());
ability.addWatcher(new ChooseBlockersRedundancyWatcher());
ability.addEffect(new ChooseBlockersRedundancyWatcherIncrementEffect());
this.addAbility(ability); this.addAbility(ability);
} }
@ -83,6 +87,32 @@ public class BrutalHordechief extends CardImpl {
public BrutalHordechief copy() { public BrutalHordechief copy() {
return new BrutalHordechief(this); return new BrutalHordechief(this);
} }
private class ChooseBlockersRedundancyWatcherIncrementEffect extends OneShotEffect {
ChooseBlockersRedundancyWatcherIncrementEffect() {
super(Outcome.Neutral);
}
ChooseBlockersRedundancyWatcherIncrementEffect(final ChooseBlockersRedundancyWatcherIncrementEffect effect) {
super(effect);
}
@Override
public boolean apply(Game game, Ability source) {
ChooseBlockersRedundancyWatcher watcher = (ChooseBlockersRedundancyWatcher) game.getState().getWatchers().get(ChooseBlockersRedundancyWatcher.class.getSimpleName());
if (watcher != null) {
watcher.increment();
return true;
}
return false;
}
@Override
public ChooseBlockersRedundancyWatcherIncrementEffect copy() {
return new ChooseBlockersRedundancyWatcherIncrementEffect(this);
}
}
} }
class BrutalHordechiefTriggeredAbility extends TriggeredAbilityImpl { class BrutalHordechiefTriggeredAbility extends TriggeredAbilityImpl {
@ -123,11 +153,11 @@ class BrutalHordechiefTriggeredAbility extends TriggeredAbilityImpl {
} }
} }
class BrutalHordechiefChooseBlockersEffect extends ContinuousRuleModifyingEffectImpl { // TODO: reverse the resolution order in case of effect multiples class BrutalHordechiefChooseBlockersEffect extends ContinuousRuleModifyingEffectImpl {
public BrutalHordechiefChooseBlockersEffect() { public BrutalHordechiefChooseBlockersEffect() {
super(Duration.EndOfTurn, Outcome.Benefit, false, false); super(Duration.EndOfTurn, Outcome.Benefit, false, false);
staticText = ", and you choose how those creatures block"; staticText = "You choose which creatures block this turn and how those creatures block";
} }
public BrutalHordechiefChooseBlockersEffect(final BrutalHordechiefChooseBlockersEffect effect) { public BrutalHordechiefChooseBlockersEffect(final BrutalHordechiefChooseBlockersEffect effect) {
@ -151,6 +181,13 @@ class BrutalHordechiefChooseBlockersEffect extends ContinuousRuleModifyingEffect
@Override @Override
public boolean applies(GameEvent event, Ability source, Game game) { public boolean applies(GameEvent event, Ability source, Game game) {
ChooseBlockersRedundancyWatcher watcher = (ChooseBlockersRedundancyWatcher) game.getState().getWatchers().get(ChooseBlockersRedundancyWatcher.class.getSimpleName());
watcher.decrement();
if (watcher.copyCountApply > 0) {
game.informPlayers(source.getSourceObject(game).getIdName() + " didn't apply");
return false;
}
watcher.copyCountApply = watcher.copyCount;
Player blockController = game.getPlayer(source.getControllerId()); Player blockController = game.getPlayer(source.getControllerId());
if (blockController != null) { if (blockController != null) {
game.getCombat().selectBlockers(blockController, game); game.getCombat().selectBlockers(blockController, game);

View file

@ -28,16 +28,14 @@
package mage.cards.c; package mage.cards.c;
import java.util.UUID; import java.util.UUID;
import mage.abilities.Ability;
import mage.abilities.TriggeredAbilityImpl; import mage.abilities.TriggeredAbilityImpl;
import mage.abilities.common.EntersBattlefieldAbility; import mage.abilities.common.EntersBattlefieldAbility;
import mage.abilities.effects.Effect; import mage.abilities.effects.Effect;
import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.CounterTargetEffect;
import mage.abilities.effects.common.EntersBattlefieldWithXCountersEffect; import mage.abilities.effects.common.EntersBattlefieldWithXCountersEffect;
import mage.cards.CardImpl; import mage.cards.CardImpl;
import mage.cards.CardSetInfo; import mage.cards.CardSetInfo;
import mage.constants.CardType; import mage.constants.CardType;
import mage.constants.Outcome;
import mage.constants.Zone; import mage.constants.Zone;
import mage.counters.CounterType; import mage.counters.CounterType;
import mage.game.Game; import mage.game.Game;
@ -53,7 +51,7 @@ import mage.target.targetpointer.FixedTarget;
public class ChaliceOfTheVoid extends CardImpl { public class ChaliceOfTheVoid extends CardImpl {
public ChaliceOfTheVoid(UUID ownerId, CardSetInfo setInfo) { public ChaliceOfTheVoid(UUID ownerId, CardSetInfo setInfo) {
super(ownerId,setInfo,new CardType[]{CardType.ARTIFACT},"{X}{X}"); super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{X}{X}");
// Chalice of the Void enters the battlefield with X charge counters on it. // Chalice of the Void enters the battlefield with X charge counters on it.
this.addAbility(new EntersBattlefieldAbility(new EntersBattlefieldWithXCountersEffect(CounterType.CHARGE.createInstance()))); this.addAbility(new EntersBattlefieldAbility(new EntersBattlefieldWithXCountersEffect(CounterType.CHARGE.createInstance())));
@ -75,7 +73,7 @@ public class ChaliceOfTheVoid extends CardImpl {
class ChaliceOfTheVoidTriggeredAbility extends TriggeredAbilityImpl { class ChaliceOfTheVoidTriggeredAbility extends TriggeredAbilityImpl {
public ChaliceOfTheVoidTriggeredAbility() { public ChaliceOfTheVoidTriggeredAbility() {
super(Zone.BATTLEFIELD, new CounterEffect()); super(Zone.BATTLEFIELD, new CounterTargetEffect());
} }
public ChaliceOfTheVoidTriggeredAbility(final ChaliceOfTheVoidTriggeredAbility abiltity) { public ChaliceOfTheVoidTriggeredAbility(final ChaliceOfTheVoidTriggeredAbility abiltity) {
@ -110,25 +108,3 @@ class ChaliceOfTheVoidTriggeredAbility extends TriggeredAbilityImpl {
return "Whenever a player casts a spell with converted mana cost equal to the number of charge counters on {this}, counter that spell."; return "Whenever a player casts a spell with converted mana cost equal to the number of charge counters on {this}, counter that spell.";
} }
} }
class CounterEffect extends OneShotEffect {
public CounterEffect() {
super(Outcome.Detriment);
}
public CounterEffect(final CounterEffect effect) {
super(effect);
}
@Override
public CounterEffect copy() {
return new CounterEffect(this);
}
@Override
public boolean apply(Game game, Ability source) {
return game.getStack().counter(this.getTargetPointer().getFirst(game, source), source.getSourceId(), game);
}
}

View file

@ -101,6 +101,7 @@ class ConundrumSphinxEffect extends OneShotEffect {
if (player != null) { if (player != null) {
if (player.getLibrary().hasCards()) { if (player.getLibrary().hasCards()) {
cardChoice.clearChoice(); cardChoice.clearChoice();
cardChoice.setMessage("Name a card");
while (!player.choose(Outcome.DrawCard, cardChoice, game) && player.canRespond()) { while (!player.choose(Outcome.DrawCard, cardChoice, game) && player.canRespond()) {
if (!player.canRespond()) { if (!player.canRespond()) {
continue Players; continue Players;

View file

@ -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 mage.cards.c;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Set;
import java.util.UUID;
import mage.MageInt;
import mage.abilities.Ability;
import mage.abilities.common.AttacksTriggeredAbility;
import mage.abilities.effects.common.ReturnFromGraveyardToBattlefieldTargetEffect;
import mage.abilities.keyword.MeleeAbility;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.*;
import mage.filter.FilterCard;
import mage.filter.common.FilterCreatureCard;
import mage.filter.predicate.Predicates;
import mage.filter.predicate.mageobject.CardTypePredicate;
import mage.filter.predicate.mageobject.ConvertedManaCostPredicate;
import mage.game.Game;
import mage.game.events.GameEvent;
import mage.game.events.GameEvent.EventType;
import mage.game.permanent.Permanent;
import mage.target.common.TargetCardInYourGraveyard;
import mage.watchers.Watcher;
/**
*
* @author L_J
*/
public class CustodiSoulcaller extends CardImpl {
public CustodiSoulcaller(UUID ownerId, CardSetInfo setInfo) {
super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{1}{W}{W}");
this.subtype.add(SubType.HUMAN);
this.subtype.add(SubType.CLERIC);
this.power = new MageInt(1);
this.toughness = new MageInt(2);
// Melee
this.addAbility(new MeleeAbility());
// Whenever Custodi Soulcaller attacks, return target creature card with converted mana cost X or less from your graveyard to the battlefield, where X is the number of players you attacked with a creature this combat.
Ability ability = new AttacksTriggeredAbility(new ReturnFromGraveyardToBattlefieldTargetEffect(), false);
ability.addWatcher(new CustodiSoulcallerWatcher());
ability.addTarget(new TargetCardInYourGraveyard(new FilterCreatureCard("creature card with converted mana cost X or less from your graveyard, where X is the number of players you attacked with a creature this combat")));
this.addAbility(ability);
}
@Override
public void adjustTargets(Ability ability, Game game) {
if (ability.getClass().equals(AttacksTriggeredAbility.class)) {
ability.getTargets().clear();
CustodiSoulcallerWatcher watcher = (CustodiSoulcallerWatcher) game.getState().getWatchers().get(CustodiSoulcallerWatcher.class.getSimpleName());
Permanent sourcePermanent = game.getPermanentOrLKIBattlefield(ability.getSourceId());
if (watcher != null && watcher.playersAttacked != null) {
int xValue = watcher.getNumberOfAttackedPlayers(sourcePermanent.getControllerId());
FilterCard filter = new FilterCard("creature card with converted mana cost " + xValue + " or less");
filter.add(new CardTypePredicate(CardType.CREATURE));
filter.add(Predicates.or(new ConvertedManaCostPredicate(ComparisonType.EQUAL_TO, xValue), new ConvertedManaCostPredicate(ComparisonType.FEWER_THAN, xValue)));
ability.getTargets().add(new TargetCardInYourGraveyard(filter));
}
}
}
public CustodiSoulcaller(final CustodiSoulcaller card) {
super(card);
}
@Override
public CustodiSoulcaller copy() {
return new CustodiSoulcaller(this);
}
}
class CustodiSoulcallerWatcher extends Watcher {
protected final HashMap<UUID, Set<UUID>> playersAttacked = new HashMap<>(0);
CustodiSoulcallerWatcher() {
super("CustodiSoulcallerWatcher", WatcherScope.GAME);
}
CustodiSoulcallerWatcher(final CustodiSoulcallerWatcher watcher) {
super(watcher);
this.playersAttacked.putAll(watcher.playersAttacked);
}
@Override
public void watch(GameEvent event, Game game) {
if (event.getType() == EventType.BEGIN_COMBAT_STEP_PRE) {
this.playersAttacked.clear();
}
else if (event.getType() == EventType.ATTACKER_DECLARED) {
Set<UUID> attackedPlayers = this.playersAttacked.getOrDefault(event.getPlayerId(), new HashSet<>(1));
attackedPlayers.add(event.getTargetId());
this.playersAttacked.put(event.getPlayerId(), attackedPlayers);
}
}
public int getNumberOfAttackedPlayers(UUID attackerId) {
return this.playersAttacked.get(attackerId).size();
}
@Override
public CustodiSoulcallerWatcher copy() {
return new CustodiSoulcallerWatcher(this);
}
}

View file

@ -30,9 +30,8 @@ package mage.cards.d;
import java.util.UUID; import java.util.UUID;
import mage.abilities.Ability; import mage.abilities.Ability;
import mage.abilities.common.CycleTriggeredAbility; import mage.abilities.common.CycleTriggeredAbility;
import mage.abilities.costs.Cost;
import mage.abilities.costs.mana.GenericManaCost; import mage.abilities.costs.mana.GenericManaCost;
import mage.abilities.costs.mana.ManaCost;
import mage.abilities.costs.mana.ManaCosts;
import mage.abilities.costs.mana.ManaCostsImpl; import mage.abilities.costs.mana.ManaCostsImpl;
import mage.abilities.dynamicvalue.common.ManacostVariableValue; import mage.abilities.dynamicvalue.common.ManacostVariableValue;
import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.OneShotEffect;
@ -98,13 +97,13 @@ class DecreeOfJusticeCycleEffect extends OneShotEffect {
@Override @Override
public boolean apply(Game game, Ability source) { public boolean apply(Game game, Ability source) {
Player player = game.getPlayer(source.getControllerId()); Player player = game.getPlayer(source.getControllerId());
ManaCosts<ManaCost> cost = new ManaCostsImpl<>("{X}");
if (player != null) { if (player != null) {
int costX = player.announceXMana(0, Integer.MAX_VALUE, "Announce the value for {X}", game, source); int X = player.announceXMana(0, Integer.MAX_VALUE, "Announce the value for {X}", game, source);
cost.add(new GenericManaCost(costX)); Cost cost = new GenericManaCost(X);
if (cost.pay(source, game, source.getSourceId(), source.getControllerId(), false, null)) { if(cost.pay(source, game, source.getSourceId(), source.getControllerId(), false)){
Token token = new SoldierToken(); Token token = new SoldierToken();
token.putOntoBattlefield(costX, game, source.getSourceId(), source.getControllerId()); token.putOntoBattlefield(X, game, source.getSourceId(), source.getControllerId());
return true;
} }
} }
return false; return false;

View file

@ -60,7 +60,7 @@ import mage.target.TargetPermanent;
public class DereviEmpyrialTactician extends CardImpl { public class DereviEmpyrialTactician extends CardImpl {
public DereviEmpyrialTactician(UUID ownerId, CardSetInfo setInfo) { public DereviEmpyrialTactician(UUID ownerId, CardSetInfo setInfo) {
super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{G}{W}{U}"); super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{G}{W}{U}");
addSuperType(SuperType.LEGENDARY); addSuperType(SuperType.LEGENDARY);
this.subtype.add(SubType.BIRD); this.subtype.add(SubType.BIRD);
this.subtype.add(SubType.WIZARD); this.subtype.add(SubType.WIZARD);
@ -74,7 +74,7 @@ public class DereviEmpyrialTactician extends CardImpl {
Ability ability = new DereviEmpyrialTacticianTriggeredAbility(new MayTapOrUntapTargetEffect()); Ability ability = new DereviEmpyrialTacticianTriggeredAbility(new MayTapOrUntapTargetEffect());
ability.addTarget(new TargetPermanent()); ability.addTarget(new TargetPermanent());
this.addAbility(ability); this.addAbility(ability);
// {1}{G}{W}{U}: Put Derevi onto the battlefield from the command zone. // {1}{G}{W}{U}: Put Derevi onto the battlefield from the command zone.
this.addAbility(new DereviEmpyrialTacticianAbility()); this.addAbility(new DereviEmpyrialTacticianAbility());
} }
@ -132,7 +132,7 @@ class DereviEmpyrialTacticianTriggeredAbility extends TriggeredAbilityImpl {
} }
} }
class DereviEmpyrialTacticianAbility extends ActivatedAbilityImpl { class DereviEmpyrialTacticianAbility extends ActivatedAbilityImpl {
public DereviEmpyrialTacticianAbility() { public DereviEmpyrialTacticianAbility() {
super(Zone.COMMAND, new PutCommanderOnBattlefieldEffect(), new ManaCostsImpl("{1}{G}{W}{U}")); super(Zone.COMMAND, new PutCommanderOnBattlefieldEffect(), new ManaCostsImpl("{1}{G}{W}{U}"));
@ -182,7 +182,7 @@ class PutCommanderOnBattlefieldEffect extends OneShotEffect {
} }
Card card = game.getCard(source.getSourceId()); Card card = game.getCard(source.getSourceId());
if (card != null) { if (card != null) {
card.putOntoBattlefield(game, Zone.COMMAND, source.getSourceId(), source.getControllerId()); player.moveCards(card, Zone.BATTLEFIELD, source, game);
return true; return true;
} }
return false; return false;

View file

@ -0,0 +1,128 @@
/*
* 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 mage.cards.d;
import java.util.UUID;
import mage.ObjectColor;
import mage.abilities.Ability;
import mage.abilities.common.BeginningOfUpkeepTriggeredAbility;
import mage.abilities.common.SimpleStaticAbility;
import mage.abilities.costs.mana.GenericManaCost;
import mage.abilities.effects.OneShotEffect;
import mage.abilities.effects.common.DontUntapInControllersUntapStepAllEffect;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
import mage.constants.Duration;
import mage.constants.Outcome;
import mage.constants.TargetController;
import mage.constants.Zone;
import mage.filter.common.FilterControlledCreaturePermanent;
import mage.filter.common.FilterCreaturePermanent;
import mage.filter.predicate.Predicates;
import mage.filter.predicate.mageobject.ColorPredicate;
import mage.filter.predicate.permanent.TappedPredicate;
import mage.game.Game;
import mage.game.permanent.Permanent;
import mage.players.Player;
import mage.target.Target;
import mage.target.common.TargetControlledCreaturePermanent;
/**
*
* @author spjspj & L_J
*/
public class DreamTides extends CardImpl {
public DreamTides(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{2}{U}{U}");
// Creatures don't untap during their controllers' untap steps.
this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new DontUntapInControllersUntapStepAllEffect(Duration.WhileOnBattlefield, TargetController.ANY, new FilterCreaturePermanent("Creatures"))));
// At the beginning of each player's upkeep, that player may choose any number of tapped nongreen creatures he or she controls and pay {2} for each creature chosen this way. If the player does, untap those creatures.
this.addAbility(new BeginningOfUpkeepTriggeredAbility(Zone.BATTLEFIELD, new DreamTidesEffect(), TargetController.ANY, false));
}
public DreamTides(final DreamTides card) {
super(card);
}
@Override
public DreamTides copy() {
return new DreamTides(this);
}
}
class DreamTidesEffect extends OneShotEffect {
private static final FilterControlledCreaturePermanent filter = new FilterControlledCreaturePermanent("tapped nongreen creature");
static {
filter.add(Predicates.not(new ColorPredicate(ObjectColor.GREEN)));
filter.add(new TappedPredicate());
}
DreamTidesEffect() {
super(Outcome.Benefit);
staticText = "that player may choose any number of tapped nongreen creatures he or she controls and pay {2} for each creature chosen this way. If the player does, untap those creatures";
}
DreamTidesEffect(DreamTidesEffect effect) {
super(effect);
}
@Override
public DreamTidesEffect copy() {
return new DreamTidesEffect(this);
}
@Override
public boolean apply(Game game, Ability source) {
Player player = game.getPlayer(targetPointer.getFirst(game, source));
Permanent sourcePermanent = game.getPermanent(source.getSourceId());
if (player != null && sourcePermanent != null) {
int countBattlefield = game.getBattlefield().getAllActivePermanents(filter, game.getActivePlayerId(), game).size();
while (player.canRespond() && countBattlefield > 0 && player.chooseUse(Outcome.AIDontUseIt, "Pay {2} and untap a tapped nongreen creature under your control?", source, game)) {
Target tappedCreatureTarget = new TargetControlledCreaturePermanent(1, 1, filter, true);
if (player.choose(Outcome.Detriment, tappedCreatureTarget, source.getSourceId(), game)) {
GenericManaCost cost = new GenericManaCost(2);
Permanent tappedCreature = game.getPermanent(tappedCreatureTarget.getFirstTarget());
if (cost.pay(source, game, source.getSourceId(), player.getId(), false)) {
tappedCreature.untap(game);
}
}
countBattlefield = game.getBattlefield().getAllActivePermanents(filter, game.getActivePlayerId(), game).size();
}
return true;
}
return false;
}
}

View file

@ -27,11 +27,13 @@
*/ */
package mage.cards.e; package mage.cards.e;
import java.util.List;
import java.util.Objects; import java.util.Objects;
import java.util.UUID; import java.util.UUID;
import mage.abilities.Ability; import mage.abilities.Ability;
import mage.abilities.common.BeginningOfUpkeepTriggeredAbility; import mage.abilities.common.BeginningOfUpkeepTriggeredAbility;
import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.OneShotEffect;
import mage.abilities.effects.common.PhaseOutAllEffect;
import mage.cards.CardImpl; import mage.cards.CardImpl;
import mage.cards.CardSetInfo; import mage.cards.CardSetInfo;
import mage.constants.CardType; import mage.constants.CardType;
@ -55,8 +57,7 @@ import mage.target.TargetPlayer;
public class Equipoise extends CardImpl { public class Equipoise extends CardImpl {
public Equipoise(UUID ownerId, CardSetInfo setInfo) { public Equipoise(UUID ownerId, CardSetInfo setInfo) {
super(ownerId,setInfo,new CardType[]{CardType.ENCHANTMENT},"{2}{W}"); super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{2}{W}");
// At the beginning of your upkeep, for each land target player controls in excess of the number you control, choose a land he or she controls, then the chosen permanents phase out. Repeat this process for artifacts and creatures. // At the beginning of your upkeep, for each land target player controls in excess of the number you control, choose a land he or she controls, then the chosen permanents phase out. Repeat this process for artifacts and creatures.
Ability ability = new BeginningOfUpkeepTriggeredAbility(new EquipoiseEffect(), TargetController.YOU, false); Ability ability = new BeginningOfUpkeepTriggeredAbility(new EquipoiseEffect(), TargetController.YOU, false);
@ -112,17 +113,12 @@ class EquipoiseEffect extends OneShotEffect {
int numberTargetPlayer = game.getBattlefield().count(filter, source.getSourceId(), targetPlayer.getId(), game); int numberTargetPlayer = game.getBattlefield().count(filter, source.getSourceId(), targetPlayer.getId(), game);
int excess = numberTargetPlayer - numberController; int excess = numberTargetPlayer - numberController;
if (excess > 0) { if (excess > 0) {
FilterPermanent filterChoose = new FilterPermanent(cardType.toString().toLowerCase() + (excess > 1 ? "s":"") +" of target player"); FilterPermanent filterChoose = new FilterPermanent(cardType.toString().toLowerCase() + (excess > 1 ? "s" : "") + " of target player");
filterChoose.add(new ControllerIdPredicate(targetPlayer.getId())); filterChoose.add(new ControllerIdPredicate(targetPlayer.getId()));
filterChoose.add(new CardTypePredicate(cardType)); filterChoose.add(new CardTypePredicate(cardType));
Target target = new TargetPermanent(excess, excess, filterChoose, true); Target target = new TargetPermanent(excess, excess, filterChoose, true);
controller.chooseTarget(outcome, target, source, game); controller.chooseTarget(outcome, target, source, game);
for (UUID permanentId:target.getTargets()) { new PhaseOutAllEffect(target.getTargets()).apply(game, source);
Permanent permanent = game.getPermanent(permanentId);
if (permanent != null) {
permanent.phaseOut(game);
}
}
} }
} }
} }

View file

@ -0,0 +1,126 @@
/*
* 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 mage.cards.g;
import java.util.UUID;
import mage.MageObject;
import mage.abilities.Ability;
import mage.abilities.common.SimpleActivatedAbility;
import mage.abilities.costs.mana.GenericManaCost;
import mage.abilities.effects.RedirectionEffect;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
import mage.constants.Duration;
import mage.constants.Outcome;
import mage.constants.Zone;
import mage.game.Game;
import mage.game.events.GameEvent;
import mage.game.permanent.Permanent;
import mage.game.stack.Spell;
import mage.players.Player;
import mage.target.TargetSource;
import mage.target.common.TargetControlledCreaturePermanent;
/**
*
* @author L_J
*/
public class GeneralsRegalia extends CardImpl {
public GeneralsRegalia(UUID ownerId, CardSetInfo setInfo) {
super(ownerId,setInfo,new CardType[]{CardType.ARTIFACT},"{3}");
// {3}: The next time a source of your choice would deal damage to you this turn, that damage is dealt to target creature you control instead.
Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new GeneralsRegaliaEffect(), new GenericManaCost(3));
ability.addTarget(new TargetControlledCreaturePermanent());
this.addAbility(ability);
}
public GeneralsRegalia(final GeneralsRegalia card) {
super(card);
}
@Override
public GeneralsRegalia copy() {
return new GeneralsRegalia(this);
}
}
class GeneralsRegaliaEffect extends RedirectionEffect {
private final TargetSource damageSource;
public GeneralsRegaliaEffect() {
super(Duration.EndOfTurn, Integer.MAX_VALUE, true);
staticText = "The next time a source of your choice would deal damage to you this turn, that damage is dealt to target creature you control instead";
this.damageSource = new TargetSource();
}
public GeneralsRegaliaEffect(final GeneralsRegaliaEffect effect) {
super(effect);
this.damageSource = effect.damageSource.copy();
}
@Override
public GeneralsRegaliaEffect copy() {
return new GeneralsRegaliaEffect(this);
}
@Override
public void init(Ability source, Game game) {
this.damageSource.choose(Outcome.PreventDamage, source.getControllerId(), source.getSourceId(), game);
super.init(source, game);
}
@Override
public boolean applies(GameEvent event, Ability source, Game game) {
// check source
MageObject object = game.getObject(event.getSourceId());
if (object == null) {
game.informPlayers("Couldn't find source of damage");
return false;
}
if (!object.getId().equals(damageSource.getFirstTarget())
&& (!(object instanceof Spell) || !((Spell) object).getSourceId().equals(damageSource.getFirstTarget()))) {
return false;
}
this.redirectTarget = source.getTargets().get(0);
// check player
Player player = game.getPlayer(event.getTargetId());
if (player != null) {
if (player.getId().equals(source.getControllerId())) {
return true;
}
}
return false;
}
}

View file

@ -0,0 +1,122 @@
/*
* 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 mage.cards.g;
import java.util.UUID;
import mage.MageInt;
import mage.MageObject;
import mage.abilities.Ability;
import mage.abilities.common.SimpleActivatedAbility;
import mage.abilities.costs.mana.ManaCostsImpl;
import mage.abilities.effects.OneShotEffect;
import mage.abilities.effects.common.continuous.BoostSourceEffect;
import mage.cards.Card;
import mage.constants.SubType;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.cards.CardsImpl;
import mage.constants.CardType;
import mage.constants.Duration;
import mage.constants.Outcome;
import mage.game.Game;
import mage.players.Library;
import mage.players.Player;
/**
*
* @author TheElk801
*/
public class GoblinMachinist extends CardImpl {
public GoblinMachinist(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{4}{R}");
this.subtype.add(SubType.GOBLIN);
this.power = new MageInt(0);
this.toughness = new MageInt(5);
// {2}{R}: Reveal cards from the top of your library until you reveal a nonland card. Goblin Machinist gets +X/+0 until end of turn, where X is that card's converted mana cost. Put the revealed cards on the bottom of your library in any order.
this.addAbility(new SimpleActivatedAbility(new GoblinMachinistEffect(), new ManaCostsImpl("{2}{R}")));
}
public GoblinMachinist(final GoblinMachinist card) {
super(card);
}
@Override
public GoblinMachinist copy() {
return new GoblinMachinist(this);
}
}
class GoblinMachinistEffect extends OneShotEffect {
public GoblinMachinistEffect() {
super(Outcome.DrawCard);
this.staticText = "Reveal cards from the top of your library until you reveal a nonland card. {this} gets +X/+0 until end of turn, where X is that card's converted mana cost. Put the revealed cards on the bottom of your library in any order";
}
public GoblinMachinistEffect(final GoblinMachinistEffect effect) {
super(effect);
}
@Override
public GoblinMachinistEffect copy() {
return new GoblinMachinistEffect(this);
}
@Override
public boolean apply(Game game, Ability source) {
Player controller = game.getPlayer(source.getControllerId());
MageObject sourceObject = source.getSourceObject(game);
if (controller != null && sourceObject != null) {
if (controller.getLibrary().hasCards()) {
CardsImpl cards = new CardsImpl();
Library library = controller.getLibrary();
Card card = null;
do {
card = library.removeFromTop(game);
if (card != null) {
cards.add(card);
}
} while (library.hasCards() && card != null && card.isLand());
if (!cards.isEmpty()) {
controller.revealCards(sourceObject.getIdName(), cards, game);
}
boolean retVal = false;
if (card != null) {
retVal = new BoostSourceEffect(card.getConvertedManaCost(), 0, Duration.EndOfTurn).apply(game, source);
}
return controller.putCardsOnBottomOfLibrary(cards, game, source, true) && retVal;
}
return true;
}
return false;
}
}

View file

@ -0,0 +1,87 @@
/*
* 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 mage.cards.j;
import java.util.UUID;
import mage.MageInt;
import mage.abilities.Ability;
import mage.abilities.DelayedTriggeredAbility;
import mage.abilities.common.BeginningOfCombatTriggeredAbility;
import mage.abilities.condition.CompoundCondition;
import mage.abilities.condition.Condition;
import mage.abilities.condition.InvertCondition;
import mage.abilities.condition.common.SourceOnBattlefieldCondition;
import mage.abilities.condition.common.SourceTappedCondition;
import mage.abilities.decorator.ConditionalContinuousEffect;
import mage.abilities.effects.common.combat.CantAttackSourceEffect;
import mage.abilities.effects.common.continuous.GainAbilityControlledEffect;
import mage.abilities.keyword.special.JohanVigilanceAbility;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
import mage.constants.SubType;
import mage.constants.Duration;
import mage.constants.SuperType;
import mage.constants.TargetController;
import mage.filter.common.FilterControlledCreaturePermanent;
/**
*
* @author L_J
*/
public class Johan extends CardImpl {
public Johan(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{R}{G}{W}");
addSuperType(SuperType.LEGENDARY);
this.subtype.add(SubType.HUMAN);
this.subtype.add(SubType.WIZARD);
this.power = new MageInt(5);
this.toughness = new MageInt(4);
// At the beginning of combat on your turn, you may have Johan gain "Johan can't attack" until end of combat. If you do, attacking doesn't cause creatures you control to tap this combat if Johan is untapped.
Condition condition = new CompoundCondition("if {this} is untapped",
new InvertCondition(SourceTappedCondition.instance),
SourceOnBattlefieldCondition.instance);
Ability ability = new BeginningOfCombatTriggeredAbility(new CantAttackSourceEffect(Duration.EndOfCombat).setText("you may have {this} gain \"{this} can't attack\" until end of combat"), TargetController.YOU, true);
ability.addEffect(new ConditionalContinuousEffect(
new GainAbilityControlledEffect(JohanVigilanceAbility.getInstance(), Duration.EndOfCombat, new FilterControlledCreaturePermanent("creatures")),
condition,
"If you do, attacking doesn't cause creatures you control to tap this combat if {this} is untapped"));
this.addAbility(ability);
}
public Johan(final Johan card) {
super(card);
}
@Override
public Johan copy() {
return new Johan(this);
}
}

View file

@ -29,9 +29,8 @@ package mage.cards.m;
import java.util.UUID; import java.util.UUID;
import mage.MageInt; import mage.MageInt;
import mage.abilities.Ability;
import mage.abilities.common.SimpleStaticAbility; import mage.abilities.common.SimpleStaticAbility;
import mage.abilities.effects.common.continuous.GainAbilityAllEffect; import mage.abilities.effects.common.continuous.GainAbilityControlledEffect;
import mage.abilities.mana.AnyColorManaAbility; import mage.abilities.mana.AnyColorManaAbility;
import mage.cards.CardImpl; import mage.cards.CardImpl;
import mage.cards.CardSetInfo; import mage.cards.CardSetInfo;
@ -39,7 +38,7 @@ import mage.constants.CardType;
import mage.constants.SubType; import mage.constants.SubType;
import mage.constants.Duration; import mage.constants.Duration;
import mage.constants.Zone; import mage.constants.Zone;
import mage.filter.StaticFilters; import mage.filter.common.FilterCreaturePermanent;
/** /**
* *
@ -47,6 +46,8 @@ import mage.filter.StaticFilters;
*/ */
public class ManaweftSliver extends CardImpl { public class ManaweftSliver extends CardImpl {
public static final FilterCreaturePermanent filter = new FilterCreaturePermanent(SubType.SLIVER, "Sliver creatures");
public ManaweftSliver(UUID ownerId, CardSetInfo setInfo) { public ManaweftSliver(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{G}"); super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{G}");
this.subtype.add(SubType.SLIVER); this.subtype.add(SubType.SLIVER);
@ -55,11 +56,11 @@ public class ManaweftSliver extends CardImpl {
this.toughness = new MageInt(1); this.toughness = new MageInt(1);
// Sliver creatures you control have "{T}: Add one mana of any color to your mana pool." // Sliver creatures you control have "{T}: Add one mana of any color to your mana pool."
Ability ability = new AnyColorManaAbility(); this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new GainAbilityControlledEffect(
this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new AnyColorManaAbility(),
new GainAbilityAllEffect(ability, Duration.WhileOnBattlefield,
Duration.WhileOnBattlefield, StaticFilters.FILTER_PERMANENT_CREATURE_SLIVERS, filter
"Sliver creatures you control have \"{T}: Add one mana of any color to your mana pool.\""))); )));
} }
public ManaweftSliver(final ManaweftSliver card) { public ManaweftSliver(final ManaweftSliver card) {

View file

@ -56,6 +56,7 @@ import mage.target.common.TargetCreaturePermanent;
import mage.filter.predicate.permanent.ControllerPredicate; import mage.filter.predicate.permanent.ControllerPredicate;
import mage.target.targetpointer.FixedTarget; import mage.target.targetpointer.FixedTarget;
import mage.watchers.Watcher; import mage.watchers.Watcher;
import mage.watchers.common.ChooseBlockersRedundancyWatcher;
/** /**
* *
@ -67,7 +68,7 @@ public class MasterWarcraft extends CardImpl {
super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{2}{R/W}{R/W}"); super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{2}{R/W}{R/W}");
// Cast Master Warcraft only before attackers are declared. // Cast Master Warcraft only before attackers are declared.
this.addAbility(new CastOnlyDuringPhaseStepSourceAbility(null, null, BeforeAttackersAreDeclaredCondition.instance, "Cast Master Warcraft only before attackers are declared")); this.addAbility(new CastOnlyDuringPhaseStepSourceAbility(null, null, BeforeAttackersAreDeclaredCondition.instance, "Cast {this} only before attackers are declared"));
// You choose which creatures attack this turn. // You choose which creatures attack this turn.
this.getSpellAbility().addEffect(new MasterWarcraftChooseAttackersEffect()); this.getSpellAbility().addEffect(new MasterWarcraftChooseAttackersEffect());
@ -79,6 +80,8 @@ public class MasterWarcraft extends CardImpl {
// (only the last resolved Master Warcraft spell's effects apply) // (only the last resolved Master Warcraft spell's effects apply)
this.getSpellAbility().addWatcher(new MasterWarcraftCastWatcher()); this.getSpellAbility().addWatcher(new MasterWarcraftCastWatcher());
this.getSpellAbility().addEffect(new MasterWarcraftCastWatcherIncrementEffect()); this.getSpellAbility().addEffect(new MasterWarcraftCastWatcherIncrementEffect());
this.getSpellAbility().addWatcher(new ChooseBlockersRedundancyWatcher());
this.getSpellAbility().addEffect(new ChooseBlockersRedundancyWatcherIncrementEffect());
} }
public MasterWarcraft(final MasterWarcraft card) { public MasterWarcraft(final MasterWarcraft card) {
@ -89,6 +92,58 @@ public class MasterWarcraft extends CardImpl {
public MasterWarcraft copy() { public MasterWarcraft copy() {
return new MasterWarcraft(this); return new MasterWarcraft(this);
} }
private class MasterWarcraftCastWatcherIncrementEffect extends OneShotEffect {
MasterWarcraftCastWatcherIncrementEffect() {
super(Outcome.Neutral);
}
MasterWarcraftCastWatcherIncrementEffect(final MasterWarcraftCastWatcherIncrementEffect effect) {
super(effect);
}
@Override
public boolean apply(Game game, Ability source) {
MasterWarcraftCastWatcher watcher = (MasterWarcraftCastWatcher) game.getState().getWatchers().get(MasterWarcraftCastWatcher.class.getSimpleName());
if (watcher != null) {
watcher.increment();
return true;
}
return false;
}
@Override
public MasterWarcraftCastWatcherIncrementEffect copy() {
return new MasterWarcraftCastWatcherIncrementEffect(this);
}
}
private class ChooseBlockersRedundancyWatcherIncrementEffect extends OneShotEffect {
ChooseBlockersRedundancyWatcherIncrementEffect() {
super(Outcome.Neutral);
}
ChooseBlockersRedundancyWatcherIncrementEffect(final ChooseBlockersRedundancyWatcherIncrementEffect effect) {
super(effect);
}
@Override
public boolean apply(Game game, Ability source) {
ChooseBlockersRedundancyWatcher watcher = (ChooseBlockersRedundancyWatcher) game.getState().getWatchers().get(ChooseBlockersRedundancyWatcher.class.getSimpleName());
if (watcher != null) {
watcher.increment();
return true;
}
return false;
}
@Override
public ChooseBlockersRedundancyWatcherIncrementEffect copy() {
return new ChooseBlockersRedundancyWatcherIncrementEffect(this);
}
}
} }
class MasterWarcraftChooseAttackersEffect extends ContinuousRuleModifyingEffectImpl { class MasterWarcraftChooseAttackersEffect extends ContinuousRuleModifyingEffectImpl {
@ -197,7 +252,7 @@ class MasterWarcraftChooseBlockersEffect extends ContinuousRuleModifyingEffectIm
@Override @Override
public boolean applies(GameEvent event, Ability source, Game game) { public boolean applies(GameEvent event, Ability source, Game game) {
MasterWarcraftCastWatcher watcher = (MasterWarcraftCastWatcher) game.getState().getWatchers().get(MasterWarcraftCastWatcher.class.getSimpleName()); ChooseBlockersRedundancyWatcher watcher = (ChooseBlockersRedundancyWatcher) game.getState().getWatchers().get(ChooseBlockersRedundancyWatcher.class.getSimpleName());
watcher.decrement(); watcher.decrement();
if (watcher.copyCountApply > 0) { if (watcher.copyCountApply > 0) {
game.informPlayers(source.getSourceObject(game).getIdName() + " didn't apply"); game.informPlayers(source.getSourceObject(game).getIdName() + " didn't apply");
@ -254,29 +309,3 @@ class MasterWarcraftCastWatcher extends Watcher {
} }
} }
} }
class MasterWarcraftCastWatcherIncrementEffect extends OneShotEffect {
MasterWarcraftCastWatcherIncrementEffect() {
super(Outcome.Neutral);
}
MasterWarcraftCastWatcherIncrementEffect(final MasterWarcraftCastWatcherIncrementEffect effect) {
super(effect);
}
@Override
public boolean apply(Game game, Ability source) {
MasterWarcraftCastWatcher watcher = (MasterWarcraftCastWatcher) game.getState().getWatchers().get(MasterWarcraftCastWatcher.class.getSimpleName());
if (watcher != null) {
watcher.increment();
return true;
}
return false;
}
@Override
public MasterWarcraftCastWatcherIncrementEffect copy() {
return new MasterWarcraftCastWatcherIncrementEffect(this);
}
}

View file

@ -0,0 +1,204 @@
/*
* 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 mage.cards.m;
import java.util.UUID;
import mage.abilities.Ability;
import mage.abilities.DelayedTriggeredAbility;
import mage.abilities.common.CastOnlyDuringPhaseStepSourceAbility;
import mage.abilities.condition.CompoundCondition;
import mage.abilities.condition.Condition;
import mage.abilities.condition.common.BeforeBlockersAreDeclaredCondition;
import mage.abilities.condition.common.IsPhaseCondition;
import mage.abilities.condition.common.MyTurnCondition;
import mage.abilities.effects.ContinuousRuleModifyingEffectImpl;
import mage.abilities.effects.OneShotEffect;
import mage.abilities.effects.common.CreateDelayedTriggeredAbilityEffect;
import mage.abilities.effects.common.RemoveFromCombatTargetEffect;
import mage.abilities.effects.common.UntapTargetEffect;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.*;
import mage.game.Game;
import mage.game.combat.CombatGroup;
import mage.game.events.GameEvent;
import mage.game.events.GameEvent.EventType;
import mage.game.permanent.Permanent;
import mage.players.Player;
import mage.target.targetpointer.FixedTarget;
import mage.watchers.Watcher;
import mage.watchers.common.ChooseBlockersRedundancyWatcher;
/**
*
* @author L_J
*/
public class Melee extends CardImpl {
public Melee(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{4}{R}");
// Cast Melee only during your turn and only during combat before blockers are declared.
Condition condition = new CompoundCondition(BeforeBlockersAreDeclaredCondition.instance,
new IsPhaseCondition(TurnPhase.COMBAT),
MyTurnCondition.instance);
this.addAbility(new CastOnlyDuringPhaseStepSourceAbility(null, null, condition, "Cast {this} only during your turn and only during combat before blockers are declared"));
// You choose which creatures block this combat and how those creatures block.
// (only the last resolved Melee spell's blocking effect applies)
this.getSpellAbility().addEffect(new MeleeChooseBlockersEffect());
this.getSpellAbility().addWatcher(new ChooseBlockersRedundancyWatcher());
this.getSpellAbility().addEffect(new ChooseBlockersRedundancyWatcherIncrementEffect());
// Whenever a creature attacks and isn't blocked this combat, untap it and remove it from combat.
this.getSpellAbility().addEffect(new CreateDelayedTriggeredAbilityEffect(new MeleeTriggeredAbility()));
}
public Melee(final Melee card) {
super(card);
}
@Override
public Melee copy() {
return new Melee(this);
}
private class ChooseBlockersRedundancyWatcherIncrementEffect extends OneShotEffect {
ChooseBlockersRedundancyWatcherIncrementEffect() {
super(Outcome.Neutral);
}
ChooseBlockersRedundancyWatcherIncrementEffect(final ChooseBlockersRedundancyWatcherIncrementEffect effect) {
super(effect);
}
@Override
public boolean apply(Game game, Ability source) {
ChooseBlockersRedundancyWatcher watcher = (ChooseBlockersRedundancyWatcher) game.getState().getWatchers().get(ChooseBlockersRedundancyWatcher.class.getSimpleName());
if (watcher != null) {
watcher.increment();
return true;
}
return false;
}
@Override
public ChooseBlockersRedundancyWatcherIncrementEffect copy() {
return new ChooseBlockersRedundancyWatcherIncrementEffect(this);
}
}
}
class MeleeChooseBlockersEffect extends ContinuousRuleModifyingEffectImpl {
public MeleeChooseBlockersEffect() {
super(Duration.EndOfCombat, Outcome.Benefit, false, false);
staticText = "You choose which creatures block this combat and how those creatures block";
}
public MeleeChooseBlockersEffect(final MeleeChooseBlockersEffect effect) {
super(effect);
}
@Override
public MeleeChooseBlockersEffect copy() {
return new MeleeChooseBlockersEffect(this);
}
@Override
public boolean apply(Game game, Ability source) {
return false;
}
@Override
public boolean checksEventType(GameEvent event, Game game) {
return event.getType() == GameEvent.EventType.DECLARING_BLOCKERS;
}
@Override
public boolean applies(GameEvent event, Ability source, Game game) {
ChooseBlockersRedundancyWatcher watcher = (ChooseBlockersRedundancyWatcher) game.getState().getWatchers().get(ChooseBlockersRedundancyWatcher.class.getSimpleName());
watcher.decrement();
watcher.copyCount--;
if (watcher.copyCountApply > 0) {
game.informPlayers(source.getSourceObject(game).getIdName() + " didn't apply");
this.discard();
return false;
}
watcher.copyCountApply = watcher.copyCount;
Player blockController = game.getPlayer(source.getControllerId());
if (blockController != null) {
game.getCombat().selectBlockers(blockController, game);
return true;
}
this.discard();
return false;
}
}
class MeleeTriggeredAbility extends DelayedTriggeredAbility {
public MeleeTriggeredAbility() {
super(new UntapTargetEffect(), Duration.EndOfCombat, false);
this.addEffect(new RemoveFromCombatTargetEffect());
}
public MeleeTriggeredAbility(MeleeTriggeredAbility ability) {
super(ability);
}
@Override
public boolean checkEventType(GameEvent event, Game game) {
return event.getType() == GameEvent.EventType.UNBLOCKED_ATTACKER;
}
@Override
public boolean checkTrigger(GameEvent event, Game game) {
Permanent permanent = game.getPermanent(event.getTargetId());
if (permanent != null) {
for (CombatGroup combatGroup : game.getCombat().getGroups()) {
if (combatGroup.getBlockers().isEmpty() && combatGroup.getAttackers().contains(event.getTargetId())) {
this.getEffects().setTargetPointer(new FixedTarget(permanent, game));
return true;
}
}
}
return false;
}
@Override
public MeleeTriggeredAbility copy() {
return new MeleeTriggeredAbility(this);
}
@Override
public String getRule() {
return "Whenever a creature attacks and isn't blocked this combat, untap it and remove it from combat.";
}
}

View file

@ -0,0 +1,95 @@
/*
* 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 mage.cards.m;
import java.util.List;
import java.util.UUID;
import mage.abilities.Ability;
import mage.abilities.effects.OneShotEffect;
import mage.cards.*;
import mage.constants.CardType;
import mage.constants.Outcome;
import mage.filter.FilterCard;
import mage.game.Game;
import mage.players.Player;
import mage.target.common.TargetCardInOpponentsGraveyard;
/**
*
* @author L_J
*/
public class Misinformation extends CardImpl {
public Misinformation(UUID ownerId, CardSetInfo setInfo) {
super(ownerId,setInfo,new CardType[]{CardType.INSTANT},"{B}");
// Put up to three target cards from an opponent's graveyard on top of his or her library in any order.
this.getSpellAbility().addTarget(new TargetCardInOpponentsGraveyard(0, 3, new FilterCard("cards from an opponent's graveyard"), true));
this.getSpellAbility().addEffect(new MisinformationEffect());
}
public Misinformation(final Misinformation card) {
super(card);
}
@Override
public Misinformation copy() {
return new Misinformation(this);
}
}
class MisinformationEffect extends OneShotEffect {
MisinformationEffect() {
super(Outcome.Detriment);
this.staticText = "Put up to three target cards from an opponent's graveyard on top of his or her library in any order";
}
MisinformationEffect(final MisinformationEffect effect) {
super(effect);
}
@Override
public MisinformationEffect copy() {
return new MisinformationEffect(this);
}
@Override
public boolean apply(Game game, Ability source) {
Player controller = game.getPlayer(source.getControllerId());
if (controller != null) {
List<UUID> targets = this.getTargetPointer().getTargets(game, source);
if (targets != null) {
Cards cards = new CardsImpl(targets);
controller.putCardsOnTopOfLibrary(cards, game, source, true);
return true;
}
}
return false;
}
}

View file

@ -35,6 +35,7 @@ import mage.abilities.Ability;
import mage.abilities.SpellAbility; import mage.abilities.SpellAbility;
import mage.abilities.common.SimpleStaticAbility; import mage.abilities.common.SimpleStaticAbility;
import mage.abilities.effects.common.continuous.BoostAllEffect; import mage.abilities.effects.common.continuous.BoostAllEffect;
import mage.abilities.keyword.special.JohanVigilanceAbility;
import mage.cards.Card; import mage.cards.Card;
import mage.cards.CardImpl; import mage.cards.CardImpl;
import mage.cards.CardSetInfo; import mage.cards.CardSetInfo;
@ -91,7 +92,7 @@ class NoAbilityPredicate implements Predicate<MageObject> {
} }
if (isFaceDown) { if (isFaceDown) {
for (Ability ability : abilities) { for (Ability ability : abilities) {
if (!ability.getSourceId().equals(input.getId())) { if (!ability.getSourceId().equals(input.getId()) && !ability.getClass().equals(JohanVigilanceAbility.class)) {
return false; return false;
} }
} }
@ -99,8 +100,7 @@ class NoAbilityPredicate implements Predicate<MageObject> {
} }
for (Ability ability : abilities) { for (Ability ability : abilities) {
if (!Objects.equals(ability.getClass(), SpellAbility.class)) { if (!Objects.equals(ability.getClass(), SpellAbility.class) && !ability.getClass().equals(JohanVigilanceAbility.class)) {
return false; return false;
} }
} }

View file

@ -42,8 +42,7 @@ import mage.constants.SubType;
import mage.constants.SuperType; import mage.constants.SuperType;
import mage.constants.Zone; import mage.constants.Zone;
import mage.filter.FilterCard; import mage.filter.FilterCard;
import mage.filter.common.FilterCreaturePermanent; import mage.filter.StaticFilters;
import mage.filter.common.FilterLandPermanent;
import mage.filter.predicate.Predicates; import mage.filter.predicate.Predicates;
import mage.filter.predicate.mageobject.CardTypePredicate; import mage.filter.predicate.mageobject.CardTypePredicate;
import mage.target.common.TargetCreaturePermanent; import mage.target.common.TargetCreaturePermanent;
@ -55,6 +54,15 @@ import mage.target.common.TargetLandPermanent;
*/ */
public class NissaGenesisMage extends CardImpl { public class NissaGenesisMage extends CardImpl {
private static final FilterCard filter = new FilterCard("any number of creature and/or land cards");
static {
filter.add(Predicates.or(
new CardTypePredicate(CardType.CREATURE),
new CardTypePredicate(CardType.LAND)
));
}
public NissaGenesisMage(UUID ownerId, CardSetInfo setInfo) { public NissaGenesisMage(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.PLANESWALKER}, "{5}{G}{G}"); super(ownerId, setInfo, new CardType[]{CardType.PLANESWALKER}, "{5}{G}{G}");
this.addSuperType(SuperType.LEGENDARY); this.addSuperType(SuperType.LEGENDARY);
@ -64,8 +72,8 @@ public class NissaGenesisMage extends CardImpl {
//+2: Untap up to two target creatures and up to two target lands. //+2: Untap up to two target creatures and up to two target lands.
Ability ability = new LoyaltyAbility(new UntapTargetEffect(false).setText("Untap up to two target creatures and up to two target lands"), +2); Ability ability = new LoyaltyAbility(new UntapTargetEffect(false).setText("Untap up to two target creatures and up to two target lands"), +2);
ability.addTarget(new TargetCreaturePermanent(0, 2, new FilterCreaturePermanent("target creatures"), false)); ability.addTarget(new TargetCreaturePermanent(0, 2, StaticFilters.FILTER_PERMANENT_CREATURES, false));
ability.addTarget(new TargetLandPermanent(0, 2, new FilterLandPermanent("target land"), false)); ability.addTarget(new TargetLandPermanent(0, 2, StaticFilters.FILTER_LANDS, false));
this.addAbility(ability); this.addAbility(ability);
//-3: Target creature gets +5/+5 until end of turn. //-3: Target creature gets +5/+5 until end of turn.
@ -74,10 +82,8 @@ public class NissaGenesisMage extends CardImpl {
this.addAbility(ability); this.addAbility(ability);
//-10: Look at the top ten cards of your library. You may put any number of creature and/or land cards from among them onto the battlefield. Put the rest on the bottom of your library in a random order.); //-10: Look at the top ten cards of your library. You may put any number of creature and/or land cards from among them onto the battlefield. Put the rest on the bottom of your library in a random order.);
FilterCard filter = new FilterCard("creature and/or land cards");
filter.add(Predicates.or(new CardTypePredicate(CardType.CREATURE), new CardTypePredicate(CardType.LAND)));
this.addAbility(new LoyaltyAbility( this.addAbility(new LoyaltyAbility(
new LookLibraryAndPickControllerEffect(10, 10, filter, false, false, Zone.BATTLEFIELD, true).setBackInRandomOrder(true), new LookLibraryAndPickControllerEffect(10, 10, filter, false, true, Zone.BATTLEFIELD, false).setBackInRandomOrder(true),
-10)); -10));
} }

View file

@ -0,0 +1,129 @@
/*
* 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 mage.cards.n;
import java.util.UUID;
import mage.MageObject;
import mage.abilities.Ability;
import mage.abilities.common.SimpleActivatedAbility;
import mage.abilities.costs.common.TapSourceCost;
import mage.abilities.costs.mana.GenericManaCost;
import mage.abilities.effects.RedirectionEffect;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
import mage.constants.Duration;
import mage.constants.Outcome;
import mage.constants.Zone;
import mage.filter.common.FilterCreaturePermanent;
import mage.game.Game;
import mage.game.events.GameEvent;
import mage.game.permanent.Permanent;
import mage.game.stack.Spell;
import mage.players.Player;
import mage.target.TargetSource;
import mage.target.common.TargetOpponentsChoicePermanent;
/**
*
* @author L_J
*/
public class NovaPentacle extends CardImpl {
public NovaPentacle(UUID ownerId, CardSetInfo setInfo) {
super(ownerId,setInfo,new CardType[]{CardType.ARTIFACT},"{4}");
// {3}, {tap}: The next time a source of your choice would deal damage to you this turn, that damage is dealt to target creature of an opponent's choice instead
Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new NovaPentacleEffect(), new GenericManaCost(3));
ability.addCost(new TapSourceCost());
ability.addTarget(new TargetOpponentsChoicePermanent(1, 1, new FilterCreaturePermanent(), false, true));
this.addAbility(ability);
}
public NovaPentacle(final NovaPentacle card) {
super(card);
}
@Override
public NovaPentacle copy() {
return new NovaPentacle(this);
}
}
class NovaPentacleEffect extends RedirectionEffect {
private final TargetSource damageSource;
public NovaPentacleEffect() {
super(Duration.EndOfTurn, Integer.MAX_VALUE, true);
staticText = "The next time a source of your choice would deal damage to you this turn, that damage is dealt to target creature of an opponent's choice instead";
this.damageSource = new TargetSource();
}
public NovaPentacleEffect(final NovaPentacleEffect effect) {
super(effect);
this.damageSource = effect.damageSource.copy();
}
@Override
public NovaPentacleEffect copy() {
return new NovaPentacleEffect(this);
}
@Override
public void init(Ability source, Game game) {
this.damageSource.choose(Outcome.PreventDamage, source.getControllerId(), source.getSourceId(), game);
super.init(source, game);
}
@Override
public boolean applies(GameEvent event, Ability source, Game game) {
// check source
MageObject object = game.getObject(event.getSourceId());
if (object == null) {
game.informPlayers("Couldn't find source of damage");
return false;
}
if (!object.getId().equals(damageSource.getFirstTarget())
&& (!(object instanceof Spell) || !((Spell) object).getSourceId().equals(damageSource.getFirstTarget()))) {
return false;
}
this.redirectTarget = source.getTargets().get(0);
// check player
Player player = game.getPlayer(event.getTargetId());
if (player != null) {
if (player.getId().equals(source.getControllerId())) {
return true;
}
}
return false;
}
}

View file

@ -31,7 +31,8 @@ import java.util.UUID;
import mage.MageInt; import mage.MageInt;
import mage.abilities.Ability; import mage.abilities.Ability;
import mage.abilities.TriggeredAbilityImpl; import mage.abilities.TriggeredAbilityImpl;
import mage.abilities.effects.ReplacementEffectImpl; import mage.abilities.effects.ContinuousRuleModifyingEffectImpl;
import mage.abilities.effects.OneShotEffect;
import mage.abilities.keyword.FirstStrikeAbility; import mage.abilities.keyword.FirstStrikeAbility;
import mage.cards.CardImpl; import mage.cards.CardImpl;
import mage.cards.CardSetInfo; import mage.cards.CardSetInfo;
@ -40,6 +41,7 @@ import mage.game.Game;
import mage.game.events.GameEvent; import mage.game.events.GameEvent;
import mage.game.events.GameEvent.EventType; import mage.game.events.GameEvent.EventType;
import mage.players.Player; import mage.players.Player;
import mage.watchers.common.ChooseBlockersRedundancyWatcher;
/** /**
* @author noxx * @author noxx
@ -75,7 +77,9 @@ public class OdricMasterTactician extends CardImpl {
class OdricMasterTacticianTriggeredAbility extends TriggeredAbilityImpl { class OdricMasterTacticianTriggeredAbility extends TriggeredAbilityImpl {
public OdricMasterTacticianTriggeredAbility() { public OdricMasterTacticianTriggeredAbility() {
super(Zone.BATTLEFIELD, new OdricMasterTacticianEffect()); super(Zone.BATTLEFIELD, new OdricMasterTacticianChooseBlockersEffect());
this.addWatcher(new ChooseBlockersRedundancyWatcher());
this.addEffect(new ChooseBlockersRedundancyWatcherIncrementEffect());
} }
public OdricMasterTacticianTriggeredAbility(final OdricMasterTacticianTriggeredAbility ability) { public OdricMasterTacticianTriggeredAbility(final OdricMasterTacticianTriggeredAbility ability) {
@ -89,52 +93,55 @@ class OdricMasterTacticianTriggeredAbility extends TriggeredAbilityImpl {
@Override @Override
public boolean checkEventType(GameEvent event, Game game) { public boolean checkEventType(GameEvent event, Game game) {
return event.getType() == EventType.DECLARED_ATTACKERS; return event.getType() == GameEvent.EventType.DECLARED_ATTACKERS;
} }
@Override @Override
public boolean checkTrigger(GameEvent event, Game game) { public boolean checkTrigger(GameEvent event, Game game) {
resetEffect(); return game.getCombat().getAttackers().size() >= 4 && game.getCombat().getAttackers().contains(this.sourceId);
if (game.getCombat().getAttackers().size() >= 4 && game.getCombat().getAttackers().contains(this.sourceId)) { }
enableEffect();
return true; private class ChooseBlockersRedundancyWatcherIncrementEffect extends OneShotEffect {
ChooseBlockersRedundancyWatcherIncrementEffect() {
super(Outcome.Neutral);
}
ChooseBlockersRedundancyWatcherIncrementEffect(final ChooseBlockersRedundancyWatcherIncrementEffect effect) {
super(effect);
}
@Override
public boolean apply(Game game, Ability source) {
ChooseBlockersRedundancyWatcher watcher = (ChooseBlockersRedundancyWatcher) game.getState().getWatchers().get(ChooseBlockersRedundancyWatcher.class.getSimpleName());
if (watcher != null) {
watcher.increment();
return true;
}
return false;
}
@Override
public ChooseBlockersRedundancyWatcherIncrementEffect copy() {
return new ChooseBlockersRedundancyWatcherIncrementEffect(this);
} }
return false;
} }
@Override
public void reset(Game game) {
resetEffect();
}
private void resetEffect() {
getEffects().get(0).setValue("apply_" + sourceId, false);
}
private void enableEffect() {
getEffects().get(0).setValue("apply_" + sourceId, true);
}
@Override
public String getRule() {
return "Whenever {this} and at least three other creatures attack, you choose which creatures block this combat and how those creatures block.";
}
} }
class OdricMasterTacticianEffect extends ReplacementEffectImpl { class OdricMasterTacticianChooseBlockersEffect extends ContinuousRuleModifyingEffectImpl {
public OdricMasterTacticianEffect() { public OdricMasterTacticianChooseBlockersEffect() {
super(Duration.EndOfCombat, Outcome.Benefit); super(Duration.EndOfCombat, Outcome.Benefit, false, false);
staticText = "Whenever {this} and at least three other creatures attack, you choose which creatures block this combat and how those creatures block";
} }
public OdricMasterTacticianEffect(final OdricMasterTacticianEffect effect) { public OdricMasterTacticianChooseBlockersEffect(final OdricMasterTacticianChooseBlockersEffect effect) {
super(effect); super(effect);
} }
@Override @Override
public OdricMasterTacticianEffect copy() { public OdricMasterTacticianChooseBlockersEffect copy() {
return new OdricMasterTacticianEffect(this); return new OdricMasterTacticianChooseBlockersEffect(this);
} }
@Override @Override
@ -142,16 +149,6 @@ class OdricMasterTacticianEffect extends ReplacementEffectImpl {
return false; return false;
} }
@Override
public boolean replaceEvent(GameEvent event, Ability source, Game game) {
Player blockController = game.getPlayer(source.getControllerId());
if (blockController != null) {
game.getCombat().selectBlockers(blockController, game);
return true;
}
return false;
}
@Override @Override
public boolean checksEventType(GameEvent event, Game game) { public boolean checksEventType(GameEvent event, Game game) {
return event.getType() == GameEvent.EventType.DECLARING_BLOCKERS; return event.getType() == GameEvent.EventType.DECLARING_BLOCKERS;
@ -159,12 +156,21 @@ class OdricMasterTacticianEffect extends ReplacementEffectImpl {
@Override @Override
public boolean applies(GameEvent event, Ability source, Game game) { public boolean applies(GameEvent event, Ability source, Game game) {
Object object = getValue("apply_" + source.getSourceId()); ChooseBlockersRedundancyWatcher watcher = (ChooseBlockersRedundancyWatcher) game.getState().getWatchers().get(ChooseBlockersRedundancyWatcher.class.getSimpleName());
if (object != null && object instanceof Boolean) { watcher.decrement();
if ((Boolean)object) { watcher.copyCount--;
return true; // replace event if (watcher.copyCountApply > 0) {
} game.informPlayers(source.getSourceObject(game).getIdName() + " didn't apply");
this.discard();
return false;
} }
watcher.copyCountApply = watcher.copyCount;
Player blockController = game.getPlayer(source.getControllerId());
if (blockController != null) {
game.getCombat().selectBlockers(blockController, game);
return true;
}
this.discard();
return false; return false;
} }
} }

View file

@ -0,0 +1,130 @@
/*
* 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 mage.cards.p;
import java.util.UUID;
import mage.MageInt;
import mage.MageObject;
import mage.abilities.Ability;
import mage.abilities.common.SimpleActivatedAbility;
import mage.abilities.costs.common.TapSourceCost;
import mage.abilities.effects.OneShotEffect;
import mage.cards.*;
import mage.cards.repository.CardRepository;
import mage.choices.Choice;
import mage.choices.ChoiceImpl;
import mage.constants.CardType;
import mage.constants.Outcome;
import mage.constants.SubType;
import mage.constants.Zone;
import mage.game.Game;
import mage.players.Player;
import mage.target.TargetPlayer;
/**
*
* @author BetaSteward_at_googlemail.com & L_J
*/
public class PetraSphinx extends CardImpl {
public PetraSphinx(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{W}{W}{W}");
this.subtype.add(SubType.SPHINX);
this.power = new MageInt(3);
this.toughness = new MageInt(4);
// {tap}: Target player chooses a card name, then reveals the top card of his or her library. If that card has the chosen name, that player puts it into his or her hand. If it doesn't, the player puts it into his or her graveyard.
Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new PetraSphinxEffect(), new TapSourceCost());
ability.addTarget(new TargetPlayer());
this.addAbility(ability);
}
public PetraSphinx(final PetraSphinx card) {
super(card);
}
@Override
public PetraSphinx copy() {
return new PetraSphinx(this);
}
}
class PetraSphinxEffect extends OneShotEffect {
public PetraSphinxEffect() {
super(Outcome.DrawCard);
staticText = "Target player chooses a card name, then reveals the top card of his or her library. If that card has the chosen name, that player puts it into his or her hand. If it doesn't, the player puts it into his or her graveyard";
}
public PetraSphinxEffect(final PetraSphinxEffect effect) {
super(effect);
}
@Override
public boolean apply(Game game, Ability source) {
MageObject sourceObject = source.getSourceObject(game);
Player controller = game.getPlayer(source.getControllerId());
Player player = game.getPlayer(targetPointer.getFirst(game, source));
if (controller != null && sourceObject != null && player != null) {
if (player.getLibrary().hasCards()) {
Choice cardChoice = new ChoiceImpl();
cardChoice.setChoices(CardRepository.instance.getNames());
cardChoice.setMessage("Name a card");
while (!player.choose(Outcome.DrawCard, cardChoice, game)) {
if (!player.canRespond()) {
return false;
}
}
String cardName = cardChoice.getChoice();
game.informPlayers(sourceObject.getLogName() + ", player: " + player.getLogName() + ", named: [" + cardName + ']');
Card card = player.getLibrary().removeFromTop(game);
if (card != null) {
Cards cards = new CardsImpl(card);
player.revealCards(sourceObject.getIdName(), cards, game);
if (card.getName().equals(cardName)) {
player.moveCards(cards, Zone.HAND, source, game);
} else {
player.moveCards(cards, Zone.GRAVEYARD, source, game);
}
}
}
return true;
}
return false;
}
@Override
public PetraSphinxEffect copy() {
return new PetraSphinxEffect(this);
}
}

View file

@ -0,0 +1,129 @@
/*
* 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 mage.cards.p;
import java.util.UUID;
import mage.MageObject;
import mage.ObjectColor;
import mage.constants.SubType;
import mage.target.common.TargetCreaturePermanent;
import mage.abilities.Ability;
import mage.abilities.common.AsEntersBattlefieldAbility;
import mage.abilities.common.SimpleStaticAbility;
import mage.abilities.effects.PreventionEffectImpl;
import mage.abilities.effects.common.AttachEffect;
import mage.abilities.effects.common.ChooseColorEffect;
import mage.constants.Outcome;
import mage.target.TargetPermanent;
import mage.abilities.keyword.EnchantAbility;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
import mage.constants.Duration;
import mage.constants.Zone;
import mage.game.Game;
import mage.game.events.GameEvent;
import mage.game.permanent.Permanent;
/**
*
* @author TheElk801
*/
public class PrismaticWard extends CardImpl {
public PrismaticWard(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{1}{W}");
this.subtype.add(SubType.AURA);
// Enchant creature
TargetPermanent auraTarget = new TargetCreaturePermanent();
this.getSpellAbility().addTarget(auraTarget);
this.getSpellAbility().addEffect(new AttachEffect(Outcome.BoostCreature));
Ability ability = new EnchantAbility(auraTarget.getTargetName());
this.addAbility(ability);
// As Prismatic Ward enters the battlefield, choose a color.
this.addAbility(new AsEntersBattlefieldAbility(new ChooseColorEffect(Outcome.Benefit)));
// Prevent all damage that would be dealt to enchanted creature by sources of the chosen color.
this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new PrismaticWardPreventDamageEffect()));
}
public PrismaticWard(final PrismaticWard card) {
super(card);
}
@Override
public PrismaticWard copy() {
return new PrismaticWard(this);
}
}
class PrismaticWardPreventDamageEffect extends PreventionEffectImpl {
public PrismaticWardPreventDamageEffect() {
super(Duration.WhileOnBattlefield, Integer.MAX_VALUE, false);
staticText = "Prevent all damage that would be dealt to enchanted creature by sources of the chosen color.";
}
public PrismaticWardPreventDamageEffect(final PrismaticWardPreventDamageEffect effect) {
super(effect);
}
@Override
public PrismaticWardPreventDamageEffect copy() {
return new PrismaticWardPreventDamageEffect(this);
}
@Override
public boolean applies(GameEvent event, Ability source, Game game) {
if (!super.applies(event, source, game)) {
return false;
}
Permanent permanent = game.getPermanent(source.getSourceId());
if (permanent == null) {
return false;
}
ObjectColor color = (ObjectColor) game.getState().getValue(permanent.getId() + "_color");
if (color == null) {
return false;
}
MageObject sourceObject = game.getObject(event.getSourceId());
if (sourceObject == null || !sourceObject.getColor(game).shares(color)) {
return false;
}
Permanent attachment = game.getPermanent(source.getSourceId());
if (attachment != null
&& attachment.getAttachedTo() != null
&& event.getTargetId().equals(attachment.getAttachedTo())) {
return true;
}
return false;
}
}

View file

@ -0,0 +1,143 @@
/*
* 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 mage.cards.s;
import java.util.List;
import java.util.UUID;
import mage.ObjectColor;
import mage.abilities.Ability;
import mage.abilities.common.SimpleActivatedAbility;
import mage.abilities.costs.mana.ManaCostsImpl;
import mage.abilities.effects.ContinuousEffectImpl;
import mage.abilities.effects.common.continuous.BoostSourceEffect;
import mage.abilities.effects.common.continuous.GainAbilityControlledEffect;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
import mage.constants.Duration;
import mage.constants.Layer;
import mage.constants.Outcome;
import mage.constants.SubLayer;
import mage.constants.SubType;
import mage.constants.Zone;
import mage.filter.StaticFilters;
import mage.game.Game;
import mage.game.permanent.Permanent;
import mage.util.SubTypeList;
/**
*
* @author TheElk801
*/
public class ShadesBreath extends CardImpl {
public ShadesBreath(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{1}{B}");
// Until end of turn, each creature you control becomes a black Shade and gains "{B}: This creature gets +1/+1 until end of turn."
this.getSpellAbility().addEffect(new ShadesBreathSetColorEffect());
this.getSpellAbility().addEffect(new ShadesBreathSetSubtypeEffect());
this.getSpellAbility().addEffect(
new GainAbilityControlledEffect(new SimpleActivatedAbility(
Zone.BATTLEFIELD,
new BoostSourceEffect(1, 1, Duration.EndOfTurn).setText("this creature gets +1/+1 until end of turn"),
new ManaCostsImpl("{B}")
), Duration.EndOfTurn, StaticFilters.FILTER_CONTROLLED_A_CREATURE)
.setText("and gains \"{B}: This creature gets +1/+1 until end of turn.\"")
);
}
public ShadesBreath(final ShadesBreath card) {
super(card);
}
@Override
public ShadesBreath copy() {
return new ShadesBreath(this);
}
}
class ShadesBreathSetColorEffect extends ContinuousEffectImpl {
public ShadesBreathSetColorEffect() {
super(Duration.EndOfTurn, Layer.ColorChangingEffects_5, SubLayer.NA, Outcome.Benefit);
staticText = "Until end of turn, each creature you control becomes a black";
}
public ShadesBreathSetColorEffect(final ShadesBreathSetColorEffect effect) {
super(effect);
}
@Override
public boolean apply(Game game, Ability source) {
List<Permanent> permanents = game.getBattlefield().getAllActivePermanents(StaticFilters.FILTER_PERMANENT_CREATURE, source.getControllerId(), game);
for (Permanent permanent : permanents) {
if (permanent != null) {
permanent.getColor(game).setColor(ObjectColor.BLACK);
}
}
return true;
}
@Override
public ShadesBreathSetColorEffect copy() {
return new ShadesBreathSetColorEffect(this);
}
}
class ShadesBreathSetSubtypeEffect extends ContinuousEffectImpl {
public ShadesBreathSetSubtypeEffect() {
super(Duration.EndOfTurn, Layer.TypeChangingEffects_4, SubLayer.NA, Outcome.Benefit);
staticText = "Shade";
}
public ShadesBreathSetSubtypeEffect(final ShadesBreathSetSubtypeEffect effect) {
super(effect);
}
@Override
public boolean apply(Game game, Ability source) {
List<Permanent> permanents = game.getBattlefield().getAllActivePermanents(StaticFilters.FILTER_PERMANENT_CREATURE, source.getControllerId(), game);
for (Permanent permanent : permanents) {
if (permanent != null) {
SubTypeList subtype = permanent.getSubtype(game);
if (subtype != null && subtype.size() != 1 || !subtype.contains(SubType.SHADE)) {
subtype.removeAll(SubType.getCreatureTypes(false));
subtype.add(SubType.SHADE);
}
}
}
return true;
}
@Override
public ShadesBreathSetSubtypeEffect copy() {
return new ShadesBreathSetSubtypeEffect(this);
}
}

View file

@ -0,0 +1,123 @@
/*
* 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 mage.cards.s;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
import mage.abilities.Ability;
import mage.abilities.effects.ContinuousEffect;
import mage.abilities.effects.OneShotEffect;
import mage.abilities.effects.common.DontUntapInControllersNextUntapStepTargetEffect;
import mage.abilities.effects.common.PreventAllDamageByAllPermanentsEffect;
import mage.abilities.effects.common.TapAllEffect;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
import mage.constants.Duration;
import mage.constants.Outcome;
import mage.filter.common.FilterCreaturePermanent;
import mage.filter.predicate.Predicates;
import mage.filter.predicate.permanent.AttackingPredicate;
import mage.filter.predicate.permanent.BlockingPredicate;
import mage.game.Game;
import mage.game.permanent.Permanent;
import mage.players.Player;
import mage.target.targetpointer.FixedTargets;
/**
*
* @author L_J
*/
public class SporeCloud extends CardImpl {
private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("blocking creatures");
static {
filter.add(new BlockingPredicate());
}
public SporeCloud(UUID ownerId, CardSetInfo setInfo) {
super(ownerId,setInfo,new CardType[]{CardType.INSTANT},"{1}{G}{G}");
// Tap all blocking creatures.
this.getSpellAbility().addEffect(new TapAllEffect(filter));
// Prevent all combat damage that would be dealt this turn.
this.getSpellAbility().addEffect(new PreventAllDamageByAllPermanentsEffect(Duration.EndOfTurn, true));
// Each attacking creature and each blocking creature doesn't untap during its controller's next untap step.
this.getSpellAbility().addEffect(new SporeCloudEffect());
}
public SporeCloud(final SporeCloud card) {
super(card);
}
@Override
public SporeCloud copy() {
return new SporeCloud(this);
}
}
class SporeCloudEffect extends OneShotEffect {
private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("Each attacking creature and each blocking creature");
static {
filter.add(Predicates.or(new AttackingPredicate(), new BlockingPredicate()));
}
public SporeCloudEffect() {
super(Outcome.Benefit);
this.staticText = "Each attacking creature and each blocking creature doesn't untap during its controller's next untap step";
}
public SporeCloudEffect(final SporeCloudEffect effect) {
super(effect);
}
@Override
public SporeCloudEffect copy() {
return new SporeCloudEffect(this);
}
@Override
public boolean apply(Game game, Ability source) {
Player controller = game.getPlayer(source.getControllerId());
if (controller != null) {
List<Permanent> doNotUntapNextUntapStep = new ArrayList<>();
for (Permanent permanent : game.getBattlefield().getActivePermanents(filter, source.getControllerId(), source.getSourceId(), game)) {
doNotUntapNextUntapStep.add(permanent);
}
if (!doNotUntapNextUntapStep.isEmpty()) {
ContinuousEffect effect = new DontUntapInControllersNextUntapStepTargetEffect("This creature");
effect.setTargetPointer(new FixedTargets(doNotUntapNextUntapStep, game));
game.addEffect(effect, source);
}
return true;
}
return false;
}
}

View file

@ -27,11 +27,14 @@
*/ */
package mage.cards.t; package mage.cards.t;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID; import java.util.UUID;
import mage.MageInt; import mage.MageInt;
import mage.abilities.Ability; import mage.abilities.Ability;
import mage.abilities.common.BeginningOfUpkeepTriggeredAbility; import mage.abilities.common.BeginningOfUpkeepTriggeredAbility;
import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.OneShotEffect;
import mage.abilities.effects.common.PhaseOutAllEffect;
import mage.abilities.keyword.PhasingAbility; import mage.abilities.keyword.PhasingAbility;
import mage.abilities.keyword.TrampleAbility; import mage.abilities.keyword.TrampleAbility;
import mage.cards.CardImpl; import mage.cards.CardImpl;
@ -41,6 +44,7 @@ import mage.constants.SubType;
import mage.constants.Outcome; import mage.constants.Outcome;
import mage.constants.SuperType; import mage.constants.SuperType;
import mage.constants.TargetController; import mage.constants.TargetController;
import mage.filter.StaticFilters;
import mage.filter.common.FilterControlledLandPermanent; import mage.filter.common.FilterControlledLandPermanent;
import mage.game.Game; import mage.game.Game;
import mage.game.permanent.Permanent; import mage.game.permanent.Permanent;
@ -53,7 +57,7 @@ import mage.players.Player;
public class Taniwha extends CardImpl { public class Taniwha extends CardImpl {
public Taniwha(UUID ownerId, CardSetInfo setInfo) { public Taniwha(UUID ownerId, CardSetInfo setInfo) {
super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{3}{U}{U}"); super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{U}{U}");
addSuperType(SuperType.LEGENDARY); addSuperType(SuperType.LEGENDARY);
this.subtype.add(SubType.SERPENT); this.subtype.add(SubType.SERPENT);
this.power = new MageInt(7); this.power = new MageInt(7);
@ -61,10 +65,10 @@ public class Taniwha extends CardImpl {
// Trample // Trample
this.addAbility(TrampleAbility.getInstance()); this.addAbility(TrampleAbility.getInstance());
// Phasing // Phasing
this.addAbility(PhasingAbility.getInstance()); this.addAbility(PhasingAbility.getInstance());
// At the beginning of your upkeep, all lands you control phase out. // At the beginning of your upkeep, all lands you control phase out.
this.addAbility(new BeginningOfUpkeepTriggeredAbility(new TaniwhaEffect(), TargetController.YOU, false)); this.addAbility(new BeginningOfUpkeepTriggeredAbility(new TaniwhaEffect(), TargetController.YOU, false));
} }
@ -99,10 +103,11 @@ class TaniwhaEffect extends OneShotEffect {
public boolean apply(Game game, Ability source) { public boolean apply(Game game, Ability source) {
Player controller = game.getPlayer(source.getControllerId()); Player controller = game.getPlayer(source.getControllerId());
if (controller != null) { if (controller != null) {
List<UUID> permIds = new ArrayList<>();
for (Permanent permanent : game.getBattlefield().getActivePermanents(new FilterControlledLandPermanent(), controller.getId(), game)) { for (Permanent permanent : game.getBattlefield().getActivePermanents(new FilterControlledLandPermanent(), controller.getId(), game)) {
permanent.phaseOut(game); permIds.add(permanent.getId());
} }
return true; return new PhaseOutAllEffect(permIds).apply(game, source);
} }
return false; return false;
} }

View file

@ -27,11 +27,14 @@
*/ */
package mage.cards.t; package mage.cards.t;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID; import java.util.UUID;
import mage.MageObject; import mage.MageObject;
import mage.abilities.Ability; import mage.abilities.Ability;
import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.OneShotEffect;
import mage.abilities.effects.common.ExileSpellEffect; import mage.abilities.effects.common.ExileSpellEffect;
import mage.abilities.effects.common.PhaseOutAllEffect;
import mage.abilities.effects.common.continuous.GainAbilityControllerEffect; import mage.abilities.effects.common.continuous.GainAbilityControllerEffect;
import mage.abilities.effects.common.continuous.LifeTotalCantChangeControllerEffect; import mage.abilities.effects.common.continuous.LifeTotalCantChangeControllerEffect;
import mage.abilities.keyword.ProtectionAbility; import mage.abilities.keyword.ProtectionAbility;
@ -170,10 +173,11 @@ class TeferisProtectionPhaseOutEffect extends OneShotEffect {
public boolean apply(Game game, Ability source) { public boolean apply(Game game, Ability source) {
Player controller = game.getPlayer(source.getControllerId()); Player controller = game.getPlayer(source.getControllerId());
if (controller != null) { if (controller != null) {
List<UUID> permIds = new ArrayList<>();
for (Permanent permanent : game.getBattlefield().getActivePermanents(StaticFilters.FILTER_CONTROLLED_PERMANENT, controller.getId(), game)) { for (Permanent permanent : game.getBattlefield().getActivePermanents(StaticFilters.FILTER_CONTROLLED_PERMANENT, controller.getId(), game)) {
permanent.phaseOut(game); permIds.add(permanent.getId());
} }
return true; return new PhaseOutAllEffect(permIds).apply(game, source);
} }
return false; return false;
} }

View file

@ -27,6 +27,7 @@
*/ */
package mage.cards.t; package mage.cards.t;
import java.util.ArrayList;
import mage.abilities.Ability; import mage.abilities.Ability;
import mage.abilities.common.BeginningOfUpkeepTriggeredAbility; import mage.abilities.common.BeginningOfUpkeepTriggeredAbility;
import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.OneShotEffect;
@ -45,8 +46,11 @@ import mage.game.permanent.Permanent;
import mage.players.Player; import mage.players.Player;
import java.util.HashSet; import java.util.HashSet;
import java.util.List;
import java.util.Set; import java.util.Set;
import java.util.UUID; import java.util.UUID;
import mage.abilities.effects.common.PhaseOutAllEffect;
import mage.filter.common.FilterControlledLandPermanent;
/** /**
* *
@ -55,7 +59,7 @@ import java.util.UUID;
public class TeferisRealm extends CardImpl { public class TeferisRealm extends CardImpl {
public TeferisRealm(UUID ownerId, CardSetInfo setInfo) { public TeferisRealm(UUID ownerId, CardSetInfo setInfo) {
super(ownerId,setInfo,new CardType[]{CardType.ENCHANTMENT},"{1}{U}{U}"); super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{1}{U}{U}");
addSuperType(SuperType.WORLD); addSuperType(SuperType.WORLD);
// At the beginning of each player's upkeep, that player chooses artifact, creature, land, or non-Aura enchantment. All nontoken permanents of that type phase out. // At the beginning of each player's upkeep, that player chooses artifact, creature, land, or non-Aura enchantment. All nontoken permanents of that type phase out.
@ -135,10 +139,11 @@ class TeferisRealmEffect extends OneShotEffect {
return false; return false;
} }
game.informPlayers(player.getLogName() + " chooses " + choosenType + "s to phase out"); game.informPlayers(player.getLogName() + " chooses " + choosenType + "s to phase out");
List<UUID> permIds = new ArrayList<>();
for (Permanent permanent : game.getBattlefield().getActivePermanents(filter, controller.getId(), game)) { for (Permanent permanent : game.getBattlefield().getActivePermanents(filter, controller.getId(), game)) {
permanent.phaseOut(game); permIds.add(permanent.getId());
} }
return true; return new PhaseOutAllEffect(permIds).apply(game, source);
} }
return false; return false;
} }

View file

@ -0,0 +1,64 @@
/*
* 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 mage.cards.t;
import java.util.UUID;
import mage.abilities.common.CastOnlyDuringPhaseStepSourceAbility;
import mage.abilities.effects.common.combat.CantBeBlockedTargetEffect;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
import mage.constants.PhaseStep;
import mage.target.common.TargetCreaturePermanent;
/**
*
* @author L_J
*/
public class Teleport extends CardImpl {
public Teleport(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{U}{U}{U}");
// Cast Teleport only during the declare attackers step.
this.addAbility(new CastOnlyDuringPhaseStepSourceAbility(null, PhaseStep.DECLARE_ATTACKERS, null, "Cast Teleport only during the declare attackers step"));
// Target creature can't be blocked this turn.
this.getSpellAbility().addEffect(new CantBeBlockedTargetEffect());
this.getSpellAbility().addTarget(new TargetCreaturePermanent());
}
public Teleport(final Teleport card) {
super(card);
}
@Override
public Teleport copy() {
return new Teleport(this);
}
}

View file

@ -0,0 +1,92 @@
/*
* 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 mage.cards.t;
import java.util.UUID;
import mage.MageInt;
import mage.abilities.Ability;
import mage.abilities.DelayedTriggeredAbility;
import mage.abilities.common.AttacksOrBlocksTriggeredAbility;
import mage.abilities.common.SimpleActivatedAbility;
import mage.abilities.common.delayed.AtTheEndOfCombatDelayedTriggeredAbility;
import mage.abilities.costs.common.TapSourceCost;
import mage.abilities.costs.mana.ManaCostsImpl;
import mage.abilities.effects.Effect;
import mage.abilities.effects.common.CreateDelayedTriggeredAbilityEffect;
import mage.abilities.effects.common.DamageControllerEffect;
import mage.abilities.effects.common.ReturnToHandTargetEffect;
import mage.abilities.effects.common.SacrificeSourceEffect;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
import mage.constants.SubType;
import mage.constants.Zone;
import mage.filter.FilterPermanent;
import mage.filter.predicate.Predicates;
import mage.filter.predicate.permanent.EnchantedPredicate;
import mage.target.TargetPermanent;
/**
*
* @author L_J
*/
public class TimeElemental extends CardImpl {
private static final FilterPermanent filter = new FilterPermanent("permanent that isn't enchanted");
static {
filter.add(Predicates.not(new EnchantedPredicate()));
}
public TimeElemental(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{U}");
this.subtype.add(SubType.ELEMENTAL);
this.power = new MageInt(0);
this.toughness = new MageInt(2);
// When Time Elemental attacks or blocks, at end of combat, sacrifice it and it deals 5 damage to you.
DelayedTriggeredAbility ability = new AtTheEndOfCombatDelayedTriggeredAbility(new SacrificeSourceEffect().setText("at end of combat, sacrifice it"));
ability.addEffect(new DamageControllerEffect(5).setText("and it deals 5 damage to you"));
this.addAbility(new AttacksOrBlocksTriggeredAbility(new CreateDelayedTriggeredAbilityEffect(ability, true), false));
// {2}{U}{U}, {tap}: Return target permanent that isn't enchanted to its owner's hand.
Ability ability2 = new SimpleActivatedAbility(Zone.BATTLEFIELD, new ReturnToHandTargetEffect(), new ManaCostsImpl("{2}{U}{U}"));
ability2.addCost(new TapSourceCost());
ability2.addTarget(new TargetPermanent(filter));
this.addAbility(ability2);
}
public TimeElemental(final TimeElemental card) {
super(card);
}
@Override
public TimeElemental copy() {
return new TimeElemental(this);
}
}

View file

@ -0,0 +1,127 @@
/*
* 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 mage.cards.v;
import java.util.UUID;
import mage.MageObject;
import mage.abilities.Ability;
import mage.abilities.common.SimpleActivatedAbility;
import mage.abilities.costs.common.TapSourceCost;
import mage.abilities.costs.mana.GenericManaCost;
import mage.abilities.effects.OneShotEffect;
import mage.cards.*;
import mage.cards.repository.CardRepository;
import mage.choices.Choice;
import mage.choices.ChoiceImpl;
import mage.constants.CardType;
import mage.constants.Outcome;
import mage.constants.Zone;
import mage.game.Game;
import mage.players.Player;
import mage.target.TargetPlayer;
/**
*
* @author BetaSteward_at_googlemail.com & L_J
*/
public class VexingArcanix extends CardImpl {
public VexingArcanix(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{4}");
// {3}, {tap}: Target player chooses a card name, then reveals the top card of his or her library. If that card has the chosen name, the player puts it into his or her hand. Otherwise, the player puts it into his or her graveyard and Vexing Arcanix deals 2 damage to him or her.
Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new VexingArcanixEffect(), new GenericManaCost(3));
ability.addCost(new TapSourceCost());
ability.addTarget(new TargetPlayer());
this.addAbility(ability);
}
public VexingArcanix(final VexingArcanix card) {
super(card);
}
@Override
public VexingArcanix copy() {
return new VexingArcanix(this);
}
}
class VexingArcanixEffect extends OneShotEffect {
public VexingArcanixEffect() {
super(Outcome.DrawCard);
staticText = "Target player chooses a card name, then reveals the top card of his or her library. If that card has the chosen name, the player puts it into his or her hand. Otherwise, the player puts it into his or her graveyard and {this} deals 2 damage to him or her";
}
public VexingArcanixEffect(final VexingArcanixEffect effect) {
super(effect);
}
@Override
public boolean apply(Game game, Ability source) {
MageObject sourceObject = source.getSourceObject(game);
Player controller = game.getPlayer(source.getControllerId());
Player player = game.getPlayer(targetPointer.getFirst(game, source));
if (controller != null && sourceObject != null && player != null) {
if (player.getLibrary().hasCards()) {
Choice cardChoice = new ChoiceImpl();
cardChoice.setChoices(CardRepository.instance.getNames());
cardChoice.setMessage("Name a card");
while (!player.choose(Outcome.DrawCard, cardChoice, game)) {
if (!player.canRespond()) {
return false;
}
}
String cardName = cardChoice.getChoice();
game.informPlayers(sourceObject.getLogName() + ", player: " + player.getLogName() + ", named: [" + cardName + ']');
Card card = player.getLibrary().removeFromTop(game);
if (card != null) {
Cards cards = new CardsImpl(card);
player.revealCards(sourceObject.getIdName(), cards, game);
if (card.getName().equals(cardName)) {
player.moveCards(cards, Zone.HAND, source, game);
} else {
player.moveCards(cards, Zone.GRAVEYARD, source, game);
player.damage(2, source.getSourceId(), game, false, true);
}
}
}
return true;
}
return false;
}
@Override
public VexingArcanixEffect copy() {
return new VexingArcanixEffect(this);
}
}

View file

@ -61,7 +61,7 @@ public class WatertrapWeaver extends CardImpl {
this.power = new MageInt(2); this.power = new MageInt(2);
this.toughness = new MageInt(2); this.toughness = new MageInt(2);
// When Watertrap Weaver enters the battlefield, tap target creature an opponent controls. That creature doesn't untap during its controller's next untap step. // When Watertrap Weaver enters the battlefield, tap target creature an opponent controls. That creature doesn't untap during its controller's next untap step.
EntersBattlefieldTriggeredAbility ability = new EntersBattlefieldTriggeredAbility(new TapTargetEffect()); EntersBattlefieldTriggeredAbility ability = new EntersBattlefieldTriggeredAbility(new TapTargetEffect());
ability.addEffect(new DontUntapInControllersNextUntapStepTargetEffect("that creature")); ability.addEffect(new DontUntapInControllersNextUntapStepTargetEffect("that creature"));
ability.addTarget(new TargetCreaturePermanent(filter)); ability.addTarget(new TargetCreaturePermanent(filter));

View file

@ -39,11 +39,11 @@ import mage.abilities.keyword.SwampwalkAbility;
import mage.cards.CardImpl; import mage.cards.CardImpl;
import mage.cards.CardSetInfo; import mage.cards.CardSetInfo;
import mage.constants.CardType; import mage.constants.CardType;
import mage.constants.SubType;
import mage.constants.Duration; import mage.constants.Duration;
import mage.constants.Layer; import mage.constants.Layer;
import mage.constants.Outcome; import mage.constants.Outcome;
import mage.constants.SubLayer; import mage.constants.SubLayer;
import mage.constants.SubType;
import mage.constants.Zone; import mage.constants.Zone;
import mage.game.Game; import mage.game.Game;
import mage.game.permanent.Permanent; import mage.game.permanent.Permanent;
@ -56,15 +56,15 @@ import mage.target.common.TargetOpponent;
public class WitchEngine extends CardImpl { public class WitchEngine extends CardImpl {
public WitchEngine(UUID ownerId, CardSetInfo setInfo) { public WitchEngine(UUID ownerId, CardSetInfo setInfo) {
super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{5}{B}"); super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{5}{B}");
this.subtype.add(SubType.HORROR); this.subtype.add(SubType.HORROR);
this.power = new MageInt(4); this.power = new MageInt(4);
this.toughness = new MageInt(4); this.toughness = new MageInt(4);
// Swampwalk // Swampwalk
this.addAbility(new SwampwalkAbility()); this.addAbility(new SwampwalkAbility());
// {tap}: Add {B}{B}{B}{B} to your mana pool. Target opponent gains control of Witch Engine. // {tap}: Add {B}{B}{B}{B} to your mana pool. Target opponent gains control of Witch Engine. (Activate this ability only any time you could cast an instant.)
Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new BasicManaEffect(Mana.BlackMana(4)), new TapSourceCost()); Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new BasicManaEffect(Mana.BlackMana(4)), new TapSourceCost());
ability.addEffect(new WitchEngineEffect()); ability.addEffect(new WitchEngineEffect());
ability.addTarget(new TargetOpponent()); ability.addTarget(new TargetOpponent());

View file

@ -114,6 +114,7 @@ public class Alliances extends ExpansionSet {
cards.add(new SetCardInfo("Lim-Dul's Vault", 192, Rarity.UNCOMMON, mage.cards.l.LimDulsVault.class)); cards.add(new SetCardInfo("Lim-Dul's Vault", 192, Rarity.UNCOMMON, mage.cards.l.LimDulsVault.class));
cards.add(new SetCardInfo("Lord of Tresserhorn", 193, Rarity.RARE, mage.cards.l.LordOfTresserhorn.class)); cards.add(new SetCardInfo("Lord of Tresserhorn", 193, Rarity.RARE, mage.cards.l.LordOfTresserhorn.class));
cards.add(new SetCardInfo("Mishra's Groundbreaker", 165, Rarity.UNCOMMON, mage.cards.m.MishrasGroundbreaker.class)); cards.add(new SetCardInfo("Mishra's Groundbreaker", 165, Rarity.UNCOMMON, mage.cards.m.MishrasGroundbreaker.class));
cards.add(new SetCardInfo("Misinformation", 19, Rarity.UNCOMMON, mage.cards.m.Misinformation.class));
cards.add(new SetCardInfo("Mystic Compass", 166, Rarity.UNCOMMON, mage.cards.m.MysticCompass.class)); cards.add(new SetCardInfo("Mystic Compass", 166, Rarity.UNCOMMON, mage.cards.m.MysticCompass.class));
cards.add(new SetCardInfo("Nature's Chosen", 81, Rarity.UNCOMMON, mage.cards.n.NaturesChosen.class)); cards.add(new SetCardInfo("Nature's Chosen", 81, Rarity.UNCOMMON, mage.cards.n.NaturesChosen.class));
cards.add(new SetCardInfo("Nature's Wrath", 82, Rarity.RARE, mage.cards.n.NaturesWrath.class)); cards.add(new SetCardInfo("Nature's Wrath", 82, Rarity.RARE, mage.cards.n.NaturesWrath.class));

View file

@ -57,7 +57,7 @@ public class Chronicles extends ExpansionSet {
cards.add(new SetCardInfo("Active Volcano", 43, Rarity.COMMON, mage.cards.a.ActiveVolcano.class)); cards.add(new SetCardInfo("Active Volcano", 43, Rarity.COMMON, mage.cards.a.ActiveVolcano.class));
cards.add(new SetCardInfo("Akron Legionnaire", 58, Rarity.RARE, mage.cards.a.AkronLegionnaire.class)); cards.add(new SetCardInfo("Akron Legionnaire", 58, Rarity.RARE, mage.cards.a.AkronLegionnaire.class));
cards.add(new SetCardInfo("Aladdin", 44, Rarity.RARE, mage.cards.a.Aladdin.class)); cards.add(new SetCardInfo("Aladdin", 44, Rarity.RARE, mage.cards.a.Aladdin.class));
cards.add(new SetCardInfo("Angelic Voices", 59, Rarity.RARE, mage.cards.a.AngelicVoices.class)); cards.add(new SetCardInfo("Angelic Voices", 59, Rarity.RARE, mage.cards.a.AngelicVoices.class));
cards.add(new SetCardInfo("Arcades Sabboth", 106, Rarity.RARE, mage.cards.a.ArcadesSabboth.class)); cards.add(new SetCardInfo("Arcades Sabboth", 106, Rarity.RARE, mage.cards.a.ArcadesSabboth.class));
cards.add(new SetCardInfo("Arena of the Ancients", 71, Rarity.RARE, mage.cards.a.ArenaOfTheAncients.class)); cards.add(new SetCardInfo("Arena of the Ancients", 71, Rarity.RARE, mage.cards.a.ArenaOfTheAncients.class));
cards.add(new SetCardInfo("Argothian Pixies", 29, Rarity.COMMON, mage.cards.a.ArgothianPixies.class)); cards.add(new SetCardInfo("Argothian Pixies", 29, Rarity.COMMON, mage.cards.a.ArgothianPixies.class));
@ -98,9 +98,10 @@ public class Chronicles extends ExpansionSet {
cards.add(new SetCardInfo("Hasran Ogress", 6, Rarity.COMMON, mage.cards.h.HasranOgress.class)); cards.add(new SetCardInfo("Hasran Ogress", 6, Rarity.COMMON, mage.cards.h.HasranOgress.class));
cards.add(new SetCardInfo("Hell's Caretaker", 7, Rarity.RARE, mage.cards.h.HellsCaretaker.class)); cards.add(new SetCardInfo("Hell's Caretaker", 7, Rarity.RARE, mage.cards.h.HellsCaretaker.class));
cards.add(new SetCardInfo("Horn of Deafening", 80, Rarity.RARE, mage.cards.h.HornOfDeafening.class)); cards.add(new SetCardInfo("Horn of Deafening", 80, Rarity.RARE, mage.cards.h.HornOfDeafening.class));
cards.add(new SetCardInfo("Indestructible Aura", 63, Rarity.COMMON, mage.cards.i.IndestructibleAura.class)); cards.add(new SetCardInfo("Indestructible Aura", 63, Rarity.COMMON, mage.cards.i.IndestructibleAura.class));
cards.add(new SetCardInfo("Ivory Guardians", 64, Rarity.UNCOMMON, mage.cards.i.IvoryGuardians.class)); cards.add(new SetCardInfo("Ivory Guardians", 64, Rarity.UNCOMMON, mage.cards.i.IvoryGuardians.class));
cards.add(new SetCardInfo("Jalum Tome", 81, Rarity.RARE, mage.cards.j.JalumTome.class)); cards.add(new SetCardInfo("Jalum Tome", 81, Rarity.RARE, mage.cards.j.JalumTome.class));
cards.add(new SetCardInfo("Johan", 112, Rarity.RARE, mage.cards.j.Johan.class));
cards.add(new SetCardInfo("Juxtapose", 22, Rarity.RARE, mage.cards.j.Juxtapose.class)); cards.add(new SetCardInfo("Juxtapose", 22, Rarity.RARE, mage.cards.j.Juxtapose.class));
cards.add(new SetCardInfo("Keepers of the Faith", 65, Rarity.COMMON, mage.cards.k.KeepersOfTheFaith.class)); cards.add(new SetCardInfo("Keepers of the Faith", 65, Rarity.COMMON, mage.cards.k.KeepersOfTheFaith.class));
cards.add(new SetCardInfo("Kei Takahashi", 113, Rarity.UNCOMMON, mage.cards.k.KeiTakahashi.class)); cards.add(new SetCardInfo("Kei Takahashi", 113, Rarity.UNCOMMON, mage.cards.k.KeiTakahashi.class));
@ -112,6 +113,7 @@ public class Chronicles extends ExpansionSet {
cards.add(new SetCardInfo("Nicol Bolas", 116, Rarity.RARE, mage.cards.n.NicolBolas.class)); cards.add(new SetCardInfo("Nicol Bolas", 116, Rarity.RARE, mage.cards.n.NicolBolas.class));
cards.add(new SetCardInfo("Obelisk of Undoing", 84, Rarity.RARE, mage.cards.o.ObeliskOfUndoing.class)); cards.add(new SetCardInfo("Obelisk of Undoing", 84, Rarity.RARE, mage.cards.o.ObeliskOfUndoing.class));
cards.add(new SetCardInfo("Palladia-Mors", 117, Rarity.RARE, mage.cards.p.PalladiaMors.class)); cards.add(new SetCardInfo("Palladia-Mors", 117, Rarity.RARE, mage.cards.p.PalladiaMors.class));
cards.add(new SetCardInfo("Petra Sphinx", 66, Rarity.RARE, mage.cards.p.PetraSphinx.class));
cards.add(new SetCardInfo("Rabid Wombat", 39, Rarity.UNCOMMON, mage.cards.r.RabidWombat.class)); cards.add(new SetCardInfo("Rabid Wombat", 39, Rarity.UNCOMMON, mage.cards.r.RabidWombat.class));
cards.add(new SetCardInfo("Rakalite", 85, Rarity.RARE, mage.cards.r.Rakalite.class)); cards.add(new SetCardInfo("Rakalite", 85, Rarity.RARE, mage.cards.r.Rakalite.class));
cards.add(new SetCardInfo("Recall", 24, Rarity.UNCOMMON, mage.cards.r.Recall.class)); cards.add(new SetCardInfo("Recall", 24, Rarity.UNCOMMON, mage.cards.r.Recall.class));
@ -127,6 +129,7 @@ public class Chronicles extends ExpansionSet {
cards.add(new SetCardInfo("Sivitri Scarzam", 119, Rarity.UNCOMMON, mage.cards.s.SivitriScarzam.class)); cards.add(new SetCardInfo("Sivitri Scarzam", 119, Rarity.UNCOMMON, mage.cards.s.SivitriScarzam.class));
cards.add(new SetCardInfo("Sol'kanar the Swamp King", 120, Rarity.RARE, mage.cards.s.SolkanarTheSwampKing.class)); cards.add(new SetCardInfo("Sol'kanar the Swamp King", 120, Rarity.RARE, mage.cards.s.SolkanarTheSwampKing.class));
cards.add(new SetCardInfo("Storm Seeker", 42, Rarity.UNCOMMON, mage.cards.s.StormSeeker.class)); cards.add(new SetCardInfo("Storm Seeker", 42, Rarity.UNCOMMON, mage.cards.s.StormSeeker.class));
cards.add(new SetCardInfo("Teleport", 26, Rarity.RARE, mage.cards.t.Teleport.class));
cards.add(new SetCardInfo("The Wretched", 11, Rarity.RARE, mage.cards.t.TheWretched.class)); cards.add(new SetCardInfo("The Wretched", 11, Rarity.RARE, mage.cards.t.TheWretched.class));
cards.add(new SetCardInfo("Tobias Andrion", 122, Rarity.UNCOMMON, mage.cards.t.TobiasAndrion.class)); cards.add(new SetCardInfo("Tobias Andrion", 122, Rarity.UNCOMMON, mage.cards.t.TobiasAndrion.class));
cards.add(new SetCardInfo("Tormod's Crypt", 89, Rarity.COMMON, mage.cards.t.TormodsCrypt.class)); cards.add(new SetCardInfo("Tormod's Crypt", 89, Rarity.COMMON, mage.cards.t.TormodsCrypt.class));

View file

@ -86,6 +86,7 @@ public class ConspiracyTakeTheCrown extends ExpansionSet {
cards.add(new SetCardInfo("Coveted Peacock", 29, Rarity.UNCOMMON, mage.cards.c.CovetedPeacock.class)); cards.add(new SetCardInfo("Coveted Peacock", 29, Rarity.UNCOMMON, mage.cards.c.CovetedPeacock.class));
cards.add(new SetCardInfo("Crown-Hunter Hireling", 50, Rarity.COMMON, mage.cards.c.CrownHunterHireling.class)); cards.add(new SetCardInfo("Crown-Hunter Hireling", 50, Rarity.COMMON, mage.cards.c.CrownHunterHireling.class));
cards.add(new SetCardInfo("Custodi Lich", 41, Rarity.RARE, mage.cards.c.CustodiLich.class)); cards.add(new SetCardInfo("Custodi Lich", 41, Rarity.RARE, mage.cards.c.CustodiLich.class));
cards.add(new SetCardInfo("Custodi Soulcaller", 15, Rarity.UNCOMMON, mage.cards.c.CustodiSoulcaller.class));
cards.add(new SetCardInfo("Daretti, Ingenious Iconoclast", 74, Rarity.MYTHIC, mage.cards.d.DarettiIngeniousIconoclast.class)); cards.add(new SetCardInfo("Daretti, Ingenious Iconoclast", 74, Rarity.MYTHIC, mage.cards.d.DarettiIngeniousIconoclast.class));
cards.add(new SetCardInfo("Deadly Designs", 42, Rarity.UNCOMMON, mage.cards.d.DeadlyDesigns.class)); cards.add(new SetCardInfo("Deadly Designs", 42, Rarity.UNCOMMON, mage.cards.d.DeadlyDesigns.class));
cards.add(new SetCardInfo("Death Wind", 131, Rarity.COMMON, mage.cards.d.DeathWind.class)); cards.add(new SetCardInfo("Death Wind", 131, Rarity.COMMON, mage.cards.d.DeathWind.class));

View file

@ -350,6 +350,7 @@ public class EighthEdition extends ExpansionSet {
cards.add(new SetCardInfo("Venerable Monk", 55, Rarity.COMMON, mage.cards.v.VenerableMonk.class)); cards.add(new SetCardInfo("Venerable Monk", 55, Rarity.COMMON, mage.cards.v.VenerableMonk.class));
cards.add(new SetCardInfo("Verduran Enchantress", 285, Rarity.RARE, mage.cards.v.VerduranEnchantress.class)); cards.add(new SetCardInfo("Verduran Enchantress", 285, Rarity.RARE, mage.cards.v.VerduranEnchantress.class));
cards.add(new SetCardInfo("Vernal Bloom", 286, Rarity.RARE, mage.cards.v.VernalBloom.class)); cards.add(new SetCardInfo("Vernal Bloom", 286, Rarity.RARE, mage.cards.v.VernalBloom.class));
cards.add(new SetCardInfo("Vexing Arcanix", 319, Rarity.RARE, mage.cards.v.VexingArcanix.class));
cards.add(new SetCardInfo("Viashino Sandstalker", 230, Rarity.UNCOMMON, mage.cards.v.ViashinoSandstalker.class)); cards.add(new SetCardInfo("Viashino Sandstalker", 230, Rarity.UNCOMMON, mage.cards.v.ViashinoSandstalker.class));
cards.add(new SetCardInfo("Vicious Hunger", 171, Rarity.COMMON, mage.cards.v.ViciousHunger.class)); cards.add(new SetCardInfo("Vicious Hunger", 171, Rarity.COMMON, mage.cards.v.ViciousHunger.class));
cards.add(new SetCardInfo("Vine Trellis", 287, Rarity.COMMON, mage.cards.v.VineTrellis.class)); cards.add(new SetCardInfo("Vine Trellis", 287, Rarity.COMMON, mage.cards.v.VineTrellis.class));

View file

@ -219,6 +219,9 @@ public class FallenEmpires extends ExpansionSet {
cards.add(new SetCardInfo("Seasinger", 52, Rarity.UNCOMMON, mage.cards.s.Seasinger.class)); cards.add(new SetCardInfo("Seasinger", 52, Rarity.UNCOMMON, mage.cards.s.Seasinger.class));
cards.add(new SetCardInfo("Soul Exchange", 28, Rarity.UNCOMMON, mage.cards.s.SoulExchange.class)); cards.add(new SetCardInfo("Soul Exchange", 28, Rarity.UNCOMMON, mage.cards.s.SoulExchange.class));
cards.add(new SetCardInfo("Spirit Shield", 175, Rarity.RARE, mage.cards.s.SpiritShield.class)); cards.add(new SetCardInfo("Spirit Shield", 175, Rarity.RARE, mage.cards.s.SpiritShield.class));
cards.add(new SetCardInfo("Spore Cloud", 83, Rarity.COMMON, mage.cards.s.SporeCloud.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Spore Cloud", 84, Rarity.COMMON, mage.cards.s.SporeCloud.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Spore Cloud", 85, Rarity.COMMON, mage.cards.s.SporeCloud.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Spore Flower", 86, Rarity.UNCOMMON, mage.cards.s.SporeFlower.class)); cards.add(new SetCardInfo("Spore Flower", 86, Rarity.UNCOMMON, mage.cards.s.SporeFlower.class));
cards.add(new SetCardInfo("Svyelunite Priest", 53, Rarity.UNCOMMON, mage.cards.s.SvyelunitePriest.class)); cards.add(new SetCardInfo("Svyelunite Priest", 53, Rarity.UNCOMMON, mage.cards.s.SvyelunitePriest.class));
cards.add(new SetCardInfo("Svyelunite Temple", 187, Rarity.UNCOMMON, mage.cards.s.SvyeluniteTemple.class)); cards.add(new SetCardInfo("Svyelunite Temple", 187, Rarity.UNCOMMON, mage.cards.s.SvyeluniteTemple.class));

View file

@ -328,6 +328,7 @@ public class FifthEdition extends ExpansionSet {
cards.add(new SetCardInfo("Pradesh Gypsies", 179, Rarity.COMMON, mage.cards.p.PradeshGypsies.class)); cards.add(new SetCardInfo("Pradesh Gypsies", 179, Rarity.COMMON, mage.cards.p.PradeshGypsies.class));
cards.add(new SetCardInfo("Primal Clay", 395, Rarity.RARE, mage.cards.p.PrimalClay.class)); cards.add(new SetCardInfo("Primal Clay", 395, Rarity.RARE, mage.cards.p.PrimalClay.class));
cards.add(new SetCardInfo("Primal Order", 180, Rarity.RARE, mage.cards.p.PrimalOrder.class)); cards.add(new SetCardInfo("Primal Order", 180, Rarity.RARE, mage.cards.p.PrimalOrder.class));
cards.add(new SetCardInfo("Prismatic Ward", 329, Rarity.COMMON, mage.cards.p.PrismaticWard.class));
cards.add(new SetCardInfo("Prodigal Sorcerer", 112, Rarity.COMMON, mage.cards.p.ProdigalSorcerer.class)); cards.add(new SetCardInfo("Prodigal Sorcerer", 112, Rarity.COMMON, mage.cards.p.ProdigalSorcerer.class));
cards.add(new SetCardInfo("Psychic Venom", 113, Rarity.COMMON, mage.cards.p.PsychicVenom.class)); cards.add(new SetCardInfo("Psychic Venom", 113, Rarity.COMMON, mage.cards.p.PsychicVenom.class));
cards.add(new SetCardInfo("Pyroblast", 262, Rarity.UNCOMMON, mage.cards.p.Pyroblast.class)); cards.add(new SetCardInfo("Pyroblast", 262, Rarity.UNCOMMON, mage.cards.p.Pyroblast.class));
@ -401,6 +402,7 @@ public class FifthEdition extends ExpansionSet {
cards.add(new SetCardInfo("Throne of Bone", 403, Rarity.UNCOMMON, mage.cards.t.ThroneOfBone.class)); cards.add(new SetCardInfo("Throne of Bone", 403, Rarity.UNCOMMON, mage.cards.t.ThroneOfBone.class));
cards.add(new SetCardInfo("Thrull Retainer", 60, Rarity.UNCOMMON, mage.cards.t.ThrullRetainer.class)); cards.add(new SetCardInfo("Thrull Retainer", 60, Rarity.UNCOMMON, mage.cards.t.ThrullRetainer.class));
cards.add(new SetCardInfo("Time Bomb", 404, Rarity.RARE, mage.cards.t.TimeBomb.class)); cards.add(new SetCardInfo("Time Bomb", 404, Rarity.RARE, mage.cards.t.TimeBomb.class));
cards.add(new SetCardInfo("Time Elemental", 129, Rarity.RARE, mage.cards.t.TimeElemental.class));
cards.add(new SetCardInfo("Titania's Song", 194, Rarity.RARE, mage.cards.t.TitaniasSong.class)); cards.add(new SetCardInfo("Titania's Song", 194, Rarity.RARE, mage.cards.t.TitaniasSong.class));
cards.add(new SetCardInfo("Torture", 61, Rarity.COMMON, Torture.class)); cards.add(new SetCardInfo("Torture", 61, Rarity.COMMON, Torture.class));
cards.add(new SetCardInfo("Touch of Death", 62, Rarity.COMMON, mage.cards.t.TouchOfDeath.class)); cards.add(new SetCardInfo("Touch of Death", 62, Rarity.COMMON, mage.cards.t.TouchOfDeath.class));

View file

@ -359,6 +359,7 @@ public class FourthEdition extends ExpansionSet {
cards.add(new SetCardInfo("Thicket Basilisk", 158, Rarity.UNCOMMON, mage.cards.t.ThicketBasilisk.class)); cards.add(new SetCardInfo("Thicket Basilisk", 158, Rarity.UNCOMMON, mage.cards.t.ThicketBasilisk.class));
cards.add(new SetCardInfo("Thoughtlace", 107, Rarity.RARE, mage.cards.t.Thoughtlace.class)); cards.add(new SetCardInfo("Thoughtlace", 107, Rarity.RARE, mage.cards.t.Thoughtlace.class));
cards.add(new SetCardInfo("Throne of Bone", 371, Rarity.UNCOMMON, mage.cards.t.ThroneOfBone.class)); cards.add(new SetCardInfo("Throne of Bone", 371, Rarity.UNCOMMON, mage.cards.t.ThroneOfBone.class));
cards.add(new SetCardInfo("Time Elemental", 108, Rarity.RARE, mage.cards.t.TimeElemental.class));
cards.add(new SetCardInfo("Titania's Song", 160, Rarity.RARE, mage.cards.t.TitaniasSong.class)); cards.add(new SetCardInfo("Titania's Song", 160, Rarity.RARE, mage.cards.t.TitaniasSong.class));
cards.add(new SetCardInfo("Tranquility", 161, Rarity.COMMON, mage.cards.t.Tranquility.class)); cards.add(new SetCardInfo("Tranquility", 161, Rarity.COMMON, mage.cards.t.Tranquility.class));
cards.add(new SetCardInfo("Triskelion", 372, Rarity.RARE, mage.cards.t.Triskelion.class)); cards.add(new SetCardInfo("Triskelion", 372, Rarity.RARE, mage.cards.t.Triskelion.class));

View file

@ -212,6 +212,7 @@ public class IceAge extends ExpansionSet {
cards.add(new SetCardInfo("Magus of the Unseen", 82, Rarity.RARE, mage.cards.m.MagusOfTheUnseen.class)); cards.add(new SetCardInfo("Magus of the Unseen", 82, Rarity.RARE, mage.cards.m.MagusOfTheUnseen.class));
cards.add(new SetCardInfo("Malachite Talisman", 303, Rarity.UNCOMMON, mage.cards.m.MalachiteTalisman.class)); cards.add(new SetCardInfo("Malachite Talisman", 303, Rarity.UNCOMMON, mage.cards.m.MalachiteTalisman.class));
cards.add(new SetCardInfo("Marton Stromgald", 199, Rarity.RARE, mage.cards.m.MartonStromgald.class)); cards.add(new SetCardInfo("Marton Stromgald", 199, Rarity.RARE, mage.cards.m.MartonStromgald.class));
cards.add(new SetCardInfo("Melee", 200, Rarity.UNCOMMON, mage.cards.m.Melee.class));
cards.add(new SetCardInfo("Melting", 201, Rarity.UNCOMMON, mage.cards.m.Melting.class)); cards.add(new SetCardInfo("Melting", 201, Rarity.UNCOMMON, mage.cards.m.Melting.class));
cards.add(new SetCardInfo("Merieke Ri Berit", 375, Rarity.RARE, mage.cards.m.MeriekeRiBerit.class)); cards.add(new SetCardInfo("Merieke Ri Berit", 375, Rarity.RARE, mage.cards.m.MeriekeRiBerit.class));
cards.add(new SetCardInfo("Mesmeric Trance", 83, Rarity.RARE, mage.cards.m.MesmericTrance.class)); cards.add(new SetCardInfo("Mesmeric Trance", 83, Rarity.RARE, mage.cards.m.MesmericTrance.class));
@ -253,6 +254,7 @@ public class IceAge extends ExpansionSet {
cards.add(new SetCardInfo("Portent", 90, Rarity.COMMON, mage.cards.p.Portent.class)); cards.add(new SetCardInfo("Portent", 90, Rarity.COMMON, mage.cards.p.Portent.class));
cards.add(new SetCardInfo("Power Sink", 91, Rarity.COMMON, mage.cards.p.PowerSink.class)); cards.add(new SetCardInfo("Power Sink", 91, Rarity.COMMON, mage.cards.p.PowerSink.class));
cards.add(new SetCardInfo("Pox", 46, Rarity.RARE, mage.cards.p.Pox.class)); cards.add(new SetCardInfo("Pox", 46, Rarity.RARE, mage.cards.p.Pox.class));
cards.add(new SetCardInfo("Prismatic Ward", 271, Rarity.COMMON, mage.cards.p.PrismaticWard.class));
cards.add(new SetCardInfo("Pygmy Allosaurus", 145, Rarity.RARE, mage.cards.p.PygmyAllosaurus.class)); cards.add(new SetCardInfo("Pygmy Allosaurus", 145, Rarity.RARE, mage.cards.p.PygmyAllosaurus.class));
cards.add(new SetCardInfo("Pyknite", 146, Rarity.COMMON, mage.cards.p.Pyknite.class)); cards.add(new SetCardInfo("Pyknite", 146, Rarity.COMMON, mage.cards.p.Pyknite.class));
cards.add(new SetCardInfo("Pyroblast", 213, Rarity.COMMON, mage.cards.p.Pyroblast.class)); cards.add(new SetCardInfo("Pyroblast", 213, Rarity.COMMON, mage.cards.p.Pyroblast.class));
@ -323,6 +325,7 @@ public class IceAge extends ExpansionSet {
cards.add(new SetCardInfo("Urza's Bauble", 318, Rarity.UNCOMMON, mage.cards.u.UrzasBauble.class)); cards.add(new SetCardInfo("Urza's Bauble", 318, Rarity.UNCOMMON, mage.cards.u.UrzasBauble.class));
cards.add(new SetCardInfo("Veldt", 358, Rarity.RARE, mage.cards.v.Veldt.class)); cards.add(new SetCardInfo("Veldt", 358, Rarity.RARE, mage.cards.v.Veldt.class));
cards.add(new SetCardInfo("Vertigo", 222, Rarity.UNCOMMON, mage.cards.v.Vertigo.class)); cards.add(new SetCardInfo("Vertigo", 222, Rarity.UNCOMMON, mage.cards.v.Vertigo.class));
cards.add(new SetCardInfo("Vexing Arcanix", 319, Rarity.RARE, mage.cards.v.VexingArcanix.class));
cards.add(new SetCardInfo("Vibrating Sphere", 320, Rarity.RARE, mage.cards.v.VibratingSphere.class)); cards.add(new SetCardInfo("Vibrating Sphere", 320, Rarity.RARE, mage.cards.v.VibratingSphere.class));
cards.add(new SetCardInfo("Walking Wall", 321, Rarity.UNCOMMON, mage.cards.w.WalkingWall.class)); cards.add(new SetCardInfo("Walking Wall", 321, Rarity.UNCOMMON, mage.cards.w.WalkingWall.class));
cards.add(new SetCardInfo("Wall of Lava", 223, Rarity.UNCOMMON, mage.cards.w.WallOfLava.class)); cards.add(new SetCardInfo("Wall of Lava", 223, Rarity.UNCOMMON, mage.cards.w.WallOfLava.class));

View file

@ -101,13 +101,13 @@ public class Legends extends ExpansionSet {
cards.add(new SetCardInfo("D'Avenant Archer", 176, Rarity.COMMON, mage.cards.d.DAvenantArcher.class)); cards.add(new SetCardInfo("D'Avenant Archer", 176, Rarity.COMMON, mage.cards.d.DAvenantArcher.class));
cards.add(new SetCardInfo("Demonic Torment", 9, Rarity.UNCOMMON, mage.cards.d.DemonicTorment.class)); cards.add(new SetCardInfo("Demonic Torment", 9, Rarity.UNCOMMON, mage.cards.d.DemonicTorment.class));
cards.add(new SetCardInfo("Devouring Deep", 50, Rarity.COMMON, mage.cards.d.DevouringDeep.class)); cards.add(new SetCardInfo("Devouring Deep", 50, Rarity.COMMON, mage.cards.d.DevouringDeep.class));
cards.add(new SetCardInfo("Disharmony", 140, Rarity.RARE, mage.cards.d.Disharmony.class)); cards.add(new SetCardInfo("Disharmony", 140, Rarity.RARE, mage.cards.d.Disharmony.class));
cards.add(new SetCardInfo("Divine Intervention", 177, Rarity.RARE, mage.cards.d.DivineIntervention.class)); cards.add(new SetCardInfo("Divine Intervention", 177, Rarity.RARE, mage.cards.d.DivineIntervention.class));
cards.add(new SetCardInfo("Divine Offering", 178, Rarity.COMMON, mage.cards.d.DivineOffering.class)); cards.add(new SetCardInfo("Divine Offering", 178, Rarity.COMMON, mage.cards.d.DivineOffering.class));
cards.add(new SetCardInfo("Divine Transformation", 179, Rarity.RARE, mage.cards.d.DivineTransformation.class)); cards.add(new SetCardInfo("Divine Transformation", 179, Rarity.RARE, mage.cards.d.DivineTransformation.class));
cards.add(new SetCardInfo("Durkwood Boars", 96, Rarity.COMMON, mage.cards.d.DurkwoodBoars.class)); cards.add(new SetCardInfo("Durkwood Boars", 96, Rarity.COMMON, mage.cards.d.DurkwoodBoars.class));
cards.add(new SetCardInfo("Dwarven Song", 141, Rarity.UNCOMMON, mage.cards.d.DwarvenSong.class)); cards.add(new SetCardInfo("Dwarven Song", 141, Rarity.UNCOMMON, mage.cards.d.DwarvenSong.class));
cards.add(new SetCardInfo("Elder Land Wurm", 180, Rarity.RARE, mage.cards.e.ElderLandWurm.class)); cards.add(new SetCardInfo("Elder Land Wurm", 180, Rarity.RARE, mage.cards.e.ElderLandWurm.class));
cards.add(new SetCardInfo("Elven Riders", 97, Rarity.RARE, mage.cards.e.ElvenRiders.class)); cards.add(new SetCardInfo("Elven Riders", 97, Rarity.RARE, mage.cards.e.ElvenRiders.class));
cards.add(new SetCardInfo("Emerald Dragonfly", 98, Rarity.COMMON, mage.cards.e.EmeraldDragonfly.class)); cards.add(new SetCardInfo("Emerald Dragonfly", 98, Rarity.COMMON, mage.cards.e.EmeraldDragonfly.class));
cards.add(new SetCardInfo("Energy Tap", 54, Rarity.COMMON, mage.cards.e.EnergyTap.class)); cards.add(new SetCardInfo("Energy Tap", 54, Rarity.COMMON, mage.cards.e.EnergyTap.class));
@ -119,20 +119,20 @@ public class Legends extends ExpansionSet {
cards.add(new SetCardInfo("Fire Sprites", 100, Rarity.COMMON, mage.cards.f.FireSprites.class)); cards.add(new SetCardInfo("Fire Sprites", 100, Rarity.COMMON, mage.cards.f.FireSprites.class));
cards.add(new SetCardInfo("Flash Counter", 56, Rarity.COMMON, mage.cards.f.FlashCounter.class)); cards.add(new SetCardInfo("Flash Counter", 56, Rarity.COMMON, mage.cards.f.FlashCounter.class));
cards.add(new SetCardInfo("Flash Flood", 57, Rarity.COMMON, mage.cards.f.FlashFlood.class)); cards.add(new SetCardInfo("Flash Flood", 57, Rarity.COMMON, mage.cards.f.FlashFlood.class));
cards.add(new SetCardInfo("Floral Spuzzem", 101, Rarity.UNCOMMON, mage.cards.f.FloralSpuzzem.class)); cards.add(new SetCardInfo("Floral Spuzzem", 101, Rarity.UNCOMMON, mage.cards.f.FloralSpuzzem.class));
cards.add(new SetCardInfo("Force Spike", 58, Rarity.COMMON, mage.cards.f.ForceSpike.class)); cards.add(new SetCardInfo("Force Spike", 58, Rarity.COMMON, mage.cards.f.ForceSpike.class));
cards.add(new SetCardInfo("Frost Giant", 146, Rarity.UNCOMMON, mage.cards.f.FrostGiant.class)); cards.add(new SetCardInfo("Frost Giant", 146, Rarity.UNCOMMON, mage.cards.f.FrostGiant.class));
cards.add(new SetCardInfo("Gaseous Form", 59, Rarity.COMMON, mage.cards.g.GaseousForm.class)); cards.add(new SetCardInfo("Gaseous Form", 59, Rarity.COMMON, mage.cards.g.GaseousForm.class));
cards.add(new SetCardInfo("Ghosts of the Damned", 12, Rarity.COMMON, mage.cards.g.GhostsOfTheDamned.class)); cards.add(new SetCardInfo("Ghosts of the Damned", 12, Rarity.COMMON, mage.cards.g.GhostsOfTheDamned.class));
cards.add(new SetCardInfo("Giant Strength", 147, Rarity.COMMON, mage.cards.g.GiantStrength.class)); cards.add(new SetCardInfo("Giant Strength", 147, Rarity.COMMON, mage.cards.g.GiantStrength.class));
cards.add(new SetCardInfo("Giant Turtle", 102, Rarity.COMMON, mage.cards.g.GiantTurtle.class)); cards.add(new SetCardInfo("Giant Turtle", 102, Rarity.COMMON, mage.cards.g.GiantTurtle.class));
cards.add(new SetCardInfo("Gravity Sphere", 149, Rarity.RARE, mage.cards.g.GravitySphere.class)); cards.add(new SetCardInfo("Gravity Sphere", 149, Rarity.RARE, mage.cards.g.GravitySphere.class));
cards.add(new SetCardInfo("Great Defender", 185, Rarity.UNCOMMON, mage.cards.g.GreatDefender.class)); cards.add(new SetCardInfo("Great Defender", 185, Rarity.UNCOMMON, mage.cards.g.GreatDefender.class));
cards.add(new SetCardInfo("Greater Realm of Preservation", 187, Rarity.UNCOMMON, mage.cards.g.GreaterRealmOfPreservation.class)); cards.add(new SetCardInfo("Greater Realm of Preservation", 187, Rarity.UNCOMMON, mage.cards.g.GreaterRealmOfPreservation.class));
cards.add(new SetCardInfo("Greed", 15, Rarity.RARE, mage.cards.g.Greed.class)); cards.add(new SetCardInfo("Greed", 15, Rarity.RARE, mage.cards.g.Greed.class));
cards.add(new SetCardInfo("Green Mana Battery", 223, Rarity.UNCOMMON, mage.cards.g.GreenManaBattery.class)); cards.add(new SetCardInfo("Green Mana Battery", 223, Rarity.UNCOMMON, mage.cards.g.GreenManaBattery.class));
cards.add(new SetCardInfo("Gwendlyn Di Corci", 268, Rarity.RARE, mage.cards.g.GwendlynDiCorci.class)); cards.add(new SetCardInfo("Gwendlyn Di Corci", 268, Rarity.RARE, mage.cards.g.GwendlynDiCorci.class));
cards.add(new SetCardInfo("Hammerheim", 247, Rarity.UNCOMMON, mage.cards.h.Hammerheim.class)); cards.add(new SetCardInfo("Hammerheim", 247, Rarity.UNCOMMON, mage.cards.h.Hammerheim.class));
cards.add(new SetCardInfo("Hazezon Tamar", 270, Rarity.RARE, mage.cards.h.HazezonTamar.class)); cards.add(new SetCardInfo("Hazezon Tamar", 270, Rarity.RARE, mage.cards.h.HazezonTamar.class));
cards.add(new SetCardInfo("Headless Horseman", 16, Rarity.COMMON, mage.cards.h.HeadlessHorseman.class)); cards.add(new SetCardInfo("Headless Horseman", 16, Rarity.COMMON, mage.cards.h.HeadlessHorseman.class));
cards.add(new SetCardInfo("Heaven's Gate", 188, Rarity.UNCOMMON, mage.cards.h.HeavensGate.class)); cards.add(new SetCardInfo("Heaven's Gate", 188, Rarity.UNCOMMON, mage.cards.h.HeavensGate.class));
@ -147,13 +147,14 @@ public class Legends extends ExpansionSet {
cards.add(new SetCardInfo("Hyperion Blacksmith", 150, Rarity.UNCOMMON, mage.cards.h.HyperionBlacksmith.class)); cards.add(new SetCardInfo("Hyperion Blacksmith", 150, Rarity.UNCOMMON, mage.cards.h.HyperionBlacksmith.class));
cards.add(new SetCardInfo("Immolation", 151, Rarity.COMMON, mage.cards.i.Immolation.class)); cards.add(new SetCardInfo("Immolation", 151, Rarity.COMMON, mage.cards.i.Immolation.class));
cards.add(new SetCardInfo("In the Eye of Chaos", 61, Rarity.RARE, mage.cards.i.InTheEyeOfChaos.class)); cards.add(new SetCardInfo("In the Eye of Chaos", 61, Rarity.RARE, mage.cards.i.InTheEyeOfChaos.class));
cards.add(new SetCardInfo("Indestructible Aura", 190, Rarity.COMMON, mage.cards.i.IndestructibleAura.class)); cards.add(new SetCardInfo("Indestructible Aura", 190, Rarity.COMMON, mage.cards.i.IndestructibleAura.class));
cards.add(new SetCardInfo("Invoke Prejudice", 62, Rarity.RARE, mage.cards.i.InvokePrejudice.class)); cards.add(new SetCardInfo("Invoke Prejudice", 62, Rarity.RARE, mage.cards.i.InvokePrejudice.class));
cards.add(new SetCardInfo("Ivory Guardians", 192, Rarity.UNCOMMON, mage.cards.i.IvoryGuardians.class)); cards.add(new SetCardInfo("Ivory Guardians", 192, Rarity.UNCOMMON, mage.cards.i.IvoryGuardians.class));
cards.add(new SetCardInfo("Jacques le Vert", 272, Rarity.RARE, mage.cards.j.JacquesLeVert.class)); cards.add(new SetCardInfo("Jacques le Vert", 272, Rarity.RARE, mage.cards.j.JacquesLeVert.class));
cards.add(new SetCardInfo("Jasmine Boreal", 273, Rarity.UNCOMMON, mage.cards.j.JasmineBoreal.class)); cards.add(new SetCardInfo("Jasmine Boreal", 273, Rarity.UNCOMMON, mage.cards.j.JasmineBoreal.class));
cards.add(new SetCardInfo("Jedit Ojanen", 274, Rarity.UNCOMMON, mage.cards.j.JeditOjanen.class)); cards.add(new SetCardInfo("Jedit Ojanen", 274, Rarity.UNCOMMON, mage.cards.j.JeditOjanen.class));
cards.add(new SetCardInfo("Jerrard of the Closed Fist", 275, Rarity.UNCOMMON, mage.cards.j.JerrardOfTheClosedFist.class)); cards.add(new SetCardInfo("Jerrard of the Closed Fist", 275, Rarity.UNCOMMON, mage.cards.j.JerrardOfTheClosedFist.class));
cards.add(new SetCardInfo("Johan", 276, Rarity.RARE, mage.cards.j.Johan.class));
cards.add(new SetCardInfo("Juxtapose", 63, Rarity.RARE, mage.cards.j.Juxtapose.class)); cards.add(new SetCardInfo("Juxtapose", 63, Rarity.RARE, mage.cards.j.Juxtapose.class));
cards.add(new SetCardInfo("Karakas", 248, Rarity.UNCOMMON, mage.cards.k.Karakas.class)); cards.add(new SetCardInfo("Karakas", 248, Rarity.UNCOMMON, mage.cards.k.Karakas.class));
cards.add(new SetCardInfo("Kasimir the Lone Wolf", 277, Rarity.UNCOMMON, mage.cards.k.KasimirTheLoneWolf.class)); cards.add(new SetCardInfo("Kasimir the Lone Wolf", 277, Rarity.UNCOMMON, mage.cards.k.KasimirTheLoneWolf.class));
@ -186,11 +187,13 @@ public class Legends extends ExpansionSet {
cards.add(new SetCardInfo("Mountain Yeti", 156, Rarity.UNCOMMON, mage.cards.m.MountainYeti.class)); cards.add(new SetCardInfo("Mountain Yeti", 156, Rarity.UNCOMMON, mage.cards.m.MountainYeti.class));
cards.add(new SetCardInfo("Nether Void", 27, Rarity.RARE, mage.cards.n.NetherVoid.class)); cards.add(new SetCardInfo("Nether Void", 27, Rarity.RARE, mage.cards.n.NetherVoid.class));
cards.add(new SetCardInfo("Nicol Bolas", 286, Rarity.RARE, mage.cards.n.NicolBolas.class)); cards.add(new SetCardInfo("Nicol Bolas", 286, Rarity.RARE, mage.cards.n.NicolBolas.class));
cards.add(new SetCardInfo("Nova Pentacle", 234, Rarity.RARE, mage.cards.n.NovaPentacle.class));
cards.add(new SetCardInfo("Osai Vultures", 198, Rarity.COMMON, mage.cards.o.OsaiVultures.class)); cards.add(new SetCardInfo("Osai Vultures", 198, Rarity.COMMON, mage.cards.o.OsaiVultures.class));
cards.add(new SetCardInfo("Palladia-Mors", 287, Rarity.RARE, mage.cards.p.PalladiaMors.class)); cards.add(new SetCardInfo("Palladia-Mors", 287, Rarity.RARE, mage.cards.p.PalladiaMors.class));
cards.add(new SetCardInfo("Part Water", 66, Rarity.UNCOMMON, mage.cards.p.PartWater.class)); cards.add(new SetCardInfo("Part Water", 66, Rarity.UNCOMMON, mage.cards.p.PartWater.class));
cards.add(new SetCardInfo("Pavel Maliki", 288, Rarity.UNCOMMON, mage.cards.p.PavelMaliki.class)); cards.add(new SetCardInfo("Pavel Maliki", 288, Rarity.UNCOMMON, mage.cards.p.PavelMaliki.class));
cards.add(new SetCardInfo("Pendelhaven", 250, Rarity.UNCOMMON, mage.cards.p.Pendelhaven.class)); cards.add(new SetCardInfo("Pendelhaven", 250, Rarity.UNCOMMON, mage.cards.p.Pendelhaven.class));
cards.add(new SetCardInfo("Petra Sphinx", 199, Rarity.RARE, mage.cards.p.PetraSphinx.class));
cards.add(new SetCardInfo("Pit Scorpion", 28, Rarity.COMMON, mage.cards.p.PitScorpion.class)); cards.add(new SetCardInfo("Pit Scorpion", 28, Rarity.COMMON, mage.cards.p.PitScorpion.class));
cards.add(new SetCardInfo("Pixie Queen", 110, Rarity.RARE, mage.cards.p.PixieQueen.class)); cards.add(new SetCardInfo("Pixie Queen", 110, Rarity.RARE, mage.cards.p.PixieQueen.class));
cards.add(new SetCardInfo("Planar Gate", 235, Rarity.RARE, mage.cards.p.PlanarGate.class)); cards.add(new SetCardInfo("Planar Gate", 235, Rarity.RARE, mage.cards.p.PlanarGate.class));
@ -216,7 +219,7 @@ public class Legends extends ExpansionSet {
cards.add(new SetCardInfo("Righteous Avengers", 203, Rarity.UNCOMMON, mage.cards.r.RighteousAvengers.class)); cards.add(new SetCardInfo("Righteous Avengers", 203, Rarity.UNCOMMON, mage.cards.r.RighteousAvengers.class));
cards.add(new SetCardInfo("Ring of Immortals", 238, Rarity.RARE, mage.cards.r.RingOfImmortals.class)); cards.add(new SetCardInfo("Ring of Immortals", 238, Rarity.RARE, mage.cards.r.RingOfImmortals.class));
cards.add(new SetCardInfo("Riven Turnbull", 294, Rarity.UNCOMMON, mage.cards.r.RivenTurnbull.class)); cards.add(new SetCardInfo("Riven Turnbull", 294, Rarity.UNCOMMON, mage.cards.r.RivenTurnbull.class));
cards.add(new SetCardInfo("Rohgahh of Kher Keep", 295, Rarity.RARE, mage.cards.r.RohgahhOfKherKeep.class)); cards.add(new SetCardInfo("Rohgahh of Kher Keep", 295, Rarity.RARE, mage.cards.r.RohgahhOfKherKeep.class));
cards.add(new SetCardInfo("Rubinia Soulsinger", 296, Rarity.RARE, mage.cards.r.RubiniaSoulsinger.class)); cards.add(new SetCardInfo("Rubinia Soulsinger", 296, Rarity.RARE, mage.cards.r.RubiniaSoulsinger.class));
cards.add(new SetCardInfo("Rust", 49, Rarity.COMMON, mage.cards.r.Rust.class)); cards.add(new SetCardInfo("Rust", 49, Rarity.COMMON, mage.cards.r.Rust.class));
cards.add(new SetCardInfo("Sea Kings' Blessing", 75, Rarity.UNCOMMON, mage.cards.s.SeaKingsBlessing.class)); cards.add(new SetCardInfo("Sea Kings' Blessing", 75, Rarity.UNCOMMON, mage.cards.s.SeaKingsBlessing.class));
@ -227,7 +230,7 @@ public class Legends extends ExpansionSet {
cards.add(new SetCardInfo("Sir Shandlar of Eberyn", 297, Rarity.UNCOMMON, mage.cards.s.SirShandlarOfEberyn.class)); cards.add(new SetCardInfo("Sir Shandlar of Eberyn", 297, Rarity.UNCOMMON, mage.cards.s.SirShandlarOfEberyn.class));
cards.add(new SetCardInfo("Sivitri Scarzam", 298, Rarity.UNCOMMON, mage.cards.s.SivitriScarzam.class)); cards.add(new SetCardInfo("Sivitri Scarzam", 298, Rarity.UNCOMMON, mage.cards.s.SivitriScarzam.class));
cards.add(new SetCardInfo("Sol'kanar the Swamp King", 299, Rarity.RARE, mage.cards.s.SolkanarTheSwampKing.class)); cards.add(new SetCardInfo("Sol'kanar the Swamp King", 299, Rarity.RARE, mage.cards.s.SolkanarTheSwampKing.class));
cards.add(new SetCardInfo("Spectral Cloak", 78, Rarity.UNCOMMON, mage.cards.s.SpectralCloak.class)); cards.add(new SetCardInfo("Spectral Cloak", 78, Rarity.UNCOMMON, mage.cards.s.SpectralCloak.class));
cards.add(new SetCardInfo("Spinal Villain", 161, Rarity.RARE, mage.cards.s.SpinalVillain.class)); cards.add(new SetCardInfo("Spinal Villain", 161, Rarity.RARE, mage.cards.s.SpinalVillain.class));
cards.add(new SetCardInfo("Spirit Link", 206, Rarity.UNCOMMON, mage.cards.s.SpiritLink.class)); cards.add(new SetCardInfo("Spirit Link", 206, Rarity.UNCOMMON, mage.cards.s.SpiritLink.class));
cards.add(new SetCardInfo("Spirit Shackle", 31, Rarity.COMMON, mage.cards.s.SpiritShackle.class)); cards.add(new SetCardInfo("Spirit Shackle", 31, Rarity.COMMON, mage.cards.s.SpiritShackle.class));
@ -237,6 +240,7 @@ public class Legends extends ExpansionSet {
cards.add(new SetCardInfo("Sylvan Library", 121, Rarity.UNCOMMON, mage.cards.s.SylvanLibrary.class)); cards.add(new SetCardInfo("Sylvan Library", 121, Rarity.UNCOMMON, mage.cards.s.SylvanLibrary.class));
cards.add(new SetCardInfo("Sylvan Paradise", 122, Rarity.UNCOMMON, mage.cards.s.SylvanParadise.class)); cards.add(new SetCardInfo("Sylvan Paradise", 122, Rarity.UNCOMMON, mage.cards.s.SylvanParadise.class));
cards.add(new SetCardInfo("Syphon Soul", 32, Rarity.COMMON, mage.cards.s.SyphonSoul.class)); cards.add(new SetCardInfo("Syphon Soul", 32, Rarity.COMMON, mage.cards.s.SyphonSoul.class));
cards.add(new SetCardInfo("Teleport", 80, Rarity.RARE, mage.cards.t.Teleport.class));
cards.add(new SetCardInfo("Tetsuo Umezawa", 302, Rarity.RARE, mage.cards.t.TetsuoUmezawa.class)); cards.add(new SetCardInfo("Tetsuo Umezawa", 302, Rarity.RARE, mage.cards.t.TetsuoUmezawa.class));
cards.add(new SetCardInfo("The Abyss", 34, Rarity.RARE, mage.cards.t.TheAbyss.class)); cards.add(new SetCardInfo("The Abyss", 34, Rarity.RARE, mage.cards.t.TheAbyss.class));
cards.add(new SetCardInfo("The Brute", 164, Rarity.COMMON, mage.cards.t.TheBrute.class)); cards.add(new SetCardInfo("The Brute", 164, Rarity.COMMON, mage.cards.t.TheBrute.class));
@ -244,6 +248,7 @@ public class Legends extends ExpansionSet {
cards.add(new SetCardInfo("The Tabernacle at Pendrell Vale", 252, Rarity.RARE, mage.cards.t.TheTabernacleAtPendrellVale.class)); cards.add(new SetCardInfo("The Tabernacle at Pendrell Vale", 252, Rarity.RARE, mage.cards.t.TheTabernacleAtPendrellVale.class));
cards.add(new SetCardInfo("The Wretched", 35, Rarity.RARE, mage.cards.t.TheWretched.class)); cards.add(new SetCardInfo("The Wretched", 35, Rarity.RARE, mage.cards.t.TheWretched.class));
cards.add(new SetCardInfo("Thunder Spirit", 208, Rarity.RARE, mage.cards.t.ThunderSpirit.class)); cards.add(new SetCardInfo("Thunder Spirit", 208, Rarity.RARE, mage.cards.t.ThunderSpirit.class));
cards.add(new SetCardInfo("Time Elemental", 81, Rarity.RARE, mage.cards.t.TimeElemental.class));
cards.add(new SetCardInfo("Tobias Andrion", 304, Rarity.UNCOMMON, mage.cards.t.TobiasAndrion.class)); cards.add(new SetCardInfo("Tobias Andrion", 304, Rarity.UNCOMMON, mage.cards.t.TobiasAndrion.class));
cards.add(new SetCardInfo("Torsten Von Ursus", 306, Rarity.UNCOMMON, mage.cards.t.TorstenVonUrsus.class)); cards.add(new SetCardInfo("Torsten Von Ursus", 306, Rarity.UNCOMMON, mage.cards.t.TorstenVonUrsus.class));
cards.add(new SetCardInfo("Tor Wauki", 305, Rarity.UNCOMMON, mage.cards.t.TorWauki.class)); cards.add(new SetCardInfo("Tor Wauki", 305, Rarity.UNCOMMON, mage.cards.t.TorWauki.class));
@ -268,7 +273,7 @@ public class Legends extends ExpansionSet {
cards.add(new SetCardInfo("White Mana Battery", 244, Rarity.UNCOMMON, mage.cards.w.WhiteManaBattery.class)); cards.add(new SetCardInfo("White Mana Battery", 244, Rarity.UNCOMMON, mage.cards.w.WhiteManaBattery.class));
cards.add(new SetCardInfo("Willow Satyr", 126, Rarity.RARE, mage.cards.w.WillowSatyr.class)); cards.add(new SetCardInfo("Willow Satyr", 126, Rarity.RARE, mage.cards.w.WillowSatyr.class));
cards.add(new SetCardInfo("Winds of Change", 169, Rarity.UNCOMMON, mage.cards.w.WindsOfChange.class)); cards.add(new SetCardInfo("Winds of Change", 169, Rarity.UNCOMMON, mage.cards.w.WindsOfChange.class));
cards.add(new SetCardInfo("Winter Blast", 127, Rarity.RARE, mage.cards.w.WinterBlast.class)); cards.add(new SetCardInfo("Winter Blast", 127, Rarity.RARE, mage.cards.w.WinterBlast.class));
cards.add(new SetCardInfo("Wolverine Pack", 128, Rarity.COMMON, mage.cards.w.WolverinePack.class)); cards.add(new SetCardInfo("Wolverine Pack", 128, Rarity.COMMON, mage.cards.w.WolverinePack.class));
cards.add(new SetCardInfo("Xira Arien", 310, Rarity.RARE, mage.cards.x.XiraArien.class)); cards.add(new SetCardInfo("Xira Arien", 310, Rarity.RARE, mage.cards.x.XiraArien.class));
cards.add(new SetCardInfo("Zephyr Falcon", 86, Rarity.COMMON, mage.cards.z.ZephyrFalcon.class)); cards.add(new SetCardInfo("Zephyr Falcon", 86, Rarity.COMMON, mage.cards.z.ZephyrFalcon.class));

View file

@ -108,7 +108,7 @@ public class MastersEdition extends ExpansionSet {
cards.add(new SetCardInfo("Dwarven Catapult", 91, Rarity.UNCOMMON, mage.cards.d.DwarvenCatapult.class)); cards.add(new SetCardInfo("Dwarven Catapult", 91, Rarity.UNCOMMON, mage.cards.d.DwarvenCatapult.class));
cards.add(new SetCardInfo("Dwarven Soldier", 92, Rarity.COMMON, DwarvenSoldier.class)); cards.add(new SetCardInfo("Dwarven Soldier", 92, Rarity.COMMON, DwarvenSoldier.class));
cards.add(new SetCardInfo("Eater of the Dead", 67, Rarity.UNCOMMON, mage.cards.e.EaterOfTheDead.class)); cards.add(new SetCardInfo("Eater of the Dead", 67, Rarity.UNCOMMON, mage.cards.e.EaterOfTheDead.class));
cards.add(new SetCardInfo("Elder Land Wurm", 11, Rarity.UNCOMMON, mage.cards.e.ElderLandWurm.class)); cards.add(new SetCardInfo("Elder Land Wurm", 11, Rarity.UNCOMMON, mage.cards.e.ElderLandWurm.class));
cards.add(new SetCardInfo("Erg Raiders", 68, Rarity.COMMON, mage.cards.e.ErgRaiders.class)); cards.add(new SetCardInfo("Erg Raiders", 68, Rarity.COMMON, mage.cards.e.ErgRaiders.class));
cards.add(new SetCardInfo("Eureka", 117, Rarity.RARE, mage.cards.e.Eureka.class)); cards.add(new SetCardInfo("Eureka", 117, Rarity.RARE, mage.cards.e.Eureka.class));
cards.add(new SetCardInfo("Exile", 12, Rarity.COMMON, mage.cards.e.Exile.class)); cards.add(new SetCardInfo("Exile", 12, Rarity.COMMON, mage.cards.e.Exile.class));
@ -183,9 +183,10 @@ public class MastersEdition extends ExpansionSet {
cards.add(new SetCardInfo("Order of the Ebon Hand", 78, Rarity.COMMON, OrderOfTheEbonHand.class)); cards.add(new SetCardInfo("Order of the Ebon Hand", 78, Rarity.COMMON, OrderOfTheEbonHand.class));
cards.add(new SetCardInfo("Oubliette", 79, Rarity.COMMON, Oubliette.class)); cards.add(new SetCardInfo("Oubliette", 79, Rarity.COMMON, Oubliette.class));
cards.add(new SetCardInfo("Paralyze", 80, Rarity.COMMON, mage.cards.p.Paralyze.class)); cards.add(new SetCardInfo("Paralyze", 80, Rarity.COMMON, mage.cards.p.Paralyze.class));
cards.add(new SetCardInfo("Petra Sphinx", 23, Rarity.RARE, mage.cards.p.PetraSphinx.class));
cards.add(new SetCardInfo("Phantom Monster", 43, Rarity.COMMON, mage.cards.p.PhantomMonster.class)); cards.add(new SetCardInfo("Phantom Monster", 43, Rarity.COMMON, mage.cards.p.PhantomMonster.class));
cards.add(new SetCardInfo("Phelddagrif", 150, Rarity.RARE, mage.cards.p.Phelddagrif.class)); cards.add(new SetCardInfo("Phelddagrif", 150, Rarity.RARE, mage.cards.p.Phelddagrif.class));
cards.add(new SetCardInfo("Phyrexian Boon", 81, Rarity.COMMON, mage.cards.p.PhyrexianBoon.class)); cards.add(new SetCardInfo("Phyrexian Boon", 81, Rarity.COMMON, mage.cards.p.PhyrexianBoon.class));
cards.add(new SetCardInfo("Phyrexian War Beast", 162, Rarity.UNCOMMON, PhyrexianWarBeast.class)); cards.add(new SetCardInfo("Phyrexian War Beast", 162, Rarity.UNCOMMON, PhyrexianWarBeast.class));
cards.add(new SetCardInfo("Plains", 181, Rarity.LAND, mage.cards.basiclands.Plains.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Plains", 181, Rarity.LAND, mage.cards.basiclands.Plains.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Plains", 182, Rarity.LAND, mage.cards.basiclands.Plains.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Plains", 182, Rarity.LAND, mage.cards.basiclands.Plains.class, NON_FULL_USE_VARIOUS));
@ -229,6 +230,7 @@ public class MastersEdition extends ExpansionSet {
cards.add(new SetCardInfo("Thrull Champion", 83, Rarity.RARE, mage.cards.t.ThrullChampion.class)); cards.add(new SetCardInfo("Thrull Champion", 83, Rarity.RARE, mage.cards.t.ThrullChampion.class));
cards.add(new SetCardInfo("Thrull Retainer", 84, Rarity.COMMON, mage.cards.t.ThrullRetainer.class)); cards.add(new SetCardInfo("Thrull Retainer", 84, Rarity.COMMON, mage.cards.t.ThrullRetainer.class));
cards.add(new SetCardInfo("Thunder Spirit", 27, Rarity.UNCOMMON, mage.cards.t.ThunderSpirit.class)); cards.add(new SetCardInfo("Thunder Spirit", 27, Rarity.UNCOMMON, mage.cards.t.ThunderSpirit.class));
cards.add(new SetCardInfo("Time Elemental", 53, Rarity.RARE, mage.cards.t.TimeElemental.class));
cards.add(new SetCardInfo("Tivadar's Crusade", 28, Rarity.UNCOMMON, mage.cards.t.TivadarsCrusade.class)); cards.add(new SetCardInfo("Tivadar's Crusade", 28, Rarity.UNCOMMON, mage.cards.t.TivadarsCrusade.class));
cards.add(new SetCardInfo("Tornado", 136, Rarity.RARE, mage.cards.t.Tornado.class)); cards.add(new SetCardInfo("Tornado", 136, Rarity.RARE, mage.cards.t.Tornado.class));
cards.add(new SetCardInfo("Urza's Bauble", 170, Rarity.UNCOMMON, mage.cards.u.UrzasBauble.class)); cards.add(new SetCardInfo("Urza's Bauble", 170, Rarity.UNCOMMON, mage.cards.u.UrzasBauble.class));
@ -239,7 +241,7 @@ public class MastersEdition extends ExpansionSet {
cards.add(new SetCardInfo("Walking Wall", 172, Rarity.UNCOMMON, mage.cards.w.WalkingWall.class)); cards.add(new SetCardInfo("Walking Wall", 172, Rarity.UNCOMMON, mage.cards.w.WalkingWall.class));
cards.add(new SetCardInfo("Wanderlust", 137, Rarity.COMMON, mage.cards.w.Wanderlust.class)); cards.add(new SetCardInfo("Wanderlust", 137, Rarity.COMMON, mage.cards.w.Wanderlust.class));
cards.add(new SetCardInfo("Winds of Change", 111, Rarity.UNCOMMON, mage.cards.w.WindsOfChange.class)); cards.add(new SetCardInfo("Winds of Change", 111, Rarity.UNCOMMON, mage.cards.w.WindsOfChange.class));
cards.add(new SetCardInfo("Winter Blast", 138, Rarity.UNCOMMON, mage.cards.w.WinterBlast.class)); cards.add(new SetCardInfo("Winter Blast", 138, Rarity.UNCOMMON, mage.cards.w.WinterBlast.class));
cards.add(new SetCardInfo("Winter Orb", 173, Rarity.RARE, mage.cards.w.WinterOrb.class)); cards.add(new SetCardInfo("Winter Orb", 173, Rarity.RARE, mage.cards.w.WinterOrb.class));
cards.add(new SetCardInfo("Wyluli Wolf", 139, Rarity.COMMON, mage.cards.w.WyluliWolf.class)); cards.add(new SetCardInfo("Wyluli Wolf", 139, Rarity.COMMON, mage.cards.w.WyluliWolf.class));
cards.add(new SetCardInfo("Yavimaya Ants", 140, Rarity.UNCOMMON, mage.cards.y.YavimayaAnts.class)); cards.add(new SetCardInfo("Yavimaya Ants", 140, Rarity.UNCOMMON, mage.cards.y.YavimayaAnts.class));

View file

@ -180,6 +180,7 @@ public class MastersEditionII extends ExpansionSet {
cards.add(new SetCardInfo("Mesmeric Trance", 55, Rarity.RARE, mage.cards.m.MesmericTrance.class)); cards.add(new SetCardInfo("Mesmeric Trance", 55, Rarity.RARE, mage.cards.m.MesmericTrance.class));
cards.add(new SetCardInfo("Meteor Shower", 135, Rarity.COMMON, mage.cards.m.MeteorShower.class)); cards.add(new SetCardInfo("Meteor Shower", 135, Rarity.COMMON, mage.cards.m.MeteorShower.class));
cards.add(new SetCardInfo("Minion of Leshrac", 104, Rarity.RARE, mage.cards.m.MinionOfLeshrac.class)); cards.add(new SetCardInfo("Minion of Leshrac", 104, Rarity.RARE, mage.cards.m.MinionOfLeshrac.class));
cards.add(new SetCardInfo("Misinformation", 105, Rarity.UNCOMMON, mage.cards.m.Misinformation.class));
cards.add(new SetCardInfo("Mudslide", 136, Rarity.RARE, mage.cards.m.Mudslide.class)); cards.add(new SetCardInfo("Mudslide", 136, Rarity.RARE, mage.cards.m.Mudslide.class));
cards.add(new SetCardInfo("Narwhal", 57, Rarity.UNCOMMON, mage.cards.n.Narwhal.class)); cards.add(new SetCardInfo("Narwhal", 57, Rarity.UNCOMMON, mage.cards.n.Narwhal.class));
cards.add(new SetCardInfo("Nature's Wrath", 172, Rarity.RARE, mage.cards.n.NaturesWrath.class)); cards.add(new SetCardInfo("Nature's Wrath", 172, Rarity.RARE, mage.cards.n.NaturesWrath.class));
@ -233,6 +234,7 @@ public class MastersEditionII extends ExpansionSet {
cards.add(new SetCardInfo("Songs of the Damned", 110, Rarity.COMMON, mage.cards.s.SongsOfTheDamned.class)); cards.add(new SetCardInfo("Songs of the Damned", 110, Rarity.COMMON, mage.cards.s.SongsOfTheDamned.class));
cards.add(new SetCardInfo("Soul Exchange", 111, Rarity.UNCOMMON, mage.cards.s.SoulExchange.class)); cards.add(new SetCardInfo("Soul Exchange", 111, Rarity.UNCOMMON, mage.cards.s.SoulExchange.class));
cards.add(new SetCardInfo("Soul Kiss", 112, Rarity.UNCOMMON, mage.cards.s.SoulKiss.class)); cards.add(new SetCardInfo("Soul Kiss", 112, Rarity.UNCOMMON, mage.cards.s.SoulKiss.class));
cards.add(new SetCardInfo("Spore Cloud", 176, Rarity.UNCOMMON, mage.cards.s.SporeCloud.class));
cards.add(new SetCardInfo("Spore Flower", 177, Rarity.UNCOMMON, mage.cards.s.SporeFlower.class)); cards.add(new SetCardInfo("Spore Flower", 177, Rarity.UNCOMMON, mage.cards.s.SporeFlower.class));
cards.add(new SetCardInfo("Stampede", 178, Rarity.UNCOMMON, mage.cards.s.Stampede.class)); cards.add(new SetCardInfo("Stampede", 178, Rarity.UNCOMMON, mage.cards.s.Stampede.class));
cards.add(new SetCardInfo("Stonehands", 151, Rarity.COMMON, mage.cards.s.Stonehands.class)); cards.add(new SetCardInfo("Stonehands", 151, Rarity.COMMON, mage.cards.s.Stonehands.class));

View file

@ -100,10 +100,10 @@ public class MastersEditionIII extends ExpansionSet {
cards.add(new SetCardInfo("Desperate Charge", 63, Rarity.COMMON, mage.cards.d.DesperateCharge.class)); cards.add(new SetCardInfo("Desperate Charge", 63, Rarity.COMMON, mage.cards.d.DesperateCharge.class));
cards.add(new SetCardInfo("Didgeridoo", 194, Rarity.UNCOMMON, mage.cards.d.Didgeridoo.class)); cards.add(new SetCardInfo("Didgeridoo", 194, Rarity.UNCOMMON, mage.cards.d.Didgeridoo.class));
cards.add(new SetCardInfo("Disenchant", 7, Rarity.COMMON, mage.cards.d.Disenchant.class)); cards.add(new SetCardInfo("Disenchant", 7, Rarity.COMMON, mage.cards.d.Disenchant.class));
cards.add(new SetCardInfo("Disharmony", 95, Rarity.UNCOMMON, mage.cards.d.Disharmony.class)); cards.add(new SetCardInfo("Disharmony", 95, Rarity.UNCOMMON, mage.cards.d.Disharmony.class));
cards.add(new SetCardInfo("Divine Intervention", 8, Rarity.RARE, mage.cards.d.DivineIntervention.class)); cards.add(new SetCardInfo("Divine Intervention", 8, Rarity.RARE, mage.cards.d.DivineIntervention.class));
cards.add(new SetCardInfo("Dong Zhou, the Tyrant", 96, Rarity.RARE, mage.cards.d.DongZhouTheTyrant.class)); cards.add(new SetCardInfo("Dong Zhou, the Tyrant", 96, Rarity.RARE, mage.cards.d.DongZhouTheTyrant.class));
cards.add(new SetCardInfo("Eightfold Maze", 9, Rarity.UNCOMMON, mage.cards.e.EightfoldMaze.class)); cards.add(new SetCardInfo("Eightfold Maze", 9, Rarity.UNCOMMON, mage.cards.e.EightfoldMaze.class));
cards.add(new SetCardInfo("Elves of Deep Shadow", 116, Rarity.COMMON, mage.cards.e.ElvesOfDeepShadow.class)); cards.add(new SetCardInfo("Elves of Deep Shadow", 116, Rarity.COMMON, mage.cards.e.ElvesOfDeepShadow.class));
cards.add(new SetCardInfo("Evil Presence", 64, Rarity.COMMON, mage.cards.e.EvilPresence.class)); cards.add(new SetCardInfo("Evil Presence", 64, Rarity.COMMON, mage.cards.e.EvilPresence.class));
cards.add(new SetCardInfo("Exorcist", 10, Rarity.UNCOMMON, mage.cards.e.Exorcist.class)); cards.add(new SetCardInfo("Exorcist", 10, Rarity.UNCOMMON, mage.cards.e.Exorcist.class));
@ -130,7 +130,7 @@ public class MastersEditionIII extends ExpansionSet {
cards.add(new SetCardInfo("Guan Yu's 1,000-Li March", 13, Rarity.RARE, mage.cards.g.GuanYus1000LiMarch.class)); cards.add(new SetCardInfo("Guan Yu's 1,000-Li March", 13, Rarity.RARE, mage.cards.g.GuanYus1000LiMarch.class));
cards.add(new SetCardInfo("Guan Yu, Sainted Warrior", 12, Rarity.UNCOMMON, mage.cards.g.GuanYuSaintedWarrior.class)); cards.add(new SetCardInfo("Guan Yu, Sainted Warrior", 12, Rarity.UNCOMMON, mage.cards.g.GuanYuSaintedWarrior.class));
cards.add(new SetCardInfo("Gwendlyn Di Corci", 149, Rarity.RARE, mage.cards.g.GwendlynDiCorci.class)); cards.add(new SetCardInfo("Gwendlyn Di Corci", 149, Rarity.RARE, mage.cards.g.GwendlynDiCorci.class));
cards.add(new SetCardInfo("Hammerheim", 207, Rarity.UNCOMMON, mage.cards.h.Hammerheim.class)); cards.add(new SetCardInfo("Hammerheim", 207, Rarity.UNCOMMON, mage.cards.h.Hammerheim.class));
cards.add(new SetCardInfo("Hazezon Tamar", 151, Rarity.RARE, mage.cards.h.HazezonTamar.class)); cards.add(new SetCardInfo("Hazezon Tamar", 151, Rarity.RARE, mage.cards.h.HazezonTamar.class));
cards.add(new SetCardInfo("Heal", 14, Rarity.COMMON, mage.cards.h.Heal.class)); cards.add(new SetCardInfo("Heal", 14, Rarity.COMMON, mage.cards.h.Heal.class));
cards.add(new SetCardInfo("Hellfire", 70, Rarity.RARE, mage.cards.h.Hellfire.class)); cards.add(new SetCardInfo("Hellfire", 70, Rarity.RARE, mage.cards.h.Hellfire.class));
@ -156,7 +156,7 @@ public class MastersEditionIII extends ExpansionSet {
cards.add(new SetCardInfo("Kobolds of Kher Keep", 107, Rarity.COMMON, mage.cards.k.KoboldsOfKherKeep.class)); cards.add(new SetCardInfo("Kobolds of Kher Keep", 107, Rarity.COMMON, mage.cards.k.KoboldsOfKherKeep.class));
cards.add(new SetCardInfo("Kobold Taskmaster", 106, Rarity.COMMON, mage.cards.k.KoboldTaskmaster.class)); cards.add(new SetCardInfo("Kobold Taskmaster", 106, Rarity.COMMON, mage.cards.k.KoboldTaskmaster.class));
cards.add(new SetCardInfo("Kongming, 'Sleeping Dragon'", 16, Rarity.RARE, mage.cards.k.KongmingSleepingDragon.class)); cards.add(new SetCardInfo("Kongming, 'Sleeping Dragon'", 16, Rarity.RARE, mage.cards.k.KongmingSleepingDragon.class));
cards.add(new SetCardInfo("Labyrinth Minotaur", 39, Rarity.COMMON, mage.cards.l.LabyrinthMinotaur.class)); cards.add(new SetCardInfo("Labyrinth Minotaur", 39, Rarity.COMMON, mage.cards.l.LabyrinthMinotaur.class));
cards.add(new SetCardInfo("Lady Caleria", 157, Rarity.UNCOMMON, mage.cards.l.LadyCaleria.class)); cards.add(new SetCardInfo("Lady Caleria", 157, Rarity.UNCOMMON, mage.cards.l.LadyCaleria.class));
cards.add(new SetCardInfo("Lady Evangela", 158, Rarity.UNCOMMON, mage.cards.l.LadyEvangela.class)); cards.add(new SetCardInfo("Lady Evangela", 158, Rarity.UNCOMMON, mage.cards.l.LadyEvangela.class));
cards.add(new SetCardInfo("Lady Orca", 159, Rarity.COMMON, mage.cards.l.LadyOrca.class)); cards.add(new SetCardInfo("Lady Orca", 159, Rarity.COMMON, mage.cards.l.LadyOrca.class));
@ -183,6 +183,7 @@ public class MastersEditionIII extends ExpansionSet {
cards.add(new SetCardInfo("Mountain", 227, Rarity.LAND, mage.cards.basiclands.Mountain.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Mountain", 227, Rarity.LAND, mage.cards.basiclands.Mountain.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Nether Void", 73, Rarity.RARE, mage.cards.n.NetherVoid.class)); cards.add(new SetCardInfo("Nether Void", 73, Rarity.RARE, mage.cards.n.NetherVoid.class));
cards.add(new SetCardInfo("Nicol Bolas", 163, Rarity.RARE, mage.cards.n.NicolBolas.class)); cards.add(new SetCardInfo("Nicol Bolas", 163, Rarity.RARE, mage.cards.n.NicolBolas.class));
cards.add(new SetCardInfo("Nova Pentacle", 200, Rarity.RARE, mage.cards.n.NovaPentacle.class));
cards.add(new SetCardInfo("Old Man of the Sea", 45, Rarity.RARE, mage.cards.o.OldManOfTheSea.class)); cards.add(new SetCardInfo("Old Man of the Sea", 45, Rarity.RARE, mage.cards.o.OldManOfTheSea.class));
cards.add(new SetCardInfo("Palladia-Mors", 164, Rarity.RARE, mage.cards.p.PalladiaMors.class)); cards.add(new SetCardInfo("Palladia-Mors", 164, Rarity.RARE, mage.cards.p.PalladiaMors.class));
cards.add(new SetCardInfo("Pavel Maliki", 165, Rarity.UNCOMMON, mage.cards.p.PavelMaliki.class)); cards.add(new SetCardInfo("Pavel Maliki", 165, Rarity.UNCOMMON, mage.cards.p.PavelMaliki.class));
@ -204,7 +205,7 @@ public class MastersEditionIII extends ExpansionSet {
cards.add(new SetCardInfo("Reveka, Wizard Savant", 49, Rarity.UNCOMMON, mage.cards.r.RevekaWizardSavant.class)); cards.add(new SetCardInfo("Reveka, Wizard Savant", 49, Rarity.UNCOMMON, mage.cards.r.RevekaWizardSavant.class));
cards.add(new SetCardInfo("Riding the Dilu Horse", 131, Rarity.UNCOMMON, mage.cards.r.RidingTheDiluHorse.class)); cards.add(new SetCardInfo("Riding the Dilu Horse", 131, Rarity.UNCOMMON, mage.cards.r.RidingTheDiluHorse.class));
cards.add(new SetCardInfo("Riven Turnbull", 171, Rarity.UNCOMMON, mage.cards.r.RivenTurnbull.class)); cards.add(new SetCardInfo("Riven Turnbull", 171, Rarity.UNCOMMON, mage.cards.r.RivenTurnbull.class));
cards.add(new SetCardInfo("Rohgahh of Kher Keep", 172, Rarity.RARE, mage.cards.r.RohgahhOfKherKeep.class)); cards.add(new SetCardInfo("Rohgahh of Kher Keep", 172, Rarity.RARE, mage.cards.r.RohgahhOfKherKeep.class));
cards.add(new SetCardInfo("Rolling Earthquake", 110, Rarity.RARE, mage.cards.r.RollingEarthquake.class)); cards.add(new SetCardInfo("Rolling Earthquake", 110, Rarity.RARE, mage.cards.r.RollingEarthquake.class));
cards.add(new SetCardInfo("Rubinia Soulsinger", 173, Rarity.RARE, mage.cards.r.RubiniaSoulsinger.class)); cards.add(new SetCardInfo("Rubinia Soulsinger", 173, Rarity.RARE, mage.cards.r.RubiniaSoulsinger.class));
cards.add(new SetCardInfo("Scrubland", 210, Rarity.RARE, mage.cards.s.Scrubland.class)); cards.add(new SetCardInfo("Scrubland", 210, Rarity.RARE, mage.cards.s.Scrubland.class));

View file

@ -158,6 +158,7 @@ public class MercadianMasques extends ExpansionSet {
cards.add(new SetCardInfo("Fresh Volunteers", 20, Rarity.COMMON, mage.cards.f.FreshVolunteers.class)); cards.add(new SetCardInfo("Fresh Volunteers", 20, Rarity.COMMON, mage.cards.f.FreshVolunteers.class));
cards.add(new SetCardInfo("Furious Assault", 191, Rarity.COMMON, mage.cards.f.FuriousAssault.class)); cards.add(new SetCardInfo("Furious Assault", 191, Rarity.COMMON, mage.cards.f.FuriousAssault.class));
cards.add(new SetCardInfo("Game Preserve", 248, Rarity.RARE, mage.cards.g.GamePreserve.class)); cards.add(new SetCardInfo("Game Preserve", 248, Rarity.RARE, mage.cards.g.GamePreserve.class));
cards.add(new SetCardInfo("General's Regalia", 295, Rarity.RARE, mage.cards.g.GeneralsRegalia.class));
cards.add(new SetCardInfo("Gerrard's Irregulars", 192, Rarity.COMMON, mage.cards.g.GerrardsIrregulars.class)); cards.add(new SetCardInfo("Gerrard's Irregulars", 192, Rarity.COMMON, mage.cards.g.GerrardsIrregulars.class));
cards.add(new SetCardInfo("Ghoul's Feast", 137, Rarity.UNCOMMON, mage.cards.g.GhoulsFeast.class)); cards.add(new SetCardInfo("Ghoul's Feast", 137, Rarity.UNCOMMON, mage.cards.g.GhoulsFeast.class));
cards.add(new SetCardInfo("Giant Caterpillar", 249, Rarity.COMMON, mage.cards.g.GiantCaterpillar.class)); cards.add(new SetCardInfo("Giant Caterpillar", 249, Rarity.COMMON, mage.cards.g.GiantCaterpillar.class));
@ -329,7 +330,7 @@ public class MercadianMasques extends ExpansionSet {
cards.add(new SetCardInfo("Tidal Bore", 109, Rarity.COMMON, mage.cards.t.TidalBore.class)); cards.add(new SetCardInfo("Tidal Bore", 109, Rarity.COMMON, mage.cards.t.TidalBore.class));
cards.add(new SetCardInfo("Tidal Kraken", 110, Rarity.RARE, mage.cards.t.TidalKraken.class)); cards.add(new SetCardInfo("Tidal Kraken", 110, Rarity.RARE, mage.cards.t.TidalKraken.class));
cards.add(new SetCardInfo("Tiger Claws", 279, Rarity.COMMON, mage.cards.t.TigerClaws.class)); cards.add(new SetCardInfo("Tiger Claws", 279, Rarity.COMMON, mage.cards.t.TigerClaws.class));
cards.add(new SetCardInfo("Timid Drake", 111, Rarity.UNCOMMON, mage.cards.t.TimidDrake.class)); cards.add(new SetCardInfo("Timid Drake", 111, Rarity.UNCOMMON, mage.cards.t.TimidDrake.class));
cards.add(new SetCardInfo("Tonic Peddler", 54, Rarity.UNCOMMON, mage.cards.t.TonicPeddler.class)); cards.add(new SetCardInfo("Tonic Peddler", 54, Rarity.UNCOMMON, mage.cards.t.TonicPeddler.class));
cards.add(new SetCardInfo("Tooth of Ramos", 313, Rarity.RARE, mage.cards.t.ToothOfRamos.class)); cards.add(new SetCardInfo("Tooth of Ramos", 313, Rarity.RARE, mage.cards.t.ToothOfRamos.class));
cards.add(new SetCardInfo("Tower of the Magistrate", 330, Rarity.RARE, mage.cards.t.TowerOfTheMagistrate.class)); cards.add(new SetCardInfo("Tower of the Magistrate", 330, Rarity.RARE, mage.cards.t.TowerOfTheMagistrate.class));

View file

@ -145,6 +145,7 @@ public class Onslaught extends ExpansionSet {
cards.add(new SetCardInfo("Glory Seeker", 31, Rarity.COMMON, mage.cards.g.GlorySeeker.class)); cards.add(new SetCardInfo("Glory Seeker", 31, Rarity.COMMON, mage.cards.g.GlorySeeker.class));
cards.add(new SetCardInfo("Gluttonous Zombie", 151, Rarity.UNCOMMON, mage.cards.g.GluttonousZombie.class)); cards.add(new SetCardInfo("Gluttonous Zombie", 151, Rarity.UNCOMMON, mage.cards.g.GluttonousZombie.class));
cards.add(new SetCardInfo("Goblin Burrows", 318, Rarity.UNCOMMON, mage.cards.g.GoblinBurrows.class)); cards.add(new SetCardInfo("Goblin Burrows", 318, Rarity.UNCOMMON, mage.cards.g.GoblinBurrows.class));
cards.add(new SetCardInfo("Goblin Machinist", 204, Rarity.UNCOMMON, mage.cards.g.GoblinMachinist.class));
cards.add(new SetCardInfo("Goblin Piledriver", 205, Rarity.RARE, mage.cards.g.GoblinPiledriver.class)); cards.add(new SetCardInfo("Goblin Piledriver", 205, Rarity.RARE, mage.cards.g.GoblinPiledriver.class));
cards.add(new SetCardInfo("Goblin Pyromancer", 206, Rarity.RARE, mage.cards.g.GoblinPyromancer.class)); cards.add(new SetCardInfo("Goblin Pyromancer", 206, Rarity.RARE, mage.cards.g.GoblinPyromancer.class));
cards.add(new SetCardInfo("Goblin Sharpshooter", 207, Rarity.RARE, mage.cards.g.GoblinSharpshooter.class)); cards.add(new SetCardInfo("Goblin Sharpshooter", 207, Rarity.RARE, mage.cards.g.GoblinSharpshooter.class));
@ -260,6 +261,7 @@ public class Onslaught extends ExpansionSet {
cards.add(new SetCardInfo("Secluded Steppe", 324, Rarity.COMMON, mage.cards.s.SecludedSteppe.class)); cards.add(new SetCardInfo("Secluded Steppe", 324, Rarity.COMMON, mage.cards.s.SecludedSteppe.class));
cards.add(new SetCardInfo("Serpentine Basilisk", 280, Rarity.UNCOMMON, mage.cards.s.SerpentineBasilisk.class)); cards.add(new SetCardInfo("Serpentine Basilisk", 280, Rarity.UNCOMMON, mage.cards.s.SerpentineBasilisk.class));
cards.add(new SetCardInfo("Severed Legion", 166, Rarity.COMMON, mage.cards.s.SeveredLegion.class)); cards.add(new SetCardInfo("Severed Legion", 166, Rarity.COMMON, mage.cards.s.SeveredLegion.class));
cards.add(new SetCardInfo("Shade's Breath", 167, Rarity.UNCOMMON, mage.cards.s.ShadesBreath.class));
cards.add(new SetCardInfo("Shaleskin Bruiser", 226, Rarity.UNCOMMON, mage.cards.s.ShaleskinBruiser.class)); cards.add(new SetCardInfo("Shaleskin Bruiser", 226, Rarity.UNCOMMON, mage.cards.s.ShaleskinBruiser.class));
cards.add(new SetCardInfo("Shared Triumph", 53, Rarity.RARE, mage.cards.s.SharedTriumph.class)); cards.add(new SetCardInfo("Shared Triumph", 53, Rarity.RARE, mage.cards.s.SharedTriumph.class));
cards.add(new SetCardInfo("Shepherd of Rot", 168, Rarity.COMMON, mage.cards.s.ShepherdOfRot.class)); cards.add(new SetCardInfo("Shepherd of Rot", 168, Rarity.COMMON, mage.cards.s.ShepherdOfRot.class));

View file

@ -78,6 +78,7 @@ public class Visions extends ExpansionSet {
cards.add(new SetCardInfo("Diamond Kaleidoscope", 143, Rarity.RARE, mage.cards.d.DiamondKaleidoscope.class)); cards.add(new SetCardInfo("Diamond Kaleidoscope", 143, Rarity.RARE, mage.cards.d.DiamondKaleidoscope.class));
cards.add(new SetCardInfo("Dormant Volcano", 161, Rarity.UNCOMMON, mage.cards.d.DormantVolcano.class)); cards.add(new SetCardInfo("Dormant Volcano", 161, Rarity.UNCOMMON, mage.cards.d.DormantVolcano.class));
cards.add(new SetCardInfo("Dragon Mask", 144, Rarity.UNCOMMON, mage.cards.d.DragonMask.class)); cards.add(new SetCardInfo("Dragon Mask", 144, Rarity.UNCOMMON, mage.cards.d.DragonMask.class));
cards.add(new SetCardInfo("Dream Tides", 31, Rarity.UNCOMMON, mage.cards.d.DreamTides.class));
cards.add(new SetCardInfo("Dwarven Vigilantes", 77, Rarity.COMMON, mage.cards.d.DwarvenVigilantes.class)); cards.add(new SetCardInfo("Dwarven Vigilantes", 77, Rarity.COMMON, mage.cards.d.DwarvenVigilantes.class));
cards.add(new SetCardInfo("Elephant Grass", 54, Rarity.UNCOMMON, mage.cards.e.ElephantGrass.class)); cards.add(new SetCardInfo("Elephant Grass", 54, Rarity.UNCOMMON, mage.cards.e.ElephantGrass.class));
cards.add(new SetCardInfo("Elven Cache", 55, Rarity.COMMON, mage.cards.e.ElvenCache.class)); cards.add(new SetCardInfo("Elven Cache", 55, Rarity.COMMON, mage.cards.e.ElvenCache.class));
@ -147,7 +148,7 @@ public class Visions extends ExpansionSet {
cards.add(new SetCardInfo("Resistance Fighter", 118, Rarity.COMMON, mage.cards.r.ResistanceFighter.class)); cards.add(new SetCardInfo("Resistance Fighter", 118, Rarity.COMMON, mage.cards.r.ResistanceFighter.class));
cards.add(new SetCardInfo("Retribution of the Meek", 119, Rarity.RARE, mage.cards.r.RetributionOfTheMeek.class)); cards.add(new SetCardInfo("Retribution of the Meek", 119, Rarity.RARE, mage.cards.r.RetributionOfTheMeek.class));
cards.add(new SetCardInfo("Righteous Aura", 120, Rarity.COMMON, mage.cards.r.RighteousAura.class)); cards.add(new SetCardInfo("Righteous Aura", 120, Rarity.COMMON, mage.cards.r.RighteousAura.class));
cards.add(new SetCardInfo("Righteous War", 134, Rarity.RARE, mage.cards.r.RighteousWar.class)); cards.add(new SetCardInfo("Righteous War", 134, Rarity.RARE, mage.cards.r.RighteousWar.class));
cards.add(new SetCardInfo("River Boa", 68, Rarity.COMMON, mage.cards.r.RiverBoa.class)); cards.add(new SetCardInfo("River Boa", 68, Rarity.COMMON, mage.cards.r.RiverBoa.class));
cards.add(new SetCardInfo("Rock Slide", 92, Rarity.COMMON, mage.cards.r.RockSlide.class)); cards.add(new SetCardInfo("Rock Slide", 92, Rarity.COMMON, mage.cards.r.RockSlide.class));
cards.add(new SetCardInfo("Rowen", 69, Rarity.RARE, mage.cards.r.Rowen.class)); cards.add(new SetCardInfo("Rowen", 69, Rarity.RARE, mage.cards.r.Rowen.class));
@ -162,7 +163,7 @@ public class Visions extends ExpansionSet {
cards.add(new SetCardInfo("Spitting Drake", 95, Rarity.UNCOMMON, mage.cards.s.SpittingDrake.class)); cards.add(new SetCardInfo("Spitting Drake", 95, Rarity.UNCOMMON, mage.cards.s.SpittingDrake.class));
cards.add(new SetCardInfo("Squandered Resources", 137, Rarity.RARE, mage.cards.s.SquanderedResources.class)); cards.add(new SetCardInfo("Squandered Resources", 137, Rarity.RARE, mage.cards.s.SquanderedResources.class));
cards.add(new SetCardInfo("Stampeding Wildebeests", 71, Rarity.UNCOMMON, mage.cards.s.StampedingWildebeests.class)); cards.add(new SetCardInfo("Stampeding Wildebeests", 71, Rarity.UNCOMMON, mage.cards.s.StampedingWildebeests.class));
cards.add(new SetCardInfo("Suleiman's Legacy", 138, Rarity.RARE, mage.cards.s.SuleimansLegacy.class)); cards.add(new SetCardInfo("Suleiman's Legacy", 138, Rarity.RARE, mage.cards.s.SuleimansLegacy.class));
cards.add(new SetCardInfo("Summer Bloom", 72, Rarity.UNCOMMON, mage.cards.s.SummerBloom.class)); cards.add(new SetCardInfo("Summer Bloom", 72, Rarity.UNCOMMON, mage.cards.s.SummerBloom.class));
cards.add(new SetCardInfo("Sun Clasp", 121, Rarity.COMMON, mage.cards.s.SunClasp.class)); cards.add(new SetCardInfo("Sun Clasp", 121, Rarity.COMMON, mage.cards.s.SunClasp.class));
cards.add(new SetCardInfo("Suq'Ata Assassin", 19, Rarity.UNCOMMON, mage.cards.s.SuqAtaAssassin.class)); cards.add(new SetCardInfo("Suq'Ata Assassin", 19, Rarity.UNCOMMON, mage.cards.s.SuqAtaAssassin.class));

View file

@ -1,373 +1,373 @@
/* /*
* Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved.
* *
* Redistribution and use in source and binary forms, with or without modification, are * Redistribution and use in source and binary forms, with or without modification, are
* permitted provided that the following conditions are met: * permitted provided that the following conditions are met:
* *
* 1. Redistributions of source code must retain the above copyright notice, this list of * 1. Redistributions of source code must retain the above copyright notice, this list of
* conditions and the following disclaimer. * conditions and the following disclaimer.
* *
* 2. Redistributions in binary form must reproduce the above copyright notice, this list * 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 * of conditions and the following disclaimer in the documentation and/or other materials
* provided with the distribution. * provided with the distribution.
* *
* THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED * 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 * 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 * 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 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 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 * 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 * 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 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
* *
* The views and conclusions contained in the software and documentation are those of the * 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 * authors and should not be interpreted as representing official policies, either expressed
* or implied, of BetaSteward_at_googlemail.com. * or implied, of BetaSteward_at_googlemail.com.
*/ */
package org.mage.test.multiplayer; package org.mage.test.multiplayer;
import java.io.FileNotFoundException; import java.io.FileNotFoundException;
import mage.constants.MultiplayerAttackOption; import mage.constants.MultiplayerAttackOption;
import mage.constants.PhaseStep; import mage.constants.PhaseStep;
import mage.constants.RangeOfInfluence; import mage.constants.RangeOfInfluence;
import mage.constants.Zone; import mage.constants.Zone;
import mage.counters.CounterType; import mage.counters.CounterType;
import mage.game.FreeForAll; import mage.game.FreeForAll;
import mage.game.Game; import mage.game.Game;
import mage.game.GameException; import mage.game.GameException;
import mage.game.permanent.Permanent; import mage.game.permanent.Permanent;
import org.junit.Assert; import org.junit.Assert;
import org.junit.Test; import org.junit.Test;
import org.mage.test.serverside.base.CardTestMultiPlayerBase; import org.mage.test.serverside.base.CardTestMultiPlayerBase;
/** /**
* *
* @author LevelX2 * @author LevelX2
*/ */
public class PlayerLeftGameRange1Test extends CardTestMultiPlayerBase { public class PlayerLeftGameRange1Test extends CardTestMultiPlayerBase {
@Override @Override
protected Game createNewGameAndPlayers() throws GameException, FileNotFoundException { protected Game createNewGameAndPlayers() throws GameException, FileNotFoundException {
// Start Life = 2 // Start Life = 2
Game game = new FreeForAll(MultiplayerAttackOption.MULTIPLE, RangeOfInfluence.ONE, 0, 2); Game game = new FreeForAll(MultiplayerAttackOption.MULTIPLE, RangeOfInfluence.ONE, 0, 2);
// Player order: A -> D -> C -> B // Player order: A -> D -> C -> B
playerA = createPlayer(game, playerA, "PlayerA"); playerA = createPlayer(game, playerA, "PlayerA");
playerB = createPlayer(game, playerB, "PlayerB"); playerB = createPlayer(game, playerB, "PlayerB");
playerC = createPlayer(game, playerC, "PlayerC"); playerC = createPlayer(game, playerC, "PlayerC");
playerD = createPlayer(game, playerD, "PlayerD"); playerD = createPlayer(game, playerD, "PlayerD");
return game; return game;
} }
/** /**
* Tests Enchantment to control other permanent * Tests Enchantment to control other permanent
*/ */
@Test @Test
public void TestControlledByEnchantment() { public void TestControlledByEnchantment() {
addCard(Zone.BATTLEFIELD, playerB, "Rootwater Commando"); addCard(Zone.BATTLEFIELD, playerB, "Rootwater Commando");
addCard(Zone.BATTLEFIELD, playerA, "Island", 4); addCard(Zone.BATTLEFIELD, playerA, "Island", 4);
// Enchant creature // Enchant creature
// You control enchanted creature. // You control enchanted creature.
addCard(Zone.HAND, playerA, "Control Magic"); addCard(Zone.HAND, playerA, "Control Magic");
addCard(Zone.BATTLEFIELD, playerC, "Silvercoat Lion"); addCard(Zone.BATTLEFIELD, playerC, "Silvercoat Lion");
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Control Magic", "Rootwater Commando"); castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Control Magic", "Rootwater Commando");
attack(3, playerC, "Silvercoat Lion", playerB); attack(3, playerC, "Silvercoat Lion", playerB);
setStopAt(3, PhaseStep.POSTCOMBAT_MAIN); setStopAt(3, PhaseStep.POSTCOMBAT_MAIN);
execute(); execute();
assertLife(playerB, 0); assertLife(playerB, 0);
assertPermanentCount(playerB, 0); assertPermanentCount(playerB, 0);
assertPermanentCount(playerA, "Rootwater Commando", 0); assertPermanentCount(playerA, "Rootwater Commando", 0);
assertGraveyardCount(playerA, "Control Magic", 1); assertGraveyardCount(playerA, "Control Magic", 1);
} }
/** /**
* Tests Sorcery to control other players permanent * Tests Sorcery to control other players permanent
*/ */
@Test @Test
public void TestControlledBySorcery() { public void TestControlledBySorcery() {
addCard(Zone.BATTLEFIELD, playerB, "Rootwater Commando"); addCard(Zone.BATTLEFIELD, playerB, "Rootwater Commando");
addCard(Zone.BATTLEFIELD, playerA, "Island", 4); addCard(Zone.BATTLEFIELD, playerA, "Island", 4);
// Exchange control of target artifact or creature and another target permanent that shares one of those types with it. // Exchange control of target artifact or creature and another target permanent that shares one of those types with it.
// (This effect lasts indefinitely.) // (This effect lasts indefinitely.)
addCard(Zone.HAND, playerA, "Legerdemain"); // Sorcery addCard(Zone.HAND, playerA, "Legerdemain"); // Sorcery
addCard(Zone.BATTLEFIELD, playerA, "Wall of Air"); addCard(Zone.BATTLEFIELD, playerA, "Wall of Air");
addCard(Zone.BATTLEFIELD, playerC, "Silvercoat Lion"); addCard(Zone.BATTLEFIELD, playerC, "Silvercoat Lion");
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Legerdemain", "Rootwater Commando^Wall of Air"); castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Legerdemain", "Rootwater Commando^Wall of Air");
attack(3, playerC, "Silvercoat Lion", playerB); attack(3, playerC, "Silvercoat Lion", playerB);
setStopAt(3, PhaseStep.POSTCOMBAT_MAIN); setStopAt(3, PhaseStep.POSTCOMBAT_MAIN);
execute(); execute();
assertLife(playerB, 0); assertLife(playerB, 0);
assertGraveyardCount(playerA, "Legerdemain", 1); assertGraveyardCount(playerA, "Legerdemain", 1);
assertPermanentCount(playerB, 0); assertPermanentCount(playerB, 0);
assertPermanentCount(playerA, "Rootwater Commando", 0); // removed from game because player B left assertPermanentCount(playerA, "Rootwater Commando", 0); // removed from game because player B left
assertPermanentCount(playerB, "Wall of Air", 0); assertPermanentCount(playerB, "Wall of Air", 0);
assertGraveyardCount(playerA, "Wall of Air", 0); assertGraveyardCount(playerA, "Wall of Air", 0);
assertPermanentCount(playerA, "Wall of Air", 1); // Returned back to player A assertPermanentCount(playerA, "Wall of Air", 1); // Returned back to player A
} }
/** /**
* Tests Instant to control other permanent * Tests Instant to control other permanent
*/ */
@Test @Test
public void TestOtherPlayerControllsCreature() { public void TestOtherPlayerControllsCreature() {
addCard(Zone.BATTLEFIELD, playerB, "Rootwater Commando"); addCard(Zone.BATTLEFIELD, playerB, "Rootwater Commando");
addCard(Zone.BATTLEFIELD, playerA, "Mountain", 4); addCard(Zone.BATTLEFIELD, playerA, "Mountain", 4);
// Untap target nonlegendary creature and gain control of it until end of turn. That creature gains haste until end of turn. // Untap target nonlegendary creature and gain control of it until end of turn. That creature gains haste until end of turn.
addCard(Zone.HAND, playerA, "Blind with Anger"); // Instant addCard(Zone.HAND, playerA, "Blind with Anger"); // Instant
addCard(Zone.BATTLEFIELD, playerC, "Silvercoat Lion"); addCard(Zone.BATTLEFIELD, playerC, "Silvercoat Lion");
castSpell(2, PhaseStep.PRECOMBAT_MAIN, playerA, "Blind with Anger", "Rootwater Commando"); castSpell(2, PhaseStep.PRECOMBAT_MAIN, playerA, "Blind with Anger", "Rootwater Commando");
attack(3, playerC, "Silvercoat Lion", playerB); attack(3, playerC, "Silvercoat Lion", playerB);
setStopAt(3, PhaseStep.POSTCOMBAT_MAIN); setStopAt(3, PhaseStep.POSTCOMBAT_MAIN);
execute(); execute();
assertLife(playerB, 0); assertLife(playerB, 0);
assertGraveyardCount(playerA, "Blind with Anger", 1); assertGraveyardCount(playerA, "Blind with Anger", 1);
assertPermanentCount(playerB, 0); assertPermanentCount(playerB, 0);
assertPermanentCount(playerA, "Rootwater Commando", 0); // Removed from game because player C left assertPermanentCount(playerA, "Rootwater Commando", 0); // Removed from game because player C left
assertPermanentCount(playerA, "Rootwater Commando", 0); // Returned back to player A assertPermanentCount(playerA, "Rootwater Commando", 0); // Returned back to player A
} }
/** /**
* Xmage throws an error involving an emblem unable to find the initial * Xmage throws an error involving an emblem unable to find the initial
* source if it has a proc. To reproduce, a Planeswalker was taken from an * source if it has a proc. To reproduce, a Planeswalker was taken from an
* original player's control, such as using Scrambleverse to shuffle Jace, * original player's control, such as using Scrambleverse to shuffle Jace,
* Unraveler of Secrets, to a second player and then the second player uses * Unraveler of Secrets, to a second player and then the second player uses
* Jace's ability to create an emblem ("Whenever an opponent casts his or * Jace's ability to create an emblem ("Whenever an opponent casts his or
* her first spell each turn, counter that spell."). Then the original * her first spell each turn, counter that spell."). Then the original
* player concedes the game and removes the Planeswalker. Once it becomes an * player concedes the game and removes the Planeswalker. Once it becomes an
* opponent of the original player's turn and that opponent plays a spell, * opponent of the original player's turn and that opponent plays a spell,
* Xmage throws an error and rollsback the turn. * Xmage throws an error and rollsback the turn.
* *
* I don't have the actual error report on my due to negligence, but what I * I don't have the actual error report on my due to negligence, but what I
* can recollect is that the error message was along the lines of "The * can recollect is that the error message was along the lines of "The
* emblem cannot find the original source. This turn will be rolled back". * emblem cannot find the original source. This turn will be rolled back".
* This error message will always appear when an opponent tries to play a * This error message will always appear when an opponent tries to play a
* spell. Player order: A -> D -> C -> B * spell. Player order: A -> D -> C -> B
*/ */
@Test @Test
public void TestOtherPlayerPlaneswalkerCreatedEmblem() { public void TestOtherPlayerPlaneswalkerCreatedEmblem() {
// +1: Scry 1, then draw a card. // +1: Scry 1, then draw a card.
// -2: Return target creature to its owner's hand. // -2: Return target creature to its owner's hand.
// -8: You get an emblem with "Whenever an opponent casts his or her first spell each turn, counter that spell." // -8: You get an emblem with "Whenever an opponent casts his or her first spell each turn, counter that spell."
addCard(Zone.BATTLEFIELD, playerB, "Jace, Unraveler of Secrets"); addCard(Zone.BATTLEFIELD, playerB, "Jace, Unraveler of Secrets");
addCounters(1, PhaseStep.DRAW, playerB, "Jace, Unraveler of Secrets", CounterType.LOYALTY, 8); addCounters(1, PhaseStep.DRAW, playerB, "Jace, Unraveler of Secrets", CounterType.LOYALTY, 8);
addCard(Zone.BATTLEFIELD, playerA, "Island", 6); addCard(Zone.BATTLEFIELD, playerA, "Island", 6);
// Enchant permanent (Target a permanent as you cast this. This card enters the battlefield attached to that permanent.) // Enchant permanent (Target a permanent as you cast this. This card enters the battlefield attached to that permanent.)
// You control enchanted permanent. // You control enchanted permanent.
addCard(Zone.HAND, playerA, "Confiscate"); // Enchantment Aura addCard(Zone.HAND, playerA, "Confiscate"); // Enchantment Aura
addCard(Zone.BATTLEFIELD, playerC, "Plains", 2); addCard(Zone.BATTLEFIELD, playerC, "Plains", 2);
addCard(Zone.HAND, playerC, "Silvercoat Lion"); addCard(Zone.HAND, playerC, "Silvercoat Lion");
addCard(Zone.BATTLEFIELD, playerD, "Plains", 2); addCard(Zone.BATTLEFIELD, playerD, "Plains", 2);
addCard(Zone.HAND, playerD, "Silvercoat Lion"); addCard(Zone.HAND, playerD, "Silvercoat Lion");
addCard(Zone.BATTLEFIELD, playerC, "Silvercoat Lion"); addCard(Zone.BATTLEFIELD, playerC, "Silvercoat Lion");
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Confiscate", "Jace, Unraveler of Secrets"); castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Confiscate", "Jace, Unraveler of Secrets");
activateAbility(1, PhaseStep.POSTCOMBAT_MAIN, playerA, "-8: You get an emblem with"); activateAbility(1, PhaseStep.POSTCOMBAT_MAIN, playerA, "-8: You get an emblem with");
castSpell(2, PhaseStep.PRECOMBAT_MAIN, playerA, "Blind with Anger", "Rootwater Commando"); castSpell(2, PhaseStep.PRECOMBAT_MAIN, playerA, "Blind with Anger", "Rootwater Commando");
attack(3, playerC, "Silvercoat Lion", playerB); attack(3, playerC, "Silvercoat Lion", playerB);
castSpell(3, PhaseStep.POSTCOMBAT_MAIN, playerC, "Silvercoat Lion"); castSpell(3, PhaseStep.POSTCOMBAT_MAIN, playerC, "Silvercoat Lion");
castSpell(5, PhaseStep.PRECOMBAT_MAIN, playerD, "Silvercoat Lion"); castSpell(5, PhaseStep.PRECOMBAT_MAIN, playerD, "Silvercoat Lion");
setStopAt(5, PhaseStep.END_TURN); setStopAt(5, PhaseStep.END_TURN);
execute(); execute();
assertLife(playerB, 0); assertLife(playerB, 0);
assertPermanentCount(playerB, 0); assertPermanentCount(playerB, 0);
assertGraveyardCount(playerA, "Confiscate", 1); assertGraveyardCount(playerA, "Confiscate", 1);
assertPermanentCount(playerA, "Jace, Unraveler of Secrets", 0); // Removed from game because player C left the game assertPermanentCount(playerA, "Jace, Unraveler of Secrets", 0); // Removed from game because player C left the game
assertEmblemCount(playerA, 1); assertEmblemCount(playerA, 1);
assertPermanentCount(playerC, "Silvercoat Lion", 2); // Emblem does not work yet on player C, because range 1 assertPermanentCount(playerC, "Silvercoat Lion", 2); // Emblem does not work yet on player C, because range 1
assertGraveyardCount(playerD, "Silvercoat Lion", 1); // Emblem should counter the spell assertGraveyardCount(playerD, "Silvercoat Lion", 1); // Emblem should counter the spell
} }
/** /**
* Situation: I attacked an opponent with some creatures with True * Situation: I attacked an opponent with some creatures with True
* Conviction in play. There were multiple "deals combat damage to a * Conviction in play. There were multiple "deals combat damage to a
* player"-triggers (Edric, Spymaster of Trest, Daxos of Meletis et al), * player"-triggers (Edric, Spymaster of Trest, Daxos of Meletis et al),
* then the opponent lost the game during the first strike combat * then the opponent lost the game during the first strike combat
* damage-step . In the second combat damage step the triggers went on the * damage-step . In the second combat damage step the triggers went on the
* stack again, although there was no player being dealt damage (multiplayer * stack again, although there was no player being dealt damage (multiplayer
* game, so the game wasn't over yet). I don't think these abilities should * game, so the game wasn't over yet). I don't think these abilities should
* trigger again here. * trigger again here.
*/ */
@Test @Test
public void TestPlayerDiesDuringFirstStrikeDamageStep() { public void TestPlayerDiesDuringFirstStrikeDamageStep() {
// Creatures you control have double strike and lifelink. // Creatures you control have double strike and lifelink.
addCard(Zone.BATTLEFIELD, playerD, "True Conviction"); addCard(Zone.BATTLEFIELD, playerD, "True Conviction");
// Whenever a creature deals combat damage to one of your opponents, its controller may draw a card. // Whenever a creature deals combat damage to one of your opponents, its controller may draw a card.
addCard(Zone.BATTLEFIELD, playerD, "Edric, Spymaster of Trest"); addCard(Zone.BATTLEFIELD, playerD, "Edric, Spymaster of Trest");
addCard(Zone.BATTLEFIELD, playerD, "Dross Crocodile", 8); // Creature 5/1 addCard(Zone.BATTLEFIELD, playerD, "Dross Crocodile", 8); // Creature 5/1
attack(2, playerD, "Dross Crocodile", playerC); attack(2, playerD, "Dross Crocodile", playerC);
setStopAt(3, PhaseStep.END_TURN); setStopAt(3, PhaseStep.END_TURN);
execute(); execute();
assertLife(playerC, -3); assertLife(playerC, -3);
assertLife(playerD, 7); assertLife(playerD, 7);
assertHandCount(playerD, 2); // 1 (normal draw) + 1 from True Convition assertHandCount(playerD, 2); // 1 (normal draw) + 1 from True Convition
assertPermanentCount(playerC, 0); assertPermanentCount(playerC, 0);
} }
/** /**
* I've encountered a case today where someone conceded on their turn. The * I've encountered a case today where someone conceded on their turn. The
* remaining phases were went through as normal, but my Luminarch Ascension * remaining phases were went through as normal, but my Luminarch Ascension
* did not trigger during the end step. * did not trigger during the end step.
*/ */
// Player order: A -> D -> C -> B // Player order: A -> D -> C -> B
@Test @Test
public void TestTurnEndTrigger() { public void TestTurnEndTrigger() {
addCard(Zone.BATTLEFIELD, playerA, "Plains", 2); addCard(Zone.BATTLEFIELD, playerA, "Plains", 2);
// At the beginning of each opponent's end step, if you didn't lose life this turn, you may put a quest counter on Luminarch Ascension. // At the beginning of each opponent's end step, if you didn't lose life this turn, you may put a quest counter on Luminarch Ascension.
// {1}{W}: Create a 4/4 white Angel creature token with flying. Activate this ability only if Luminarch Ascension has four or more quest counters on it.. // {1}{W}: Create a 4/4 white Angel creature token with flying. Activate this ability only if Luminarch Ascension has four or more quest counters on it..
addCard(Zone.HAND, playerA, "Luminarch Ascension"); // Enchantment {1}{W} addCard(Zone.HAND, playerA, "Luminarch Ascension"); // Enchantment {1}{W}
addCard(Zone.HAND, playerC, "Lightning Bolt"); addCard(Zone.HAND, playerC, "Lightning Bolt");
addCard(Zone.BATTLEFIELD, playerC, "Mountain", 1); addCard(Zone.BATTLEFIELD, playerC, "Mountain", 1);
addCard(Zone.HAND, playerD, "Silvercoat Lion"); addCard(Zone.HAND, playerD, "Silvercoat Lion");
addCard(Zone.BATTLEFIELD, playerD, "Plains", 2); addCard(Zone.BATTLEFIELD, playerD, "Plains", 2);
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Luminarch Ascension"); castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Luminarch Ascension");
castSpell(2, PhaseStep.PRECOMBAT_MAIN, playerD, "Silvercoat Lion"); castSpell(2, PhaseStep.PRECOMBAT_MAIN, playerD, "Silvercoat Lion");
castSpell(2, PhaseStep.BEGIN_COMBAT, playerC, "Lightning Bolt", playerD); castSpell(2, PhaseStep.BEGIN_COMBAT, playerC, "Lightning Bolt", playerD);
setStopAt(3, PhaseStep.PRECOMBAT_MAIN); setStopAt(3, PhaseStep.PRECOMBAT_MAIN);
execute(); execute();
assertPermanentCount(playerA, "Luminarch Ascension", 1); assertPermanentCount(playerA, "Luminarch Ascension", 1);
assertGraveyardCount(playerC, "Lightning Bolt", 1); assertGraveyardCount(playerC, "Lightning Bolt", 1);
assertLife(playerD, -1); assertLife(playerD, -1);
Assert.assertFalse("Player D is no longer in the game", playerD.isInGame()); Assert.assertFalse("Player D is no longer in the game", playerD.isInGame());
assertCounterCount(playerA, "Luminarch Ascension", CounterType.QUEST, 1); // 1 from turn 2 assertCounterCount(playerA, "Luminarch Ascension", CounterType.QUEST, 1); // 1 from turn 2
} }
@Test @Test
public void TestTurnEndTriggerAfterConcede() { public void TestTurnEndTriggerAfterConcede() {
addCard(Zone.BATTLEFIELD, playerA, "Plains", 2); addCard(Zone.BATTLEFIELD, playerA, "Plains", 2);
// At the beginning of each opponent's end step, if you didn't lose life this turn, you may put a quest counter on Luminarch Ascension. // At the beginning of each opponent's end step, if you didn't lose life this turn, you may put a quest counter on Luminarch Ascension.
// {1}{W}: Create a 4/4 white Angel creature token with flying. Activate this ability only if Luminarch Ascension has four or more quest counters on it.. // {1}{W}: Create a 4/4 white Angel creature token with flying. Activate this ability only if Luminarch Ascension has four or more quest counters on it..
addCard(Zone.HAND, playerA, "Luminarch Ascension"); // Enchantment {1}{W} addCard(Zone.HAND, playerA, "Luminarch Ascension"); // Enchantment {1}{W}
addCard(Zone.HAND, playerD, "Silvercoat Lion"); addCard(Zone.HAND, playerD, "Silvercoat Lion");
addCard(Zone.BATTLEFIELD, playerD, "Plains", 2); addCard(Zone.BATTLEFIELD, playerD, "Plains", 2);
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Luminarch Ascension"); castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Luminarch Ascension");
castSpell(2, PhaseStep.PRECOMBAT_MAIN, playerD, "Silvercoat Lion"); castSpell(2, PhaseStep.PRECOMBAT_MAIN, playerD, "Silvercoat Lion");
concede(2, PhaseStep.BEGIN_COMBAT, playerD); concede(2, PhaseStep.BEGIN_COMBAT, playerD);
setStopAt(3, PhaseStep.PRECOMBAT_MAIN); setStopAt(3, PhaseStep.PRECOMBAT_MAIN);
execute(); execute();
assertPermanentCount(playerA, "Luminarch Ascension", 1); assertPermanentCount(playerA, "Luminarch Ascension", 1);
assertLife(playerD, 2); assertLife(playerD, 2);
Assert.assertFalse("Player D is no longer in the game", playerD.isInGame()); Assert.assertFalse("Player D is no longer in the game", playerD.isInGame());
assertCounterCount(playerA, "Luminarch Ascension", CounterType.QUEST, 1); // 1 from turn 2 assertCounterCount(playerA, "Luminarch Ascension", CounterType.QUEST, 1); // 1 from turn 2
} }
/** /**
* Pithing Needle keeps the named card's abilities disabled even after the * Pithing Needle keeps the named card's abilities disabled even after the
* player controlling the Needle loses the game. * player controlling the Needle loses the game.
* *
* I saw it happen during a Commander game. A player cast Pithing Needle * I saw it happen during a Commander game. A player cast Pithing Needle
* targeting my Proteus Staff. After I killed him, I still couldn't activate * targeting my Proteus Staff. After I killed him, I still couldn't activate
* the Staff. * the Staff.
*/ */
@Test @Test
public void TestPithingNeedle() { public void TestPithingNeedle() {
addCard(Zone.BATTLEFIELD, playerA, "Plains", 1); addCard(Zone.BATTLEFIELD, playerA, "Plains", 1);
// As Pithing Needle enters the battlefield, name a card. // As Pithing Needle enters the battlefield, name a card.
// Activated abilities of sources with the chosen name can't be activated unless they're mana abilities. // Activated abilities of sources with the chosen name can't be activated unless they're mana abilities.
addCard(Zone.HAND, playerA, "Pithing Needle"); // Artifact {1} addCard(Zone.HAND, playerA, "Pithing Needle"); // Artifact {1}
addCard(Zone.BATTLEFIELD, playerA, "Silvercoat Lion", 1); addCard(Zone.BATTLEFIELD, playerA, "Silvercoat Lion", 1);
addCard(Zone.LIBRARY, playerA, "Pillarfield Ox", 1); addCard(Zone.LIBRARY, playerA, "Pillarfield Ox", 1);
addCard(Zone.BATTLEFIELD, playerD, "Island", 3); addCard(Zone.BATTLEFIELD, playerD, "Island", 3);
// {2}{U}, {T}: Put target creature on the bottom of its owner's library. That creature's controller reveals cards from the // {2}{U}, {T}: Put target creature on the bottom of its owner's library. That creature's controller reveals cards from the
// top of his or her library until he or she reveals a creature card. The player puts that card onto the battlefield and the // top of his or her library until he or she reveals a creature card. The player puts that card onto the battlefield and the
// rest on the bottom of his or her library in any order. Activate this ability only any time you could cast a sorcery. // rest on the bottom of his or her library in any order. Activate this ability only any time you could cast a sorcery.
addCard(Zone.BATTLEFIELD, playerD, "Proteus Staff", 1); addCard(Zone.BATTLEFIELD, playerD, "Proteus Staff", 1);
addCard(Zone.BATTLEFIELD, playerD, "Eager Cadet", 1); addCard(Zone.BATTLEFIELD, playerD, "Eager Cadet", 1);
addCard(Zone.LIBRARY, playerD, "Storm Crow", 2); addCard(Zone.LIBRARY, playerD, "Storm Crow", 2);
addCard(Zone.BATTLEFIELD, playerC, "Island", 3); addCard(Zone.BATTLEFIELD, playerC, "Island", 3);
addCard(Zone.BATTLEFIELD, playerC, "Proteus Staff", 1); addCard(Zone.BATTLEFIELD, playerC, "Proteus Staff", 1);
addCard(Zone.BATTLEFIELD, playerC, "Wall of Air", 1); addCard(Zone.BATTLEFIELD, playerC, "Wall of Air", 1);
addCard(Zone.LIBRARY, playerC, "Wind Drake", 2); addCard(Zone.LIBRARY, playerC, "Wind Drake", 2);
addCard(Zone.BATTLEFIELD, playerB, "Island", 3); addCard(Zone.BATTLEFIELD, playerB, "Island", 3);
addCard(Zone.BATTLEFIELD, playerB, "Proteus Staff", 1); addCard(Zone.BATTLEFIELD, playerB, "Proteus Staff", 1);
skipInitShuffling(); skipInitShuffling();
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Pithing Needle"); castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Pithing Needle");
setChoice(playerA, "Proteus Staff"); setChoice(playerA, "Proteus Staff");
activateAbility(2, PhaseStep.PRECOMBAT_MAIN, playerD, "{2}{U}", "Silvercoat Lion"); // not allowed activateAbility(2, PhaseStep.PRECOMBAT_MAIN, playerD, "{2}{U}", "Silvercoat Lion"); // not allowed
activateAbility(3, PhaseStep.PRECOMBAT_MAIN, playerC, "{2}{U}", "Eager Cadet"); // allowed because Needle out of range activateAbility(3, PhaseStep.PRECOMBAT_MAIN, playerC, "{2}{U}", "Eager Cadet"); // allowed because Needle out of range
concede(3, PhaseStep.POSTCOMBAT_MAIN, playerA); concede(3, PhaseStep.POSTCOMBAT_MAIN, playerA);
activateAbility(4, PhaseStep.PRECOMBAT_MAIN, playerB, "{2}{U}", "Wall of Air"); // allowed because Needle lost game activateAbility(4, PhaseStep.PRECOMBAT_MAIN, playerB, "{2}{U}", "Wall of Air"); // allowed because Needle lost game
setStopAt(4, PhaseStep.POSTCOMBAT_MAIN); setStopAt(4, PhaseStep.POSTCOMBAT_MAIN);
execute(); execute();
assertPermanentCount(playerA, 0); assertLife(playerA, 2);
Assert.assertFalse("Player A is no longer in the game", playerA.isInGame());
assertLife(playerA, 2);
Assert.assertFalse("Player A is no longer in the game", playerA.isInGame()); assertPermanentCount(playerA, 0);
Permanent staffPlayerD = getPermanent("Proteus Staff", playerD); Permanent staffPlayerD = getPermanent("Proteus Staff", playerD);
Assert.assertFalse("Staff of player D could not be used", staffPlayerD.isTapped()); Assert.assertFalse("Staff of player D could not be used", staffPlayerD.isTapped());
assertPermanentCount(playerD, "Eager Cadet", 0); assertPermanentCount(playerD, "Eager Cadet", 0);
assertPermanentCount(playerD, "Storm Crow", 1); assertPermanentCount(playerD, "Storm Crow", 1);
Permanent staffPlayerC = getPermanent("Proteus Staff", playerC); Permanent staffPlayerC = getPermanent("Proteus Staff", playerC);
Assert.assertTrue("Staff of player C could be used", staffPlayerC.isTapped()); Assert.assertTrue("Staff of player C could be used", staffPlayerC.isTapped());
assertPermanentCount(playerC, "Wall of Air", 0); assertPermanentCount(playerC, "Wall of Air", 0);
assertPermanentCount(playerC, "Wind Drake", 1); assertPermanentCount(playerC, "Wind Drake", 1);
Permanent staffPlayerB = getPermanent("Proteus Staff", playerB); Permanent staffPlayerB = getPermanent("Proteus Staff", playerB);
Assert.assertTrue("Staff of player B could be used", staffPlayerB.isTapped()); Assert.assertTrue("Staff of player B could be used", staffPlayerB.isTapped());
} }
} }

View file

@ -57,6 +57,7 @@ import mage.filter.predicate.Predicates;
import mage.filter.predicate.mageobject.NamePredicate; import mage.filter.predicate.mageobject.NamePredicate;
import mage.filter.predicate.permanent.SummoningSicknessPredicate; import mage.filter.predicate.permanent.SummoningSicknessPredicate;
import mage.game.Game; import mage.game.Game;
import mage.game.GameImpl;
import mage.game.Graveyard; import mage.game.Graveyard;
import mage.game.Table; import mage.game.Table;
import mage.game.combat.CombatGroup; import mage.game.combat.CombatGroup;
@ -519,6 +520,7 @@ public class TestPlayer implements Player {
} }
if (groups[0].equals("Concede")) { if (groups[0].equals("Concede")) {
game.concede(getId()); game.concede(getId());
((GameImpl) game).checkConcede();
actions.remove(action); actions.remove(action);
} }
} }
@ -1182,6 +1184,11 @@ public class TestPlayer implements Player {
computerPlayer.abort(); computerPlayer.abort();
} }
@Override
public void signalPlayerConcede() {
computerPlayer.signalPlayerConcede();
}
@Override @Override
public void abortReset() { public void abortReset() {
computerPlayer.abortReset(); computerPlayer.abortReset();

View file

@ -27,6 +27,8 @@
*/ */
package org.mage.test.stub; package org.mage.test.stub;
import java.io.Serializable;
import java.util.*;
import mage.MageObject; import mage.MageObject;
import mage.abilities.*; import mage.abilities.*;
import mage.abilities.costs.AlternativeSourceCosts; import mage.abilities.costs.AlternativeSourceCosts;
@ -62,9 +64,6 @@ import mage.target.TargetAmount;
import mage.target.TargetCard; import mage.target.TargetCard;
import mage.target.common.TargetCardInLibrary; import mage.target.common.TargetCardInLibrary;
import java.io.Serializable;
import java.util.*;
/** /**
* *
* @author Quercitron * @author Quercitron
@ -702,6 +701,11 @@ public class PlayerStub implements Player {
} }
@Override
public void signalPlayerConcede() {
}
@Override @Override
public void abortReset() { public void abortReset() {

View file

@ -27,7 +27,6 @@ public class YouGainedLifeCondition extends IntCompareCondition {
@Override @Override
public String toString() { public String toString() {
return String.format("if you gained %s or more life this turn ", value); return String.format("if you gained %s or more life this turn ", value + 1);
} }
} }

View file

@ -270,7 +270,7 @@ public class LookLibraryAndPickControllerEffect extends LookLibraryControllerEff
} else { } else {
sb.append('P'); sb.append('P');
} }
sb.append("put ").append(filter.getMessage()).append(" from among them onto the "); sb.append("ut ").append(filter.getMessage()).append(" from among them onto the ");
} else { } else {
sb.append(". Put "); sb.append(". Put ");
if (numberToPick.calculate(null, null, this) > 1) { if (numberToPick.calculate(null, null, this) > 1) {

View file

@ -0,0 +1,85 @@
/*
* 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 mage.abilities.effects.common;
import java.util.List;
import java.util.UUID;
import mage.abilities.Ability;
import mage.abilities.effects.OneShotEffect;
import mage.constants.Outcome;
import mage.game.Game;
import mage.game.permanent.Permanent;
/**
* This class should only be used within the application of another effect
*
* @author TheElk801
*/
public class PhaseOutAllEffect extends OneShotEffect {
private final List<UUID> idList;
public PhaseOutAllEffect(List<UUID> idList) {
super(Outcome.Neutral);
this.idList = idList;
}
public PhaseOutAllEffect(final PhaseOutAllEffect effect) {
super(effect);
this.idList = effect.idList;
}
@Override
public PhaseOutAllEffect copy() {
return new PhaseOutAllEffect(this);
}
@Override
public boolean apply(Game game, Ability source) {
// First we phase out everything that isn't attached to anything
// Anything attached to these permanents will phase out indirectly
for (UUID permanentId : idList) {
Permanent permanent = game.getPermanent(permanentId);
if (permanent != null) {
Permanent attachedTo = game.getPermanent(permanent.getAttachedTo());
if (attachedTo == null) {
permanent.phaseOut(game);
}
}
}
// Once this is done, we'll have permanents which are attached to something but haven't phased out
// These will be phased out directly
for (UUID permanentId : idList) {
Permanent permanent = game.getPermanent(permanentId);
if (permanent != null && permanent.isPhasedIn()) {
permanent.phaseOut(game);
}
}
return true;
}
}

View file

@ -0,0 +1,70 @@
/*
* 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 mage.abilities.effects.common.combat;
import mage.constants.Duration;
import mage.abilities.Ability;
import mage.abilities.effects.RestrictionEffect;
import mage.game.Game;
import mage.game.permanent.Permanent;
/**
*
* @author BetaSteward_at_googlemail.com & L_J
*/
public class CantAttackSourceEffect extends RestrictionEffect {
public CantAttackSourceEffect(Duration duration) {
super(duration);
this.staticText = "{this} can't attack";
}
public CantAttackSourceEffect(final CantAttackSourceEffect effect) {
super(effect);
}
@Override
public boolean applies(Permanent permanent, Ability source, Game game) {
if (permanent.getId().equals(source.getSourceId())) {
return true;
}
return false;
}
@Override
public boolean canAttack(Game game) {
return false;
}
@Override
public CantAttackSourceEffect copy() {
return new CantAttackSourceEffect(this);
}
}

View file

@ -0,0 +1,67 @@
/*
* 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 mage.abilities.keyword.special;
import mage.constants.Zone;
import mage.abilities.MageSingleton;
import mage.abilities.StaticAbility;
import java.io.ObjectStreamException;
/**
*
* @author BetaSteward_at_googlemail.com & L_J
*/
public class JohanVigilanceAbility extends StaticAbility implements MageSingleton { // special instance of "attacking doesn't cause this to tap" granted by Johan's ability
private static final JohanVigilanceAbility instance = new JohanVigilanceAbility();
private Object readResolve() throws ObjectStreamException {
return instance;
}
public static JohanVigilanceAbility getInstance() {
return instance;
}
private JohanVigilanceAbility() {
super(Zone.BATTLEFIELD, null);
}
@Override
public String getRule() {
return "";
}
@Override
public JohanVigilanceAbility copy() {
return instance;
}
}

View file

@ -173,7 +173,7 @@ public interface Game extends MageItem, Serializable {
UUID getPriorityPlayerId(); UUID getPriorityPlayerId();
boolean gameOver(UUID playerId); boolean checkIfGameIsOver();
boolean hasEnded(); boolean hasEnded();
@ -347,6 +347,8 @@ public interface Game extends MageItem, Serializable {
void concede(UUID playerId); void concede(UUID playerId);
void setConcedingPlayer(UUID playerId);
void setManaPaymentMode(UUID playerId, boolean autoPayment); void setManaPaymentMode(UUID playerId, boolean autoPayment);
void setManaPaymentModeRestricted(UUID playerId, boolean autoPaymentRestricted); void setManaPaymentModeRestricted(UUID playerId, boolean autoPaymentRestricted);

View file

@ -161,6 +161,8 @@ public abstract class GameImpl implements Game, Serializable {
private final LinkedList<UUID> stackObjectsCheck = new LinkedList<>(); // used to check if different sources used the stack private final LinkedList<UUID> stackObjectsCheck = new LinkedList<>(); // used to check if different sources used the stack
// used to set the counters a permanent adds the battlefield (if no replacement effect is used e.g. Persist) // used to set the counters a permanent adds the battlefield (if no replacement effect is used e.g. Persist)
protected Map<UUID, Counters> enterWithCounters = new HashMap<>(); protected Map<UUID, Counters> enterWithCounters = new HashMap<>();
// used to proceed player conceding requests
private final LinkedList<UUID> concedingPlayers = new LinkedList<>(); // used to handle asynchronous request of a player to leave the game
public GameImpl(MultiplayerAttackOption attackOption, RangeOfInfluence range, int freeMulligans, int startLife) { public GameImpl(MultiplayerAttackOption attackOption, RangeOfInfluence range, int freeMulligans, int startLife) {
this.id = UUID.randomUUID(); this.id = UUID.randomUUID();
@ -535,26 +537,58 @@ public abstract class GameImpl implements Game, Serializable {
} }
} }
/** // /**
* Starts check if game is over or if playerId is given let the player // * Starts check if game is over or if playerId is given let the player
* concede. // * concede.
* // *
* @param playerId // * @param playerId
* @return // * @return
*/ // */
// @Override
// public synchronized boolean gameOver(UUID playerId) {
// if (playerId == null) {
// boolean result = checkIfGameIsOver();
// return result;
// } else {
// logger.debug("Game over for player Id: " + playerId + " gameId " + getId());
// concedingPlayers.add(playerId);
// Player player = getPlayer(state.getPriorityPlayerId());
// if (player != null && player.isHuman()) {
// player.signalPlayerConcede();
// } else {
// checkConcede();
// }
// return true;
// }
// }
@Override @Override
public synchronized boolean gameOver(UUID playerId) { public void setConcedingPlayer(UUID playerId) {
if (playerId == null) { Player player = getPlayer(state.getPriorityPlayerId());
boolean result = checkIfGameIsOver(); if (player != null) {
return result; if (!player.hasLeft() && player.isHuman()) {
if (!concedingPlayers.contains(playerId)) {
logger.debug("Game over for player Id: " + playerId + " gameId " + getId());
concedingPlayers.add(playerId);
player.signalPlayerConcede();
}
} else {
// no asynchronous action so check directly
checkConcede();
}
} else { } else {
logger.debug("Game over for player Id: " + playerId + " gameId " + getId()); checkConcede();
leave(playerId); checkIfGameIsOver();
return true;
} }
} }
private boolean checkIfGameIsOver() { public void checkConcede() {
while (!concedingPlayers.isEmpty()) {
leave(concedingPlayers.removeFirst());
}
}
@Override
public boolean checkIfGameIsOver() {
if (state.isGameOver()) { if (state.isGameOver()) {
return true; return true;
} }
@ -578,7 +612,7 @@ public abstract class GameImpl implements Game, Serializable {
} }
for (Player player : state.getPlayers().values()) { for (Player player : state.getPlayers().values()) {
if (!player.hasLeft() && !player.hasLost()) { if (!player.hasLeft() && !player.hasLost()) {
logger.debug(new StringBuilder("Player ").append(player.getName()).append(" has won gameId: ").append(this.getId())); logger.debug("Player " + player.getName() + " has won gameId: " + this.getId());
player.won(this); player.won(this);
} }
} }
@ -696,13 +730,13 @@ public abstract class GameImpl implements Game, Serializable {
Player player = getPlayer(playerList.get()); Player player = getPlayer(playerList.get());
boolean wasPaused = state.isPaused(); boolean wasPaused = state.isPaused();
state.resume(); state.resume();
if (!gameOver(null)) { if (!checkIfGameIsOver()) {
fireInformEvent("Turn " + state.getTurnNum()); fireInformEvent("Turn " + state.getTurnNum());
if (checkStopOnTurnOption()) { if (checkStopOnTurnOption()) {
return; return;
} }
state.getTurn().resumePlay(this, wasPaused); state.getTurn().resumePlay(this, wasPaused);
if (!isPaused() && !gameOver(null)) { if (!isPaused() && !checkIfGameIsOver()) {
endOfTurn(); endOfTurn();
player = playerList.getNext(this); player = playerList.getNext(this);
state.setTurnNum(state.getTurnNum() + 1); state.setTurnNum(state.getTurnNum() + 1);
@ -712,11 +746,11 @@ public abstract class GameImpl implements Game, Serializable {
} }
protected void play(UUID nextPlayerId) { protected void play(UUID nextPlayerId) {
if (!isPaused() && !gameOver(null)) { if (!isPaused() && !checkIfGameIsOver()) {
playerList = state.getPlayerList(nextPlayerId); playerList = state.getPlayerList(nextPlayerId);
Player playerByOrder = getPlayer(playerList.get()); Player playerByOrder = getPlayer(playerList.get());
state.setPlayerByOrderId(playerByOrder.getId()); state.setPlayerByOrderId(playerByOrder.getId());
while (!isPaused() && !gameOver(null)) { while (!isPaused() && !checkIfGameIsOver()) {
if (!playExtraTurns()) { if (!playExtraTurns()) {
break; break;
} }
@ -733,7 +767,7 @@ public abstract class GameImpl implements Game, Serializable {
state.setPlayerByOrderId(playerByOrder.getId()); state.setPlayerByOrderId(playerByOrder.getId());
} }
} }
if (gameOver(null) && !isSimulation()) { if (checkIfGameIsOver() && !isSimulation()) {
winnerId = findWinnersAndLosers(); winnerId = findWinnersAndLosers();
StringBuilder sb = new StringBuilder("GAME END gameId: ").append(this.getId()).append(' '); StringBuilder sb = new StringBuilder("GAME END gameId: ").append(this.getId()).append(' ');
int count = 0; int count = 0;
@ -816,7 +850,7 @@ public abstract class GameImpl implements Game, Serializable {
skipTurn = state.getTurn().play(this, player); skipTurn = state.getTurn().play(this, player);
} while (executingRollback); } while (executingRollback);
if (isPaused() || gameOver(null)) { if (isPaused() || checkIfGameIsOver()) {
return false; return false;
} }
if (!skipTurn) { if (!skipTurn) {
@ -854,7 +888,7 @@ public abstract class GameImpl implements Game, Serializable {
saveState(false); saveState(false);
if (gameOver(null)) { if (checkIfGameIsOver()) {
return; return;
} }
@ -1245,7 +1279,7 @@ public abstract class GameImpl implements Game, Serializable {
clearAllBookmarks(); clearAllBookmarks();
try { try {
applyEffects(); applyEffects();
while (!isPaused() && !gameOver(null) && !this.getTurn().isEndTurnRequested()) { while (!isPaused() && !checkIfGameIsOver() && !this.getTurn().isEndTurnRequested()) {
if (!resuming) { if (!resuming) {
state.getPlayers().resetPassed(); state.getPlayers().resetPassed();
state.getPlayerList().setCurrent(activePlayerId); state.getPlayerList().setCurrent(activePlayerId);
@ -1254,14 +1288,14 @@ public abstract class GameImpl implements Game, Serializable {
} }
fireUpdatePlayersEvent(); fireUpdatePlayersEvent();
Player player; Player player;
while (!isPaused() && !gameOver(null)) { while (!isPaused() && !checkIfGameIsOver()) {
try { try {
if (bookmark == 0) { if (bookmark == 0) {
bookmark = bookmarkState(); bookmark = bookmarkState();
} }
player = getPlayer(state.getPlayerList().get()); player = getPlayer(state.getPlayerList().get());
state.setPriorityPlayerId(player.getId()); state.setPriorityPlayerId(player.getId());
while (!player.isPassed() && player.canRespond() && !isPaused() && !gameOver(null)) { while (!player.isPassed() && player.canRespond() && !isPaused() && !checkIfGameIsOver()) {
if (!resuming) { if (!resuming) {
// 603.3. Once an ability has triggered, its controller puts it on the stack as an object that's not a card the next time a player would receive priority // 603.3. Once an ability has triggered, its controller puts it on the stack as an object that's not a card the next time a player would receive priority
checkStateAndTriggered(); checkStateAndTriggered();
@ -1270,7 +1304,7 @@ public abstract class GameImpl implements Game, Serializable {
resetLKI(); resetLKI();
} }
saveState(false); saveState(false);
if (isPaused() || gameOver(null)) { if (isPaused() || checkIfGameIsOver()) {
return; return;
} }
// resetPassed should be called if player performs any action // resetPassed should be called if player performs any action
@ -1289,13 +1323,14 @@ public abstract class GameImpl implements Game, Serializable {
} }
resetShortLivingLKI(); resetShortLivingLKI();
resuming = false; resuming = false;
if (isPaused() || gameOver(null)) { if (isPaused() || checkIfGameIsOver()) {
return; return;
} }
if (allPassed()) { if (allPassed()) {
if (!state.getStack().isEmpty()) { if (!state.getStack().isEmpty()) {
//20091005 - 115.4 //20091005 - 115.4
resolve(); resolve();
checkConcede();
applyEffects(); applyEffects();
state.getPlayers().resetPassed(); state.getPlayers().resetPassed();
fireUpdatePlayersEvent(); fireUpdatePlayersEvent();
@ -1609,11 +1644,11 @@ public abstract class GameImpl implements Game, Serializable {
public boolean checkStateAndTriggered() { public boolean checkStateAndTriggered() {
boolean somethingHappened = false; boolean somethingHappened = false;
//20091005 - 115.5 //20091005 - 115.5
while (!isPaused() && !gameOver(null)) { while (!isPaused() && !checkIfGameIsOver()) {
if (!checkStateBasedActions()) { if (!checkStateBasedActions()) {
// nothing happened so check triggers // nothing happened so check triggers
state.handleSimultaneousEvent(this); state.handleSimultaneousEvent(this);
if (isPaused() || gameOver(null) || getTurn().isEndTurnRequested() || !checkTriggered()) { if (isPaused() || checkIfGameIsOver() || getTurn().isEndTurnRequested() || !checkTriggered()) {
break; break;
} }
} }
@ -1621,6 +1656,7 @@ public abstract class GameImpl implements Game, Serializable {
applyEffects(); // needed e.g if boost effects end and cause creatures to die applyEffects(); // needed e.g if boost effects end and cause creatures to die
somethingHappened = true; somethingHappened = true;
} }
checkConcede();
return somethingHappened; return somethingHappened;
} }
@ -1734,7 +1770,6 @@ public abstract class GameImpl implements Game, Serializable {
} }
} }
List<Permanent> planeswalkers = new ArrayList<>();
List<Permanent> legendary = new ArrayList<>(); List<Permanent> legendary = new ArrayList<>();
List<Permanent> worldEnchantment = new ArrayList<>(); List<Permanent> worldEnchantment = new ArrayList<>();
for (Permanent perm : getBattlefield().getAllActivePermanents()) { for (Permanent perm : getBattlefield().getAllActivePermanents()) {
@ -1781,7 +1816,6 @@ public abstract class GameImpl implements Game, Serializable {
continue; continue;
} }
} }
planeswalkers.add(perm);
} }
if (perm.isWorld()) { if (perm.isWorld()) {
worldEnchantment.add(perm); worldEnchantment.add(perm);
@ -2288,7 +2322,6 @@ public abstract class GameImpl implements Game, Serializable {
* @param playerId * @param playerId
*/ */
protected void leave(UUID playerId) { // needs to be executed from the game thread, not from the concede thread of conceding player! protected void leave(UUID playerId) { // needs to be executed from the game thread, not from the concede thread of conceding player!
Player player = getPlayer(playerId); Player player = getPlayer(playerId);
if (player == null || player.hasLeft()) { if (player == null || player.hasLeft()) {
logger.debug("Player already left " + (player != null ? player.getName() : playerId)); logger.debug("Player already left " + (player != null ? player.getName() : playerId));

View file

@ -34,6 +34,7 @@ import mage.abilities.Ability;
import mage.abilities.effects.RequirementEffect; import mage.abilities.effects.RequirementEffect;
import mage.abilities.effects.RestrictionEffect; import mage.abilities.effects.RestrictionEffect;
import mage.abilities.keyword.VigilanceAbility; import mage.abilities.keyword.VigilanceAbility;
import mage.abilities.keyword.special.JohanVigilanceAbility;
import mage.constants.Outcome; import mage.constants.Outcome;
import mage.constants.Zone; import mage.constants.Zone;
import mage.filter.StaticFilters; import mage.filter.StaticFilters;
@ -264,7 +265,7 @@ public class Combat implements Serializable, Copyable<Combat> {
player.selectAttackers(game, attackingPlayerId); player.selectAttackers(game, attackingPlayerId);
} }
firstTime = false; firstTime = false;
if (game.isPaused() || game.gameOver(null) || game.executingRollback()) { if (game.isPaused() || game.checkIfGameIsOver() || game.executingRollback()) {
return; return;
} }
// because of possible undo during declare attackers it's neccassary to call here the methods with "game.getCombat()." to get the current combat object!!! // because of possible undo during declare attackers it's neccassary to call here the methods with "game.getCombat()." to get the current combat object!!!
@ -461,7 +462,7 @@ public class Combat implements Serializable, Copyable<Combat> {
} }
while (choose) { while (choose) {
controller.selectBlockers(game, defenderId); controller.selectBlockers(game, defenderId);
if (game.isPaused() || game.gameOver(null) || game.executingRollback()) { if (game.isPaused() || game.checkIfGameIsOver() || game.executingRollback()) {
return; return;
} }
if (!game.getCombat().checkBlockRestrictions(defender, game)) { if (!game.getCombat().checkBlockRestrictions(defender, game)) {
@ -1091,7 +1092,7 @@ public class Combat implements Serializable, Copyable<Combat> {
@SuppressWarnings("deprecation") @SuppressWarnings("deprecation")
public boolean declareAttacker(UUID creatureId, UUID defenderId, UUID playerId, Game game) { public boolean declareAttacker(UUID creatureId, UUID defenderId, UUID playerId, Game game) {
Permanent attacker = game.getPermanent(creatureId); Permanent attacker = game.getPermanent(creatureId);
if (!attacker.getAbilities().containsKey(VigilanceAbility.getInstance().getId())) { if (!attacker.getAbilities().containsKey(VigilanceAbility.getInstance().getId()) && !attacker.getAbilities().containsKey(JohanVigilanceAbility.getInstance().getId())) {
if (!attacker.isTapped()) { if (!attacker.isTapped()) {
attacker.setTapped(true); attacker.setTapped(true);
attackersTappedByAttack.add(attacker.getId()); attackersTappedByAttack.add(attacker.getId());

View file

@ -78,10 +78,16 @@ public interface Permanent extends Card, Controllable {
boolean isPhasedIn(); boolean isPhasedIn();
boolean isPhasedOutIndirectly();
boolean phaseIn(Game game); boolean phaseIn(Game game);
boolean phaseIn(Game game, boolean onlyDirect);
boolean phaseOut(Game game); boolean phaseOut(Game game);
boolean phaseOut(Game game, boolean indirectPhase);
boolean isMonstrous(); boolean isMonstrous();
void setMonstrous(boolean value); void setMonstrous(boolean value);

View file

@ -89,6 +89,7 @@ public abstract class PermanentImpl extends CardImpl implements Permanent {
protected boolean controlledFromStartOfControllerTurn; protected boolean controlledFromStartOfControllerTurn;
protected int turnsOnBattlefield; protected int turnsOnBattlefield;
protected boolean phasedIn = true; protected boolean phasedIn = true;
protected boolean indirectPhase = false;
protected boolean faceDown; protected boolean faceDown;
protected boolean attacking; protected boolean attacking;
protected int blocking; protected int blocking;
@ -138,6 +139,7 @@ public abstract class PermanentImpl extends CardImpl implements Permanent {
this.controlledFromStartOfControllerTurn = permanent.controlledFromStartOfControllerTurn; this.controlledFromStartOfControllerTurn = permanent.controlledFromStartOfControllerTurn;
this.turnsOnBattlefield = permanent.turnsOnBattlefield; this.turnsOnBattlefield = permanent.turnsOnBattlefield;
this.phasedIn = permanent.phasedIn; this.phasedIn = permanent.phasedIn;
this.indirectPhase = permanent.indirectPhase;
this.faceDown = permanent.faceDown; this.faceDown = permanent.faceDown;
this.attacking = permanent.attacking; this.attacking = permanent.attacking;
this.blocking = permanent.blocking; this.blocking = permanent.blocking;
@ -461,14 +463,32 @@ public abstract class PermanentImpl extends CardImpl implements Permanent {
return phasedIn; return phasedIn;
} }
@Override
public boolean isPhasedOutIndirectly() {
return !phasedIn && indirectPhase;
}
@Override @Override
public boolean phaseIn(Game game) { public boolean phaseIn(Game game) {
return phaseIn(game, true);
}
@Override
public boolean phaseIn(Game game, boolean onlyDirect) {
if (!phasedIn) { if (!phasedIn) {
if (!replaceEvent(EventType.PHASE_IN, game)) { if (!replaceEvent(EventType.PHASE_IN, game)
&& ((onlyDirect && !indirectPhase) || (!onlyDirect))) {
this.phasedIn = true; this.phasedIn = true;
this.indirectPhase = false;
if (!game.isSimulation()) { if (!game.isSimulation()) {
game.informPlayers(getLogName() + " phased in"); game.informPlayers(getLogName() + " phased in");
} }
for (UUID attachedId : this.getAttachments()) {
Permanent attachedPerm = game.getPermanent(attachedId);
if (attachedPerm != null) {
attachedPerm.phaseIn(game, false);
}
}
fireEvent(EventType.PHASED_IN, game); fireEvent(EventType.PHASED_IN, game);
return true; return true;
} }
@ -478,9 +498,21 @@ public abstract class PermanentImpl extends CardImpl implements Permanent {
@Override @Override
public boolean phaseOut(Game game) { public boolean phaseOut(Game game) {
return phaseOut(game, false);
}
@Override
public boolean phaseOut(Game game, boolean indirectPhase) {
if (phasedIn) { if (phasedIn) {
if (!replaceEvent(EventType.PHASE_OUT, game)) { if (!replaceEvent(EventType.PHASE_OUT, game)) {
for (UUID attachedId : this.getAttachments()) {
Permanent attachedPerm = game.getPermanent(attachedId);
if (attachedPerm != null) {
attachedPerm.phaseOut(game, true);
}
}
this.phasedIn = false; this.phasedIn = false;
this.indirectPhase = indirectPhase;
if (!game.isSimulation()) { if (!game.isSimulation()) {
game.informPlayers(getLogName() + " phased out"); game.informPlayers(getLogName() + " phased out");
} }

View file

@ -95,7 +95,7 @@ public abstract class Phase implements Serializable {
} }
public boolean play(Game game, UUID activePlayerId) { public boolean play(Game game, UUID activePlayerId) {
if (game.isPaused() || game.gameOver(null)) { if (game.isPaused() || game.checkIfGameIsOver()) {
return false; return false;
} }
@ -104,7 +104,7 @@ public abstract class Phase implements Serializable {
if (beginPhase(game, activePlayerId)) { if (beginPhase(game, activePlayerId)) {
for (Step step : steps) { for (Step step : steps) {
if (game.isPaused() || game.gameOver(null)) { if (game.isPaused() || game.checkIfGameIsOver()) {
return false; return false;
} }
if (game.getTurn().isEndTurnRequested() && step.getType()!=PhaseStep.CLEANUP) { if (game.getTurn().isEndTurnRequested() && step.getType()!=PhaseStep.CLEANUP) {
@ -122,7 +122,7 @@ public abstract class Phase implements Serializable {
} }
} }
if (game.isPaused() || game.gameOver(null)) { if (game.isPaused() || game.checkIfGameIsOver()) {
return false; return false;
} }
count++; count++;
@ -143,7 +143,7 @@ public abstract class Phase implements Serializable {
} }
public boolean resumePlay(Game game, PhaseStep stepType, boolean wasPaused) { public boolean resumePlay(Game game, PhaseStep stepType, boolean wasPaused) {
if (game.isPaused() || game.gameOver(null)) { if (game.isPaused() || game.checkIfGameIsOver()) {
return false; return false;
} }
@ -157,7 +157,7 @@ public abstract class Phase implements Serializable {
resumeStep(game, wasPaused); resumeStep(game, wasPaused);
while (it.hasNext()) { while (it.hasNext()) {
step = it.next(); step = it.next();
if (game.isPaused() || game.gameOver(null)) { if (game.isPaused() || game.checkIfGameIsOver()) {
return false; return false;
} }
currentStep = step; currentStep = step;
@ -169,7 +169,7 @@ public abstract class Phase implements Serializable {
} }
} }
if (game.isPaused() || game.gameOver(null)) { if (game.isPaused() || game.checkIfGameIsOver()) {
return false; return false;
} }
count++; count++;
@ -206,13 +206,13 @@ public abstract class Phase implements Serializable {
if (!currentStep.skipStep(game, activePlayerId)) { if (!currentStep.skipStep(game, activePlayerId)) {
game.getState().increaseStepNum(); game.getState().increaseStepNum();
prePriority(game, activePlayerId); prePriority(game, activePlayerId);
if (!game.isPaused() && !game.gameOver(null) && !game.executingRollback()) { if (!game.isPaused() && !game.checkIfGameIsOver() && !game.executingRollback()) {
currentStep.priority(game, activePlayerId, false); currentStep.priority(game, activePlayerId, false);
if (game.executingRollback()) { if (game.executingRollback()) {
return; return;
} }
} }
if (!game.isPaused() && !game.gameOver(null) && !game.executingRollback()) { if (!game.isPaused() && !game.checkIfGameIsOver() && !game.executingRollback()) {
postPriority(game, activePlayerId); postPriority(game, activePlayerId);
} }
} }
@ -233,11 +233,11 @@ public abstract class Phase implements Serializable {
prePriority(game, activePlayerId); prePriority(game, activePlayerId);
} }
case PRIORITY: case PRIORITY:
if (!game.isPaused() && !game.gameOver(null)) { if (!game.isPaused() && !game.checkIfGameIsOver()) {
currentStep.priority(game, activePlayerId, resuming); currentStep.priority(game, activePlayerId, resuming);
} }
case POST: case POST:
if (!game.isPaused() && !game.gameOver(null)) { if (!game.isPaused() && !game.checkIfGameIsOver()) {
postPriority(game, activePlayerId); postPriority(game, activePlayerId);
} }
} }

View file

@ -127,7 +127,7 @@ public class Turn implements Serializable {
public boolean play(Game game, Player activePlayer) { public boolean play(Game game, Player activePlayer) {
activePlayer.becomesActivePlayer(); activePlayer.becomesActivePlayer();
this.setDeclareAttackersStepStarted(false); this.setDeclareAttackersStepStarted(false);
if (game.isPaused() || game.gameOver(null)) { if (game.isPaused() || game.checkIfGameIsOver()) {
return false; return false;
} }
@ -143,7 +143,7 @@ public class Turn implements Serializable {
resetCounts(); resetCounts();
game.getPlayer(activePlayer.getId()).beginTurn(game); game.getPlayer(activePlayer.getId()).beginTurn(game);
for (Phase phase : phases) { for (Phase phase : phases) {
if (game.isPaused() || game.gameOver(null)) { if (game.isPaused() || game.checkIfGameIsOver()) {
return false; return false;
} }
if (!isEndTurnRequested() || phase.getType() == TurnPhase.END) { if (!isEndTurnRequested() || phase.getType() == TurnPhase.END) {
@ -189,7 +189,7 @@ public class Turn implements Serializable {
} }
while (it.hasNext()) { while (it.hasNext()) {
phase = it.next(); phase = it.next();
if (game.isPaused() || game.gameOver(null)) { if (game.isPaused() || game.checkIfGameIsOver()) {
return; return;
} }
currentPhase = phase; currentPhase = phase;

View file

@ -444,6 +444,8 @@ public interface Player extends MageItem, Copyable<Player> {
void abortReset(); void abortReset();
void signalPlayerConcede();
void skip(); void skip();
// priority, undo, ... // priority, undo, ...

View file

@ -1484,16 +1484,15 @@ public abstract class PlayerImpl implements Player, Serializable {
// phasing out is known as phasing out "indirectly." An enchantment or Equipment // phasing out is known as phasing out "indirectly." An enchantment or Equipment
// that phased out indirectly won't phase in by itself, but instead phases in // that phased out indirectly won't phase in by itself, but instead phases in
// along with the card it's attached to. // along with the card it's attached to.
for (UUID attachmentId : permanent.getAttachments()) { Permanent attachedTo = game.getPermanent(permanent.getAttachedTo());
Permanent attachment = game.getPermanent(attachmentId); if (!(attachedTo != null && attachedTo.getControllerId().equals(this.getId()))) {
if (attachment != null) { permanent.phaseOut(game, false);
attachment.phaseOut(game);
}
} }
permanent.phaseOut(game);
} }
for (Permanent permanent : phasedOut) { for (Permanent permanent : phasedOut) {
permanent.phaseIn(game); if (!permanent.isPhasedOutIndirectly()) {
permanent.phaseIn(game);
}
} }
} }
@ -2039,9 +2038,9 @@ public abstract class PlayerImpl implements Player, Serializable {
@Override @Override
public void concede(Game game) { public void concede(Game game) {
game.gameOver(playerId); game.setConcedingPlayer(playerId);
lost(game); lost(game);
this.left = true; // this.left = true;
} }
@Override @Override
@ -2136,7 +2135,7 @@ public abstract class PlayerImpl implements Player, Serializable {
// for draw - first all players that have lost have to be set to lost // for draw - first all players that have lost have to be set to lost
if (!hasLeft()) { if (!hasLeft()) {
logger.debug("Game over playerId: " + playerId); logger.debug("Game over playerId: " + playerId);
game.gameOver(playerId); game.setConcedingPlayer(playerId);
} }
} }
@ -2197,7 +2196,7 @@ public abstract class PlayerImpl implements Player, Serializable {
this.draws = true; this.draws = true;
game.fireEvent(GameEvent.getEvent(GameEvent.EventType.DRAW_PLAYER, null, null, playerId)); game.fireEvent(GameEvent.getEvent(GameEvent.EventType.DRAW_PLAYER, null, null, playerId));
game.informPlayers("For " + this.getLogName() + " the game is a draw."); game.informPlayers("For " + this.getLogName() + " the game is a draw.");
game.gameOver(playerId); game.setConcedingPlayer(playerId);
} }
} }
@ -3579,6 +3578,11 @@ public abstract class PlayerImpl implements Player, Serializable {
abort = false; abort = false;
} }
@Override
public void signalPlayerConcede() {
}
@Override @Override
public boolean scry(int value, Ability source, public boolean scry(int value, Ability source,
Game game Game game

View file

@ -0,0 +1,80 @@
/*
* 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 mage.watchers.common;
import mage.constants.WatcherScope;
import mage.game.Game;
import mage.game.events.GameEvent;
import mage.watchers.Watcher;
/**
*
* @author L_J
*/
public class ChooseBlockersRedundancyWatcher extends Watcher { // workaround for solving timestamp issues regarding "you choose which creatures block and how those creatures block" effects
public int copyCount = 0;
public int copyCountApply = 0;
public ChooseBlockersRedundancyWatcher() {
super(ChooseBlockersRedundancyWatcher.class.getSimpleName(), WatcherScope.GAME);
}
public ChooseBlockersRedundancyWatcher(final ChooseBlockersRedundancyWatcher watcher) {
super(watcher);
this.copyCount = watcher.copyCount;
this.copyCountApply = watcher.copyCountApply;
}
@Override
public void reset() {
copyCount = 0;
copyCountApply = 0;
}
@Override
public ChooseBlockersRedundancyWatcher copy() {
return new ChooseBlockersRedundancyWatcher(this);
}
@Override
public void watch(GameEvent event, Game game) {
}
public void increment() {
copyCount++;
copyCountApply = copyCount;
}
public void decrement() {
if (copyCountApply > 0) {
copyCountApply--;
}
}
}