mirror of
https://github.com/correl/mage.git
synced 2024-11-14 19:19:32 +00:00
Added missing fields to many copy constructors. (#8957)
This commit is contained in:
parent
d061526924
commit
82708e4273
79 changed files with 813 additions and 599 deletions
|
@ -76,7 +76,11 @@ public class CardDownloadData {
|
||||||
this.tokenDescriptor = card.tokenDescriptor;
|
this.tokenDescriptor = card.tokenDescriptor;
|
||||||
this.tokenClassName = card.tokenClassName;
|
this.tokenClassName = card.tokenClassName;
|
||||||
this.fileName = card.fileName;
|
this.fileName = card.fileName;
|
||||||
|
this.splitCard = card.splitCard;
|
||||||
|
this.flipCard = card.flipCard;
|
||||||
|
this.flippedSide = card.flippedSide;
|
||||||
|
this.downloadName = card.downloadName;
|
||||||
|
this.isType2 = card.isType2;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -31,6 +31,7 @@ public class MomirGame extends GameImpl {
|
||||||
|
|
||||||
public MomirGame(final MomirGame game) {
|
public MomirGame(final MomirGame game) {
|
||||||
super(game);
|
super(game);
|
||||||
|
this.numPlayers = game.numPlayers;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -68,7 +68,7 @@ public class ComputerPlayer6 extends ComputerPlayer /*implements Player*/ {
|
||||||
|
|
||||||
protected Set<String> actionCache;
|
protected Set<String> actionCache;
|
||||||
private static final List<TreeOptimizer> optimizers = new ArrayList<>();
|
private static final List<TreeOptimizer> optimizers = new ArrayList<>();
|
||||||
protected int lastLoggedTurn = 0;
|
protected int lastLoggedTurn;
|
||||||
protected static final String BLANKS = "...............................................";
|
protected static final String BLANKS = "...............................................";
|
||||||
|
|
||||||
static {
|
static {
|
||||||
|
@ -80,11 +80,7 @@ public class ComputerPlayer6 extends ComputerPlayer /*implements Player*/ {
|
||||||
|
|
||||||
public ComputerPlayer6(String name, RangeOfInfluence range, int skill) {
|
public ComputerPlayer6(String name, RangeOfInfluence range, int skill) {
|
||||||
super(name, range);
|
super(name, range);
|
||||||
if (skill < 4) {
|
maxDepth = Math.max(skill, 4);
|
||||||
maxDepth = 4;
|
|
||||||
} else {
|
|
||||||
maxDepth = skill;
|
|
||||||
}
|
|
||||||
maxThink = skill * 3;
|
maxThink = skill * 3;
|
||||||
maxNodes = Config2.maxNodes;
|
maxNodes = Config2.maxNodes;
|
||||||
getSuggestedActions();
|
getSuggestedActions();
|
||||||
|
@ -94,7 +90,11 @@ public class ComputerPlayer6 extends ComputerPlayer /*implements Player*/ {
|
||||||
public ComputerPlayer6(final ComputerPlayer6 player) {
|
public ComputerPlayer6(final ComputerPlayer6 player) {
|
||||||
super(player);
|
super(player);
|
||||||
this.maxDepth = player.maxDepth;
|
this.maxDepth = player.maxDepth;
|
||||||
|
this.maxNodes = player.maxNodes;
|
||||||
|
this.maxThink = player.maxThink;
|
||||||
|
this.lastLoggedTurn = player.lastLoggedTurn;
|
||||||
this.currentScore = player.currentScore;
|
this.currentScore = player.currentScore;
|
||||||
|
this.root = player.root;
|
||||||
if (player.combat != null) {
|
if (player.combat != null) {
|
||||||
this.combat = player.combat.copy();
|
this.combat = player.combat.copy();
|
||||||
}
|
}
|
||||||
|
@ -102,6 +102,8 @@ public class ComputerPlayer6 extends ComputerPlayer /*implements Player*/ {
|
||||||
this.targets.addAll(player.targets);
|
this.targets.addAll(player.targets);
|
||||||
this.choices.addAll(player.choices);
|
this.choices.addAll(player.choices);
|
||||||
this.actionCache = player.actionCache;
|
this.actionCache = player.actionCache;
|
||||||
|
this.attackersList.addAll(player.attackersList);
|
||||||
|
this.attackersToCheck.addAll(player.attackersToCheck);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -58,6 +58,7 @@ public class SimulatedPlayer2 extends ComputerPlayer {
|
||||||
this.suggested = new ArrayList<>(player.suggested);
|
this.suggested = new ArrayList<>(player.suggested);
|
||||||
// this.allActions = player.allActions; // dynamic, no need to copy
|
// this.allActions = player.allActions; // dynamic, no need to copy
|
||||||
this.originalPlayer = player.originalPlayer.copy();
|
this.originalPlayer = player.originalPlayer.copy();
|
||||||
|
this.forced = player.forced;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -67,7 +67,7 @@ import java.util.Map.Entry;
|
||||||
public class ComputerPlayer extends PlayerImpl implements Player {
|
public class ComputerPlayer extends PlayerImpl implements Player {
|
||||||
|
|
||||||
private static final Logger log = Logger.getLogger(ComputerPlayer.class);
|
private static final Logger log = Logger.getLogger(ComputerPlayer.class);
|
||||||
private long lastThinkTime = 0; // msecs for last AI actions calc
|
private long lastThinkTime; // msecs for last AI actions calc
|
||||||
|
|
||||||
protected int PASSIVITY_PENALTY = 5; // Penalty value for doing nothing if some actions are available
|
protected int PASSIVITY_PENALTY = 5; // Penalty value for doing nothing if some actions are available
|
||||||
|
|
||||||
|
@ -105,6 +105,9 @@ public class ComputerPlayer extends PlayerImpl implements Player {
|
||||||
|
|
||||||
public ComputerPlayer(final ComputerPlayer player) {
|
public ComputerPlayer(final ComputerPlayer player) {
|
||||||
super(player);
|
super(player);
|
||||||
|
this.lastThinkTime = player.lastThinkTime;
|
||||||
|
this.PASSIVITY_PENALTY = player.PASSIVITY_PENALTY;
|
||||||
|
this.COMPUTER_DISABLE_TIMEOUT_IN_GAME_SIMULATIONS = player.COMPUTER_DISABLE_TIMEOUT_IN_GAME_SIMULATIONS;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -31,10 +31,13 @@ public class ComputerPlayerMCTS extends ComputerPlayer implements Player {
|
||||||
private static final int THINK_MAX_RATIO = 100;
|
private static final int THINK_MAX_RATIO = 100;
|
||||||
private static final double THINK_TIME_MULTIPLIER = 2.0;
|
private static final double THINK_TIME_MULTIPLIER = 2.0;
|
||||||
private static final boolean USE_MULTIPLE_THREADS = true;
|
private static final boolean USE_MULTIPLE_THREADS = true;
|
||||||
|
private static final Logger logger = Logger.getLogger(ComputerPlayerMCTS.class);
|
||||||
|
|
||||||
protected transient MCTSNode root;
|
protected transient MCTSNode root;
|
||||||
|
protected String lastPhase = "";
|
||||||
|
protected long totalThinkTime;
|
||||||
|
protected long totalSimulations;
|
||||||
protected int maxThinkTime;
|
protected int maxThinkTime;
|
||||||
private static final Logger logger = Logger.getLogger(ComputerPlayerMCTS.class);
|
|
||||||
private int poolSize;
|
private int poolSize;
|
||||||
|
|
||||||
public ComputerPlayerMCTS(String name, RangeOfInfluence range, int skill) {
|
public ComputerPlayerMCTS(String name, RangeOfInfluence range, int skill) {
|
||||||
|
@ -50,6 +53,11 @@ public class ComputerPlayerMCTS extends ComputerPlayer implements Player {
|
||||||
|
|
||||||
public ComputerPlayerMCTS(final ComputerPlayerMCTS player) {
|
public ComputerPlayerMCTS(final ComputerPlayerMCTS player) {
|
||||||
super(player);
|
super(player);
|
||||||
|
this.maxThinkTime = player.maxThinkTime;
|
||||||
|
this.poolSize = player.poolSize;
|
||||||
|
this.lastPhase = player.lastPhase;
|
||||||
|
this.totalSimulations = player.totalSimulations;
|
||||||
|
this.totalThinkTime = player.totalThinkTime;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -57,8 +65,6 @@ public class ComputerPlayerMCTS extends ComputerPlayer implements Player {
|
||||||
return new ComputerPlayerMCTS(this);
|
return new ComputerPlayerMCTS(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected String lastPhase = "";
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean priority(Game game) {
|
public boolean priority(Game game) {
|
||||||
if (game.getStep().getType() == PhaseStep.UPKEEP) {
|
if (game.getStep().getType() == PhaseStep.UPKEEP) {
|
||||||
|
@ -152,9 +158,6 @@ public class ComputerPlayerMCTS extends ComputerPlayer implements Player {
|
||||||
MCTSNode.logHitMiss();
|
MCTSNode.logHitMiss();
|
||||||
}
|
}
|
||||||
|
|
||||||
protected long totalThinkTime = 0;
|
|
||||||
protected long totalSimulations = 0;
|
|
||||||
|
|
||||||
protected void applyMCTS(final Game game, final NextAction action) {
|
protected void applyMCTS(final Game game, final NextAction action) {
|
||||||
|
|
||||||
int thinkTime = calculateThinkTime(game, action);
|
int thinkTime = calculateThinkTime(game, action);
|
||||||
|
|
|
@ -30,8 +30,8 @@ import java.util.*;
|
||||||
*/
|
*/
|
||||||
public class SimulatedPlayerMCTS extends MCTSPlayer {
|
public class SimulatedPlayerMCTS extends MCTSPlayer {
|
||||||
|
|
||||||
private boolean isSimulatedPlayer;
|
private final boolean isSimulatedPlayer;
|
||||||
private int actionCount = 0;
|
private int actionCount;
|
||||||
private static final Logger logger = Logger.getLogger(SimulatedPlayerMCTS.class);
|
private static final Logger logger = Logger.getLogger(SimulatedPlayerMCTS.class);
|
||||||
|
|
||||||
public SimulatedPlayerMCTS(Player originalPlayer, boolean isSimulatedPlayer) {
|
public SimulatedPlayerMCTS(Player originalPlayer, boolean isSimulatedPlayer) {
|
||||||
|
@ -43,6 +43,7 @@ public class SimulatedPlayerMCTS extends MCTSPlayer {
|
||||||
public SimulatedPlayerMCTS(final SimulatedPlayerMCTS player) {
|
public SimulatedPlayerMCTS(final SimulatedPlayerMCTS player) {
|
||||||
super(player);
|
super(player);
|
||||||
this.isSimulatedPlayer = player.isSimulatedPlayer;
|
this.isSimulatedPlayer = player.isSimulatedPlayer;
|
||||||
|
this.actionCount = player.actionCount;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -40,8 +40,8 @@ public class ComputerPlayer2 extends ComputerPlayer implements Player {
|
||||||
protected int maxDepth;
|
protected int maxDepth;
|
||||||
protected int maxNodes;
|
protected int maxNodes;
|
||||||
protected int maxThink;
|
protected int maxThink;
|
||||||
protected int nodeCount = 0;
|
protected int nodeCount;
|
||||||
protected long thinkTime = 0;
|
protected long thinkTime;
|
||||||
protected transient LinkedList<Ability> actions = new LinkedList<>();
|
protected transient LinkedList<Ability> actions = new LinkedList<>();
|
||||||
protected transient List<UUID> targets = new ArrayList<>();
|
protected transient List<UUID> targets = new ArrayList<>();
|
||||||
protected transient List<String> choices = new ArrayList<>();
|
protected transient List<String> choices = new ArrayList<>();
|
||||||
|
@ -59,6 +59,10 @@ public class ComputerPlayer2 extends ComputerPlayer implements Player {
|
||||||
public ComputerPlayer2(final ComputerPlayer2 player) {
|
public ComputerPlayer2(final ComputerPlayer2 player) {
|
||||||
super(player);
|
super(player);
|
||||||
this.maxDepth = player.maxDepth;
|
this.maxDepth = player.maxDepth;
|
||||||
|
this.maxNodes = player.maxNodes;
|
||||||
|
this.maxThink = player.maxThink;
|
||||||
|
this.nodeCount = player.nodeCount;
|
||||||
|
this.thinkTime = player.thinkTime;
|
||||||
this.currentScore = player.currentScore;
|
this.currentScore = player.currentScore;
|
||||||
if (player.combat != null) {
|
if (player.combat != null) {
|
||||||
this.combat = player.combat.copy();
|
this.combat = player.combat.copy();
|
||||||
|
|
|
@ -28,9 +28,9 @@ import java.util.concurrent.ConcurrentLinkedQueue;
|
||||||
public class SimulatedPlayer extends ComputerPlayer {
|
public class SimulatedPlayer extends ComputerPlayer {
|
||||||
|
|
||||||
private static final Logger logger = Logger.getLogger(SimulatedPlayer.class);
|
private static final Logger logger = Logger.getLogger(SimulatedPlayer.class);
|
||||||
private boolean isSimulatedPlayer;
|
private final boolean isSimulatedPlayer;
|
||||||
private transient ConcurrentLinkedQueue<Ability> allActions;
|
private transient ConcurrentLinkedQueue<Ability> allActions;
|
||||||
private static PassAbility pass = new PassAbility();
|
private static final PassAbility pass = new PassAbility();
|
||||||
protected int maxDepth;
|
protected int maxDepth;
|
||||||
|
|
||||||
public SimulatedPlayer(Player originalPlayer, boolean isSimulatedPlayer, int maxDepth) {
|
public SimulatedPlayer(Player originalPlayer, boolean isSimulatedPlayer, int maxDepth) {
|
||||||
|
@ -44,6 +44,7 @@ public class SimulatedPlayer extends ComputerPlayer {
|
||||||
public SimulatedPlayer(final SimulatedPlayer player) {
|
public SimulatedPlayer(final SimulatedPlayer player) {
|
||||||
super(player);
|
super(player);
|
||||||
this.isSimulatedPlayer = player.isSimulatedPlayer;
|
this.isSimulatedPlayer = player.isSimulatedPlayer;
|
||||||
|
this.maxDepth = player.maxDepth;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -61,8 +61,9 @@ class CaromEffect extends RedirectionEffect {
|
||||||
staticText = "The next " + amount + " damage that would be dealt to target creature this turn is dealt to another target creature instead";
|
staticText = "The next " + amount + " damage that would be dealt to target creature this turn is dealt to another target creature instead";
|
||||||
}
|
}
|
||||||
|
|
||||||
public CaromEffect(final CaromEffect effect) {
|
private CaromEffect(final CaromEffect effect) {
|
||||||
super(effect);
|
super(effect);
|
||||||
|
this.redirectToObject = effect.redirectToObject;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -30,7 +30,8 @@ public final class DesecratorHag extends CardImpl {
|
||||||
this.power = new MageInt(2);
|
this.power = new MageInt(2);
|
||||||
this.toughness = new MageInt(2);
|
this.toughness = new MageInt(2);
|
||||||
|
|
||||||
// When Desecrator Hag enters the battlefield, return to your hand the creature card in your graveyard with the greatest power. If two or more cards are tied for greatest power, you choose one of them.
|
// When Desecrator Hag enters the battlefield, return to your hand the creature card in your graveyard with the greatest power.
|
||||||
|
// If two or more cards are tied for greatest power, you choose one of them.
|
||||||
this.addAbility(new EntersBattlefieldTriggeredAbility(new DesecratorHagEffect(), false));
|
this.addAbility(new EntersBattlefieldTriggeredAbility(new DesecratorHagEffect(), false));
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -47,17 +48,21 @@ public final class DesecratorHag extends CardImpl {
|
||||||
|
|
||||||
class DesecratorHagEffect extends OneShotEffect {
|
class DesecratorHagEffect extends OneShotEffect {
|
||||||
|
|
||||||
int creatureGreatestPower = 0;
|
int creatureGreatestPower;
|
||||||
Cards cards = new CardsImpl();
|
Cards cards = new CardsImpl();
|
||||||
TargetCard target = new TargetCard(Zone.GRAVEYARD, new FilterCard());
|
TargetCard target = new TargetCard(Zone.GRAVEYARD, new FilterCard());
|
||||||
|
|
||||||
public DesecratorHagEffect() {
|
public DesecratorHagEffect() {
|
||||||
super(Outcome.DrawCard);
|
super(Outcome.DrawCard);
|
||||||
this.staticText = "return to your hand the creature card in your graveyard with the greatest power. If two or more cards are tied for greatest power, you choose one of them";
|
this.staticText = "return to your hand the creature card in your graveyard with the greatest power. " +
|
||||||
|
"If two or more cards are tied for greatest power, you choose one of them";
|
||||||
}
|
}
|
||||||
|
|
||||||
public DesecratorHagEffect(final DesecratorHagEffect effect) {
|
public DesecratorHagEffect(final DesecratorHagEffect effect) {
|
||||||
super(effect);
|
super(effect);
|
||||||
|
this.creatureGreatestPower = effect.creatureGreatestPower;
|
||||||
|
this.cards = effect.cards.copy();
|
||||||
|
this.target = effect.target.copy();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -68,35 +73,40 @@ class DesecratorHagEffect extends OneShotEffect {
|
||||||
@Override
|
@Override
|
||||||
public boolean apply(Game game, Ability source) {
|
public boolean apply(Game game, Ability source) {
|
||||||
Player you = game.getPlayer(source.getControllerId());
|
Player you = game.getPlayer(source.getControllerId());
|
||||||
if (you != null) {
|
if (you == null) {
|
||||||
for (Card card : you.getGraveyard().getCards(game)) {
|
return false;
|
||||||
if (card.isCreature(game)) {
|
}
|
||||||
if (card.getPower().getValue() > creatureGreatestPower) {
|
|
||||||
creatureGreatestPower = card.getPower().getValue();
|
for (Card card : you.getGraveyard().getCards(game)) {
|
||||||
cards.clear();
|
if (card.isCreature(game)) {
|
||||||
|
if (card.getPower().getValue() > creatureGreatestPower) {
|
||||||
|
creatureGreatestPower = card.getPower().getValue();
|
||||||
|
cards.clear();
|
||||||
|
cards.add(card);
|
||||||
|
} else {
|
||||||
|
if (card.getPower().getValue() == creatureGreatestPower) {
|
||||||
cards.add(card);
|
cards.add(card);
|
||||||
} else {
|
|
||||||
if (card.getPower().getValue() == creatureGreatestPower) {
|
|
||||||
cards.add(card);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (cards.isEmpty()) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
if (cards.size() > 1
|
|
||||||
&& you.choose(Outcome.DrawCard, cards, target, game)) {
|
|
||||||
if (target != null) {
|
|
||||||
Card card = game.getCard(target.getFirstTarget());
|
|
||||||
if (card != null) {
|
|
||||||
return you.moveCards(card, Zone.HAND, source, game);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
return you.moveCards(cards, Zone.HAND, source, game);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return false;
|
|
||||||
|
if (cards.isEmpty()) {
|
||||||
|
return false;
|
||||||
|
} else if (cards.size() == 1) {
|
||||||
|
return you.moveCards(cards, Zone.HAND, source, game);
|
||||||
|
} else {
|
||||||
|
if (you.choose(Outcome.DrawCard, cards, target, game)) {
|
||||||
|
if (target == null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
Card card = game.getCard(target.getFirstTarget());
|
||||||
|
if (card != null) {
|
||||||
|
return you.moveCards(card, Zone.HAND, source, game);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -33,7 +33,9 @@ public final class DesperateGambit extends CardImpl {
|
||||||
public DesperateGambit(UUID ownerId, CardSetInfo setInfo) {
|
public DesperateGambit(UUID ownerId, CardSetInfo setInfo) {
|
||||||
super(ownerId,setInfo,new CardType[]{CardType.INSTANT},"{R}");
|
super(ownerId,setInfo,new CardType[]{CardType.INSTANT},"{R}");
|
||||||
|
|
||||||
// Choose a source you control and flip a coin. If you win the flip, the next time that source would deal damage this turn, it deals double that damage instead. If you lose the flip, the next time it would deal damage this turn, prevent that damage.
|
// Choose a source you control and flip a coin.
|
||||||
|
// If you win the flip, the next time that source would deal damage this turn, it deals double that damage instead.
|
||||||
|
// If you lose the flip, the next time it would deal damage this turn, prevent that damage.
|
||||||
this.getSpellAbility().addEffect(new DesperateGambitEffect());
|
this.getSpellAbility().addEffect(new DesperateGambitEffect());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -54,13 +56,16 @@ class DesperateGambitEffect extends PreventionEffectImpl {
|
||||||
|
|
||||||
public DesperateGambitEffect() {
|
public DesperateGambitEffect() {
|
||||||
super(Duration.EndOfTurn, Integer.MAX_VALUE, false);
|
super(Duration.EndOfTurn, Integer.MAX_VALUE, false);
|
||||||
staticText = "Choose a source you control and flip a coin. If you win the flip, the next time that source would deal damage this turn, it deals double that damage instead. If you lose the flip, the next time it would deal damage this turn, prevent that damage";
|
staticText = "Choose a source you control and flip a coin. " +
|
||||||
|
"If you win the flip, the next time that source would deal damage this turn, it deals double that damage instead. " +
|
||||||
|
"If you lose the flip, the next time it would deal damage this turn, prevent that damage";
|
||||||
this.target = new TargetControlledSource();
|
this.target = new TargetControlledSource();
|
||||||
}
|
}
|
||||||
|
|
||||||
public DesperateGambitEffect(final DesperateGambitEffect effect) {
|
public DesperateGambitEffect(final DesperateGambitEffect effect) {
|
||||||
super(effect);
|
super(effect);
|
||||||
this.target = effect.target.copy();
|
this.target = effect.target.copy();
|
||||||
|
this.wonFlip = effect.wonFlip;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -80,7 +80,7 @@ class DoublingSeasonTokenEffect extends ReplacementEffectImpl {
|
||||||
|
|
||||||
class DoublingSeasonCounterEffect extends ReplacementEffectImpl {
|
class DoublingSeasonCounterEffect extends ReplacementEffectImpl {
|
||||||
|
|
||||||
private boolean landPlayed = false; // a played land is not an effect
|
private boolean landPlayed; // a played land is not an effect
|
||||||
|
|
||||||
DoublingSeasonCounterEffect() {
|
DoublingSeasonCounterEffect() {
|
||||||
super(Duration.WhileOnBattlefield, Outcome.BoostCreature, false);
|
super(Duration.WhileOnBattlefield, Outcome.BoostCreature, false);
|
||||||
|
@ -89,6 +89,7 @@ class DoublingSeasonCounterEffect extends ReplacementEffectImpl {
|
||||||
|
|
||||||
private DoublingSeasonCounterEffect(final DoublingSeasonCounterEffect effect) {
|
private DoublingSeasonCounterEffect(final DoublingSeasonCounterEffect effect) {
|
||||||
super(effect);
|
super(effect);
|
||||||
|
this.landPlayed = effect.landPlayed;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -110,8 +111,7 @@ class DoublingSeasonCounterEffect extends ReplacementEffectImpl {
|
||||||
}
|
}
|
||||||
if (permanent == null) {
|
if (permanent == null) {
|
||||||
permanent = game.getPermanentEntering(event.getTargetId());
|
permanent = game.getPermanentEntering(event.getTargetId());
|
||||||
landPlayed = (permanent != null
|
landPlayed = (permanent != null && permanent.isLand(game)); // a played land is not an effect
|
||||||
&& permanent.isLand(game)); // a played land is not an effect
|
|
||||||
}
|
}
|
||||||
return permanent != null
|
return permanent != null
|
||||||
&& permanent.isControlledBy(source.getControllerId())
|
&& permanent.isControlledBy(source.getControllerId())
|
||||||
|
|
|
@ -8,6 +8,7 @@ import mage.abilities.common.SimpleActivatedAbility;
|
||||||
import mage.abilities.common.SimpleStaticAbility;
|
import mage.abilities.common.SimpleStaticAbility;
|
||||||
import mage.abilities.common.delayed.AtTheEndOfCombatDelayedTriggeredAbility;
|
import mage.abilities.common.delayed.AtTheEndOfCombatDelayedTriggeredAbility;
|
||||||
import mage.abilities.condition.Condition;
|
import mage.abilities.condition.Condition;
|
||||||
|
import mage.abilities.costs.mana.GenericManaCost;
|
||||||
import mage.abilities.costs.mana.ManaCostsImpl;
|
import mage.abilities.costs.mana.ManaCostsImpl;
|
||||||
import mage.abilities.decorator.ConditionalContinuousRuleModifyingEffect;
|
import mage.abilities.decorator.ConditionalContinuousRuleModifyingEffect;
|
||||||
import mage.abilities.effects.ContinuousEffect;
|
import mage.abilities.effects.ContinuousEffect;
|
||||||
|
@ -101,7 +102,7 @@ class DreadWightTriggeredAbility extends TriggeredAbilityImpl {
|
||||||
|
|
||||||
class DreadWightEffect extends OneShotEffect {
|
class DreadWightEffect extends OneShotEffect {
|
||||||
|
|
||||||
String rule = "doesn't untap during its controller's untap step for as long as it has a paralyzation counter on it.";
|
static final String rule = "doesn't untap during its controller's untap step for as long as it has a paralyzation counter on it.";
|
||||||
|
|
||||||
public DreadWightEffect() {
|
public DreadWightEffect() {
|
||||||
super(Outcome.Detriment);
|
super(Outcome.Detriment);
|
||||||
|
@ -122,44 +123,42 @@ class DreadWightEffect extends OneShotEffect {
|
||||||
@Override
|
@Override
|
||||||
public boolean apply(Game game, Ability source) {
|
public boolean apply(Game game, Ability source) {
|
||||||
Permanent permanent = game.getPermanent(targetPointer.getFirst(game, source));
|
Permanent permanent = game.getPermanent(targetPointer.getFirst(game, source));
|
||||||
if (permanent != null) {
|
if (permanent == null) {
|
||||||
// add paralyzation counter
|
return false;
|
||||||
Effect effect = new AddCountersTargetEffect(CounterType.PARALYZATION.createInstance());
|
|
||||||
effect.setTargetPointer(new FixedTarget(permanent, game));
|
|
||||||
effect.apply(game, source);
|
|
||||||
// tap permanent
|
|
||||||
permanent.tap(source, game);
|
|
||||||
// does not untap while paralyzation counter is on it
|
|
||||||
ContinuousRuleModifyingEffect effect2 = new DreadWightDoNotUntapEffect(
|
|
||||||
Duration.WhileOnBattlefield,
|
|
||||||
permanent.getId());
|
|
||||||
effect2.setText("This creature doesn't untap during its controller's untap step for as long as it has a paralyzation counter on it");
|
|
||||||
Condition condition = new DreadWightCounterCondition(permanent.getId());
|
|
||||||
ConditionalContinuousRuleModifyingEffect conditionalEffect = new ConditionalContinuousRuleModifyingEffect(
|
|
||||||
effect2,
|
|
||||||
condition);
|
|
||||||
Ability ability = new SimpleStaticAbility(
|
|
||||||
Zone.BATTLEFIELD,
|
|
||||||
conditionalEffect);
|
|
||||||
ContinuousEffect effect3 = new GainAbilityTargetEffect(
|
|
||||||
ability,
|
|
||||||
Duration.WhileOnBattlefield);
|
|
||||||
ability.setRuleVisible(true);
|
|
||||||
effect3.setTargetPointer(new FixedTarget(permanent, game));
|
|
||||||
game.addEffect(effect3, source);
|
|
||||||
// each gains 4: remove paralyzation counter
|
|
||||||
Ability activatedAbility = new SimpleActivatedAbility(
|
|
||||||
Zone.BATTLEFIELD,
|
|
||||||
new RemoveCounterSourceEffect(CounterType.PARALYZATION.createInstance()),
|
|
||||||
new ManaCostsImpl("{4}"));
|
|
||||||
ContinuousEffect effect4 = new GainAbilityTargetEffect(
|
|
||||||
activatedAbility,
|
|
||||||
Duration.WhileOnBattlefield);
|
|
||||||
effect4.setTargetPointer(new FixedTarget(permanent, game));
|
|
||||||
game.addEffect(effect4, source);
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
return false;
|
// add paralyzation counter
|
||||||
|
Effect effect = new AddCountersTargetEffect(CounterType.PARALYZATION.createInstance());
|
||||||
|
effect.setTargetPointer(new FixedTarget(permanent, game));
|
||||||
|
effect.apply(game, source);
|
||||||
|
|
||||||
|
// tap permanent
|
||||||
|
permanent.tap(source, game);
|
||||||
|
|
||||||
|
// does not untap while paralyzation counter is on it
|
||||||
|
ContinuousRuleModifyingEffect effect2 = new DreadWightDoNotUntapEffect(Duration.WhileOnBattlefield, permanent.getId());
|
||||||
|
effect2.setText(rule);
|
||||||
|
|
||||||
|
Condition condition = new DreadWightCounterCondition(permanent.getId());
|
||||||
|
ConditionalContinuousRuleModifyingEffect conditionalEffect = new ConditionalContinuousRuleModifyingEffect(
|
||||||
|
effect2,
|
||||||
|
condition);
|
||||||
|
|
||||||
|
Ability ability = new SimpleStaticAbility(Zone.BATTLEFIELD, conditionalEffect);
|
||||||
|
ContinuousEffect effect3 = new GainAbilityTargetEffect(ability, Duration.WhileOnBattlefield);
|
||||||
|
ability.setRuleVisible(true);
|
||||||
|
effect3.setTargetPointer(new FixedTarget(permanent, game));
|
||||||
|
game.addEffect(effect3, source);
|
||||||
|
|
||||||
|
// each gains 4: remove paralyzation counter
|
||||||
|
Ability activatedAbility = new SimpleActivatedAbility(
|
||||||
|
Zone.BATTLEFIELD,
|
||||||
|
new RemoveCounterSourceEffect(CounterType.PARALYZATION.createInstance()),
|
||||||
|
new GenericManaCost(4));
|
||||||
|
ContinuousEffect effect4 = new GainAbilityTargetEffect(activatedAbility, Duration.WhileOnBattlefield);
|
||||||
|
effect4.setTargetPointer(new FixedTarget(permanent, game));
|
||||||
|
game.addEffect(effect4, source);
|
||||||
|
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -97,12 +97,21 @@ class DubiousChallengeEffect extends OneShotEffect {
|
||||||
|
|
||||||
class DubiousChallengeMoveToBattlefieldEffect extends OneShotEffect {
|
class DubiousChallengeMoveToBattlefieldEffect extends OneShotEffect {
|
||||||
|
|
||||||
|
private Cards cards;
|
||||||
|
private Player player;
|
||||||
|
|
||||||
public DubiousChallengeMoveToBattlefieldEffect() {
|
public DubiousChallengeMoveToBattlefieldEffect() {
|
||||||
super(Outcome.Benefit);
|
super(Outcome.Benefit);
|
||||||
}
|
}
|
||||||
|
|
||||||
public DubiousChallengeMoveToBattlefieldEffect(final DubiousChallengeMoveToBattlefieldEffect effect) {
|
public DubiousChallengeMoveToBattlefieldEffect(final DubiousChallengeMoveToBattlefieldEffect effect) {
|
||||||
super(effect);
|
super(effect);
|
||||||
|
if (effect.cards != null) {
|
||||||
|
this.cards = effect.cards.copy();
|
||||||
|
}
|
||||||
|
if (effect.player != null) {
|
||||||
|
this.player = effect.player.copy();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -117,12 +126,10 @@ class DubiousChallengeMoveToBattlefieldEffect extends OneShotEffect {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean apply(Game game, Ability source) {
|
public boolean apply(Game game, Ability source) {
|
||||||
if (cards != null && player != null) {
|
if (cards == null || player == null) {
|
||||||
return player.moveCards(cards, Zone.BATTLEFIELD, source, game);
|
return false;
|
||||||
}
|
}
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
private Cards cards;
|
return player.moveCards(cards, Zone.BATTLEFIELD, source, game);
|
||||||
private Player player;
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -61,17 +61,21 @@ class ElkinBottleExileEffect extends OneShotEffect {
|
||||||
@Override
|
@Override
|
||||||
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) {
|
||||||
Card card = controller.getLibrary().getFromTop(game);
|
return false;
|
||||||
if (card != null) {
|
|
||||||
controller.moveCardsToExile(card, source, game, true, source.getSourceId(), CardUtil.createObjectRealtedWindowTitle(source, game, null));
|
|
||||||
ContinuousEffect effect = new ElkinBottleCastFromExileEffect();
|
|
||||||
effect.setTargetPointer(new FixedTarget(card.getId(), game));
|
|
||||||
game.addEffect(effect, source);
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
return false;
|
|
||||||
|
Card card = controller.getLibrary().getFromTop(game);
|
||||||
|
if (card == null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
controller.moveCardsToExile(card, source, game, true, source.getSourceId(), CardUtil.createObjectRealtedWindowTitle(source, game, null));
|
||||||
|
ContinuousEffect effect = new ElkinBottleCastFromExileEffect();
|
||||||
|
effect.setTargetPointer(new FixedTarget(card.getId(), game));
|
||||||
|
game.addEffect(effect, source);
|
||||||
|
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -86,6 +90,7 @@ class ElkinBottleCastFromExileEffect extends AsThoughEffectImpl {
|
||||||
|
|
||||||
public ElkinBottleCastFromExileEffect(final ElkinBottleCastFromExileEffect effect) {
|
public ElkinBottleCastFromExileEffect(final ElkinBottleCastFromExileEffect effect) {
|
||||||
super(effect);
|
super(effect);
|
||||||
|
this.sameStep = effect.sameStep;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -96,9 +101,9 @@ class ElkinBottleCastFromExileEffect extends AsThoughEffectImpl {
|
||||||
@Override
|
@Override
|
||||||
public boolean isInactive(Ability source, Game game) {
|
public boolean isInactive(Ability source, Game game) {
|
||||||
if (game.getPhase().getStep().getType() == PhaseStep.UPKEEP) {
|
if (game.getPhase().getStep().getType() == PhaseStep.UPKEEP) {
|
||||||
if (!sameStep && game.isActivePlayer(source.getControllerId()) || game.getPlayer(source.getControllerId()).hasReachedNextTurnAfterLeaving()) {
|
return !sameStep
|
||||||
return true;
|
&& game.isActivePlayer(source.getControllerId())
|
||||||
}
|
|| game.getPlayer(source.getControllerId()).hasReachedNextTurnAfterLeaving();
|
||||||
} else {
|
} else {
|
||||||
sameStep = false;
|
sameStep = false;
|
||||||
}
|
}
|
||||||
|
|
|
@ -34,7 +34,9 @@ public final class FoodChain extends CardImpl {
|
||||||
public FoodChain(UUID ownerId, CardSetInfo setInfo) {
|
public FoodChain(UUID ownerId, CardSetInfo setInfo) {
|
||||||
super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{2}{G}");
|
super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{2}{G}");
|
||||||
|
|
||||||
// Exile a creature you control: Add X mana of any one color, where X is the exiled creature's converted mana cost plus one. Spend this mana only to cast creature spells.
|
// Exile a creature you control: Add X mana of any one color,
|
||||||
|
// where X is the exiled creature's converted mana cost plus one.
|
||||||
|
// Spend this mana only to cast creature spells.
|
||||||
Ability ability = new SimpleManaAbility(Zone.BATTLEFIELD, new FoodChainManaEffect(),
|
Ability ability = new SimpleManaAbility(Zone.BATTLEFIELD, new FoodChainManaEffect(),
|
||||||
new ExileTargetCost(new TargetControlledCreaturePermanent(1, 1, StaticFilters.FILTER_CONTROLLED_A_CREATURE, true)));
|
new ExileTargetCost(new TargetControlledCreaturePermanent(1, 1, StaticFilters.FILTER_CONTROLLED_A_CREATURE, true)));
|
||||||
this.addAbility(ability);
|
this.addAbility(ability);
|
||||||
|
@ -68,11 +70,13 @@ class FoodChainManaEffect extends ManaEffect {
|
||||||
ConditionalManaBuilder manaBuilder = new FoodChainManaBuilder();
|
ConditionalManaBuilder manaBuilder = new FoodChainManaBuilder();
|
||||||
|
|
||||||
FoodChainManaEffect() {
|
FoodChainManaEffect() {
|
||||||
this.staticText = "Add X mana of any one color, where X is 1 plus the exiled creature's mana value. Spend this mana only to cast creature spells";
|
this.staticText = "Add X mana of any one color, where X is 1 plus the exiled creature's mana value. " +
|
||||||
|
"Spend this mana only to cast creature spells";
|
||||||
}
|
}
|
||||||
|
|
||||||
FoodChainManaEffect(final FoodChainManaEffect effect) {
|
FoodChainManaEffect(final FoodChainManaEffect effect) {
|
||||||
super(effect);
|
super(effect);
|
||||||
|
this.manaBuilder = effect.manaBuilder;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -83,21 +87,25 @@ class FoodChainManaEffect extends ManaEffect {
|
||||||
@Override
|
@Override
|
||||||
public List<Mana> getNetMana(Game game, Ability source) {
|
public List<Mana> getNetMana(Game game, Ability source) {
|
||||||
List<Mana> netMana = new ArrayList<>();
|
List<Mana> netMana = new ArrayList<>();
|
||||||
if (game != null) {
|
if (game == null) {
|
||||||
int cmc = -1;
|
return netMana;
|
||||||
for (Permanent permanent : game.getBattlefield().getAllActivePermanents(source.getControllerId())) {
|
}
|
||||||
if (permanent.isCreature(game)) {
|
|
||||||
cmc = Math.max(cmc, permanent.getManaCost().manaValue());
|
int cmc = -1;
|
||||||
}
|
for (Permanent permanent : game.getBattlefield().getAllActivePermanents(source.getControllerId())) {
|
||||||
}
|
if (permanent.isCreature(game)) {
|
||||||
if (cmc != -1) {
|
cmc = Math.max(cmc, permanent.getManaCost().manaValue());
|
||||||
netMana.add(manaBuilder.setMana(Mana.BlackMana(cmc + 1), source, game).build());
|
|
||||||
netMana.add(manaBuilder.setMana(Mana.BlueMana(cmc + 1), source, game).build());
|
|
||||||
netMana.add(manaBuilder.setMana(Mana.RedMana(cmc + 1), source, game).build());
|
|
||||||
netMana.add(manaBuilder.setMana(Mana.GreenMana(cmc + 1), source, game).build());
|
|
||||||
netMana.add(manaBuilder.setMana(Mana.WhiteMana(cmc + 1), source, game).build());
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (cmc != -1) {
|
||||||
|
netMana.add(manaBuilder.setMana(Mana.BlackMana(cmc + 1), source, game).build());
|
||||||
|
netMana.add(manaBuilder.setMana(Mana.BlueMana( cmc + 1), source, game).build());
|
||||||
|
netMana.add(manaBuilder.setMana(Mana.RedMana( cmc + 1), source, game).build());
|
||||||
|
netMana.add(manaBuilder.setMana(Mana.GreenMana(cmc + 1), source, game).build());
|
||||||
|
netMana.add(manaBuilder.setMana(Mana.WhiteMana(cmc + 1), source, game).build());
|
||||||
|
}
|
||||||
|
|
||||||
return netMana;
|
return netMana;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -107,24 +115,27 @@ class FoodChainManaEffect extends ManaEffect {
|
||||||
if (game == null) {
|
if (game == null) {
|
||||||
return mana;
|
return mana;
|
||||||
}
|
}
|
||||||
|
|
||||||
Player controller = game.getPlayer(source.getControllerId());
|
Player controller = game.getPlayer(source.getControllerId());
|
||||||
if (controller != null) {
|
if (controller == null) {
|
||||||
int manaCostExiled = 0;
|
return mana;
|
||||||
for (Cost cost : source.getCosts()) {
|
}
|
||||||
if (cost.isPaid() && cost instanceof ExileTargetCost) {
|
|
||||||
for (Card card : ((ExileTargetCost) cost).getPermanents()) {
|
int manaCostExiled = 0;
|
||||||
manaCostExiled += card.getManaValue();
|
for (Cost cost : source.getCosts()) {
|
||||||
}
|
if (cost.isPaid() && cost instanceof ExileTargetCost) {
|
||||||
|
for (Card card : ((ExileTargetCost) cost).getPermanents()) {
|
||||||
|
manaCostExiled += card.getManaValue();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ChoiceColor choice = new ChoiceColor();
|
|
||||||
if (!controller.choose(Outcome.PutManaInPool, choice, game)) {
|
|
||||||
return mana;
|
|
||||||
}
|
|
||||||
Mana chosen = choice.getMana(manaCostExiled + 1);
|
|
||||||
return manaBuilder.setMana(chosen, source, game).build();
|
|
||||||
}
|
}
|
||||||
return mana;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
ChoiceColor choice = new ChoiceColor();
|
||||||
|
if (!controller.choose(Outcome.PutManaInPool, choice, game)) {
|
||||||
|
return mana;
|
||||||
|
}
|
||||||
|
|
||||||
|
Mana chosen = choice.getMana(manaCostExiled + 1);
|
||||||
|
return manaBuilder.setMana(chosen, source, game).build();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -86,7 +86,7 @@ class FrayingSanityTriggeredAbility extends TriggeredAbilityImpl {
|
||||||
|
|
||||||
class FrayingSanityEffect extends OneShotEffect {
|
class FrayingSanityEffect extends OneShotEffect {
|
||||||
|
|
||||||
int xAmount = 0;
|
int xAmount;
|
||||||
|
|
||||||
public FrayingSanityEffect() {
|
public FrayingSanityEffect() {
|
||||||
super(Outcome.Detriment);
|
super(Outcome.Detriment);
|
||||||
|
@ -95,6 +95,7 @@ class FrayingSanityEffect extends OneShotEffect {
|
||||||
|
|
||||||
public FrayingSanityEffect(final FrayingSanityEffect effect) {
|
public FrayingSanityEffect(final FrayingSanityEffect effect) {
|
||||||
super(effect);
|
super(effect);
|
||||||
|
this.xAmount = effect.xAmount;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -33,7 +33,8 @@ public final class GabrielAngelfire extends CardImpl {
|
||||||
this.power = new MageInt(4);
|
this.power = new MageInt(4);
|
||||||
this.toughness = new MageInt(4);
|
this.toughness = new MageInt(4);
|
||||||
|
|
||||||
// At the beginning of your upkeep, choose flying, first strike, trample, or rampage 3. Gabriel Angelfire gains that ability until your next upkeep.
|
// At the beginning of your upkeep, choose flying, first strike, trample, or rampage 3.
|
||||||
|
// Gabriel Angelfire gains that ability until your next upkeep.
|
||||||
this.addAbility(new BeginningOfUpkeepTriggeredAbility(new GabrielAngelfireGainAbilityEffect(), TargetController.YOU, false));
|
this.addAbility(new BeginningOfUpkeepTriggeredAbility(new GabrielAngelfireGainAbilityEffect(), TargetController.YOU, false));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -64,9 +65,10 @@ class GabrielAngelfireGainAbilityEffect extends GainAbilitySourceEffect {
|
||||||
staticText = "choose flying, first strike, trample, or rampage 3. {this} gains that ability until your next upkeep";
|
staticText = "choose flying, first strike, trample, or rampage 3. {this} gains that ability until your next upkeep";
|
||||||
}
|
}
|
||||||
|
|
||||||
public GabrielAngelfireGainAbilityEffect(final GabrielAngelfireGainAbilityEffect effect) {
|
private GabrielAngelfireGainAbilityEffect(final GabrielAngelfireGainAbilityEffect effect) {
|
||||||
super(effect);
|
super(effect);
|
||||||
ability.newId();
|
ability.newId();
|
||||||
|
this.sameStep = effect.sameStep;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -77,9 +79,7 @@ class GabrielAngelfireGainAbilityEffect extends GainAbilitySourceEffect {
|
||||||
@Override
|
@Override
|
||||||
public boolean isInactive(Ability source, Game game) {
|
public boolean isInactive(Ability source, Game game) {
|
||||||
if (game.getPhase().getStep().getType() == PhaseStep.UPKEEP) {
|
if (game.getPhase().getStep().getType() == PhaseStep.UPKEEP) {
|
||||||
if (!sameStep && game.isActivePlayer(source.getControllerId()) || game.getPlayer(source.getControllerId()).hasReachedNextTurnAfterLeaving()) {
|
return !sameStep && game.isActivePlayer(source.getControllerId()) || game.getPlayer(source.getControllerId()).hasReachedNextTurnAfterLeaving();
|
||||||
return true;
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
sameStep = false;
|
sameStep = false;
|
||||||
}
|
}
|
||||||
|
@ -89,29 +89,32 @@ class GabrielAngelfireGainAbilityEffect extends GainAbilitySourceEffect {
|
||||||
@Override
|
@Override
|
||||||
public void init(Ability source, Game game) {
|
public void init(Ability source, Game game) {
|
||||||
super.init(source, game);
|
super.init(source, game);
|
||||||
|
|
||||||
Player controller = game.getPlayer(source.getControllerId());
|
Player controller = game.getPlayer(source.getControllerId());
|
||||||
if (controller != null) {
|
if (controller == null) {
|
||||||
Choice choice = new ChoiceImpl(true);
|
return;
|
||||||
choice.setMessage("Choose one");
|
}
|
||||||
choice.setChoices(choices);
|
|
||||||
if (controller.choose(outcome, choice, game)) {
|
Choice choice = new ChoiceImpl(true);
|
||||||
switch (choice.getChoice()) {
|
choice.setMessage("Choose one");
|
||||||
case "First strike":
|
choice.setChoices(choices);
|
||||||
ability = FirstStrikeAbility.getInstance();
|
if (controller.choose(outcome, choice, game)) {
|
||||||
break;
|
switch (choice.getChoice()) {
|
||||||
case "Trample":
|
case "First strike":
|
||||||
ability = TrampleAbility.getInstance();
|
ability = FirstStrikeAbility.getInstance();
|
||||||
break;
|
break;
|
||||||
case "Rampage 3":
|
case "Trample":
|
||||||
ability = new RampageAbility(3);
|
ability = TrampleAbility.getInstance();
|
||||||
break;
|
break;
|
||||||
default:
|
case "Rampage 3":
|
||||||
ability = FlyingAbility.getInstance();
|
ability = new RampageAbility(3);
|
||||||
break;
|
break;
|
||||||
}
|
default:
|
||||||
} else {
|
ability = FlyingAbility.getInstance();
|
||||||
discard();
|
break;
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
discard();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -50,11 +50,10 @@ public final class GloomwidowsFeast extends CardImpl {
|
||||||
|
|
||||||
class GloomwidowsFeastEffect extends OneShotEffect {
|
class GloomwidowsFeastEffect extends OneShotEffect {
|
||||||
|
|
||||||
boolean applied = false;
|
|
||||||
|
|
||||||
public GloomwidowsFeastEffect() {
|
public GloomwidowsFeastEffect() {
|
||||||
super(Outcome.DestroyPermanent);
|
super(Outcome.DestroyPermanent);
|
||||||
this.staticText = "Destroy target creature with flying. If that creature was blue or black, create a 1/2 green Spider creature token with reach";
|
this.staticText = "Destroy target creature with flying. " +
|
||||||
|
"If that creature was blue or black, create a 1/2 green Spider creature token with reach";
|
||||||
}
|
}
|
||||||
|
|
||||||
public GloomwidowsFeastEffect(final GloomwidowsFeastEffect effect) {
|
public GloomwidowsFeastEffect(final GloomwidowsFeastEffect effect) {
|
||||||
|
@ -69,15 +68,20 @@ class GloomwidowsFeastEffect extends OneShotEffect {
|
||||||
@Override
|
@Override
|
||||||
public boolean apply(Game game, Ability source) {
|
public boolean apply(Game game, Ability source) {
|
||||||
Permanent targetCreature = game.getPermanent(source.getFirstTarget());
|
Permanent targetCreature = game.getPermanent(source.getFirstTarget());
|
||||||
if (targetCreature != null) {
|
if (targetCreature == null) {
|
||||||
targetCreature.destroy(source, game, false);
|
return false;
|
||||||
Permanent destroyedCreature = getTargetPointer().getFirstTargetPermanentOrLKI(game, source);
|
}
|
||||||
if (destroyedCreature.getColor(game).isBlue()
|
|
||||||
|| destroyedCreature.getColor(game).isBlack()) {
|
targetCreature.destroy(source, game, false);
|
||||||
SpiderToken token = new SpiderToken();
|
Permanent destroyedCreature = getTargetPointer().getFirstTargetPermanentOrLKI(game, source);
|
||||||
token.putOntoBattlefield(1, game, source, source.getControllerId());
|
if (destroyedCreature == null) {
|
||||||
return true;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (destroyedCreature.getColor(game).isBlue() || destroyedCreature.getColor(game).isBlack()) {
|
||||||
|
SpiderToken token = new SpiderToken();
|
||||||
|
token.putOntoBattlefield(1, game, source, source.getControllerId());
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
package mage.cards.g;
|
package mage.cards.g;
|
||||||
|
|
||||||
|
import javafx.event.EventType;
|
||||||
import mage.MageInt;
|
import mage.MageInt;
|
||||||
import mage.MageObject;
|
import mage.MageObject;
|
||||||
import mage.abilities.Ability;
|
import mage.abilities.Ability;
|
||||||
|
@ -55,6 +56,7 @@ class GoblinPsychopathEffect extends ReplacementEffectImpl {
|
||||||
|
|
||||||
public GoblinPsychopathEffect(final GoblinPsychopathEffect effect) {
|
public GoblinPsychopathEffect(final GoblinPsychopathEffect effect) {
|
||||||
super(effect);
|
super(effect);
|
||||||
|
this.wonFlip = effect.wonFlip;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -88,10 +90,14 @@ class GoblinPsychopathEffect extends ReplacementEffectImpl {
|
||||||
public boolean replaceEvent(GameEvent event, Ability source, Game game) {
|
public boolean replaceEvent(GameEvent event, Ability source, Game game) {
|
||||||
MageObject object = game.getObject(event.getSourceId());
|
MageObject object = game.getObject(event.getSourceId());
|
||||||
Player controller = game.getPlayer(source.getControllerId());
|
Player controller = game.getPlayer(source.getControllerId());
|
||||||
if (controller == null || object == null
|
if (object == null || controller == null) {
|
||||||
|| !(this.applies(event, source, game) && event instanceof DamageEvent && event.getAmount() > 0)) {
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!(this.applies(event, source, game) && event instanceof DamageEvent && event.getAmount() > 0)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
DamageEvent damageEvent = (DamageEvent) event;
|
DamageEvent damageEvent = (DamageEvent) event;
|
||||||
if (!damageEvent.isCombatDamage() || wonFlip) {
|
if (!damageEvent.isCombatDamage() || wonFlip) {
|
||||||
return false;
|
return false;
|
||||||
|
|
|
@ -61,7 +61,7 @@ public final class Godsend extends CardImpl {
|
||||||
|
|
||||||
class GodsendTriggeredAbility extends TriggeredAbilityImpl {
|
class GodsendTriggeredAbility extends TriggeredAbilityImpl {
|
||||||
|
|
||||||
private Set<UUID> possibleTargets = new HashSet<>();
|
private final Set<UUID> possibleTargets = new HashSet<>();
|
||||||
|
|
||||||
GodsendTriggeredAbility() {
|
GodsendTriggeredAbility() {
|
||||||
super(Zone.BATTLEFIELD, new GodsendExileEffect(), true);
|
super(Zone.BATTLEFIELD, new GodsendExileEffect(), true);
|
||||||
|
@ -69,6 +69,7 @@ class GodsendTriggeredAbility extends TriggeredAbilityImpl {
|
||||||
|
|
||||||
GodsendTriggeredAbility(final GodsendTriggeredAbility ability) {
|
GodsendTriggeredAbility(final GodsendTriggeredAbility ability) {
|
||||||
super(ability);
|
super(ability);
|
||||||
|
this.possibleTargets.addAll(ability.possibleTargets);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -153,13 +154,19 @@ class GodsendExileEffect extends OneShotEffect {
|
||||||
Permanent creature = game.getPermanent(this.getTargetPointer().getFirst(game, source));
|
Permanent creature = game.getPermanent(this.getTargetPointer().getFirst(game, source));
|
||||||
Player controller = game.getPlayer(source.getControllerId());
|
Player controller = game.getPlayer(source.getControllerId());
|
||||||
Permanent sourcePermanent = game.getPermanentOrLKIBattlefield(source.getSourceId());
|
Permanent sourcePermanent = game.getPermanentOrLKIBattlefield(source.getSourceId());
|
||||||
if (creature != null && controller != null && sourcePermanent != null) {
|
if (creature == null || controller == null || sourcePermanent == null) {
|
||||||
UUID exileId = CardUtil.getCardExileZoneId(game, source);
|
return false;
|
||||||
controller.moveCardToExileWithInfo(creature, exileId,
|
|
||||||
sourcePermanent.getIdName() + " (" + sourcePermanent.getZoneChangeCounter(game) + ')', source, game, Zone.BATTLEFIELD, true);
|
|
||||||
|
|
||||||
}
|
}
|
||||||
return false;
|
|
||||||
|
UUID exileId = CardUtil.getCardExileZoneId(game, source);
|
||||||
|
return controller.moveCardToExileWithInfo(
|
||||||
|
creature,
|
||||||
|
exileId,
|
||||||
|
sourcePermanent.getIdName() + " (" + sourcePermanent.getZoneChangeCounter(game) + ')',
|
||||||
|
source,
|
||||||
|
game,
|
||||||
|
Zone.BATTLEFIELD,
|
||||||
|
true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -190,19 +197,30 @@ class GodsendRuleModifyingEffect extends ContinuousRuleModifyingEffectImpl {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean applies(GameEvent event, Ability source, Game game) {
|
public boolean applies(GameEvent event, Ability source, Game game) {
|
||||||
if (event.getType() == GameEvent.EventType.CAST_SPELL && game.getOpponents(source.getControllerId()).contains(event.getPlayerId())) {
|
if (event.getType() != GameEvent.EventType.CAST_SPELL) {
|
||||||
MageObject object = game.getObject(event.getSourceId());
|
return false;
|
||||||
if (object != null) {
|
}
|
||||||
ExileZone exileZone = game.getExile().getExileZone(CardUtil.getCardExileZoneId(game, source));
|
|
||||||
if ((exileZone != null)) {
|
if (!game.getOpponents(source.getControllerId()).contains(event.getPlayerId())) {
|
||||||
for (Card card : exileZone.getCards(game)) {
|
return false;
|
||||||
if ((card.getName().equals(object.getName()))) {
|
}
|
||||||
return true;
|
|
||||||
}
|
MageObject object = game.getObject(event.getSourceId());
|
||||||
}
|
if (object == null) {
|
||||||
}
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
ExileZone exileZone = game.getExile().getExileZone(CardUtil.getCardExileZoneId(game, source));
|
||||||
|
if (exileZone == null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (Card card : exileZone.getCards(game)) {
|
||||||
|
if ((card.getName().equals(object.getName()))) {
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -102,6 +102,7 @@ class GrinningTotemMayPlayEffect extends AsThoughEffectImpl {
|
||||||
|
|
||||||
public GrinningTotemMayPlayEffect(final GrinningTotemMayPlayEffect effect) {
|
public GrinningTotemMayPlayEffect(final GrinningTotemMayPlayEffect effect) {
|
||||||
super(effect);
|
super(effect);
|
||||||
|
this.sameStep = effect.sameStep;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -112,9 +113,7 @@ class GrinningTotemMayPlayEffect extends AsThoughEffectImpl {
|
||||||
@Override
|
@Override
|
||||||
public boolean isInactive(Ability source, Game game) {
|
public boolean isInactive(Ability source, Game game) {
|
||||||
if (game.getPhase().getStep().getType() == PhaseStep.UPKEEP) {
|
if (game.getPhase().getStep().getType() == PhaseStep.UPKEEP) {
|
||||||
if (!sameStep && game.isActivePlayer(source.getControllerId()) || game.getPlayer(source.getControllerId()).hasReachedNextTurnAfterLeaving()) {
|
return !sameStep && game.isActivePlayer(source.getControllerId()) || game.getPlayer(source.getControllerId()).hasReachedNextTurnAfterLeaving();
|
||||||
return true;
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
sameStep = false;
|
sameStep = false;
|
||||||
}
|
}
|
||||||
|
@ -198,10 +197,10 @@ class GrinningTotemPutIntoGraveyardEffect 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());
|
||||||
ExileZone zone = game.getExile().getExileZone(exileZoneId);
|
ExileZone zone = game.getExile().getExileZone(exileZoneId);
|
||||||
if (controller != null && zone != null) {
|
if (controller == null || zone == null) {
|
||||||
return controller.moveCards(zone, Zone.GRAVEYARD, source, game);
|
return false;
|
||||||
}
|
}
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
return controller.moveCards(zone, Zone.GRAVEYARD, source, game);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -34,8 +34,9 @@ public final class GuardDogs extends CardImpl {
|
||||||
this.power = new MageInt(2);
|
this.power = new MageInt(2);
|
||||||
this.toughness = new MageInt(2);
|
this.toughness = new MageInt(2);
|
||||||
|
|
||||||
// {2}{W}, {T}: Choose a permanent you control. Prevent all combat damage target creature would deal this turn if it shares a color with that permanent.
|
// {2}{W}, {T}: Choose a permanent you control.
|
||||||
Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new GuardDogsEffect(), new ManaCostsImpl("{2}{W}"));
|
// Prevent all combat damage target creature would deal this turn if it shares a color with that permanent.
|
||||||
|
Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new GuardDogsEffect(), new ManaCostsImpl<>("{2}{W}"));
|
||||||
ability.addCost(new TapSourceCost());
|
ability.addCost(new TapSourceCost());
|
||||||
ability.addTarget(new TargetCreaturePermanent());
|
ability.addTarget(new TargetCreaturePermanent());
|
||||||
this.addAbility(ability);
|
this.addAbility(ability);
|
||||||
|
@ -57,13 +58,14 @@ class GuardDogsEffect extends PreventionEffectImpl {
|
||||||
|
|
||||||
public GuardDogsEffect() {
|
public GuardDogsEffect() {
|
||||||
super(Duration.EndOfTurn, Integer.MAX_VALUE, true);
|
super(Duration.EndOfTurn, Integer.MAX_VALUE, true);
|
||||||
this.staticText = "Choose a permanent you control. Prevent all combat damage target creature would deal this turn if it shares a color with that permanent";
|
this.staticText = "Choose a permanent you control. " +
|
||||||
|
"Prevent all combat damage target creature would deal this turn if it shares a color with that permanent";
|
||||||
}
|
}
|
||||||
|
|
||||||
public GuardDogsEffect(final GuardDogsEffect effect) {
|
private GuardDogsEffect(final GuardDogsEffect effect) {
|
||||||
super(effect);
|
super(effect);
|
||||||
|
this.controlledTarget = effect.controlledTarget.copy();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void init(Ability source, Game game) {
|
public void init(Ability source, Game game) {
|
||||||
|
@ -72,7 +74,6 @@ class GuardDogsEffect extends PreventionEffectImpl {
|
||||||
this.controlledTarget.choose(Outcome.PreventDamage, source.getControllerId(), source.getSourceId(), source, game);
|
this.controlledTarget.choose(Outcome.PreventDamage, source.getControllerId(), source.getSourceId(), source, game);
|
||||||
super.init(source, game);
|
super.init(source, game);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public GuardDogsEffect copy() {
|
public GuardDogsEffect copy() {
|
||||||
|
@ -81,20 +82,21 @@ class GuardDogsEffect extends PreventionEffectImpl {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean applies(GameEvent event, Ability source, Game game) {
|
public boolean applies(GameEvent event, Ability source, Game game) {
|
||||||
if (!this.used && super.applies(event, source, game)) {
|
if (this.used || !super.applies(event, source, game)) {
|
||||||
MageObject mageObject = game.getObject(event.getSourceId());
|
return false;
|
||||||
if (mageObject != null
|
|
||||||
&& controlledTarget.getFirstTarget() != null) {
|
|
||||||
Permanent permanent = game.getPermanentOrLKIBattlefield(controlledTarget.getFirstTarget());
|
|
||||||
Permanent targetPermanent = getTargetPointer().getFirstTargetPermanentOrLKI(game, source);
|
|
||||||
if (permanent != null
|
|
||||||
&& targetPermanent != null
|
|
||||||
&& this.getTargetPointer().getTargets(game, source).contains(event.getSourceId())
|
|
||||||
&& permanent.getColor(game).shares(targetPermanent.getColor(game))) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return false;
|
MageObject mageObject = game.getObject(event.getSourceId());
|
||||||
|
if (mageObject == null || controlledTarget.getFirstTarget() == null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
Permanent permanent = game.getPermanentOrLKIBattlefield(controlledTarget.getFirstTarget());
|
||||||
|
Permanent targetPermanent = getTargetPointer().getFirstTargetPermanentOrLKI(game, source);
|
||||||
|
if (permanent == null || targetPermanent == null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return this.getTargetPointer().getTargets(game, source).contains(event.getSourceId())
|
||||||
|
&& permanent.getColor(game).shares(targetPermanent.getColor(game));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -40,7 +40,7 @@ public final class HisokaMinamoSensei extends CardImpl {
|
||||||
this.toughness = new MageInt(3);
|
this.toughness = new MageInt(3);
|
||||||
|
|
||||||
// {2}{U}, Discard a card: Counter target spell if it has the same converted mana cost as the discarded card.
|
// {2}{U}, Discard a card: Counter target spell if it has the same converted mana cost as the discarded card.
|
||||||
Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new HisokaMinamoSenseiCounterEffect(), new ManaCostsImpl("{2}{U}"));
|
Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new HisokaMinamoSenseiCounterEffect(), new ManaCostsImpl<>("{2}{U}"));
|
||||||
ability.addTarget(new TargetSpell());
|
ability.addTarget(new TargetSpell());
|
||||||
TargetCardInHand targetCard = new TargetCardInHand(new FilterCard("a card"));
|
TargetCardInHand targetCard = new TargetCardInHand(new FilterCard("a card"));
|
||||||
ability.addCost(new HisokaMinamoSenseiDiscardTargetCost(targetCard));
|
ability.addCost(new HisokaMinamoSenseiDiscardTargetCost(targetCard));
|
||||||
|
@ -60,7 +60,7 @@ public final class HisokaMinamoSensei extends CardImpl {
|
||||||
|
|
||||||
class HisokaMinamoSenseiDiscardTargetCost extends CostImpl {
|
class HisokaMinamoSenseiDiscardTargetCost extends CostImpl {
|
||||||
|
|
||||||
protected Card card = null;
|
protected Card card;
|
||||||
|
|
||||||
public HisokaMinamoSenseiDiscardTargetCost(TargetCardInHand target) {
|
public HisokaMinamoSenseiDiscardTargetCost(TargetCardInHand target) {
|
||||||
this.addTarget(target);
|
this.addTarget(target);
|
||||||
|
@ -69,23 +69,27 @@ class HisokaMinamoSenseiDiscardTargetCost extends CostImpl {
|
||||||
|
|
||||||
public HisokaMinamoSenseiDiscardTargetCost(HisokaMinamoSenseiDiscardTargetCost cost) {
|
public HisokaMinamoSenseiDiscardTargetCost(HisokaMinamoSenseiDiscardTargetCost cost) {
|
||||||
super(cost);
|
super(cost);
|
||||||
|
this.card = cost.card.copy();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean pay(Ability ability, Game game, Ability source, UUID controllerId, boolean noMana, Cost costToPay) {
|
public boolean pay(Ability ability, Game game, Ability source, UUID controllerId, boolean noMana, Cost costToPay) {
|
||||||
if (targets.choose(Outcome.Discard, controllerId, source.getSourceId(), source, game)) {
|
if (!targets.choose(Outcome.Discard, controllerId, source.getSourceId(), source, game)) {
|
||||||
Player player = game.getPlayer(controllerId);
|
return paid;
|
||||||
if(player != null) {
|
}
|
||||||
for (UUID targetId : targets.get(0).getTargets()) {
|
|
||||||
card = player.getHand().get(targetId, game);
|
|
||||||
if (card == null) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
paid |= player.discard(card, true, source, game);
|
|
||||||
|
|
||||||
}
|
Player player = game.getPlayer(controllerId);
|
||||||
|
if (player == null) {
|
||||||
|
return paid;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (UUID targetId : targets.get(0).getTargets()) {
|
||||||
|
card = player.getHand().get(targetId, game);
|
||||||
|
if (card != null) {
|
||||||
|
paid |= player.discard(card, true, source, game);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return paid;
|
return paid;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -106,24 +110,32 @@ class HisokaMinamoSenseiDiscardTargetCost extends CostImpl {
|
||||||
}
|
}
|
||||||
|
|
||||||
class HisokaMinamoSenseiCounterEffect extends OneShotEffect {
|
class HisokaMinamoSenseiCounterEffect extends OneShotEffect {
|
||||||
|
|
||||||
HisokaMinamoSenseiCounterEffect() {
|
HisokaMinamoSenseiCounterEffect() {
|
||||||
super(Outcome.Detriment);
|
super(Outcome.Detriment);
|
||||||
staticText = "Counter target spell if it has the same mana value as the discarded card";
|
staticText = "Counter target spell if it has the same mana value as the discarded card";
|
||||||
}
|
}
|
||||||
|
|
||||||
HisokaMinamoSenseiCounterEffect(final HisokaMinamoSenseiCounterEffect effect) {
|
private HisokaMinamoSenseiCounterEffect(final HisokaMinamoSenseiCounterEffect effect) {
|
||||||
super(effect);
|
super(effect);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean apply(Game game, Ability source) {
|
public boolean apply(Game game, Ability source) {
|
||||||
Spell spell = game.getStack().getSpell(targetPointer.getFirst(game, source));
|
Spell spell = game.getStack().getSpell(targetPointer.getFirst(game, source));
|
||||||
if (spell != null) {
|
if (spell == null) {
|
||||||
HisokaMinamoSenseiDiscardTargetCost cost = (HisokaMinamoSenseiDiscardTargetCost) source.getCosts().get(0);
|
return false;
|
||||||
if (cost != null && cost.getDiscardedCard().getManaValue() == spell.getManaValue()) {
|
|
||||||
return game.getStack().counter(targetPointer.getFirst(game, source), source, game);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
HisokaMinamoSenseiDiscardTargetCost cost = (HisokaMinamoSenseiDiscardTargetCost) source.getCosts().get(0);
|
||||||
|
if (cost == null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (cost.getDiscardedCard().getManaValue() == spell.getManaValue()) {
|
||||||
|
return game.getStack().counter(targetPointer.getFirst(game, source), source, game);
|
||||||
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -39,9 +39,10 @@ public final class IllusionaryPresence extends CardImpl {
|
||||||
this.toughness = new MageInt(2);
|
this.toughness = new MageInt(2);
|
||||||
|
|
||||||
// Cumulative upkeep {U}
|
// Cumulative upkeep {U}
|
||||||
this.addAbility(new CumulativeUpkeepAbility(new ManaCostsImpl("{U}")));
|
this.addAbility(new CumulativeUpkeepAbility(new ManaCostsImpl<>("{U}")));
|
||||||
|
|
||||||
// At the beginning of your upkeep, choose a land type. Illusionary Presence gains landwalk of the chosen type until end of turn.
|
// At the beginning of your upkeep, choose a land type.
|
||||||
|
// Illusionary Presence gains landwalk of the chosen type until end of turn.
|
||||||
Ability ability = new BeginningOfUpkeepTriggeredAbility(Zone.BATTLEFIELD, new ChooseBasicLandTypeEffect(Outcome.Neutral), TargetController.YOU, false);
|
Ability ability = new BeginningOfUpkeepTriggeredAbility(Zone.BATTLEFIELD, new ChooseBasicLandTypeEffect(Outcome.Neutral), TargetController.YOU, false);
|
||||||
ability.addEffect(new IllusionaryPresenceEffect());
|
ability.addEffect(new IllusionaryPresenceEffect());
|
||||||
this.addAbility(ability);
|
this.addAbility(ability);
|
||||||
|
@ -60,8 +61,6 @@ public final class IllusionaryPresence extends CardImpl {
|
||||||
|
|
||||||
class IllusionaryPresenceEffect extends OneShotEffect {
|
class IllusionaryPresenceEffect extends OneShotEffect {
|
||||||
|
|
||||||
Ability gainedAbility;
|
|
||||||
|
|
||||||
public IllusionaryPresenceEffect() {
|
public IllusionaryPresenceEffect() {
|
||||||
super(Outcome.Benefit);
|
super(Outcome.Benefit);
|
||||||
this.staticText = "{this} gains landwalk of the chosen type until end of turn";
|
this.staticText = "{this} gains landwalk of the chosen type until end of turn";
|
||||||
|
@ -79,33 +78,38 @@ class IllusionaryPresenceEffect extends OneShotEffect {
|
||||||
@Override
|
@Override
|
||||||
public boolean apply(Game game, Ability source) {
|
public boolean apply(Game game, Ability source) {
|
||||||
MageObject mageObject = game.getObject(source);
|
MageObject mageObject = game.getObject(source);
|
||||||
if (mageObject != null) {
|
if (mageObject == null) {
|
||||||
SubType landTypeChoice = SubType.byDescription((String) game.getState().getValue(mageObject.getId().toString() + "BasicLandType"));
|
return false;
|
||||||
if (landTypeChoice != null) {
|
|
||||||
switch (landTypeChoice) {
|
|
||||||
case PLAINS:
|
|
||||||
gainedAbility = new PlainswalkAbility();
|
|
||||||
break;
|
|
||||||
case FOREST:
|
|
||||||
gainedAbility = new ForestwalkAbility();
|
|
||||||
break;
|
|
||||||
case SWAMP:
|
|
||||||
gainedAbility = new SwampwalkAbility();
|
|
||||||
break;
|
|
||||||
case ISLAND:
|
|
||||||
gainedAbility = new IslandwalkAbility();
|
|
||||||
break;
|
|
||||||
case MOUNTAIN:
|
|
||||||
gainedAbility = new MountainwalkAbility();
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if (gainedAbility != null) {
|
|
||||||
GainAbilitySourceEffect effect = new GainAbilitySourceEffect(gainedAbility, Duration.EndOfTurn);
|
|
||||||
game.addEffect(effect, source);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return false;
|
|
||||||
|
SubType landTypeChoice = SubType.byDescription((String) game.getState().getValue(mageObject.getId().toString() + "BasicLandType"));
|
||||||
|
if (landTypeChoice == null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
Ability gainedAbility;
|
||||||
|
switch (landTypeChoice) {
|
||||||
|
case PLAINS:
|
||||||
|
gainedAbility = new PlainswalkAbility();
|
||||||
|
break;
|
||||||
|
case FOREST:
|
||||||
|
gainedAbility = new ForestwalkAbility();
|
||||||
|
break;
|
||||||
|
case SWAMP:
|
||||||
|
gainedAbility = new SwampwalkAbility();
|
||||||
|
break;
|
||||||
|
case ISLAND:
|
||||||
|
gainedAbility = new IslandwalkAbility();
|
||||||
|
break;
|
||||||
|
case MOUNTAIN:
|
||||||
|
gainedAbility = new MountainwalkAbility();
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
GainAbilitySourceEffect effect = new GainAbilitySourceEffect(gainedAbility, Duration.EndOfTurn);
|
||||||
|
game.addEffect(effect, source);
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -141,8 +141,10 @@ class ChooseTwoBasicLandTypesEffect extends OneShotEffect {
|
||||||
this.staticText = "choose two basic land types";
|
this.staticText = "choose two basic land types";
|
||||||
}
|
}
|
||||||
|
|
||||||
public ChooseTwoBasicLandTypesEffect(final ChooseTwoBasicLandTypesEffect effect) {
|
private ChooseTwoBasicLandTypesEffect(final ChooseTwoBasicLandTypesEffect effect) {
|
||||||
super(effect);
|
super(effect);
|
||||||
|
this.choiceOne = effect.choiceOne;
|
||||||
|
this.choiceTwo = effect.choiceTwo;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -33,7 +33,9 @@ public final class ImminentDoom extends CardImpl {
|
||||||
// Imminent Doom enters the battlefield with a doom counter on it.
|
// Imminent Doom enters the battlefield with a doom counter on it.
|
||||||
this.addAbility(new EntersBattlefieldAbility(new AddCountersSourceEffect(CounterType.DOOM.createInstance(1)), "with a doom counter on it"));
|
this.addAbility(new EntersBattlefieldAbility(new AddCountersSourceEffect(CounterType.DOOM.createInstance(1)), "with a doom counter on it"));
|
||||||
|
|
||||||
// Whenever you cast a spell with converted mana cost equal to the number of doom counters on Imminent Doom, Imminent Doom deals that much damage to any target. Then put a doom counter on Imminent Doom.
|
// Whenever you cast a spell with converted mana cost equal to the number of doom counters on Imminent Doom,
|
||||||
|
// Imminent Doom deals that much damage to any target.
|
||||||
|
// Then put a doom counter on Imminent Doom.
|
||||||
Ability ability = new ImminentDoomTriggeredAbility();
|
Ability ability = new ImminentDoomTriggeredAbility();
|
||||||
ability.addTarget(new TargetAnyTarget());
|
ability.addTarget(new TargetAnyTarget());
|
||||||
this.addAbility(ability);
|
this.addAbility(ability);
|
||||||
|
@ -52,7 +54,8 @@ public final class ImminentDoom extends CardImpl {
|
||||||
|
|
||||||
class ImminentDoomTriggeredAbility extends TriggeredAbilityImpl {
|
class ImminentDoomTriggeredAbility extends TriggeredAbilityImpl {
|
||||||
|
|
||||||
private String rule = "Whenever you cast a spell with mana value equal to the number of doom counters on {this}, {this} deals that much damage to any target. Then put a doom counter on {this}.";
|
private static final String rule = "Whenever you cast a spell with mana value equal to the number of doom counters on {this}, " +
|
||||||
|
"{this} deals that much damage to any target. Then put a doom counter on {this}.";
|
||||||
|
|
||||||
public ImminentDoomTriggeredAbility() {
|
public ImminentDoomTriggeredAbility() {
|
||||||
super(Zone.BATTLEFIELD, new ImminentDoomEffect());
|
super(Zone.BATTLEFIELD, new ImminentDoomEffect());
|
||||||
|
@ -74,16 +77,24 @@ class ImminentDoomTriggeredAbility extends TriggeredAbilityImpl {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean checkTrigger(GameEvent event, Game game) {
|
public boolean checkTrigger(GameEvent event, Game game) {
|
||||||
if (event.getPlayerId().equals(this.getControllerId())) {
|
if (!event.getPlayerId().equals(this.getControllerId())) {
|
||||||
Permanent imminentDoom = game.getPermanent(getSourceId());
|
return false;
|
||||||
Spell spell = game.getStack().getSpell(event.getTargetId());
|
}
|
||||||
if (spell != null
|
|
||||||
&& imminentDoom != null
|
Permanent imminentDoom = game.getPermanent(getSourceId());
|
||||||
&& spell.getManaValue() == imminentDoom.getCounters(game).getCount(CounterType.DOOM)) {
|
Spell spell = game.getStack().getSpell(event.getTargetId());
|
||||||
game.getState().setValue("ImminentDoomCount" + getSourceId().toString(), imminentDoom.getCounters(game).getCount(CounterType.DOOM)); // store its current value
|
if (imminentDoom == null || spell == null) {
|
||||||
return true;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
if (spell.getManaValue() == imminentDoom.getCounters(game).getCount(CounterType.DOOM)) {
|
||||||
|
// store its current value
|
||||||
|
game.getState().setValue(
|
||||||
|
"ImminentDoomCount" + getSourceId().toString(),
|
||||||
|
imminentDoom.getCounters(game).getCount(CounterType.DOOM)
|
||||||
|
);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -111,13 +122,13 @@ class ImminentDoomEffect extends OneShotEffect {
|
||||||
@Override
|
@Override
|
||||||
public boolean apply(Game game, Ability source) {
|
public boolean apply(Game game, Ability source) {
|
||||||
Permanent imminentDoom = game.getPermanent(source.getSourceId());
|
Permanent imminentDoom = game.getPermanent(source.getSourceId());
|
||||||
if (imminentDoom != null) {
|
if (imminentDoom == null) {
|
||||||
Effect effect = new DamageTargetEffect((int) game.getState().getValue("ImminentDoomCount" + source.getSourceId().toString()));
|
return false;
|
||||||
effect.apply(game, source);
|
|
||||||
imminentDoom.addCounters(CounterType.DOOM.createInstance(), source.getControllerId(), source, game);
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
Effect effect = new DamageTargetEffect((int) game.getState().getValue("ImminentDoomCount" + source.getSourceId().toString()));
|
||||||
|
effect.apply(game, source);
|
||||||
|
imminentDoom.addCounters(CounterType.DOOM.createInstance(), source.getControllerId(), source, game);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -48,11 +48,14 @@ class ImpulsiveManeuversEffect extends PreventionEffectImpl {
|
||||||
|
|
||||||
public ImpulsiveManeuversEffect() {
|
public ImpulsiveManeuversEffect() {
|
||||||
super(Duration.EndOfTurn, Integer.MAX_VALUE, false);
|
super(Duration.EndOfTurn, Integer.MAX_VALUE, false);
|
||||||
staticText = "flip a coin. If you win the flip, the next time that creature would deal combat damage this turn, it deals double that damage instead. If you lose the flip, the next time that creature would deal combat damage this turn, prevent that damage";
|
staticText = "flip a coin. " +
|
||||||
|
"If you win the flip, the next time that creature would deal combat damage this turn, it deals double that damage instead. " +
|
||||||
|
"If you lose the flip, the next time that creature would deal combat damage this turn, prevent that damage";
|
||||||
}
|
}
|
||||||
|
|
||||||
public ImpulsiveManeuversEffect(final ImpulsiveManeuversEffect effect) {
|
public ImpulsiveManeuversEffect(final ImpulsiveManeuversEffect effect) {
|
||||||
super(effect);
|
super(effect);
|
||||||
|
this.wonFlip = effect.wonFlip;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -86,21 +89,25 @@ class ImpulsiveManeuversEffect extends PreventionEffectImpl {
|
||||||
public boolean replaceEvent(GameEvent event, Ability source, Game game) {
|
public boolean replaceEvent(GameEvent event, Ability source, Game game) {
|
||||||
MageObject object = game.getObject(event.getSourceId());
|
MageObject object = game.getObject(event.getSourceId());
|
||||||
Player controller = game.getPlayer(source.getControllerId());
|
Player controller = game.getPlayer(source.getControllerId());
|
||||||
if (controller != null && object != null) {
|
if (controller == null || object == null) {
|
||||||
if (super.applies(event, source, game) && event instanceof DamageEvent && event.getAmount() > 0) {
|
return false;
|
||||||
DamageEvent damageEvent = (DamageEvent) event;
|
|
||||||
if (damageEvent.isCombatDamage()) {
|
|
||||||
if (wonFlip) {
|
|
||||||
event.setAmount(CardUtil.overflowMultiply(event.getAmount(), 2));
|
|
||||||
this.discard();
|
|
||||||
} else {
|
|
||||||
preventDamageAction(event, source, game);
|
|
||||||
this.discard();
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return false;
|
|
||||||
|
if (!super.applies(event, source, game)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!(event instanceof DamageEvent) || !((DamageEvent) event).isCombatDamage() || event.getAmount() <= 0) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (wonFlip) {
|
||||||
|
event.setAmount(CardUtil.overflowMultiply(event.getAmount(), 2));
|
||||||
|
} else {
|
||||||
|
preventDamageAction(event, source, game);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.discard();
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -60,7 +60,7 @@ public final class IncubationDruid extends CardImpl {
|
||||||
|
|
||||||
class AnyColorLandsProduceManaEffect extends ManaEffect {
|
class AnyColorLandsProduceManaEffect extends ManaEffect {
|
||||||
|
|
||||||
private boolean inManaTypeCalculation = false;
|
private boolean inManaTypeCalculation;
|
||||||
|
|
||||||
AnyColorLandsProduceManaEffect() {
|
AnyColorLandsProduceManaEffect() {
|
||||||
super();
|
super();
|
||||||
|
@ -70,6 +70,7 @@ class AnyColorLandsProduceManaEffect extends ManaEffect {
|
||||||
|
|
||||||
private AnyColorLandsProduceManaEffect(final AnyColorLandsProduceManaEffect effect) {
|
private AnyColorLandsProduceManaEffect(final AnyColorLandsProduceManaEffect effect) {
|
||||||
super(effect);
|
super(effect);
|
||||||
|
this.inManaTypeCalculation = effect.inManaTypeCalculation;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -17,7 +17,6 @@ import mage.constants.CardType;
|
||||||
import mage.constants.SuperType;
|
import mage.constants.SuperType;
|
||||||
import mage.constants.Zone;
|
import mage.constants.Zone;
|
||||||
import mage.filter.StaticFilters;
|
import mage.filter.StaticFilters;
|
||||||
import mage.filter.common.FilterArtifactPermanent;
|
|
||||||
import mage.game.Game;
|
import mage.game.Game;
|
||||||
import mage.game.events.GameEvent;
|
import mage.game.events.GameEvent;
|
||||||
import mage.target.common.TargetCardInLibrary;
|
import mage.target.common.TargetCardInLibrary;
|
||||||
|
@ -39,8 +38,9 @@ public final class InventorsFair extends CardImpl {
|
||||||
// {t}: Add {C}.
|
// {t}: Add {C}.
|
||||||
this.addAbility(new ColorlessManaAbility());
|
this.addAbility(new ColorlessManaAbility());
|
||||||
|
|
||||||
// {4}, {T}, Sacrifice Inventors' Fair: Search your library for an artifact card, reveal it, put it into your hand, then shuffle your library.
|
// {4}, {T}, Sacrifice Inventors' Fair: Search your library for an artifact card, reveal it,
|
||||||
// Activate this ability only if you control threeor more artifacts.
|
// put it into your hand, then shuffle your library.
|
||||||
|
// Activate this ability only if you control three or more artifacts.
|
||||||
Ability ability = new ActivateIfConditionActivatedAbility(Zone.BATTLEFIELD, new SearchLibraryPutInHandEffect(new TargetCardInLibrary(StaticFilters.FILTER_CARD_ARTIFACT), true),
|
Ability ability = new ActivateIfConditionActivatedAbility(Zone.BATTLEFIELD, new SearchLibraryPutInHandEffect(new TargetCardInLibrary(StaticFilters.FILTER_CARD_ARTIFACT), true),
|
||||||
new GenericManaCost(4), MetalcraftCondition.instance);
|
new GenericManaCost(4), MetalcraftCondition.instance);
|
||||||
ability.addCost(new TapSourceCost());
|
ability.addCost(new TapSourceCost());
|
||||||
|
@ -61,8 +61,6 @@ public final class InventorsFair extends CardImpl {
|
||||||
|
|
||||||
class InventorsFairAbility extends TriggeredAbilityImpl {
|
class InventorsFairAbility extends TriggeredAbilityImpl {
|
||||||
|
|
||||||
private FilterArtifactPermanent filter = new FilterArtifactPermanent();
|
|
||||||
|
|
||||||
public InventorsFairAbility() {
|
public InventorsFairAbility() {
|
||||||
super(Zone.BATTLEFIELD, new GainLifeEffect(1));
|
super(Zone.BATTLEFIELD, new GainLifeEffect(1));
|
||||||
}
|
}
|
||||||
|
@ -88,7 +86,7 @@ class InventorsFairAbility extends TriggeredAbilityImpl {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean checkInterveningIfClause(Game game) {
|
public boolean checkInterveningIfClause(Game game) {
|
||||||
return game.getBattlefield().countAll(filter, this.controllerId, game) >= 3;
|
return game.getBattlefield().countAll(StaticFilters.FILTER_CONTROLLED_PERMANENT_ARTIFACT, this.controllerId, game) >= 3;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -8,7 +8,7 @@ import mage.MageInt;
|
||||||
import mage.ObjectColor;
|
import mage.ObjectColor;
|
||||||
import mage.abilities.Ability;
|
import mage.abilities.Ability;
|
||||||
import mage.abilities.common.SimpleActivatedAbility;
|
import mage.abilities.common.SimpleActivatedAbility;
|
||||||
import mage.abilities.costs.mana.ManaCostsImpl;
|
import mage.abilities.costs.mana.GenericManaCost;
|
||||||
import mage.abilities.effects.ContinuousEffectImpl;
|
import mage.abilities.effects.ContinuousEffectImpl;
|
||||||
import mage.abilities.effects.common.continuous.GainAbilitySourceEffect;
|
import mage.abilities.effects.common.continuous.GainAbilitySourceEffect;
|
||||||
import mage.abilities.keyword.DoubleStrikeAbility;
|
import mage.abilities.keyword.DoubleStrikeAbility;
|
||||||
|
@ -38,7 +38,7 @@ public final class JodahsAvenger extends CardImpl {
|
||||||
this.toughness = new MageInt(4);
|
this.toughness = new MageInt(4);
|
||||||
|
|
||||||
// {0}: Until end of turn, Jodah's Avenger gets -1/-1 and gains your choice of double strike, protection from red, vigilance, or shadow.
|
// {0}: Until end of turn, Jodah's Avenger gets -1/-1 and gains your choice of double strike, protection from red, vigilance, or shadow.
|
||||||
this.addAbility(new SimpleActivatedAbility(Zone.BATTLEFIELD, new JodahsAvengerEffect(), new ManaCostsImpl("{0}")));
|
this.addAbility(new SimpleActivatedAbility(Zone.BATTLEFIELD, new JodahsAvengerEffect(), new GenericManaCost(0)));
|
||||||
}
|
}
|
||||||
|
|
||||||
private JodahsAvenger(final JodahsAvenger card) {
|
private JodahsAvenger(final JodahsAvenger card) {
|
||||||
|
@ -70,6 +70,7 @@ class JodahsAvengerEffect extends ContinuousEffectImpl {
|
||||||
|
|
||||||
public JodahsAvengerEffect(final JodahsAvengerEffect effect) {
|
public JodahsAvengerEffect(final JodahsAvengerEffect effect) {
|
||||||
super(effect);
|
super(effect);
|
||||||
|
this.gainedAbility = effect.gainedAbility.copy();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -80,41 +81,46 @@ class JodahsAvengerEffect extends ContinuousEffectImpl {
|
||||||
@Override
|
@Override
|
||||||
public void init(Ability source, Game game) {
|
public void init(Ability source, Game game) {
|
||||||
super.init(source, game);
|
super.init(source, game);
|
||||||
|
|
||||||
Player controller = game.getPlayer(source.getControllerId());
|
Player controller = game.getPlayer(source.getControllerId());
|
||||||
if (controller != null) {
|
if (controller == null) {
|
||||||
Choice choice = new ChoiceImpl(true);
|
return;
|
||||||
choice.setMessage("Choose one");
|
}
|
||||||
choice.setChoices(choices);
|
|
||||||
if (controller.choose(outcome, choice, game)) {
|
Choice choice = new ChoiceImpl(true);
|
||||||
switch (choice.getChoice()) {
|
choice.setMessage("Choose one");
|
||||||
case "Double strike":
|
choice.setChoices(choices);
|
||||||
gainedAbility = DoubleStrikeAbility.getInstance();
|
if (controller.choose(outcome, choice, game)) {
|
||||||
break;
|
switch (choice.getChoice()) {
|
||||||
case "Vigilance":
|
case "Double strike":
|
||||||
gainedAbility = VigilanceAbility.getInstance();
|
gainedAbility = DoubleStrikeAbility.getInstance();
|
||||||
break;
|
break;
|
||||||
case "Shadow":
|
case "Vigilance":
|
||||||
gainedAbility = ShadowAbility.getInstance();
|
gainedAbility = VigilanceAbility.getInstance();
|
||||||
break;
|
break;
|
||||||
default:
|
case "Shadow":
|
||||||
gainedAbility = ProtectionAbility.from(ObjectColor.RED);
|
gainedAbility = ShadowAbility.getInstance();
|
||||||
break;
|
break;
|
||||||
}
|
default:
|
||||||
} else {
|
gainedAbility = ProtectionAbility.from(ObjectColor.RED);
|
||||||
discard();
|
break;
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
discard();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean apply(Game game, Ability source) {
|
public boolean apply(Game game, Ability source) {
|
||||||
Permanent sourceObject = game.getPermanent(source.getSourceId());
|
Permanent sourceObject = game.getPermanent(source.getSourceId());
|
||||||
if (sourceObject != null) {
|
if (sourceObject == null) {
|
||||||
sourceObject.addPower(-1);
|
return false;
|
||||||
sourceObject.addToughness(-1);
|
|
||||||
game.addEffect(new GainAbilitySourceEffect(gainedAbility, Duration.EndOfTurn), source);
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
return false;
|
|
||||||
|
sourceObject.addPower(-1);
|
||||||
|
sourceObject.addToughness(-1);
|
||||||
|
game.addEffect(new GainAbilitySourceEffect(gainedAbility, Duration.EndOfTurn), source);
|
||||||
|
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -56,6 +56,7 @@ class JointAssaultBoostTargetEffect extends ContinuousEffectImpl {
|
||||||
super(effect);
|
super(effect);
|
||||||
this.power = effect.power;
|
this.power = effect.power;
|
||||||
this.toughness = effect.toughness;
|
this.toughness = effect.toughness;
|
||||||
|
this.paired = effect.paired;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -66,12 +67,11 @@ class JointAssaultBoostTargetEffect extends ContinuousEffectImpl {
|
||||||
@Override
|
@Override
|
||||||
public void init(Ability source, Game game) {
|
public void init(Ability source, Game game) {
|
||||||
super.init(source, game);
|
super.init(source, game);
|
||||||
|
|
||||||
UUID permanentId = targetPointer.getFirst(game, source);
|
UUID permanentId = targetPointer.getFirst(game, source);
|
||||||
Permanent target = game.getPermanent(permanentId);
|
Permanent target = game.getPermanent(permanentId);
|
||||||
if (target != null) {
|
if (target != null && target.getPairedCard() != null) {
|
||||||
if (target.getPairedCard() != null) {
|
this.paired = target.getPairedCard();
|
||||||
this.paired = target.getPairedCard();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -46,7 +46,8 @@ public final class KarnLiberated extends CardImpl {
|
||||||
ability2.addTarget(new TargetPermanent());
|
ability2.addTarget(new TargetPermanent());
|
||||||
this.addAbility(ability2);
|
this.addAbility(ability2);
|
||||||
|
|
||||||
// -14: Restart the game, leaving in exile all non-Aura permanent cards exiled with Karn Liberated. Then put those cards onto the battlefield under your control.
|
// -14: Restart the game, leaving in exile all non-Aura permanent cards exiled with Karn Liberated.
|
||||||
|
// Then put those cards onto the battlefield under your control.
|
||||||
this.addAbility(new LoyaltyAbility(new KarnLiberatedEffect(), -14));
|
this.addAbility(new LoyaltyAbility(new KarnLiberatedEffect(), -14));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -62,11 +63,10 @@ public final class KarnLiberated extends CardImpl {
|
||||||
|
|
||||||
class KarnLiberatedEffect extends OneShotEffect {
|
class KarnLiberatedEffect extends OneShotEffect {
|
||||||
|
|
||||||
private UUID exileId;
|
|
||||||
|
|
||||||
public KarnLiberatedEffect() {
|
public KarnLiberatedEffect() {
|
||||||
super(Outcome.ExtraTurn);
|
super(Outcome.ExtraTurn);
|
||||||
this.staticText = "Restart the game, leaving in exile all non-Aura permanent cards exiled with {this}. Then put those cards onto the battlefield under your control";
|
this.staticText = "Restart the game, leaving in exile all non-Aura permanent cards exiled with {this}. " +
|
||||||
|
"Then put those cards onto the battlefield under your control";
|
||||||
}
|
}
|
||||||
|
|
||||||
public KarnLiberatedEffect(final KarnLiberatedEffect effect) {
|
public KarnLiberatedEffect(final KarnLiberatedEffect effect) {
|
||||||
|
@ -75,6 +75,7 @@ class KarnLiberatedEffect extends OneShotEffect {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean apply(Game game, Ability source) {
|
public boolean apply(Game game, Ability source) {
|
||||||
|
UUID exileId = null;
|
||||||
MageObject sourceObject = source.getSourceObject(game);
|
MageObject sourceObject = source.getSourceObject(game);
|
||||||
if (sourceObject == null) {
|
if (sourceObject == null) {
|
||||||
return false;
|
return false;
|
||||||
|
@ -84,8 +85,7 @@ class KarnLiberatedEffect extends OneShotEffect {
|
||||||
exileId = CardUtil.getExileZoneId(game, source.getSourceId(), source.getSourceObjectZoneChangeCounter());
|
exileId = CardUtil.getExileZoneId(game, source.getSourceId(), source.getSourceObjectZoneChangeCounter());
|
||||||
if (zone.getId().equals(exileId)) {
|
if (zone.getId().equals(exileId)) {
|
||||||
for (Card card : zone.getCards(game)) {
|
for (Card card : zone.getCards(game)) {
|
||||||
if (!card.hasSubtype(SubType.AURA, game)
|
if (!card.hasSubtype(SubType.AURA, game) && card.isPermanent(game)) {
|
||||||
&& card.isPermanent(game)) {
|
|
||||||
cards.add(card);
|
cards.add(card);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -59,8 +59,6 @@ public final class KrovikanVampire extends CardImpl {
|
||||||
|
|
||||||
class KrovikanVampireEffect extends OneShotEffect {
|
class KrovikanVampireEffect extends OneShotEffect {
|
||||||
|
|
||||||
Set<UUID> creaturesAffected = new HashSet<>();
|
|
||||||
|
|
||||||
KrovikanVampireEffect() {
|
KrovikanVampireEffect() {
|
||||||
super(Outcome.Neutral);
|
super(Outcome.Neutral);
|
||||||
staticText = "put that card onto the battlefield under your control. Sacrifice it when you lose control of {this}";
|
staticText = "put that card onto the battlefield under your control. Sacrifice it when you lose control of {this}";
|
||||||
|
@ -74,25 +72,24 @@ class KrovikanVampireEffect 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());
|
||||||
Permanent krovikanVampire = game.getPermanent(source.getSourceId());
|
Permanent krovikanVampire = game.getPermanent(source.getSourceId());
|
||||||
creaturesAffected = (Set<UUID>) game.getState().getValue(source.getSourceId() + "creatureToGainControl");
|
Set<UUID> creaturesAffected = (Set<UUID>) game.getState().getValue(source.getSourceId() + "creatureToGainControl");
|
||||||
if (creaturesAffected != null
|
if (creaturesAffected == null || controller == null || krovikanVampire == null) {
|
||||||
&& controller != null
|
return false;
|
||||||
&& krovikanVampire != null) {
|
|
||||||
creaturesAffected.stream().map((creatureId) -> {
|
|
||||||
controller.moveCards(game.getCard(creatureId), Zone.BATTLEFIELD, source, game, false, false, false, null);
|
|
||||||
return creatureId;
|
|
||||||
}).map((creatureId) -> {
|
|
||||||
OneShotEffect effect = new SacrificeTargetEffect();
|
|
||||||
effect.setText("Sacrifice this if Krovikan Vampire leaves the battlefield or its current controller loses control of it.");
|
|
||||||
effect.setTargetPointer(new FixedTarget(creatureId, game));
|
|
||||||
return effect;
|
|
||||||
}).map((effect) -> new KrovikanVampireDelayedTriggeredAbility(effect, krovikanVampire.getId())).forEachOrdered((dTA) -> {
|
|
||||||
game.addDelayedTriggeredAbility(dTA, source);
|
|
||||||
});
|
|
||||||
creaturesAffected.clear();
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
return false;
|
|
||||||
|
creaturesAffected.stream().map((creatureId) -> {
|
||||||
|
controller.moveCards(game.getCard(creatureId), Zone.BATTLEFIELD, source, game, false, false, false, null);
|
||||||
|
return creatureId;
|
||||||
|
}).map((creatureId) -> {
|
||||||
|
OneShotEffect effect = new SacrificeTargetEffect();
|
||||||
|
effect.setText("Sacrifice this if Krovikan Vampire leaves the battlefield or its current controller loses control of it.");
|
||||||
|
effect.setTargetPointer(new FixedTarget(creatureId, game));
|
||||||
|
return effect;
|
||||||
|
}).map((effect) -> new KrovikanVampireDelayedTriggeredAbility(effect, krovikanVampire.getId())).forEachOrdered((dTA) -> {
|
||||||
|
game.addDelayedTriggeredAbility(dTA, source);
|
||||||
|
});
|
||||||
|
creaturesAffected.clear();
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -109,21 +106,24 @@ class KrovikanVampireInterveningIfCondition implements Condition {
|
||||||
public boolean apply(Game game, Ability source) {
|
public boolean apply(Game game, Ability source) {
|
||||||
KrovikanVampireCreaturesDiedWatcher watcherDied = game.getState().getWatcher(KrovikanVampireCreaturesDiedWatcher.class);
|
KrovikanVampireCreaturesDiedWatcher watcherDied = game.getState().getWatcher(KrovikanVampireCreaturesDiedWatcher.class);
|
||||||
KrovikanVampireCreaturesDamagedWatcher watcherDamaged = game.getState().getWatcher(KrovikanVampireCreaturesDamagedWatcher.class);
|
KrovikanVampireCreaturesDamagedWatcher watcherDamaged = game.getState().getWatcher(KrovikanVampireCreaturesDamagedWatcher.class);
|
||||||
if (watcherDied != null) {
|
if (watcherDied == null) {
|
||||||
Set<UUID> creaturesThatDiedThisTurn = watcherDied.getDiedThisTurn();
|
return false;
|
||||||
creaturesThatDiedThisTurn.stream().filter((mor) -> (watcherDamaged != null)).forEachOrdered((mor) -> {
|
|
||||||
watcherDamaged.getDamagedBySource().stream().filter((mor2) -> (mor2 != null
|
|
||||||
&& mor == mor2)).forEachOrdered((_item) -> {
|
|
||||||
creaturesAffected.add(mor);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
if (creaturesAffected != null
|
|
||||||
&& creaturesAffected.size() > 0) {
|
|
||||||
game.getState().setValue(source.getSourceId() + "creatureToGainControl", creaturesAffected);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return false;
|
|
||||||
|
Set<UUID> creaturesThatDiedThisTurn = watcherDied.getDiedThisTurn();
|
||||||
|
creaturesThatDiedThisTurn.stream().filter((mor) -> (watcherDamaged != null)).forEachOrdered((mor) -> {
|
||||||
|
watcherDamaged.getDamagedBySource().stream().filter((mor2) -> (mor2 != null
|
||||||
|
&& mor == mor2)).forEachOrdered((_item) -> {
|
||||||
|
creaturesAffected.add(mor);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
if (creaturesAffected == null || creaturesAffected.isEmpty()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
game.getState().setValue(source.getSourceId() + "creatureToGainControl", creaturesAffected);
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -142,14 +142,15 @@ class KrovikanVampireCreaturesDamagedWatcher extends Watcher {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void watch(GameEvent event, Game game) {
|
public void watch(GameEvent event, Game game) {
|
||||||
if (event.getType() != GameEvent.EventType.DAMAGED_PERMANENT
|
if (event.getType() != GameEvent.EventType.DAMAGED_PERMANENT || !sourceId.equals(event.getSourceId())) {
|
||||||
|| !sourceId.equals(event.getSourceId())) {
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
Permanent permanent = game.getPermanent(event.getTargetId());
|
Permanent permanent = game.getPermanent(event.getTargetId());
|
||||||
if (permanent == null || !permanent.isCreature(game)) {
|
if (permanent == null || !permanent.isCreature(game)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
damagedBySource.add(event.getTargetId());
|
damagedBySource.add(event.getTargetId());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -215,14 +216,10 @@ class KrovikanVampireDelayedTriggeredAbility extends DelayedTriggeredAbility {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean checkTrigger(GameEvent event, Game game) {
|
public boolean checkTrigger(GameEvent event, Game game) {
|
||||||
if (event.getType() == GameEvent.EventType.LOST_CONTROL
|
if (event.getType() == GameEvent.EventType.LOST_CONTROL || event.getType() == GameEvent.EventType.ZONE_CHANGE) {
|
||||||
&& event.getTargetId().equals(krovikanVampire)) {
|
return event.getTargetId().equals(krovikanVampire);
|
||||||
return true;
|
|
||||||
}
|
|
||||||
if (event.getType() == GameEvent.EventType.ZONE_CHANGE
|
|
||||||
&& event.getTargetId().equals(krovikanVampire)) {
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -60,6 +60,7 @@ class LivingBreakthroughEffect extends ContinuousRuleModifyingEffectImpl {
|
||||||
|
|
||||||
private LivingBreakthroughEffect(final LivingBreakthroughEffect effect) {
|
private LivingBreakthroughEffect(final LivingBreakthroughEffect effect) {
|
||||||
super(effect);
|
super(effect);
|
||||||
|
this.manaValue = effect.manaValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -70,6 +70,7 @@ class MarshlandBloodcasterEffect extends ContinuousEffectImpl {
|
||||||
|
|
||||||
public MarshlandBloodcasterEffect(final MarshlandBloodcasterEffect effect) {
|
public MarshlandBloodcasterEffect(final MarshlandBloodcasterEffect effect) {
|
||||||
super(effect);
|
super(effect);
|
||||||
|
this.spellsCast = effect.spellsCast;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -6,6 +6,7 @@ import mage.abilities.Ability;
|
||||||
import mage.abilities.common.SimpleActivatedAbility;
|
import mage.abilities.common.SimpleActivatedAbility;
|
||||||
import mage.abilities.costs.common.SacrificeSourceCost;
|
import mage.abilities.costs.common.SacrificeSourceCost;
|
||||||
import mage.abilities.costs.common.TapSourceCost;
|
import mage.abilities.costs.common.TapSourceCost;
|
||||||
|
import mage.abilities.costs.mana.GenericManaCost;
|
||||||
import mage.abilities.costs.mana.ManaCostsImpl;
|
import mage.abilities.costs.mana.ManaCostsImpl;
|
||||||
import mage.abilities.effects.SearchEffect;
|
import mage.abilities.effects.SearchEffect;
|
||||||
import mage.abilities.effects.common.CreateTokenEffect;
|
import mage.abilities.effects.common.CreateTokenEffect;
|
||||||
|
@ -30,8 +31,10 @@ public final class MyrIncubator extends CardImpl {
|
||||||
public MyrIncubator(UUID ownerId, CardSetInfo setInfo) {
|
public MyrIncubator(UUID ownerId, CardSetInfo setInfo) {
|
||||||
super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{6}");
|
super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{6}");
|
||||||
|
|
||||||
// {6}, {tap}, Sacrifice Myr Incubator: Search your library for any number of artifact cards, exile them, then put that many 1/1 colorless Myr artifact creature tokens onto the battlefield. Then shuffle your library.
|
// {6}, {tap}, Sacrifice Myr Incubator: Search your library for any number of artifact cards, exile them,
|
||||||
Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new MyrIncubatorEffect(), new ManaCostsImpl("{6}"));
|
// then put that many 1/1 colorless Myr artifact creature tokens onto the battlefield.
|
||||||
|
// Then shuffle your library.
|
||||||
|
Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new MyrIncubatorEffect(), new GenericManaCost(6));
|
||||||
ability.addCost(new TapSourceCost());
|
ability.addCost(new TapSourceCost());
|
||||||
ability.addCost(new SacrificeSourceCost());
|
ability.addCost(new SacrificeSourceCost());
|
||||||
this.addAbility(ability);
|
this.addAbility(ability);
|
||||||
|
@ -56,32 +59,39 @@ class MyrIncubatorEffect extends SearchEffect {
|
||||||
filter.add(CardType.ARTIFACT.getPredicate());
|
filter.add(CardType.ARTIFACT.getPredicate());
|
||||||
}
|
}
|
||||||
|
|
||||||
int tokensToCreate = 0;
|
int tokensToCreate;
|
||||||
|
|
||||||
MyrIncubatorEffect() {
|
MyrIncubatorEffect() {
|
||||||
super(new TargetCardInLibrary(0, Integer.MAX_VALUE, filter), Outcome.Neutral);
|
super(new TargetCardInLibrary(0, Integer.MAX_VALUE, filter), Outcome.Neutral);
|
||||||
staticText = "Search your library for any number of artifact cards, exile them, then create that many 1/1 colorless Myr artifact creature tokens. Then shuffle";
|
staticText = "Search your library for any number of artifact cards, exile them, " +
|
||||||
|
"then create that many 1/1 colorless Myr artifact creature tokens. " +
|
||||||
|
"Then shuffle";
|
||||||
}
|
}
|
||||||
|
|
||||||
MyrIncubatorEffect(final MyrIncubatorEffect effect) {
|
MyrIncubatorEffect(final MyrIncubatorEffect effect) {
|
||||||
super(effect);
|
super(effect);
|
||||||
|
this.tokensToCreate = effect.tokensToCreate;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
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) {
|
||||||
&& controller.searchLibrary(target, source, game)) {
|
return false;
|
||||||
if (!target.getTargets().isEmpty()) {
|
}
|
||||||
tokensToCreate = target.getTargets().size();
|
|
||||||
controller.moveCards(new CardsImpl(target.getTargets()), Zone.EXILED, source, game);
|
if (!controller.searchLibrary(target, source, game)) {
|
||||||
}
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!target.getTargets().isEmpty()) {
|
||||||
|
tokensToCreate = target.getTargets().size();
|
||||||
|
controller.moveCards(new CardsImpl(target.getTargets()), Zone.EXILED, source, game);
|
||||||
CreateTokenEffect effect = new CreateTokenEffect(new MyrToken(), tokensToCreate);
|
CreateTokenEffect effect = new CreateTokenEffect(new MyrToken(), tokensToCreate);
|
||||||
effect.apply(game, source);
|
effect.apply(game, source);
|
||||||
controller.shuffleLibrary(source, game);
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
return false;
|
controller.shuffleLibrary(source, game);
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -55,7 +55,6 @@ public final class NaturesBlessing extends CardImpl {
|
||||||
class NaturesBlessingEffect extends OneShotEffect {
|
class NaturesBlessingEffect extends OneShotEffect {
|
||||||
|
|
||||||
private static final Set<String> choices = new HashSet<>();
|
private static final Set<String> choices = new HashSet<>();
|
||||||
private Ability gainedAbility;
|
|
||||||
|
|
||||||
static {
|
static {
|
||||||
choices.add("+1/+1 counter");
|
choices.add("+1/+1 counter");
|
||||||
|
@ -82,30 +81,33 @@ class NaturesBlessingEffect 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());
|
||||||
Permanent targetPermanent = game.getPermanent(this.getTargetPointer().getFirst(game, source));
|
Permanent targetPermanent = game.getPermanent(this.getTargetPointer().getFirst(game, source));
|
||||||
if (controller != null && targetPermanent != null) {
|
if (controller == null || targetPermanent == null) {
|
||||||
Choice choice = new ChoiceImpl(true);
|
return false;
|
||||||
choice.setMessage("Choose one");
|
|
||||||
choice.setChoices(choices);
|
|
||||||
if (controller.choose(outcome, choice, game)) {
|
|
||||||
switch (choice.getChoice()) {
|
|
||||||
case "Banding":
|
|
||||||
gainedAbility = BandingAbility.getInstance();
|
|
||||||
break;
|
|
||||||
case "First strike":
|
|
||||||
gainedAbility = FirstStrikeAbility.getInstance();
|
|
||||||
break;
|
|
||||||
case "Trample":
|
|
||||||
gainedAbility = TrampleAbility.getInstance();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (gainedAbility != null) {
|
|
||||||
game.addEffect(new GainAbilityTargetEffect(gainedAbility, Duration.Custom), source);
|
|
||||||
} else {
|
|
||||||
targetPermanent.addCounters(CounterType.P1P1.createInstance(), source.getControllerId(), source, game);
|
|
||||||
game.informPlayers(controller.getLogName() + " puts a +1/+1 counter on " + targetPermanent.getLogName());
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
return false;
|
|
||||||
|
Ability gainedAbility = null;
|
||||||
|
Choice choice = new ChoiceImpl(true);
|
||||||
|
choice.setMessage("Choose one");
|
||||||
|
choice.setChoices(choices);
|
||||||
|
if (controller.choose(outcome, choice, game)) {
|
||||||
|
switch (choice.getChoice()) {
|
||||||
|
case "Banding":
|
||||||
|
gainedAbility = BandingAbility.getInstance();
|
||||||
|
break;
|
||||||
|
case "First strike":
|
||||||
|
gainedAbility = FirstStrikeAbility.getInstance();
|
||||||
|
break;
|
||||||
|
case "Trample":
|
||||||
|
gainedAbility = TrampleAbility.getInstance();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (gainedAbility != null) {
|
||||||
|
game.addEffect(new GainAbilityTargetEffect(gainedAbility, Duration.Custom), source);
|
||||||
|
} else {
|
||||||
|
targetPermanent.addCounters(CounterType.P1P1.createInstance(), source.getControllerId(), source, game);
|
||||||
|
game.informPlayers(controller.getLogName() + " puts a +1/+1 counter on " + targetPermanent.getLogName());
|
||||||
|
}
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -60,6 +60,7 @@ class NecromancersStockpileDiscardTargetCost extends CostImpl {
|
||||||
|
|
||||||
public NecromancersStockpileDiscardTargetCost(NecromancersStockpileDiscardTargetCost cost) {
|
public NecromancersStockpileDiscardTargetCost(NecromancersStockpileDiscardTargetCost cost) {
|
||||||
super(cost);
|
super(cost);
|
||||||
|
this.isZombieCard = cost.isZombieCard;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -46,6 +46,7 @@ class PredatoryFocusEffect extends AsThoughEffectImpl {
|
||||||
|
|
||||||
public PredatoryFocusEffect(PredatoryFocusEffect effect) {
|
public PredatoryFocusEffect(PredatoryFocusEffect effect) {
|
||||||
super(effect);
|
super(effect);
|
||||||
|
this.choseUse = effect.choseUse;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -49,6 +49,7 @@ class PrimitiveEtchingsAbility extends TriggeredAbilityImpl {
|
||||||
|
|
||||||
PrimitiveEtchingsAbility(final PrimitiveEtchingsAbility ability) {
|
PrimitiveEtchingsAbility(final PrimitiveEtchingsAbility ability) {
|
||||||
super(ability);
|
super(ability);
|
||||||
|
this.lastTriggeredTurn = ability.lastTriggeredTurn;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -87,6 +87,7 @@ class RaziaBorosArchangelEffect extends RedirectionEffect {
|
||||||
|
|
||||||
public RaziaBorosArchangelEffect(final RaziaBorosArchangelEffect effect) {
|
public RaziaBorosArchangelEffect(final RaziaBorosArchangelEffect effect) {
|
||||||
super(effect);
|
super(effect);
|
||||||
|
this.redirectToObject = effect.redirectToObject;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -47,8 +47,9 @@ class RowenAbility extends TriggeredAbilityImpl {
|
||||||
super(Zone.BATTLEFIELD, new InfoEffect(""), false);
|
super(Zone.BATTLEFIELD, new InfoEffect(""), false);
|
||||||
}
|
}
|
||||||
|
|
||||||
RowenAbility(final RowenAbility ability) {
|
private RowenAbility(final RowenAbility ability) {
|
||||||
super(ability);
|
super(ability);
|
||||||
|
this.lastTriggeredTurn = ability.lastTriggeredTurn;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -54,7 +54,7 @@ class ChooseNumberEffect extends OneShotEffect {
|
||||||
staticText = "choose a number";
|
staticText = "choose a number";
|
||||||
}
|
}
|
||||||
|
|
||||||
public ChooseNumberEffect(final ChooseNumberEffect effect) {
|
private ChooseNumberEffect(final ChooseNumberEffect effect) {
|
||||||
super(effect);
|
super(effect);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -83,14 +83,12 @@ class ChooseNumberEffect extends OneShotEffect {
|
||||||
|
|
||||||
class SanctumPrelateReplacementEffect extends ContinuousRuleModifyingEffectImpl {
|
class SanctumPrelateReplacementEffect extends ContinuousRuleModifyingEffectImpl {
|
||||||
|
|
||||||
Integer choiceValue;
|
|
||||||
|
|
||||||
public SanctumPrelateReplacementEffect() {
|
public SanctumPrelateReplacementEffect() {
|
||||||
super(Duration.WhileOnBattlefield, Outcome.Detriment);
|
super(Duration.WhileOnBattlefield, Outcome.Detriment);
|
||||||
staticText = "Noncreature spells with mana value equal to the chosen number can't be cast";
|
staticText = "Noncreature spells with mana value equal to the chosen number can't be cast";
|
||||||
}
|
}
|
||||||
|
|
||||||
public SanctumPrelateReplacementEffect(final SanctumPrelateReplacementEffect effect) {
|
private SanctumPrelateReplacementEffect(final SanctumPrelateReplacementEffect effect) {
|
||||||
super(effect);
|
super(effect);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -120,7 +118,7 @@ class SanctumPrelateReplacementEffect extends ContinuousRuleModifyingEffectImpl
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean applies(GameEvent event, Ability source, Game game) {
|
public boolean applies(GameEvent event, Ability source, Game game) {
|
||||||
choiceValue = (Integer) game.getState().getValue(source.getSourceId().toString());
|
Integer choiceValue = (Integer) game.getState().getValue(source.getSourceId().toString());
|
||||||
Spell spell = game.getStack().getSpell(event.getTargetId());
|
Spell spell = game.getStack().getSpell(event.getTargetId());
|
||||||
|
|
||||||
if (spell != null && !spell.isCreature(game)) {
|
if (spell != null && !spell.isCreature(game)) {
|
||||||
|
|
|
@ -12,6 +12,7 @@ import mage.constants.CardType;
|
||||||
import mage.constants.SubType;
|
import mage.constants.SubType;
|
||||||
import mage.constants.Zone;
|
import mage.constants.Zone;
|
||||||
import mage.counters.CounterType;
|
import mage.counters.CounterType;
|
||||||
|
import mage.filter.StaticFilters;
|
||||||
import mage.filter.common.FilterLandPermanent;
|
import mage.filter.common.FilterLandPermanent;
|
||||||
import mage.game.Game;
|
import mage.game.Game;
|
||||||
import mage.game.events.GameEvent;
|
import mage.game.events.GameEvent;
|
||||||
|
@ -45,8 +46,6 @@ public final class ScuteMob extends CardImpl {
|
||||||
|
|
||||||
class ScuteMobAbility extends TriggeredAbilityImpl {
|
class ScuteMobAbility extends TriggeredAbilityImpl {
|
||||||
|
|
||||||
private FilterLandPermanent filter = new FilterLandPermanent();
|
|
||||||
|
|
||||||
public ScuteMobAbility() {
|
public ScuteMobAbility() {
|
||||||
super(Zone.BATTLEFIELD, new AddCountersSourceEffect(CounterType.P1P1.createInstance(4)));
|
super(Zone.BATTLEFIELD, new AddCountersSourceEffect(CounterType.P1P1.createInstance(4)));
|
||||||
}
|
}
|
||||||
|
@ -72,7 +71,7 @@ class ScuteMobAbility extends TriggeredAbilityImpl {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean checkInterveningIfClause(Game game) {
|
public boolean checkInterveningIfClause(Game game) {
|
||||||
return game.getBattlefield().countAll(filter, this.controllerId, game) >= 5;
|
return game.getBattlefield().countAll(StaticFilters.FILTER_LAND, this.controllerId, game) >= 5;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -31,6 +31,7 @@ public final class SlumberingTora extends CardImpl {
|
||||||
|
|
||||||
public SlumberingTora(UUID ownerId, CardSetInfo setInfo) {
|
public SlumberingTora(UUID ownerId, CardSetInfo setInfo) {
|
||||||
super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{3}");
|
super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{3}");
|
||||||
|
|
||||||
// {2}, Discard a Spirit or Arcane card: Slumbering Tora becomes an X/X Cat artifact creature until end of turn,
|
// {2}, Discard a Spirit or Arcane card: Slumbering Tora becomes an X/X Cat artifact creature until end of turn,
|
||||||
// where X is the discarded card's converted mana cost.
|
// where X is the discarded card's converted mana cost.
|
||||||
Ability ability = new SimpleActivatedAbility(new SlumberingToraEffect(), new ManaCostsImpl("{2}"));
|
Ability ability = new SimpleActivatedAbility(new SlumberingToraEffect(), new ManaCostsImpl("{2}"));
|
||||||
|
@ -49,7 +50,7 @@ public final class SlumberingTora extends CardImpl {
|
||||||
|
|
||||||
private static class SlumberingToraEffect extends ContinuousEffectImpl {
|
private static class SlumberingToraEffect extends ContinuousEffectImpl {
|
||||||
|
|
||||||
private int convManaCosts = 0;
|
private int convManaCosts;
|
||||||
|
|
||||||
private SlumberingToraEffect() {
|
private SlumberingToraEffect() {
|
||||||
super(Duration.EndOfTurn, Outcome.BecomeCreature);
|
super(Duration.EndOfTurn, Outcome.BecomeCreature);
|
||||||
|
@ -59,6 +60,7 @@ public final class SlumberingTora extends CardImpl {
|
||||||
|
|
||||||
private SlumberingToraEffect(final SlumberingToraEffect effect) {
|
private SlumberingToraEffect(final SlumberingToraEffect effect) {
|
||||||
super(effect);
|
super(effect);
|
||||||
|
this.convManaCosts = effect.convManaCosts;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -80,13 +80,24 @@ class SoulEchoOpponentsChoiceEffect extends OneShotEffect {
|
||||||
Permanent permanent = game.getPermanentOrLKIBattlefield(source.getSourceId());
|
Permanent permanent = game.getPermanentOrLKIBattlefield(source.getSourceId());
|
||||||
Player controller = game.getPlayer(source.getControllerId());
|
Player controller = game.getPlayer(source.getControllerId());
|
||||||
Player opponent = game.getPlayer(targetPointer.getFirst(game, source));
|
Player opponent = game.getPlayer(targetPointer.getFirst(game, source));
|
||||||
if (controller != null && opponent != null && permanent != null) {
|
if (controller == null || opponent == null || permanent == null) {
|
||||||
if (opponent.chooseUse(outcome, "Have all damage dealt to " + controller.getLogName() + " be decremented from echo counters on " + permanent.getLogName() + " until " + controller.getLogName() + "'s next upkeep instead?", source, game)) {
|
return false;
|
||||||
game.informPlayers("Until " + controller.getLogName() + "'s next upkeep, for each 1 damage that would be dealt to " + controller.getLogName() + ", an echo counter from " + permanent.getLogName() + " is removed instead");
|
}
|
||||||
game.addEffect(new SoulEchoReplacementEffect(), source);
|
|
||||||
}
|
String msg1 = "Have all damage dealt to " + controller.getLogName() +
|
||||||
|
" be decremented from echo counters on " + permanent.getLogName() +
|
||||||
|
" until " + controller.getLogName() + "'s next upkeep instead?";
|
||||||
|
|
||||||
|
String msg2 = "Until " + controller.getLogName() +
|
||||||
|
"'s next upkeep, for each 1 damage that would be dealt to " + controller.getLogName() +
|
||||||
|
", an echo counter from " + permanent.getLogName() + " is removed instead";
|
||||||
|
|
||||||
|
if (opponent.chooseUse(outcome, msg1, source, game)) {
|
||||||
|
game.informPlayers(msg2);
|
||||||
|
game.addEffect(new SoulEchoReplacementEffect(), source);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -99,16 +110,15 @@ class SoulEchoReplacementEffect extends ReplacementEffectImpl {
|
||||||
super(Duration.Custom, Outcome.PreventDamage);
|
super(Duration.Custom, Outcome.PreventDamage);
|
||||||
}
|
}
|
||||||
|
|
||||||
SoulEchoReplacementEffect(final SoulEchoReplacementEffect effect) {
|
private SoulEchoReplacementEffect(final SoulEchoReplacementEffect effect) {
|
||||||
super(effect);
|
super(effect);
|
||||||
|
this.sameStep = effect.sameStep;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isInactive(Ability source, Game game) {
|
public boolean isInactive(Ability source, Game game) {
|
||||||
if (game.getPhase().getStep().getType() == PhaseStep.UPKEEP) {
|
if (game.getPhase().getStep().getType() == PhaseStep.UPKEEP) {
|
||||||
if (!sameStep && game.isActivePlayer(source.getControllerId()) || game.getPlayer(source.getControllerId()).hasReachedNextTurnAfterLeaving()) {
|
return !sameStep && game.isActivePlayer(source.getControllerId()) || game.getPlayer(source.getControllerId()).hasReachedNextTurnAfterLeaving();
|
||||||
return true;
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
sameStep = false;
|
sameStep = false;
|
||||||
}
|
}
|
||||||
|
@ -117,14 +127,18 @@ class SoulEchoReplacementEffect extends ReplacementEffectImpl {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean replaceEvent(GameEvent event, Ability source, Game game) {
|
public boolean replaceEvent(GameEvent event, Ability source, Game game) {
|
||||||
DamageEvent damageEvent = (DamageEvent) event;
|
|
||||||
int damage = damageEvent.getAmount();
|
|
||||||
Permanent permanent = game.getPermanentOrLKIBattlefield(source.getSourceId());
|
Permanent permanent = game.getPermanentOrLKIBattlefield(source.getSourceId());
|
||||||
Player controller = game.getPlayer(source.getControllerId());
|
Player controller = game.getPlayer(source.getControllerId());
|
||||||
if (permanent != null && controller != null) {
|
if (permanent == null && controller == null) {
|
||||||
permanent.removeCounters(CounterType.ECHO.createInstance(damage), source, game);
|
return false;
|
||||||
game.informPlayers(controller.getLogName() + ": " + damage + " damage replaced with " + permanent.getLogName());
|
|
||||||
}
|
}
|
||||||
|
DamageEvent damageEvent = (DamageEvent) event;
|
||||||
|
int damage = damageEvent.getAmount();
|
||||||
|
|
||||||
|
permanent.removeCounters(CounterType.ECHO.createInstance(damage), source, game);
|
||||||
|
game.informPlayers(controller.getLogName() + ": " + damage + " damage replaced with " + permanent.getLogName());
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -45,7 +45,7 @@ class CheeseStandsAloneContinuousEffect extends ContinuousRuleModifyingEffectImp
|
||||||
|
|
||||||
private static final FilterControlledPermanent filter = new FilterControlledPermanent();
|
private static final FilterControlledPermanent filter = new FilterControlledPermanent();
|
||||||
|
|
||||||
private boolean wonAlready = false;
|
private boolean wonAlready;
|
||||||
|
|
||||||
static {
|
static {
|
||||||
filter.add(new NamePredicate("The Cheese Stands Alone"));
|
filter.add(new NamePredicate("The Cheese Stands Alone"));
|
||||||
|
@ -56,8 +56,9 @@ class CheeseStandsAloneContinuousEffect extends ContinuousRuleModifyingEffectImp
|
||||||
staticText = "When you control no permanents other than {this} and have no cards in hand, you win the game";
|
staticText = "When you control no permanents other than {this} and have no cards in hand, you win the game";
|
||||||
}
|
}
|
||||||
|
|
||||||
public CheeseStandsAloneContinuousEffect(final CheeseStandsAloneContinuousEffect effect) {
|
private CheeseStandsAloneContinuousEffect(final CheeseStandsAloneContinuousEffect effect) {
|
||||||
super(effect);
|
super(effect);
|
||||||
|
this.wonAlready = effect.wonAlready;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -67,8 +67,9 @@ class UrzasAvengerEffect extends ContinuousEffectImpl {
|
||||||
this.staticText = "{this} gets -1/-1 and gains your choice of banding, flying, first strike, or trample until end of turn";
|
this.staticText = "{this} gets -1/-1 and gains your choice of banding, flying, first strike, or trample until end of turn";
|
||||||
}
|
}
|
||||||
|
|
||||||
public UrzasAvengerEffect(final UrzasAvengerEffect effect) {
|
private UrzasAvengerEffect(final UrzasAvengerEffect effect) {
|
||||||
super(effect);
|
super(effect);
|
||||||
|
this.gainedAbility = effect.gainedAbility;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -100,8 +100,6 @@ class VerdantSuccessionTriggeredAbility extends TriggeredAbilityImpl {
|
||||||
|
|
||||||
class VerdantSuccessionEffect extends OneShotEffect {
|
class VerdantSuccessionEffect extends OneShotEffect {
|
||||||
|
|
||||||
private Permanent permanent;
|
|
||||||
|
|
||||||
VerdantSuccessionEffect() {
|
VerdantSuccessionEffect() {
|
||||||
super(Outcome.PutCardInPlay);
|
super(Outcome.PutCardInPlay);
|
||||||
}
|
}
|
||||||
|
@ -118,26 +116,36 @@ class VerdantSuccessionEffect extends OneShotEffect {
|
||||||
@Override
|
@Override
|
||||||
public boolean apply(Game game, Ability source) {
|
public boolean apply(Game game, Ability source) {
|
||||||
MageObject mageObject = game.getObject(source);
|
MageObject mageObject = game.getObject(source);
|
||||||
if(mageObject != null) {
|
if (mageObject == null) {
|
||||||
permanent = (Permanent) game.getState().getValue("verdantSuccession" + mageObject);
|
return false;
|
||||||
if (permanent != null) {
|
}
|
||||||
Player controller = game.getPlayer(permanent.getControllerId());
|
|
||||||
if (controller != null) {
|
Permanent permanent = (Permanent) game.getState().getValue("verdantSuccession" + mageObject);
|
||||||
FilterCard filterCard = new FilterCard("Card named " + permanent.getName());
|
if (permanent == null) {
|
||||||
filterCard.add(new NamePredicate(permanent.getName()));
|
return false;
|
||||||
TargetCardInLibrary target = new TargetCardInLibrary(filterCard);
|
}
|
||||||
controller.searchLibrary(target, source, game);
|
|
||||||
if (!target.getTargets().isEmpty()) {
|
Player controller = game.getPlayer(permanent.getControllerId());
|
||||||
Card card = game.getCard(target.getFirstTarget());
|
if (controller == null) {
|
||||||
if (card != null
|
return false;
|
||||||
&& controller.moveCards(card, Zone.BATTLEFIELD, source, game)) {
|
}
|
||||||
controller.shuffleLibrary(source, game);
|
|
||||||
}
|
FilterCard filterCard = new FilterCard("Card named " + permanent.getName());
|
||||||
return true;
|
filterCard.add(new NamePredicate(permanent.getName()));
|
||||||
}
|
|
||||||
}
|
TargetCardInLibrary target = new TargetCardInLibrary(filterCard);
|
||||||
|
if (!controller.searchLibrary(target, source, game)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!target.getTargets().isEmpty()) {
|
||||||
|
Card card = game.getCard(target.getFirstTarget());
|
||||||
|
if (card != null) {
|
||||||
|
controller.moveCards(card, Zone.BATTLEFIELD, source, game);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return false;
|
|
||||||
|
controller.shuffleLibrary(source, game); // Shuffle even if no card was found since it revealed the order of cards.
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,8 +2,11 @@
|
||||||
package mage.cards.w;
|
package mage.cards.w;
|
||||||
|
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
|
|
||||||
|
import mage.Mana;
|
||||||
import mage.abilities.Ability;
|
import mage.abilities.Ability;
|
||||||
import mage.abilities.common.SimpleActivatedAbility;
|
import mage.abilities.common.SimpleActivatedAbility;
|
||||||
|
import mage.abilities.costs.mana.ManaCost;
|
||||||
import mage.abilities.costs.mana.ManaCostsImpl;
|
import mage.abilities.costs.mana.ManaCostsImpl;
|
||||||
import mage.abilities.dynamicvalue.DynamicValue;
|
import mage.abilities.dynamicvalue.DynamicValue;
|
||||||
import mage.abilities.dynamicvalue.common.ManacostVariableValue;
|
import mage.abilities.dynamicvalue.common.ManacostVariableValue;
|
||||||
|
@ -28,7 +31,7 @@ public final class WarCadence extends CardImpl {
|
||||||
super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{2}{R}");
|
super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{2}{R}");
|
||||||
|
|
||||||
// {X}{R}: This turn, creatures can't block unless their controller pays {X} for each blocking creature they control.
|
// {X}{R}: This turn, creatures can't block unless their controller pays {X} for each blocking creature they control.
|
||||||
this.addAbility(new SimpleActivatedAbility(Zone.BATTLEFIELD, new WarCadenceReplacementEffect(), new ManaCostsImpl("{X}{R}")));
|
this.addAbility(new SimpleActivatedAbility(Zone.BATTLEFIELD, new WarCadenceReplacementEffect(), new ManaCostsImpl<>("{X}{R}")));
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -53,26 +56,28 @@ class WarCadenceReplacementEffect extends ReplacementEffectImpl {
|
||||||
|
|
||||||
WarCadenceReplacementEffect(WarCadenceReplacementEffect effect) {
|
WarCadenceReplacementEffect(WarCadenceReplacementEffect effect) {
|
||||||
super(effect);
|
super(effect);
|
||||||
|
this.xCosts = effect.xCosts.copy();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean replaceEvent(GameEvent event, Ability source, Game game) {
|
public boolean replaceEvent(GameEvent event, Ability source, Game game) {
|
||||||
Player player = game.getPlayer(event.getPlayerId());
|
Player player = game.getPlayer(event.getPlayerId());
|
||||||
if (player != null) {
|
if (player == null) {
|
||||||
int amount = xCosts.calculate(game, source, this);
|
return false;
|
||||||
if (amount > 0) {
|
|
||||||
String mana = "{" + amount + '}';
|
|
||||||
ManaCostsImpl cost = new ManaCostsImpl(mana);
|
|
||||||
if (cost.canPay(source, source, event.getPlayerId(), game)
|
|
||||||
&& player.chooseUse(Outcome.Benefit, "Pay " + mana + " to declare blocker?", source, game)) {
|
|
||||||
if (cost.payOrRollback(source, game, source, event.getPlayerId())) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return false;
|
|
||||||
|
int amount = xCosts.calculate(game, source, this);
|
||||||
|
if (amount <= 0) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
String mana = "{" + amount + '}';
|
||||||
|
ManaCostsImpl<ManaCost> cost = new ManaCostsImpl<>(mana);
|
||||||
|
if (cost.canPay(source, source, event.getPlayerId(), game)
|
||||||
|
&& player.chooseUse(Outcome.Benefit, "Pay " + mana + " to declare blocker?", source, game)) {
|
||||||
|
return !cost.payOrRollback(source, game, source, event.getPlayerId());
|
||||||
|
}
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -54,6 +54,7 @@ class WarTaxCantAttackUnlessPaysEffect extends PayCostToAttackBlockEffectImpl {
|
||||||
|
|
||||||
WarTaxCantAttackUnlessPaysEffect(WarTaxCantAttackUnlessPaysEffect effect) {
|
WarTaxCantAttackUnlessPaysEffect(WarTaxCantAttackUnlessPaysEffect effect) {
|
||||||
super(effect);
|
super(effect);
|
||||||
|
this.xCosts = effect.xCosts.copy();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -54,9 +54,6 @@ public final class Woeleecher extends CardImpl {
|
||||||
|
|
||||||
class WoeleecherEffect extends OneShotEffect {
|
class WoeleecherEffect extends OneShotEffect {
|
||||||
|
|
||||||
private int numberCountersOriginal = 0;
|
|
||||||
private int numberCountersAfter = 0;
|
|
||||||
|
|
||||||
public WoeleecherEffect() {
|
public WoeleecherEffect() {
|
||||||
super(Outcome.ReturnToHand);
|
super(Outcome.ReturnToHand);
|
||||||
this.staticText = "Remove a -1/-1 counter from target creature. If you do, you gain 2 life";
|
this.staticText = "Remove a -1/-1 counter from target creature. If you do, you gain 2 life";
|
||||||
|
@ -75,15 +72,19 @@ class WoeleecherEffect extends OneShotEffect {
|
||||||
public boolean apply(Game game, Ability source) {
|
public boolean apply(Game game, Ability source) {
|
||||||
Permanent target = game.getPermanent(source.getFirstTarget());
|
Permanent target = game.getPermanent(source.getFirstTarget());
|
||||||
Player you = game.getPlayer(source.getControllerId());
|
Player you = game.getPlayer(source.getControllerId());
|
||||||
if (target != null && you != null) {
|
if (target == null || you == null) {
|
||||||
numberCountersOriginal = target.getCounters(game).getCount(CounterType.M1M1);
|
return false;
|
||||||
target.removeCounters(CounterType.M1M1.createInstance(), source, game);
|
}
|
||||||
numberCountersAfter = target.getCounters(game).getCount(CounterType.M1M1);
|
|
||||||
if (numberCountersAfter < numberCountersOriginal && you != null) {
|
int numberCountersOriginal = target.getCounters(game).getCount(CounterType.M1M1);
|
||||||
you.gainLife(2, game, source);
|
target.removeCounters(CounterType.M1M1.createInstance(), source, game);
|
||||||
return true;
|
int numberCountersAfter = target.getCounters(game).getCount(CounterType.M1M1);
|
||||||
}
|
|
||||||
|
if (numberCountersAfter < numberCountersOriginal) {
|
||||||
|
you.gainLife(2, game, source);
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -31,7 +31,7 @@ import java.util.*;
|
||||||
public class RandomPlayer extends ComputerPlayer {
|
public class RandomPlayer extends ComputerPlayer {
|
||||||
|
|
||||||
private final boolean isSimulatedPlayer;
|
private final boolean isSimulatedPlayer;
|
||||||
private int actionCount = 0;
|
private int actionCount;
|
||||||
|
|
||||||
protected PassAbility pass = new PassAbility();
|
protected PassAbility pass = new PassAbility();
|
||||||
|
|
||||||
|
@ -43,6 +43,8 @@ public class RandomPlayer extends ComputerPlayer {
|
||||||
public RandomPlayer(final RandomPlayer player) {
|
public RandomPlayer(final RandomPlayer player) {
|
||||||
super(player);
|
super(player);
|
||||||
this.isSimulatedPlayer = player.isSimulatedPlayer;
|
this.isSimulatedPlayer = player.isSimulatedPlayer;
|
||||||
|
this.actionCount = player.actionCount;
|
||||||
|
this.pass = player.pass.copy();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -83,7 +83,7 @@ public class TestPlayer implements Player {
|
||||||
public static final String DIE_ROLL = "[die_roll]: ";
|
public static final String DIE_ROLL = "[die_roll]: ";
|
||||||
|
|
||||||
private int maxCallsWithoutAction = 400;
|
private int maxCallsWithoutAction = 400;
|
||||||
private int foundNoAction = 0;
|
private int foundNoAction;
|
||||||
|
|
||||||
// full playable AI, TODO: can be deleted?
|
// full playable AI, TODO: can be deleted?
|
||||||
private boolean AIPlayer;
|
private boolean AIPlayer;
|
||||||
|
@ -106,9 +106,9 @@ public class TestPlayer implements Player {
|
||||||
// - enable checks for wrong or missing choice commands (you must set up all choices by unit test)
|
// - enable checks for wrong or missing choice commands (you must set up all choices by unit test)
|
||||||
// - enable inner choice dialogs accessable by set up choices
|
// - enable inner choice dialogs accessable by set up choices
|
||||||
// (example: card call TestPlayer's choice, but it uses another choices, see docs in TestComputerPlayer)
|
// (example: card call TestPlayer's choice, but it uses another choices, see docs in TestComputerPlayer)
|
||||||
private boolean strictChooseMode = false;
|
private boolean strictChooseMode;
|
||||||
|
|
||||||
private String[] groupsForTargetHandling = null;
|
private String[] groupsForTargetHandling;
|
||||||
|
|
||||||
// Tracks the initial turns (turn 0s) both players are given at the start of the game.
|
// Tracks the initial turns (turn 0s) both players are given at the start of the game.
|
||||||
// Before actual turns start. Needed for checking attacker/blocker legality in the tests
|
// Before actual turns start. Needed for checking attacker/blocker legality in the tests
|
||||||
|
@ -146,6 +146,7 @@ public class TestPlayer implements Player {
|
||||||
this.groupsForTargetHandling = testPlayer.groupsForTargetHandling.clone();
|
this.groupsForTargetHandling = testPlayer.groupsForTargetHandling.clone();
|
||||||
}
|
}
|
||||||
this.strictChooseMode = testPlayer.strictChooseMode;
|
this.strictChooseMode = testPlayer.strictChooseMode;
|
||||||
|
this.maxCallsWithoutAction = testPlayer.maxCallsWithoutAction;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void addChoice(String choice) {
|
public void addChoice(String choice) {
|
||||||
|
|
|
@ -23,10 +23,10 @@ public abstract class TriggeredAbilityImpl extends AbilityImpl implements Trigge
|
||||||
|
|
||||||
protected boolean optional;
|
protected boolean optional;
|
||||||
protected boolean leavesTheBattlefieldTrigger;
|
protected boolean leavesTheBattlefieldTrigger;
|
||||||
private boolean triggersOnce = false;
|
private boolean triggersOnce;
|
||||||
private boolean doOnlyOnce = false;
|
private boolean doOnlyOnce;
|
||||||
private GameEvent triggerEvent = null;
|
private GameEvent triggerEvent;
|
||||||
private String triggerPhrase = null;
|
private String triggerPhrase;
|
||||||
|
|
||||||
public TriggeredAbilityImpl(Zone zone, Effect effect) {
|
public TriggeredAbilityImpl(Zone zone, Effect effect) {
|
||||||
this(zone, effect, false);
|
this(zone, effect, false);
|
||||||
|
@ -55,6 +55,7 @@ public abstract class TriggeredAbilityImpl extends AbilityImpl implements Trigge
|
||||||
this.triggersOnce = ability.triggersOnce;
|
this.triggersOnce = ability.triggersOnce;
|
||||||
this.doOnlyOnce = ability.doOnlyOnce;
|
this.doOnlyOnce = ability.doOnlyOnce;
|
||||||
this.triggerPhrase = ability.triggerPhrase;
|
this.triggerPhrase = ability.triggerPhrase;
|
||||||
|
this.triggerEvent = ability.triggerEvent;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -15,8 +15,8 @@ import mage.target.targetpointer.FixedTarget;
|
||||||
*/
|
*/
|
||||||
public class BlocksAttachedTriggeredAbility extends TriggeredAbilityImpl {
|
public class BlocksAttachedTriggeredAbility extends TriggeredAbilityImpl {
|
||||||
|
|
||||||
private boolean setFixedTargetPointer;
|
private final boolean setFixedTargetPointer;
|
||||||
private String attachedDescription;
|
private final String attachedDescription;
|
||||||
private boolean setFixedTargetPointerToBlocked;
|
private boolean setFixedTargetPointerToBlocked;
|
||||||
|
|
||||||
public BlocksAttachedTriggeredAbility(Effect effect, String attachedDescription, boolean optional) {
|
public BlocksAttachedTriggeredAbility(Effect effect, String attachedDescription, boolean optional) {
|
||||||
|
@ -40,6 +40,7 @@ public class BlocksAttachedTriggeredAbility extends TriggeredAbilityImpl {
|
||||||
super(ability);
|
super(ability);
|
||||||
this.setFixedTargetPointer = ability.setFixedTargetPointer;
|
this.setFixedTargetPointer = ability.setFixedTargetPointer;
|
||||||
this.attachedDescription = ability.attachedDescription;
|
this.attachedDescription = ability.attachedDescription;
|
||||||
|
this.setFixedTargetPointerToBlocked = ability.setFixedTargetPointerToBlocked;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -16,13 +16,14 @@ import java.util.UUID;
|
||||||
*/
|
*/
|
||||||
public class CyclingDiscardCost extends CostImpl {
|
public class CyclingDiscardCost extends CostImpl {
|
||||||
|
|
||||||
private MageObjectReference cycledCard = null;
|
private MageObjectReference cycledCard;
|
||||||
|
|
||||||
public CyclingDiscardCost() {
|
public CyclingDiscardCost() {
|
||||||
}
|
}
|
||||||
|
|
||||||
private CyclingDiscardCost(CyclingDiscardCost cost) {
|
private CyclingDiscardCost(CyclingDiscardCost cost) {
|
||||||
super(cost);
|
super(cost);
|
||||||
|
this.cycledCard = cost.cycledCard;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -49,6 +49,7 @@ public class ManaCostsImpl<T extends ManaCost> extends ArrayList<T> implements M
|
||||||
this.add(cost.copy());
|
this.add(cost.copy());
|
||||||
}
|
}
|
||||||
this.phyrexian = costs.phyrexian;
|
this.phyrexian = costs.phyrexian;
|
||||||
|
this.phyrexianPaid = costs.phyrexianPaid;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -42,9 +42,7 @@ public abstract class EffectImpl implements Effect {
|
||||||
if (effect.values != null) {
|
if (effect.values != null) {
|
||||||
values = new HashMap<>();
|
values = new HashMap<>();
|
||||||
Map<String, Object> map = effect.values;
|
Map<String, Object> map = effect.values;
|
||||||
for (Map.Entry<String, Object> entry : map.entrySet()) {
|
values.putAll(map);
|
||||||
values.put(entry.getKey(), entry.getValue());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -21,6 +21,7 @@ public class DontUntapInControllersNextUntapStepSourceEffect extends ContinuousR
|
||||||
|
|
||||||
public DontUntapInControllersNextUntapStepSourceEffect(final DontUntapInControllersNextUntapStepSourceEffect effect) {
|
public DontUntapInControllersNextUntapStepSourceEffect(final DontUntapInControllersNextUntapStepSourceEffect effect) {
|
||||||
super(effect);
|
super(effect);
|
||||||
|
this.validForTurnNum = effect.validForTurnNum;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -17,7 +17,6 @@ import mage.util.CardUtil;
|
||||||
public class ExileCardsFromTopOfLibraryTargetEffect extends OneShotEffect {
|
public class ExileCardsFromTopOfLibraryTargetEffect extends OneShotEffect {
|
||||||
|
|
||||||
int amount;
|
int amount;
|
||||||
String targetName;
|
|
||||||
|
|
||||||
public ExileCardsFromTopOfLibraryTargetEffect(int amount) {
|
public ExileCardsFromTopOfLibraryTargetEffect(int amount) {
|
||||||
this(amount, null);
|
this(amount, null);
|
||||||
|
|
|
@ -10,9 +10,10 @@ import mage.game.ExileZone;
|
||||||
import mage.game.Game;
|
import mage.game.Game;
|
||||||
import mage.players.Player;
|
import mage.players.Player;
|
||||||
|
|
||||||
|
// TODO: Remove this class? Nothing uses it.
|
||||||
public class ReturnCreaturesFromExileEffect extends OneShotEffect {
|
public class ReturnCreaturesFromExileEffect extends OneShotEffect {
|
||||||
|
|
||||||
private UUID exileId;
|
private final UUID exileId;
|
||||||
private boolean byOwner;
|
private boolean byOwner;
|
||||||
|
|
||||||
public ReturnCreaturesFromExileEffect(UUID exileId, boolean byOwner, String description) {
|
public ReturnCreaturesFromExileEffect(UUID exileId, boolean byOwner, String description) {
|
||||||
|
@ -23,9 +24,10 @@ public class ReturnCreaturesFromExileEffect extends OneShotEffect {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public ReturnCreaturesFromExileEffect(final ReturnCreaturesFromExileEffect effect) {
|
private ReturnCreaturesFromExileEffect(final ReturnCreaturesFromExileEffect effect) {
|
||||||
super(effect);
|
super(effect);
|
||||||
this.exileId = effect.exileId;
|
this.exileId = effect.exileId;
|
||||||
|
this.byOwner = effect.byOwner;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -29,6 +29,7 @@ public class MustBeBlockedByAllAttachedEffect extends RequirementEffect {
|
||||||
|
|
||||||
public MustBeBlockedByAllAttachedEffect(final MustBeBlockedByAllAttachedEffect effect) {
|
public MustBeBlockedByAllAttachedEffect(final MustBeBlockedByAllAttachedEffect effect) {
|
||||||
super(effect);
|
super(effect);
|
||||||
|
this.attachmentType = effect.attachmentType;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -11,7 +11,7 @@ import mage.game.permanent.Permanent;
|
||||||
*/
|
*/
|
||||||
public class BecomesCreatureIfVehicleEffect extends ContinuousEffectImpl {
|
public class BecomesCreatureIfVehicleEffect extends ContinuousEffectImpl {
|
||||||
|
|
||||||
private CardType addedType = CardType.CREATURE;
|
private static final CardType addedType = CardType.CREATURE;
|
||||||
|
|
||||||
public BecomesCreatureIfVehicleEffect() {
|
public BecomesCreatureIfVehicleEffect() {
|
||||||
super(Duration.WhileOnBattlefield, Layer.TypeChangingEffects_4, SubLayer.NA, Outcome.Benefit);
|
super(Duration.WhileOnBattlefield, Layer.TypeChangingEffects_4, SubLayer.NA, Outcome.Benefit);
|
||||||
|
|
|
@ -22,7 +22,7 @@ public class BecomesCreatureTargetEffect extends ContinuousEffectImpl {
|
||||||
protected boolean addStillALandText;
|
protected boolean addStillALandText;
|
||||||
protected boolean loseName;
|
protected boolean loseName;
|
||||||
protected boolean keepAbilities;
|
protected boolean keepAbilities;
|
||||||
protected boolean removeSubtypes = false;
|
protected boolean removeSubtypes;
|
||||||
|
|
||||||
|
|
||||||
public BecomesCreatureTargetEffect(Token token, boolean loseAllAbilities, boolean stillALand, Duration duration) {
|
public BecomesCreatureTargetEffect(Token token, boolean loseAllAbilities, boolean stillALand, Duration duration) {
|
||||||
|
@ -58,6 +58,7 @@ public class BecomesCreatureTargetEffect extends ContinuousEffectImpl {
|
||||||
this.addStillALandText = effect.addStillALandText;
|
this.addStillALandText = effect.addStillALandText;
|
||||||
this.loseName = effect.loseName;
|
this.loseName = effect.loseName;
|
||||||
this.keepAbilities = effect.keepAbilities;
|
this.keepAbilities = effect.keepAbilities;
|
||||||
|
this.removeSubtypes = effect.removeSubtypes;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -57,6 +57,7 @@ public class GainControlTargetEffect extends ContinuousEffectImpl {
|
||||||
super(effect);
|
super(effect);
|
||||||
this.controllingPlayerId = effect.controllingPlayerId;
|
this.controllingPlayerId = effect.controllingPlayerId;
|
||||||
this.fixedControl = effect.fixedControl;
|
this.fixedControl = effect.fixedControl;
|
||||||
|
this.firstControlChange = effect.firstControlChange;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -32,7 +32,7 @@ public class AmassEffect extends OneShotEffect {
|
||||||
}
|
}
|
||||||
|
|
||||||
private final DynamicValue amassNumber;
|
private final DynamicValue amassNumber;
|
||||||
private UUID amassedCreatureId = null;
|
private UUID amassedCreatureId;
|
||||||
|
|
||||||
public AmassEffect(int amassNumber) {
|
public AmassEffect(int amassNumber) {
|
||||||
this(StaticValue.get(amassNumber));
|
this(StaticValue.get(amassNumber));
|
||||||
|
@ -53,6 +53,7 @@ public class AmassEffect extends OneShotEffect {
|
||||||
private AmassEffect(final AmassEffect effect) {
|
private AmassEffect(final AmassEffect effect) {
|
||||||
super(effect);
|
super(effect);
|
||||||
this.amassNumber = effect.amassNumber;
|
this.amassNumber = effect.amassNumber;
|
||||||
|
this.amassedCreatureId = effect.amassedCreatureId;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -39,6 +39,7 @@ public class ProtectionChosenColorAttachedEffect extends ContinuousEffectImpl {
|
||||||
this.protectionAbility = effect.protectionAbility.copy();
|
this.protectionAbility = effect.protectionAbility.copy();
|
||||||
}
|
}
|
||||||
this.notRemoveItself = effect.notRemoveItself;
|
this.notRemoveItself = effect.notRemoveItself;
|
||||||
|
this.notRemoveControlled = effect.notRemoveControlled;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -135,7 +135,7 @@ class ReturnAttackerToHandTargetCost extends CostImpl {
|
||||||
filter.add(UnblockedPredicate.instance);
|
filter.add(UnblockedPredicate.instance);
|
||||||
}
|
}
|
||||||
|
|
||||||
private UUID defendingPlayerId = null;
|
private UUID defendingPlayerId;
|
||||||
|
|
||||||
public ReturnAttackerToHandTargetCost() {
|
public ReturnAttackerToHandTargetCost() {
|
||||||
this.addTarget(new TargetControlledPermanent(filter));
|
this.addTarget(new TargetControlledPermanent(filter));
|
||||||
|
@ -144,6 +144,7 @@ class ReturnAttackerToHandTargetCost extends CostImpl {
|
||||||
|
|
||||||
public ReturnAttackerToHandTargetCost(ReturnAttackerToHandTargetCost cost) {
|
public ReturnAttackerToHandTargetCost(ReturnAttackerToHandTargetCost cost) {
|
||||||
super(cost);
|
super(cost);
|
||||||
|
this.defendingPlayerId = cost.defendingPlayerId;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -152,8 +153,7 @@ class ReturnAttackerToHandTargetCost extends CostImpl {
|
||||||
for (UUID targetId : targets.get(0).getTargets()) {
|
for (UUID targetId : targets.get(0).getTargets()) {
|
||||||
Permanent permanent = game.getPermanent(targetId);
|
Permanent permanent = game.getPermanent(targetId);
|
||||||
Player controller = game.getPlayer(controllerId);
|
Player controller = game.getPlayer(controllerId);
|
||||||
if (permanent == null
|
if (permanent == null || controller == null) {
|
||||||
|| controller == null) {
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
defendingPlayerId = game.getCombat().getDefenderId(permanent.getId());
|
defendingPlayerId = game.getCombat().getDefenderId(permanent.getId());
|
||||||
|
|
|
@ -12,8 +12,8 @@ import mage.util.CardUtil;
|
||||||
|
|
||||||
public class VanishingUpkeepAbility extends BeginningOfUpkeepTriggeredAbility {
|
public class VanishingUpkeepAbility extends BeginningOfUpkeepTriggeredAbility {
|
||||||
|
|
||||||
private int vanishingAmount;
|
private final int vanishingAmount;
|
||||||
private String permanentType;
|
private final String permanentType;
|
||||||
|
|
||||||
public VanishingUpkeepAbility(int vanishingEffect) {
|
public VanishingUpkeepAbility(int vanishingEffect) {
|
||||||
super(new VanishingEffect(), TargetController.YOU, false);
|
super(new VanishingEffect(), TargetController.YOU, false);
|
||||||
|
@ -27,9 +27,10 @@ public class VanishingUpkeepAbility extends BeginningOfUpkeepTriggeredAbility {
|
||||||
this.permanentType = permanentType;
|
this.permanentType = permanentType;
|
||||||
}
|
}
|
||||||
|
|
||||||
public VanishingUpkeepAbility(final VanishingUpkeepAbility ability) {
|
private VanishingUpkeepAbility(final VanishingUpkeepAbility ability) {
|
||||||
super(ability);
|
super(ability);
|
||||||
this.vanishingAmount = ability.vanishingAmount;
|
this.vanishingAmount = ability.vanishingAmount;
|
||||||
|
this.permanentType = ability.permanentType;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -63,15 +64,16 @@ class VanishingEffect extends OneShotEffect {
|
||||||
@Override
|
@Override
|
||||||
public boolean apply(Game game, Ability source) {
|
public boolean apply(Game game, Ability source) {
|
||||||
Permanent p = game.getPermanent(source.getSourceId());
|
Permanent p = game.getPermanent(source.getSourceId());
|
||||||
if (p != null) {
|
if (p == null) {
|
||||||
int amount = p.getCounters(game).getCount(CounterType.TIME);
|
return false;
|
||||||
if (amount > 0) {
|
|
||||||
p.removeCounters(CounterType.TIME.createInstance(), source, game);
|
|
||||||
game.informPlayers("Removed a time counter from " + p.getLogName() + " (" + amount + " left)");
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
return false;
|
|
||||||
|
int amount = p.getCounters(game).getCount(CounterType.TIME);
|
||||||
|
if (amount > 0) {
|
||||||
|
p.removeCounters(CounterType.TIME.createInstance(), source, game);
|
||||||
|
game.informPlayers("Removed a time counter from " + p.getLogName() + " (" + amount + " left)");
|
||||||
|
}
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -73,7 +73,7 @@ class AnyColorLandsProduceManaEffect extends ManaEffect {
|
||||||
private final FilterPermanent filter;
|
private final FilterPermanent filter;
|
||||||
private final boolean onlyColors; // false if mana types can be produced (also Colorless mana), if true only colors can be produced (no Colorless mana).
|
private final boolean onlyColors; // false if mana types can be produced (also Colorless mana), if true only colors can be produced (no Colorless mana).
|
||||||
|
|
||||||
private boolean inManaTypeCalculation = false;
|
private boolean inManaTypeCalculation;
|
||||||
|
|
||||||
AnyColorLandsProduceManaEffect(TargetController targetController, boolean onlyColors, FilterPermanent filter) {
|
AnyColorLandsProduceManaEffect(TargetController targetController, boolean onlyColors, FilterPermanent filter) {
|
||||||
super();
|
super();
|
||||||
|
@ -93,6 +93,7 @@ class AnyColorLandsProduceManaEffect extends ManaEffect {
|
||||||
super(effect);
|
super(effect);
|
||||||
this.filter = effect.filter.copy();
|
this.filter = effect.filter.copy();
|
||||||
this.onlyColors = effect.onlyColors;
|
this.onlyColors = effect.onlyColors;
|
||||||
|
this.inManaTypeCalculation = effect.inManaTypeCalculation;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -57,7 +57,7 @@ class AnyColorPermanentTypesManaEffect extends ManaEffect {
|
||||||
private final FilterPermanent filter;
|
private final FilterPermanent filter;
|
||||||
private final boolean onlyColors; // false if mana types can be produced (also Colorless mana), if true only colors can be produced (no Colorless mana).
|
private final boolean onlyColors; // false if mana types can be produced (also Colorless mana), if true only colors can be produced (no Colorless mana).
|
||||||
|
|
||||||
private boolean inManaTypeCalculation = false;
|
private boolean inManaTypeCalculation;
|
||||||
|
|
||||||
public AnyColorPermanentTypesManaEffect(TargetController targetController, boolean onlyColors, FilterPermanent permanentTypes) {
|
public AnyColorPermanentTypesManaEffect(TargetController targetController, boolean onlyColors, FilterPermanent permanentTypes) {
|
||||||
super();
|
super();
|
||||||
|
@ -72,6 +72,7 @@ class AnyColorPermanentTypesManaEffect extends ManaEffect {
|
||||||
super(effect);
|
super(effect);
|
||||||
this.filter = effect.filter.copy();
|
this.filter = effect.filter.copy();
|
||||||
this.onlyColors = effect.onlyColors;
|
this.onlyColors = effect.onlyColors;
|
||||||
|
this.inManaTypeCalculation = effect.inManaTypeCalculation;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -85,9 +85,9 @@ public class GameState implements Serializable, Copyable<GameState> {
|
||||||
private Exile exile;
|
private Exile exile;
|
||||||
private Battlefield battlefield;
|
private Battlefield battlefield;
|
||||||
private int turnNum = 1;
|
private int turnNum = 1;
|
||||||
private int stepNum = 0;
|
private int stepNum;
|
||||||
private UUID turnId = null;
|
private UUID turnId;
|
||||||
private boolean extraTurn = false;
|
private boolean extraTurn;
|
||||||
private boolean legendaryRuleActive = true;
|
private boolean legendaryRuleActive = true;
|
||||||
private boolean gameOver;
|
private boolean gameOver;
|
||||||
private boolean paused;
|
private boolean paused;
|
||||||
|
@ -105,8 +105,8 @@ public class GameState implements Serializable, Copyable<GameState> {
|
||||||
private int permanentOrderNumber;
|
private int permanentOrderNumber;
|
||||||
private final Map<UUID, FilterCreaturePermanent> usePowerInsteadOfToughnessForDamageLethalityFilters = new HashMap<>();
|
private final Map<UUID, FilterCreaturePermanent> usePowerInsteadOfToughnessForDamageLethalityFilters = new HashMap<>();
|
||||||
private Set<MageObjectReference> commandersToStay = new HashSet<>(); // commanders that do not go back to command zone
|
private Set<MageObjectReference> commandersToStay = new HashSet<>(); // commanders that do not go back to command zone
|
||||||
private boolean manaBurn = false;
|
private boolean manaBurn;
|
||||||
private boolean hasDayNight = false;
|
private boolean hasDayNight;
|
||||||
private boolean isDaytime = true;
|
private boolean isDaytime = true;
|
||||||
|
|
||||||
private int applyEffectsCounter; // Upcounting number of each applyEffects execution
|
private int applyEffectsCounter; // Upcounting number of each applyEffects execution
|
||||||
|
@ -157,6 +157,7 @@ public class GameState implements Serializable, Copyable<GameState> {
|
||||||
this.battlefield = state.battlefield.copy();
|
this.battlefield = state.battlefield.copy();
|
||||||
this.turnNum = state.turnNum;
|
this.turnNum = state.turnNum;
|
||||||
this.stepNum = state.stepNum;
|
this.stepNum = state.stepNum;
|
||||||
|
this.turnId = state.turnId;
|
||||||
this.extraTurn = state.extraTurn;
|
this.extraTurn = state.extraTurn;
|
||||||
this.legendaryRuleActive = state.legendaryRuleActive;
|
this.legendaryRuleActive = state.legendaryRuleActive;
|
||||||
this.effects = state.effects.copy();
|
this.effects = state.effects.copy();
|
||||||
|
@ -199,6 +200,7 @@ public class GameState implements Serializable, Copyable<GameState> {
|
||||||
this.commandersToStay.addAll(state.commandersToStay);
|
this.commandersToStay.addAll(state.commandersToStay);
|
||||||
this.hasDayNight = state.hasDayNight;
|
this.hasDayNight = state.hasDayNight;
|
||||||
this.isDaytime = state.isDaytime;
|
this.isDaytime = state.isDaytime;
|
||||||
|
this.manaBurn = state.manaBurn;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void clearOnGameRestart() {
|
public void clearOnGameRestart() {
|
||||||
|
|
|
@ -39,6 +39,7 @@ public abstract class GameTinyLeadersImpl extends GameImpl {
|
||||||
public GameTinyLeadersImpl(final GameTinyLeadersImpl game) {
|
public GameTinyLeadersImpl(final GameTinyLeadersImpl game) {
|
||||||
super(game);
|
super(game);
|
||||||
this.alsoHand = game.alsoHand;
|
this.alsoHand = game.alsoHand;
|
||||||
|
this.alsoLibrary = game.alsoLibrary;
|
||||||
this.startingPlayerSkipsDraw = game.startingPlayerSkipsDraw;
|
this.startingPlayerSkipsDraw = game.startingPlayerSkipsDraw;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -50,35 +51,37 @@ public abstract class GameTinyLeadersImpl extends GameImpl {
|
||||||
// move tiny leader to command zone
|
// move tiny leader to command zone
|
||||||
for (UUID playerId : state.getPlayerList(startingPlayerId)) {
|
for (UUID playerId : state.getPlayerList(startingPlayerId)) {
|
||||||
Player player = getPlayer(playerId);
|
Player player = getPlayer(playerId);
|
||||||
if (player != null) {
|
if (player == null) {
|
||||||
String commanderName = player.getMatchPlayer().getDeck().getName();
|
continue;
|
||||||
Card commander = findCommander(this, player, commanderName);
|
}
|
||||||
|
|
||||||
|
String commanderName = player.getMatchPlayer().getDeck().getName();
|
||||||
|
Card commander = findCommander(this, player, commanderName);
|
||||||
|
if (commander != null) {
|
||||||
|
// already exists - just move to zone (example: game restart by Karn Liberated)
|
||||||
|
commander.moveToZone(Zone.COMMAND, null, this, true);
|
||||||
|
} else {
|
||||||
|
// create new commander
|
||||||
|
commander = getCommanderCard(commanderName, player.getId());
|
||||||
if (commander != null) {
|
if (commander != null) {
|
||||||
// already exists - just move to zone (example: game restart by Karn Liberated)
|
Set<Card> cards = new HashSet<>();
|
||||||
|
cards.add(commander);
|
||||||
|
this.loadCards(cards, playerId);
|
||||||
|
player.addCommanderId(commander.getId());
|
||||||
commander.moveToZone(Zone.COMMAND, null, this, true);
|
commander.moveToZone(Zone.COMMAND, null, this, true);
|
||||||
|
Ability ability = new SimpleStaticAbility(Zone.COMMAND, new InfoEffect("Commander effects"));
|
||||||
|
ability.addEffect(new CommanderReplacementEffect(commander.getId(), alsoHand, alsoLibrary, false, "Commander"));
|
||||||
|
ability.addEffect(new CommanderCostModification(commander));
|
||||||
|
// Commander rule #4 was removed Jan. 18, 2016
|
||||||
|
// ability.addEffect(new CommanderManaReplacementEffect(player.getId(), CardUtil.getColorIdentity(commander)));
|
||||||
|
CommanderInfoWatcher watcher = new CommanderInfoWatcher("Commander", commander.getId(), false);
|
||||||
|
getState().addWatcher(watcher);
|
||||||
|
watcher.addCardInfoToCommander(this);
|
||||||
|
this.getState().addAbility(ability, null);
|
||||||
} else {
|
} else {
|
||||||
// create new commander
|
// GameWorker.call processing errors and write it in magediag.log by defalt
|
||||||
commander = getCommanderCard(commanderName, player.getId());
|
// Test use case: create tiny game with random generated deck - game freezes with empty battlefield
|
||||||
if (commander != null) {
|
throw new IllegalStateException("Commander card could not be created. Name: [" + player.getMatchPlayer().getDeck().getName() + ']');
|
||||||
Set<Card> cards = new HashSet<>();
|
|
||||||
cards.add(commander);
|
|
||||||
this.loadCards(cards, playerId);
|
|
||||||
player.addCommanderId(commander.getId());
|
|
||||||
commander.moveToZone(Zone.COMMAND, null, this, true);
|
|
||||||
Ability ability = new SimpleStaticAbility(Zone.COMMAND, new InfoEffect("Commander effects"));
|
|
||||||
ability.addEffect(new CommanderReplacementEffect(commander.getId(), alsoHand, alsoLibrary, false, "Commander"));
|
|
||||||
ability.addEffect(new CommanderCostModification(commander));
|
|
||||||
// Commander rule #4 was removed Jan. 18, 2016
|
|
||||||
// ability.addEffect(new CommanderManaReplacementEffect(player.getId(), CardUtil.getColorIdentity(commander)));
|
|
||||||
CommanderInfoWatcher watcher = new CommanderInfoWatcher("Commander", commander.getId(), false);
|
|
||||||
getState().addWatcher(watcher);
|
|
||||||
watcher.addCardInfoToCommander(this);
|
|
||||||
this.getState().addAbility(ability, null);
|
|
||||||
} else {
|
|
||||||
// GameWorker.call processing errors and write it in magediag.log by defalt
|
|
||||||
// Test use case: create tiny game with random generated deck - game freezes with empty battlefield
|
|
||||||
throw new IllegalStateException("Commander card could not be created. Name: [" + player.getMatchPlayer().getDeck().getName() + ']');
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -73,7 +73,9 @@ public abstract class PermanentImpl extends CardImpl implements Permanent {
|
||||||
protected boolean morphed = false;
|
protected boolean morphed = false;
|
||||||
protected int classLevel = 1;
|
protected int classLevel = 1;
|
||||||
protected final Set<UUID> goadingPlayers = new HashSet<>();
|
protected final Set<UUID> goadingPlayers = new HashSet<>();
|
||||||
|
// The UUID of the controller under who the permanent first entered the battelfield under.
|
||||||
protected UUID originalControllerId;
|
protected UUID originalControllerId;
|
||||||
|
// The UUID of the current controller.
|
||||||
protected UUID controllerId;
|
protected UUID controllerId;
|
||||||
protected UUID beforeResetControllerId;
|
protected UUID beforeResetControllerId;
|
||||||
protected int damage;
|
protected int damage;
|
||||||
|
@ -129,6 +131,7 @@ public abstract class PermanentImpl extends CardImpl implements Permanent {
|
||||||
this.flipped = permanent.flipped;
|
this.flipped = permanent.flipped;
|
||||||
this.originalControllerId = permanent.originalControllerId;
|
this.originalControllerId = permanent.originalControllerId;
|
||||||
this.controllerId = permanent.controllerId;
|
this.controllerId = permanent.controllerId;
|
||||||
|
this.beforeResetControllerId = permanent.controllerId;
|
||||||
this.damage = permanent.damage;
|
this.damage = permanent.damage;
|
||||||
this.controlledFromStartOfControllerTurn = permanent.controlledFromStartOfControllerTurn;
|
this.controlledFromStartOfControllerTurn = permanent.controlledFromStartOfControllerTurn;
|
||||||
this.turnsOnBattlefield = permanent.turnsOnBattlefield;
|
this.turnsOnBattlefield = permanent.turnsOnBattlefield;
|
||||||
|
@ -141,11 +144,9 @@ public abstract class PermanentImpl extends CardImpl implements Permanent {
|
||||||
this.deathtouched = permanent.deathtouched;
|
this.deathtouched = permanent.deathtouched;
|
||||||
this.markedLifelink = permanent.markedLifelink;
|
this.markedLifelink = permanent.markedLifelink;
|
||||||
|
|
||||||
for (Map.Entry<String, List<UUID>> entry : permanent.connectedCards.entrySet()) {
|
this.connectedCards.putAll(permanent.connectedCards);
|
||||||
this.connectedCards.put(entry.getKey(), entry.getValue());
|
|
||||||
}
|
|
||||||
if (permanent.dealtDamageByThisTurn != null) {
|
if (permanent.dealtDamageByThisTurn != null) {
|
||||||
dealtDamageByThisTurn = new HashSet<>(permanent.dealtDamageByThisTurn);
|
this.dealtDamageByThisTurn = new HashSet<>(permanent.dealtDamageByThisTurn);
|
||||||
}
|
}
|
||||||
if (permanent.markedDamage != null) {
|
if (permanent.markedDamage != null) {
|
||||||
markedDamage = new ArrayList<>();
|
markedDamage = new ArrayList<>();
|
||||||
|
@ -171,6 +172,7 @@ public abstract class PermanentImpl extends CardImpl implements Permanent {
|
||||||
this.bandedCards.addAll(permanent.bandedCards);
|
this.bandedCards.addAll(permanent.bandedCards);
|
||||||
this.timesLoyaltyUsed = permanent.timesLoyaltyUsed;
|
this.timesLoyaltyUsed = permanent.timesLoyaltyUsed;
|
||||||
this.transformCount = permanent.transformCount;
|
this.transformCount = permanent.transformCount;
|
||||||
|
this.removedFromCombat = permanent.removedFromCombat;
|
||||||
|
|
||||||
this.morphed = permanent.morphed;
|
this.morphed = permanent.morphed;
|
||||||
this.manifested = permanent.manifested;
|
this.manifested = permanent.manifested;
|
||||||
|
@ -193,6 +195,14 @@ public abstract class PermanentImpl extends CardImpl implements Permanent {
|
||||||
abilities.setControllerId(controllerId);
|
abilities.setControllerId(controllerId);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Used to override the original controller of a permanent to be different than the player who cast the spell
|
||||||
|
* or activated the ability.
|
||||||
|
*
|
||||||
|
* E.g. Xantcha, Sleeper Agent. Who enters the battlefield directly under someone else's control.
|
||||||
|
*
|
||||||
|
* @param originalControllerId The UUID of the original controller of the permanent
|
||||||
|
*/
|
||||||
@Override
|
@Override
|
||||||
public void setOriginalControllerId(UUID originalControllerId) {
|
public void setOriginalControllerId(UUID originalControllerId) {
|
||||||
this.originalControllerId = originalControllerId;
|
this.originalControllerId = originalControllerId;
|
||||||
|
@ -764,6 +774,7 @@ public abstract class PermanentImpl extends CardImpl implements Permanent {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean checkControlChanged(Game game) {
|
public boolean checkControlChanged(Game game) {
|
||||||
|
// TODO Put a break point and see what's going on with controllerID, beforeResetControllerID, and originalControllerID
|
||||||
if (!controllerId.equals(beforeResetControllerId)) {
|
if (!controllerId.equals(beforeResetControllerId)) {
|
||||||
this.removeFromCombat(game);
|
this.removeFromCombat(game);
|
||||||
this.controlledFromStartOfControllerTurn = false;
|
this.controlledFromStartOfControllerTurn = false;
|
||||||
|
@ -904,7 +915,7 @@ public abstract class PermanentImpl extends CardImpl implements Permanent {
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
private int doDamage(int damageAmount, UUID attackerId, Ability source, Game game, boolean preventable, boolean combat, boolean markDamage, List<UUID> appliedEffects) {
|
private int doDamage(int damageAmount, UUID attackerId, Ability source, Game game, boolean preventable, boolean combat, boolean markDamage, List<UUID> appliedEffects) {
|
||||||
int damageDone = 0;
|
int damageDone;
|
||||||
if (damageAmount < 1 || !canDamage(game.getObject(attackerId), game)) {
|
if (damageAmount < 1 || !canDamage(game.getObject(attackerId), game)) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -1758,20 +1769,22 @@ public abstract class PermanentImpl extends CardImpl implements Permanent {
|
||||||
public boolean moveToZone(Zone toZone, Ability source, Game game, boolean flag, List<UUID> appliedEffects) {
|
public boolean moveToZone(Zone toZone, Ability source, Game game, boolean flag, List<UUID> appliedEffects) {
|
||||||
Zone fromZone = game.getState().getZone(objectId);
|
Zone fromZone = game.getState().getZone(objectId);
|
||||||
Player controller = game.getPlayer(controllerId);
|
Player controller = game.getPlayer(controllerId);
|
||||||
if (controller != null) {
|
if (controller == null) {
|
||||||
ZoneChangeEvent event = new ZoneChangeEvent(this, source, controllerId, fromZone, toZone, appliedEffects);
|
return false;
|
||||||
ZoneChangeInfo zoneChangeInfo;
|
|
||||||
if (toZone == Zone.LIBRARY) {
|
|
||||||
zoneChangeInfo = new ZoneChangeInfo.Library(event, flag /* put on top */);
|
|
||||||
} else {
|
|
||||||
zoneChangeInfo = new ZoneChangeInfo(event);
|
|
||||||
}
|
|
||||||
boolean successfullyMoved = ZonesHandler.moveCard(zoneChangeInfo, game, source);
|
|
||||||
//20180810 - 701.3d
|
|
||||||
detachAllAttachments(game);
|
|
||||||
return successfullyMoved;
|
|
||||||
}
|
}
|
||||||
return false;
|
|
||||||
|
ZoneChangeEvent event = new ZoneChangeEvent(this, source, controllerId, fromZone, toZone, appliedEffects);
|
||||||
|
ZoneChangeInfo zoneChangeInfo;
|
||||||
|
if (toZone == Zone.LIBRARY) {
|
||||||
|
zoneChangeInfo = new ZoneChangeInfo.Library(event, flag /* put on top */);
|
||||||
|
} else {
|
||||||
|
zoneChangeInfo = new ZoneChangeInfo(event);
|
||||||
|
}
|
||||||
|
boolean successfullyMoved = ZonesHandler.moveCard(zoneChangeInfo, game, source);
|
||||||
|
//20180810 - 701.3d
|
||||||
|
detachAllAttachments(game);
|
||||||
|
|
||||||
|
return successfullyMoved;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -81,6 +81,7 @@ public abstract class TokenImpl extends MageObjectImpl implements Token {
|
||||||
this.expansionSetCodeChecked = token.expansionSetCodeChecked;
|
this.expansionSetCodeChecked = token.expansionSetCodeChecked;
|
||||||
this.copySourceCard = token.copySourceCard; // will never be changed
|
this.copySourceCard = token.copySourceCard; // will never be changed
|
||||||
this.availableImageSetCodes = token.availableImageSetCodes;
|
this.availableImageSetCodes = token.availableImageSetCodes;
|
||||||
|
this.tokenDescriptor = token.tokenDescriptor;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -30,6 +30,7 @@ public class SpellStack extends ArrayDeque<StackObject> {
|
||||||
for (StackObject spell : stack) {
|
for (StackObject spell : stack) {
|
||||||
this.addLast(spell.copy());
|
this.addLast(spell.copy());
|
||||||
}
|
}
|
||||||
|
this.dateLastAdded = stack.dateLastAdded;
|
||||||
}
|
}
|
||||||
|
|
||||||
//resolve top StackObject
|
//resolve top StackObject
|
||||||
|
|
Loading…
Reference in a new issue