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.tokenClassName = card.tokenClassName;
|
||||
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
|
||||
|
|
|
@ -31,6 +31,7 @@ public class MomirGame extends GameImpl {
|
|||
|
||||
public MomirGame(final MomirGame game) {
|
||||
super(game);
|
||||
this.numPlayers = game.numPlayers;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -68,7 +68,7 @@ public class ComputerPlayer6 extends ComputerPlayer /*implements Player*/ {
|
|||
|
||||
protected Set<String> actionCache;
|
||||
private static final List<TreeOptimizer> optimizers = new ArrayList<>();
|
||||
protected int lastLoggedTurn = 0;
|
||||
protected int lastLoggedTurn;
|
||||
protected static final String BLANKS = "...............................................";
|
||||
|
||||
static {
|
||||
|
@ -80,11 +80,7 @@ public class ComputerPlayer6 extends ComputerPlayer /*implements Player*/ {
|
|||
|
||||
public ComputerPlayer6(String name, RangeOfInfluence range, int skill) {
|
||||
super(name, range);
|
||||
if (skill < 4) {
|
||||
maxDepth = 4;
|
||||
} else {
|
||||
maxDepth = skill;
|
||||
}
|
||||
maxDepth = Math.max(skill, 4);
|
||||
maxThink = skill * 3;
|
||||
maxNodes = Config2.maxNodes;
|
||||
getSuggestedActions();
|
||||
|
@ -94,7 +90,11 @@ public class ComputerPlayer6 extends ComputerPlayer /*implements Player*/ {
|
|||
public ComputerPlayer6(final ComputerPlayer6 player) {
|
||||
super(player);
|
||||
this.maxDepth = player.maxDepth;
|
||||
this.maxNodes = player.maxNodes;
|
||||
this.maxThink = player.maxThink;
|
||||
this.lastLoggedTurn = player.lastLoggedTurn;
|
||||
this.currentScore = player.currentScore;
|
||||
this.root = player.root;
|
||||
if (player.combat != null) {
|
||||
this.combat = player.combat.copy();
|
||||
}
|
||||
|
@ -102,6 +102,8 @@ public class ComputerPlayer6 extends ComputerPlayer /*implements Player*/ {
|
|||
this.targets.addAll(player.targets);
|
||||
this.choices.addAll(player.choices);
|
||||
this.actionCache = player.actionCache;
|
||||
this.attackersList.addAll(player.attackersList);
|
||||
this.attackersToCheck.addAll(player.attackersToCheck);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -58,6 +58,7 @@ public class SimulatedPlayer2 extends ComputerPlayer {
|
|||
this.suggested = new ArrayList<>(player.suggested);
|
||||
// this.allActions = player.allActions; // dynamic, no need to copy
|
||||
this.originalPlayer = player.originalPlayer.copy();
|
||||
this.forced = player.forced;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -67,7 +67,7 @@ import java.util.Map.Entry;
|
|||
public class ComputerPlayer extends PlayerImpl implements Player {
|
||||
|
||||
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
|
||||
|
||||
|
@ -105,6 +105,9 @@ public class ComputerPlayer extends PlayerImpl implements Player {
|
|||
|
||||
public ComputerPlayer(final ComputerPlayer 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
|
||||
|
|
|
@ -31,10 +31,13 @@ public class ComputerPlayerMCTS extends ComputerPlayer implements Player {
|
|||
private static final int THINK_MAX_RATIO = 100;
|
||||
private static final double THINK_TIME_MULTIPLIER = 2.0;
|
||||
private static final boolean USE_MULTIPLE_THREADS = true;
|
||||
private static final Logger logger = Logger.getLogger(ComputerPlayerMCTS.class);
|
||||
|
||||
protected transient MCTSNode root;
|
||||
protected String lastPhase = "";
|
||||
protected long totalThinkTime;
|
||||
protected long totalSimulations;
|
||||
protected int maxThinkTime;
|
||||
private static final Logger logger = Logger.getLogger(ComputerPlayerMCTS.class);
|
||||
private int poolSize;
|
||||
|
||||
public ComputerPlayerMCTS(String name, RangeOfInfluence range, int skill) {
|
||||
|
@ -50,6 +53,11 @@ public class ComputerPlayerMCTS extends ComputerPlayer implements Player {
|
|||
|
||||
public ComputerPlayerMCTS(final ComputerPlayerMCTS player) {
|
||||
super(player);
|
||||
this.maxThinkTime = player.maxThinkTime;
|
||||
this.poolSize = player.poolSize;
|
||||
this.lastPhase = player.lastPhase;
|
||||
this.totalSimulations = player.totalSimulations;
|
||||
this.totalThinkTime = player.totalThinkTime;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -57,8 +65,6 @@ public class ComputerPlayerMCTS extends ComputerPlayer implements Player {
|
|||
return new ComputerPlayerMCTS(this);
|
||||
}
|
||||
|
||||
protected String lastPhase = "";
|
||||
|
||||
@Override
|
||||
public boolean priority(Game game) {
|
||||
if (game.getStep().getType() == PhaseStep.UPKEEP) {
|
||||
|
@ -152,9 +158,6 @@ public class ComputerPlayerMCTS extends ComputerPlayer implements Player {
|
|||
MCTSNode.logHitMiss();
|
||||
}
|
||||
|
||||
protected long totalThinkTime = 0;
|
||||
protected long totalSimulations = 0;
|
||||
|
||||
protected void applyMCTS(final Game game, final NextAction action) {
|
||||
|
||||
int thinkTime = calculateThinkTime(game, action);
|
||||
|
|
|
@ -30,8 +30,8 @@ import java.util.*;
|
|||
*/
|
||||
public class SimulatedPlayerMCTS extends MCTSPlayer {
|
||||
|
||||
private boolean isSimulatedPlayer;
|
||||
private int actionCount = 0;
|
||||
private final boolean isSimulatedPlayer;
|
||||
private int actionCount;
|
||||
private static final Logger logger = Logger.getLogger(SimulatedPlayerMCTS.class);
|
||||
|
||||
public SimulatedPlayerMCTS(Player originalPlayer, boolean isSimulatedPlayer) {
|
||||
|
@ -43,6 +43,7 @@ public class SimulatedPlayerMCTS extends MCTSPlayer {
|
|||
public SimulatedPlayerMCTS(final SimulatedPlayerMCTS player) {
|
||||
super(player);
|
||||
this.isSimulatedPlayer = player.isSimulatedPlayer;
|
||||
this.actionCount = player.actionCount;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -40,8 +40,8 @@ public class ComputerPlayer2 extends ComputerPlayer implements Player {
|
|||
protected int maxDepth;
|
||||
protected int maxNodes;
|
||||
protected int maxThink;
|
||||
protected int nodeCount = 0;
|
||||
protected long thinkTime = 0;
|
||||
protected int nodeCount;
|
||||
protected long thinkTime;
|
||||
protected transient LinkedList<Ability> actions = new LinkedList<>();
|
||||
protected transient List<UUID> targets = 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) {
|
||||
super(player);
|
||||
this.maxDepth = player.maxDepth;
|
||||
this.maxNodes = player.maxNodes;
|
||||
this.maxThink = player.maxThink;
|
||||
this.nodeCount = player.nodeCount;
|
||||
this.thinkTime = player.thinkTime;
|
||||
this.currentScore = player.currentScore;
|
||||
if (player.combat != null) {
|
||||
this.combat = player.combat.copy();
|
||||
|
|
|
@ -28,9 +28,9 @@ import java.util.concurrent.ConcurrentLinkedQueue;
|
|||
public class SimulatedPlayer extends ComputerPlayer {
|
||||
|
||||
private static final Logger logger = Logger.getLogger(SimulatedPlayer.class);
|
||||
private boolean isSimulatedPlayer;
|
||||
private final boolean isSimulatedPlayer;
|
||||
private transient ConcurrentLinkedQueue<Ability> allActions;
|
||||
private static PassAbility pass = new PassAbility();
|
||||
private static final PassAbility pass = new PassAbility();
|
||||
protected int maxDepth;
|
||||
|
||||
public SimulatedPlayer(Player originalPlayer, boolean isSimulatedPlayer, int maxDepth) {
|
||||
|
@ -44,6 +44,7 @@ public class SimulatedPlayer extends ComputerPlayer {
|
|||
public SimulatedPlayer(final SimulatedPlayer player) {
|
||||
super(player);
|
||||
this.isSimulatedPlayer = player.isSimulatedPlayer;
|
||||
this.maxDepth = player.maxDepth;
|
||||
}
|
||||
|
||||
@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";
|
||||
}
|
||||
|
||||
public CaromEffect(final CaromEffect effect) {
|
||||
private CaromEffect(final CaromEffect effect) {
|
||||
super(effect);
|
||||
this.redirectToObject = effect.redirectToObject;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -30,7 +30,8 @@ public final class DesecratorHag extends CardImpl {
|
|||
this.power = 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));
|
||||
|
||||
}
|
||||
|
@ -47,17 +48,21 @@ public final class DesecratorHag extends CardImpl {
|
|||
|
||||
class DesecratorHagEffect extends OneShotEffect {
|
||||
|
||||
int creatureGreatestPower = 0;
|
||||
int creatureGreatestPower;
|
||||
Cards cards = new CardsImpl();
|
||||
TargetCard target = new TargetCard(Zone.GRAVEYARD, new FilterCard());
|
||||
|
||||
public DesecratorHagEffect() {
|
||||
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) {
|
||||
super(effect);
|
||||
this.creatureGreatestPower = effect.creatureGreatestPower;
|
||||
this.cards = effect.cards.copy();
|
||||
this.target = effect.target.copy();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -68,35 +73,40 @@ class DesecratorHagEffect extends OneShotEffect {
|
|||
@Override
|
||||
public boolean apply(Game game, Ability source) {
|
||||
Player you = game.getPlayer(source.getControllerId());
|
||||
if (you != null) {
|
||||
for (Card card : you.getGraveyard().getCards(game)) {
|
||||
if (card.isCreature(game)) {
|
||||
if (card.getPower().getValue() > creatureGreatestPower) {
|
||||
creatureGreatestPower = card.getPower().getValue();
|
||||
cards.clear();
|
||||
if (you == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (Card card : you.getGraveyard().getCards(game)) {
|
||||
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);
|
||||
} 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) {
|
||||
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());
|
||||
}
|
||||
|
||||
|
@ -54,13 +56,16 @@ class DesperateGambitEffect extends PreventionEffectImpl {
|
|||
|
||||
public DesperateGambitEffect() {
|
||||
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();
|
||||
}
|
||||
|
||||
public DesperateGambitEffect(final DesperateGambitEffect effect) {
|
||||
super(effect);
|
||||
this.target = effect.target.copy();
|
||||
this.wonFlip = effect.wonFlip;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -80,7 +80,7 @@ class DoublingSeasonTokenEffect 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() {
|
||||
super(Duration.WhileOnBattlefield, Outcome.BoostCreature, false);
|
||||
|
@ -89,6 +89,7 @@ class DoublingSeasonCounterEffect extends ReplacementEffectImpl {
|
|||
|
||||
private DoublingSeasonCounterEffect(final DoublingSeasonCounterEffect effect) {
|
||||
super(effect);
|
||||
this.landPlayed = effect.landPlayed;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -110,8 +111,7 @@ class DoublingSeasonCounterEffect extends ReplacementEffectImpl {
|
|||
}
|
||||
if (permanent == null) {
|
||||
permanent = game.getPermanentEntering(event.getTargetId());
|
||||
landPlayed = (permanent != null
|
||||
&& permanent.isLand(game)); // a played land is not an effect
|
||||
landPlayed = (permanent != null && permanent.isLand(game)); // a played land is not an effect
|
||||
}
|
||||
return permanent != null
|
||||
&& permanent.isControlledBy(source.getControllerId())
|
||||
|
|
|
@ -8,6 +8,7 @@ import mage.abilities.common.SimpleActivatedAbility;
|
|||
import mage.abilities.common.SimpleStaticAbility;
|
||||
import mage.abilities.common.delayed.AtTheEndOfCombatDelayedTriggeredAbility;
|
||||
import mage.abilities.condition.Condition;
|
||||
import mage.abilities.costs.mana.GenericManaCost;
|
||||
import mage.abilities.costs.mana.ManaCostsImpl;
|
||||
import mage.abilities.decorator.ConditionalContinuousRuleModifyingEffect;
|
||||
import mage.abilities.effects.ContinuousEffect;
|
||||
|
@ -101,7 +102,7 @@ class DreadWightTriggeredAbility extends TriggeredAbilityImpl {
|
|||
|
||||
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() {
|
||||
super(Outcome.Detriment);
|
||||
|
@ -122,44 +123,42 @@ class DreadWightEffect extends OneShotEffect {
|
|||
@Override
|
||||
public boolean apply(Game game, Ability source) {
|
||||
Permanent permanent = game.getPermanent(targetPointer.getFirst(game, source));
|
||||
if (permanent != null) {
|
||||
// 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("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;
|
||||
if (permanent == null) {
|
||||
return false;
|
||||
}
|
||||
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 {
|
||||
|
||||
private Cards cards;
|
||||
private Player player;
|
||||
|
||||
public DubiousChallengeMoveToBattlefieldEffect() {
|
||||
super(Outcome.Benefit);
|
||||
}
|
||||
|
||||
public DubiousChallengeMoveToBattlefieldEffect(final DubiousChallengeMoveToBattlefieldEffect effect) {
|
||||
super(effect);
|
||||
if (effect.cards != null) {
|
||||
this.cards = effect.cards.copy();
|
||||
}
|
||||
if (effect.player != null) {
|
||||
this.player = effect.player.copy();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -117,12 +126,10 @@ class DubiousChallengeMoveToBattlefieldEffect extends OneShotEffect {
|
|||
|
||||
@Override
|
||||
public boolean apply(Game game, Ability source) {
|
||||
if (cards != null && player != null) {
|
||||
return player.moveCards(cards, Zone.BATTLEFIELD, source, game);
|
||||
if (cards == null || player == null) {
|
||||
return false;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private Cards cards;
|
||||
private Player player;
|
||||
return player.moveCards(cards, Zone.BATTLEFIELD, source, game);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -61,17 +61,21 @@ class ElkinBottleExileEffect extends OneShotEffect {
|
|||
@Override
|
||||
public boolean apply(Game game, Ability source) {
|
||||
Player controller = game.getPlayer(source.getControllerId());
|
||||
if (controller != null) {
|
||||
Card card = controller.getLibrary().getFromTop(game);
|
||||
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;
|
||||
if (controller == null) {
|
||||
return false;
|
||||
}
|
||||
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) {
|
||||
super(effect);
|
||||
this.sameStep = effect.sameStep;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -96,9 +101,9 @@ class ElkinBottleCastFromExileEffect extends AsThoughEffectImpl {
|
|||
@Override
|
||||
public boolean isInactive(Ability source, Game game) {
|
||||
if (game.getPhase().getStep().getType() == PhaseStep.UPKEEP) {
|
||||
if (!sameStep && game.isActivePlayer(source.getControllerId()) || game.getPlayer(source.getControllerId()).hasReachedNextTurnAfterLeaving()) {
|
||||
return true;
|
||||
}
|
||||
return !sameStep
|
||||
&& game.isActivePlayer(source.getControllerId())
|
||||
|| game.getPlayer(source.getControllerId()).hasReachedNextTurnAfterLeaving();
|
||||
} else {
|
||||
sameStep = false;
|
||||
}
|
||||
|
|
|
@ -34,7 +34,9 @@ public final class FoodChain extends CardImpl {
|
|||
public FoodChain(UUID ownerId, CardSetInfo setInfo) {
|
||||
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(),
|
||||
new ExileTargetCost(new TargetControlledCreaturePermanent(1, 1, StaticFilters.FILTER_CONTROLLED_A_CREATURE, true)));
|
||||
this.addAbility(ability);
|
||||
|
@ -68,11 +70,13 @@ class FoodChainManaEffect extends ManaEffect {
|
|||
ConditionalManaBuilder manaBuilder = new FoodChainManaBuilder();
|
||||
|
||||
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) {
|
||||
super(effect);
|
||||
this.manaBuilder = effect.manaBuilder;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -83,21 +87,25 @@ class FoodChainManaEffect extends ManaEffect {
|
|||
@Override
|
||||
public List<Mana> getNetMana(Game game, Ability source) {
|
||||
List<Mana> netMana = new ArrayList<>();
|
||||
if (game != null) {
|
||||
int cmc = -1;
|
||||
for (Permanent permanent : game.getBattlefield().getAllActivePermanents(source.getControllerId())) {
|
||||
if (permanent.isCreature(game)) {
|
||||
cmc = Math.max(cmc, permanent.getManaCost().manaValue());
|
||||
}
|
||||
}
|
||||
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());
|
||||
if (game == null) {
|
||||
return netMana;
|
||||
}
|
||||
|
||||
int cmc = -1;
|
||||
for (Permanent permanent : game.getBattlefield().getAllActivePermanents(source.getControllerId())) {
|
||||
if (permanent.isCreature(game)) {
|
||||
cmc = Math.max(cmc, permanent.getManaCost().manaValue());
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
|
@ -107,24 +115,27 @@ class FoodChainManaEffect extends ManaEffect {
|
|||
if (game == null) {
|
||||
return mana;
|
||||
}
|
||||
|
||||
Player controller = game.getPlayer(source.getControllerId());
|
||||
if (controller != null) {
|
||||
int manaCostExiled = 0;
|
||||
for (Cost cost : source.getCosts()) {
|
||||
if (cost.isPaid() && cost instanceof ExileTargetCost) {
|
||||
for (Card card : ((ExileTargetCost) cost).getPermanents()) {
|
||||
manaCostExiled += card.getManaValue();
|
||||
}
|
||||
if (controller == null) {
|
||||
return mana;
|
||||
}
|
||||
|
||||
int manaCostExiled = 0;
|
||||
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 {
|
||||
|
||||
int xAmount = 0;
|
||||
int xAmount;
|
||||
|
||||
public FrayingSanityEffect() {
|
||||
super(Outcome.Detriment);
|
||||
|
@ -95,6 +95,7 @@ class FrayingSanityEffect extends OneShotEffect {
|
|||
|
||||
public FrayingSanityEffect(final FrayingSanityEffect effect) {
|
||||
super(effect);
|
||||
this.xAmount = effect.xAmount;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -33,7 +33,8 @@ public final class GabrielAngelfire extends CardImpl {
|
|||
this.power = 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));
|
||||
}
|
||||
|
||||
|
@ -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";
|
||||
}
|
||||
|
||||
public GabrielAngelfireGainAbilityEffect(final GabrielAngelfireGainAbilityEffect effect) {
|
||||
private GabrielAngelfireGainAbilityEffect(final GabrielAngelfireGainAbilityEffect effect) {
|
||||
super(effect);
|
||||
ability.newId();
|
||||
this.sameStep = effect.sameStep;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -77,9 +79,7 @@ class GabrielAngelfireGainAbilityEffect extends GainAbilitySourceEffect {
|
|||
@Override
|
||||
public boolean isInactive(Ability source, Game game) {
|
||||
if (game.getPhase().getStep().getType() == PhaseStep.UPKEEP) {
|
||||
if (!sameStep && game.isActivePlayer(source.getControllerId()) || game.getPlayer(source.getControllerId()).hasReachedNextTurnAfterLeaving()) {
|
||||
return true;
|
||||
}
|
||||
return !sameStep && game.isActivePlayer(source.getControllerId()) || game.getPlayer(source.getControllerId()).hasReachedNextTurnAfterLeaving();
|
||||
} else {
|
||||
sameStep = false;
|
||||
}
|
||||
|
@ -89,29 +89,32 @@ class GabrielAngelfireGainAbilityEffect extends GainAbilitySourceEffect {
|
|||
@Override
|
||||
public void init(Ability source, Game game) {
|
||||
super.init(source, game);
|
||||
|
||||
Player controller = game.getPlayer(source.getControllerId());
|
||||
if (controller != null) {
|
||||
Choice choice = new ChoiceImpl(true);
|
||||
choice.setMessage("Choose one");
|
||||
choice.setChoices(choices);
|
||||
if (controller.choose(outcome, choice, game)) {
|
||||
switch (choice.getChoice()) {
|
||||
case "First strike":
|
||||
ability = FirstStrikeAbility.getInstance();
|
||||
break;
|
||||
case "Trample":
|
||||
ability = TrampleAbility.getInstance();
|
||||
break;
|
||||
case "Rampage 3":
|
||||
ability = new RampageAbility(3);
|
||||
break;
|
||||
default:
|
||||
ability = FlyingAbility.getInstance();
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
discard();
|
||||
if (controller == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
Choice choice = new ChoiceImpl(true);
|
||||
choice.setMessage("Choose one");
|
||||
choice.setChoices(choices);
|
||||
if (controller.choose(outcome, choice, game)) {
|
||||
switch (choice.getChoice()) {
|
||||
case "First strike":
|
||||
ability = FirstStrikeAbility.getInstance();
|
||||
break;
|
||||
case "Trample":
|
||||
ability = TrampleAbility.getInstance();
|
||||
break;
|
||||
case "Rampage 3":
|
||||
ability = new RampageAbility(3);
|
||||
break;
|
||||
default:
|
||||
ability = FlyingAbility.getInstance();
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
discard();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -50,11 +50,10 @@ public final class GloomwidowsFeast extends CardImpl {
|
|||
|
||||
class GloomwidowsFeastEffect extends OneShotEffect {
|
||||
|
||||
boolean applied = false;
|
||||
|
||||
public GloomwidowsFeastEffect() {
|
||||
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) {
|
||||
|
@ -69,15 +68,20 @@ class GloomwidowsFeastEffect extends OneShotEffect {
|
|||
@Override
|
||||
public boolean apply(Game game, Ability source) {
|
||||
Permanent targetCreature = game.getPermanent(source.getFirstTarget());
|
||||
if (targetCreature != null) {
|
||||
targetCreature.destroy(source, game, false);
|
||||
Permanent destroyedCreature = getTargetPointer().getFirstTargetPermanentOrLKI(game, source);
|
||||
if (destroyedCreature.getColor(game).isBlue()
|
||||
|| destroyedCreature.getColor(game).isBlack()) {
|
||||
SpiderToken token = new SpiderToken();
|
||||
token.putOntoBattlefield(1, game, source, source.getControllerId());
|
||||
return true;
|
||||
}
|
||||
if (targetCreature == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
targetCreature.destroy(source, game, false);
|
||||
Permanent destroyedCreature = getTargetPointer().getFirstTargetPermanentOrLKI(game, source);
|
||||
if (destroyedCreature == null) {
|
||||
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;
|
||||
}
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
package mage.cards.g;
|
||||
|
||||
import javafx.event.EventType;
|
||||
import mage.MageInt;
|
||||
import mage.MageObject;
|
||||
import mage.abilities.Ability;
|
||||
|
@ -55,6 +56,7 @@ class GoblinPsychopathEffect extends ReplacementEffectImpl {
|
|||
|
||||
public GoblinPsychopathEffect(final GoblinPsychopathEffect effect) {
|
||||
super(effect);
|
||||
this.wonFlip = effect.wonFlip;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -88,10 +90,14 @@ class GoblinPsychopathEffect extends ReplacementEffectImpl {
|
|||
public boolean replaceEvent(GameEvent event, Ability source, Game game) {
|
||||
MageObject object = game.getObject(event.getSourceId());
|
||||
Player controller = game.getPlayer(source.getControllerId());
|
||||
if (controller == null || object == null
|
||||
|| !(this.applies(event, source, game) && event instanceof DamageEvent && event.getAmount() > 0)) {
|
||||
if (object == null || controller == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!(this.applies(event, source, game) && event instanceof DamageEvent && event.getAmount() > 0)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
DamageEvent damageEvent = (DamageEvent) event;
|
||||
if (!damageEvent.isCombatDamage() || wonFlip) {
|
||||
return false;
|
||||
|
|
|
@ -61,7 +61,7 @@ public final class Godsend extends CardImpl {
|
|||
|
||||
class GodsendTriggeredAbility extends TriggeredAbilityImpl {
|
||||
|
||||
private Set<UUID> possibleTargets = new HashSet<>();
|
||||
private final Set<UUID> possibleTargets = new HashSet<>();
|
||||
|
||||
GodsendTriggeredAbility() {
|
||||
super(Zone.BATTLEFIELD, new GodsendExileEffect(), true);
|
||||
|
@ -69,6 +69,7 @@ class GodsendTriggeredAbility extends TriggeredAbilityImpl {
|
|||
|
||||
GodsendTriggeredAbility(final GodsendTriggeredAbility ability) {
|
||||
super(ability);
|
||||
this.possibleTargets.addAll(ability.possibleTargets);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -153,13 +154,19 @@ class GodsendExileEffect extends OneShotEffect {
|
|||
Permanent creature = game.getPermanent(this.getTargetPointer().getFirst(game, source));
|
||||
Player controller = game.getPlayer(source.getControllerId());
|
||||
Permanent sourcePermanent = game.getPermanentOrLKIBattlefield(source.getSourceId());
|
||||
if (creature != null && controller != null && sourcePermanent != null) {
|
||||
UUID exileId = CardUtil.getCardExileZoneId(game, source);
|
||||
controller.moveCardToExileWithInfo(creature, exileId,
|
||||
sourcePermanent.getIdName() + " (" + sourcePermanent.getZoneChangeCounter(game) + ')', source, game, Zone.BATTLEFIELD, true);
|
||||
|
||||
if (creature == null || controller == null || sourcePermanent == null) {
|
||||
return false;
|
||||
}
|
||||
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
|
||||
public boolean applies(GameEvent event, Ability source, Game game) {
|
||||
if (event.getType() == GameEvent.EventType.CAST_SPELL && game.getOpponents(source.getControllerId()).contains(event.getPlayerId())) {
|
||||
MageObject object = game.getObject(event.getSourceId());
|
||||
if (object != null) {
|
||||
ExileZone exileZone = game.getExile().getExileZone(CardUtil.getCardExileZoneId(game, source));
|
||||
if ((exileZone != null)) {
|
||||
for (Card card : exileZone.getCards(game)) {
|
||||
if ((card.getName().equals(object.getName()))) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (event.getType() != GameEvent.EventType.CAST_SPELL) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!game.getOpponents(source.getControllerId()).contains(event.getPlayerId())) {
|
||||
return false;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -102,6 +102,7 @@ class GrinningTotemMayPlayEffect extends AsThoughEffectImpl {
|
|||
|
||||
public GrinningTotemMayPlayEffect(final GrinningTotemMayPlayEffect effect) {
|
||||
super(effect);
|
||||
this.sameStep = effect.sameStep;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -112,9 +113,7 @@ class GrinningTotemMayPlayEffect extends AsThoughEffectImpl {
|
|||
@Override
|
||||
public boolean isInactive(Ability source, Game game) {
|
||||
if (game.getPhase().getStep().getType() == PhaseStep.UPKEEP) {
|
||||
if (!sameStep && game.isActivePlayer(source.getControllerId()) || game.getPlayer(source.getControllerId()).hasReachedNextTurnAfterLeaving()) {
|
||||
return true;
|
||||
}
|
||||
return !sameStep && game.isActivePlayer(source.getControllerId()) || game.getPlayer(source.getControllerId()).hasReachedNextTurnAfterLeaving();
|
||||
} else {
|
||||
sameStep = false;
|
||||
}
|
||||
|
@ -198,10 +197,10 @@ class GrinningTotemPutIntoGraveyardEffect extends OneShotEffect {
|
|||
public boolean apply(Game game, Ability source) {
|
||||
Player controller = game.getPlayer(source.getControllerId());
|
||||
ExileZone zone = game.getExile().getExileZone(exileZoneId);
|
||||
if (controller != null && zone != null) {
|
||||
return controller.moveCards(zone, Zone.GRAVEYARD, source, game);
|
||||
if (controller == null || zone == null) {
|
||||
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.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.
|
||||
Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new GuardDogsEffect(), new ManaCostsImpl("{2}{W}"));
|
||||
// {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.
|
||||
Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new GuardDogsEffect(), new ManaCostsImpl<>("{2}{W}"));
|
||||
ability.addCost(new TapSourceCost());
|
||||
ability.addTarget(new TargetCreaturePermanent());
|
||||
this.addAbility(ability);
|
||||
|
@ -57,13 +58,14 @@ class GuardDogsEffect extends PreventionEffectImpl {
|
|||
|
||||
public GuardDogsEffect() {
|
||||
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);
|
||||
this.controlledTarget = effect.controlledTarget.copy();
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
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);
|
||||
super.init(source, game);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public GuardDogsEffect copy() {
|
||||
|
@ -81,20 +82,21 @@ class GuardDogsEffect extends PreventionEffectImpl {
|
|||
|
||||
@Override
|
||||
public boolean applies(GameEvent event, Ability source, Game game) {
|
||||
if (!this.used && super.applies(event, source, game)) {
|
||||
MageObject mageObject = game.getObject(event.getSourceId());
|
||||
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;
|
||||
}
|
||||
}
|
||||
if (this.used || !super.applies(event, source, game)) {
|
||||
return false;
|
||||
}
|
||||
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);
|
||||
|
||||
// {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());
|
||||
TargetCardInHand targetCard = new TargetCardInHand(new FilterCard("a card"));
|
||||
ability.addCost(new HisokaMinamoSenseiDiscardTargetCost(targetCard));
|
||||
|
@ -60,7 +60,7 @@ public final class HisokaMinamoSensei extends CardImpl {
|
|||
|
||||
class HisokaMinamoSenseiDiscardTargetCost extends CostImpl {
|
||||
|
||||
protected Card card = null;
|
||||
protected Card card;
|
||||
|
||||
public HisokaMinamoSenseiDiscardTargetCost(TargetCardInHand target) {
|
||||
this.addTarget(target);
|
||||
|
@ -69,23 +69,27 @@ class HisokaMinamoSenseiDiscardTargetCost extends CostImpl {
|
|||
|
||||
public HisokaMinamoSenseiDiscardTargetCost(HisokaMinamoSenseiDiscardTargetCost cost) {
|
||||
super(cost);
|
||||
this.card = cost.card.copy();
|
||||
}
|
||||
|
||||
@Override
|
||||
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)) {
|
||||
Player player = game.getPlayer(controllerId);
|
||||
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);
|
||||
if (!targets.choose(Outcome.Discard, controllerId, source.getSourceId(), source, game)) {
|
||||
return paid;
|
||||
}
|
||||
|
||||
}
|
||||
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;
|
||||
}
|
||||
|
||||
|
@ -106,24 +110,32 @@ class HisokaMinamoSenseiDiscardTargetCost extends CostImpl {
|
|||
}
|
||||
|
||||
class HisokaMinamoSenseiCounterEffect extends OneShotEffect {
|
||||
|
||||
HisokaMinamoSenseiCounterEffect() {
|
||||
super(Outcome.Detriment);
|
||||
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);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean apply(Game game, Ability source) {
|
||||
Spell spell = game.getStack().getSpell(targetPointer.getFirst(game, source));
|
||||
if (spell != null) {
|
||||
HisokaMinamoSenseiDiscardTargetCost cost = (HisokaMinamoSenseiDiscardTargetCost) source.getCosts().get(0);
|
||||
if (cost != null && cost.getDiscardedCard().getManaValue() == spell.getManaValue()) {
|
||||
return game.getStack().counter(targetPointer.getFirst(game, source), source, game);
|
||||
}
|
||||
if (spell == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
|
|
|
@ -39,9 +39,10 @@ public final class IllusionaryPresence extends CardImpl {
|
|||
this.toughness = new MageInt(2);
|
||||
|
||||
// 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.addEffect(new IllusionaryPresenceEffect());
|
||||
this.addAbility(ability);
|
||||
|
@ -60,8 +61,6 @@ public final class IllusionaryPresence extends CardImpl {
|
|||
|
||||
class IllusionaryPresenceEffect extends OneShotEffect {
|
||||
|
||||
Ability gainedAbility;
|
||||
|
||||
public IllusionaryPresenceEffect() {
|
||||
super(Outcome.Benefit);
|
||||
this.staticText = "{this} gains landwalk of the chosen type until end of turn";
|
||||
|
@ -79,33 +78,38 @@ class IllusionaryPresenceEffect extends OneShotEffect {
|
|||
@Override
|
||||
public boolean apply(Game game, Ability source) {
|
||||
MageObject mageObject = game.getObject(source);
|
||||
if (mageObject != null) {
|
||||
SubType landTypeChoice = SubType.byDescription((String) game.getState().getValue(mageObject.getId().toString() + "BasicLandType"));
|
||||
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;
|
||||
}
|
||||
}
|
||||
if (mageObject == null) {
|
||||
return false;
|
||||
}
|
||||
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";
|
||||
}
|
||||
|
||||
public ChooseTwoBasicLandTypesEffect(final ChooseTwoBasicLandTypesEffect effect) {
|
||||
private ChooseTwoBasicLandTypesEffect(final ChooseTwoBasicLandTypesEffect effect) {
|
||||
super(effect);
|
||||
this.choiceOne = effect.choiceOne;
|
||||
this.choiceTwo = effect.choiceTwo;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -33,7 +33,9 @@ public final class ImminentDoom extends CardImpl {
|
|||
// 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"));
|
||||
|
||||
// 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.addTarget(new TargetAnyTarget());
|
||||
this.addAbility(ability);
|
||||
|
@ -52,7 +54,8 @@ public final class ImminentDoom extends CardImpl {
|
|||
|
||||
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() {
|
||||
super(Zone.BATTLEFIELD, new ImminentDoomEffect());
|
||||
|
@ -74,16 +77,24 @@ class ImminentDoomTriggeredAbility extends TriggeredAbilityImpl {
|
|||
|
||||
@Override
|
||||
public boolean checkTrigger(GameEvent event, Game game) {
|
||||
if (event.getPlayerId().equals(this.getControllerId())) {
|
||||
Permanent imminentDoom = game.getPermanent(getSourceId());
|
||||
Spell spell = game.getStack().getSpell(event.getTargetId());
|
||||
if (spell != null
|
||||
&& imminentDoom != null
|
||||
&& spell.getManaValue() == imminentDoom.getCounters(game).getCount(CounterType.DOOM)) {
|
||||
game.getState().setValue("ImminentDoomCount" + getSourceId().toString(), imminentDoom.getCounters(game).getCount(CounterType.DOOM)); // store its current value
|
||||
return true;
|
||||
}
|
||||
}
|
||||
if (!event.getPlayerId().equals(this.getControllerId())) {
|
||||
return false;
|
||||
}
|
||||
|
||||
Permanent imminentDoom = game.getPermanent(getSourceId());
|
||||
Spell spell = game.getStack().getSpell(event.getTargetId());
|
||||
if (imminentDoom == null || spell == null) {
|
||||
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;
|
||||
}
|
||||
|
||||
|
@ -111,13 +122,13 @@ class ImminentDoomEffect extends OneShotEffect {
|
|||
@Override
|
||||
public boolean apply(Game game, Ability source) {
|
||||
Permanent imminentDoom = game.getPermanent(source.getSourceId());
|
||||
if (imminentDoom != null) {
|
||||
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;
|
||||
if (imminentDoom == null) {
|
||||
return false;
|
||||
}
|
||||
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() {
|
||||
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) {
|
||||
super(effect);
|
||||
this.wonFlip = effect.wonFlip;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -86,21 +89,25 @@ class ImpulsiveManeuversEffect extends PreventionEffectImpl {
|
|||
public boolean replaceEvent(GameEvent event, Ability source, Game game) {
|
||||
MageObject object = game.getObject(event.getSourceId());
|
||||
Player controller = game.getPlayer(source.getControllerId());
|
||||
if (controller != null && object != null) {
|
||||
if (super.applies(event, source, game) && event instanceof DamageEvent && event.getAmount() > 0) {
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (controller == null || object == null) {
|
||||
return false;
|
||||
}
|
||||
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 {
|
||||
|
||||
private boolean inManaTypeCalculation = false;
|
||||
private boolean inManaTypeCalculation;
|
||||
|
||||
AnyColorLandsProduceManaEffect() {
|
||||
super();
|
||||
|
@ -70,6 +70,7 @@ class AnyColorLandsProduceManaEffect extends ManaEffect {
|
|||
|
||||
private AnyColorLandsProduceManaEffect(final AnyColorLandsProduceManaEffect effect) {
|
||||
super(effect);
|
||||
this.inManaTypeCalculation = effect.inManaTypeCalculation;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -17,7 +17,6 @@ import mage.constants.CardType;
|
|||
import mage.constants.SuperType;
|
||||
import mage.constants.Zone;
|
||||
import mage.filter.StaticFilters;
|
||||
import mage.filter.common.FilterArtifactPermanent;
|
||||
import mage.game.Game;
|
||||
import mage.game.events.GameEvent;
|
||||
import mage.target.common.TargetCardInLibrary;
|
||||
|
@ -39,8 +38,9 @@ public final class InventorsFair extends CardImpl {
|
|||
// {t}: Add {C}.
|
||||
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.
|
||||
// Activate this ability only if you control threeor more artifacts.
|
||||
// {4}, {T}, Sacrifice Inventors' Fair: Search your library for an artifact card, reveal it,
|
||||
// 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),
|
||||
new GenericManaCost(4), MetalcraftCondition.instance);
|
||||
ability.addCost(new TapSourceCost());
|
||||
|
@ -61,8 +61,6 @@ public final class InventorsFair extends CardImpl {
|
|||
|
||||
class InventorsFairAbility extends TriggeredAbilityImpl {
|
||||
|
||||
private FilterArtifactPermanent filter = new FilterArtifactPermanent();
|
||||
|
||||
public InventorsFairAbility() {
|
||||
super(Zone.BATTLEFIELD, new GainLifeEffect(1));
|
||||
}
|
||||
|
@ -88,7 +86,7 @@ class InventorsFairAbility extends TriggeredAbilityImpl {
|
|||
|
||||
@Override
|
||||
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
|
||||
|
|
|
@ -8,7 +8,7 @@ import mage.MageInt;
|
|||
import mage.ObjectColor;
|
||||
import mage.abilities.Ability;
|
||||
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.common.continuous.GainAbilitySourceEffect;
|
||||
import mage.abilities.keyword.DoubleStrikeAbility;
|
||||
|
@ -38,7 +38,7 @@ public final class JodahsAvenger extends CardImpl {
|
|||
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.
|
||||
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) {
|
||||
|
@ -70,6 +70,7 @@ class JodahsAvengerEffect extends ContinuousEffectImpl {
|
|||
|
||||
public JodahsAvengerEffect(final JodahsAvengerEffect effect) {
|
||||
super(effect);
|
||||
this.gainedAbility = effect.gainedAbility.copy();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -80,41 +81,46 @@ class JodahsAvengerEffect extends ContinuousEffectImpl {
|
|||
@Override
|
||||
public void init(Ability source, Game game) {
|
||||
super.init(source, game);
|
||||
|
||||
Player controller = game.getPlayer(source.getControllerId());
|
||||
if (controller != null) {
|
||||
Choice choice = new ChoiceImpl(true);
|
||||
choice.setMessage("Choose one");
|
||||
choice.setChoices(choices);
|
||||
if (controller.choose(outcome, choice, game)) {
|
||||
switch (choice.getChoice()) {
|
||||
case "Double strike":
|
||||
gainedAbility = DoubleStrikeAbility.getInstance();
|
||||
break;
|
||||
case "Vigilance":
|
||||
gainedAbility = VigilanceAbility.getInstance();
|
||||
break;
|
||||
case "Shadow":
|
||||
gainedAbility = ShadowAbility.getInstance();
|
||||
break;
|
||||
default:
|
||||
gainedAbility = ProtectionAbility.from(ObjectColor.RED);
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
discard();
|
||||
if (controller == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
Choice choice = new ChoiceImpl(true);
|
||||
choice.setMessage("Choose one");
|
||||
choice.setChoices(choices);
|
||||
if (controller.choose(outcome, choice, game)) {
|
||||
switch (choice.getChoice()) {
|
||||
case "Double strike":
|
||||
gainedAbility = DoubleStrikeAbility.getInstance();
|
||||
break;
|
||||
case "Vigilance":
|
||||
gainedAbility = VigilanceAbility.getInstance();
|
||||
break;
|
||||
case "Shadow":
|
||||
gainedAbility = ShadowAbility.getInstance();
|
||||
break;
|
||||
default:
|
||||
gainedAbility = ProtectionAbility.from(ObjectColor.RED);
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
discard();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean apply(Game game, Ability source) {
|
||||
Permanent sourceObject = game.getPermanent(source.getSourceId());
|
||||
if (sourceObject != null) {
|
||||
sourceObject.addPower(-1);
|
||||
sourceObject.addToughness(-1);
|
||||
game.addEffect(new GainAbilitySourceEffect(gainedAbility, Duration.EndOfTurn), source);
|
||||
return true;
|
||||
if (sourceObject == null) {
|
||||
return false;
|
||||
}
|
||||
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);
|
||||
this.power = effect.power;
|
||||
this.toughness = effect.toughness;
|
||||
this.paired = effect.paired;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -66,12 +67,11 @@ class JointAssaultBoostTargetEffect extends ContinuousEffectImpl {
|
|||
@Override
|
||||
public void init(Ability source, Game game) {
|
||||
super.init(source, game);
|
||||
|
||||
UUID permanentId = targetPointer.getFirst(game, source);
|
||||
Permanent target = game.getPermanent(permanentId);
|
||||
if (target != null) {
|
||||
if (target.getPairedCard() != null) {
|
||||
this.paired = target.getPairedCard();
|
||||
}
|
||||
if (target != null && target.getPairedCard() != null) {
|
||||
this.paired = target.getPairedCard();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -46,7 +46,8 @@ public final class KarnLiberated extends CardImpl {
|
|||
ability2.addTarget(new TargetPermanent());
|
||||
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));
|
||||
}
|
||||
|
||||
|
@ -62,11 +63,10 @@ public final class KarnLiberated extends CardImpl {
|
|||
|
||||
class KarnLiberatedEffect extends OneShotEffect {
|
||||
|
||||
private UUID exileId;
|
||||
|
||||
public KarnLiberatedEffect() {
|
||||
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) {
|
||||
|
@ -75,6 +75,7 @@ class KarnLiberatedEffect extends OneShotEffect {
|
|||
|
||||
@Override
|
||||
public boolean apply(Game game, Ability source) {
|
||||
UUID exileId = null;
|
||||
MageObject sourceObject = source.getSourceObject(game);
|
||||
if (sourceObject == null) {
|
||||
return false;
|
||||
|
@ -84,8 +85,7 @@ class KarnLiberatedEffect extends OneShotEffect {
|
|||
exileId = CardUtil.getExileZoneId(game, source.getSourceId(), source.getSourceObjectZoneChangeCounter());
|
||||
if (zone.getId().equals(exileId)) {
|
||||
for (Card card : zone.getCards(game)) {
|
||||
if (!card.hasSubtype(SubType.AURA, game)
|
||||
&& card.isPermanent(game)) {
|
||||
if (!card.hasSubtype(SubType.AURA, game) && card.isPermanent(game)) {
|
||||
cards.add(card);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -59,8 +59,6 @@ public final class KrovikanVampire extends CardImpl {
|
|||
|
||||
class KrovikanVampireEffect extends OneShotEffect {
|
||||
|
||||
Set<UUID> creaturesAffected = new HashSet<>();
|
||||
|
||||
KrovikanVampireEffect() {
|
||||
super(Outcome.Neutral);
|
||||
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) {
|
||||
Player controller = game.getPlayer(source.getControllerId());
|
||||
Permanent krovikanVampire = game.getPermanent(source.getSourceId());
|
||||
creaturesAffected = (Set<UUID>) game.getState().getValue(source.getSourceId() + "creatureToGainControl");
|
||||
if (creaturesAffected != null
|
||||
&& controller != null
|
||||
&& 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;
|
||||
Set<UUID> creaturesAffected = (Set<UUID>) game.getState().getValue(source.getSourceId() + "creatureToGainControl");
|
||||
if (creaturesAffected == null || controller == null || krovikanVampire == null) {
|
||||
return false;
|
||||
}
|
||||
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
|
||||
|
@ -109,21 +106,24 @@ class KrovikanVampireInterveningIfCondition implements Condition {
|
|||
public boolean apply(Game game, Ability source) {
|
||||
KrovikanVampireCreaturesDiedWatcher watcherDied = game.getState().getWatcher(KrovikanVampireCreaturesDiedWatcher.class);
|
||||
KrovikanVampireCreaturesDamagedWatcher watcherDamaged = game.getState().getWatcher(KrovikanVampireCreaturesDamagedWatcher.class);
|
||||
if (watcherDied != null) {
|
||||
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.size() > 0) {
|
||||
game.getState().setValue(source.getSourceId() + "creatureToGainControl", creaturesAffected);
|
||||
return true;
|
||||
}
|
||||
if (watcherDied == null) {
|
||||
return false;
|
||||
}
|
||||
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
|
||||
|
@ -142,14 +142,15 @@ class KrovikanVampireCreaturesDamagedWatcher extends Watcher {
|
|||
|
||||
@Override
|
||||
public void watch(GameEvent event, Game game) {
|
||||
if (event.getType() != GameEvent.EventType.DAMAGED_PERMANENT
|
||||
|| !sourceId.equals(event.getSourceId())) {
|
||||
if (event.getType() != GameEvent.EventType.DAMAGED_PERMANENT || !sourceId.equals(event.getSourceId())) {
|
||||
return;
|
||||
}
|
||||
|
||||
Permanent permanent = game.getPermanent(event.getTargetId());
|
||||
if (permanent == null || !permanent.isCreature(game)) {
|
||||
return;
|
||||
}
|
||||
|
||||
damagedBySource.add(event.getTargetId());
|
||||
}
|
||||
|
||||
|
@ -215,14 +216,10 @@ class KrovikanVampireDelayedTriggeredAbility extends DelayedTriggeredAbility {
|
|||
|
||||
@Override
|
||||
public boolean checkTrigger(GameEvent event, Game game) {
|
||||
if (event.getType() == GameEvent.EventType.LOST_CONTROL
|
||||
&& event.getTargetId().equals(krovikanVampire)) {
|
||||
return true;
|
||||
}
|
||||
if (event.getType() == GameEvent.EventType.ZONE_CHANGE
|
||||
&& event.getTargetId().equals(krovikanVampire)) {
|
||||
return true;
|
||||
if (event.getType() == GameEvent.EventType.LOST_CONTROL || event.getType() == GameEvent.EventType.ZONE_CHANGE) {
|
||||
return event.getTargetId().equals(krovikanVampire);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
|
@ -60,6 +60,7 @@ class LivingBreakthroughEffect extends ContinuousRuleModifyingEffectImpl {
|
|||
|
||||
private LivingBreakthroughEffect(final LivingBreakthroughEffect effect) {
|
||||
super(effect);
|
||||
this.manaValue = effect.manaValue;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -70,6 +70,7 @@ class MarshlandBloodcasterEffect extends ContinuousEffectImpl {
|
|||
|
||||
public MarshlandBloodcasterEffect(final MarshlandBloodcasterEffect effect) {
|
||||
super(effect);
|
||||
this.spellsCast = effect.spellsCast;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -6,6 +6,7 @@ import mage.abilities.Ability;
|
|||
import mage.abilities.common.SimpleActivatedAbility;
|
||||
import mage.abilities.costs.common.SacrificeSourceCost;
|
||||
import mage.abilities.costs.common.TapSourceCost;
|
||||
import mage.abilities.costs.mana.GenericManaCost;
|
||||
import mage.abilities.costs.mana.ManaCostsImpl;
|
||||
import mage.abilities.effects.SearchEffect;
|
||||
import mage.abilities.effects.common.CreateTokenEffect;
|
||||
|
@ -30,8 +31,10 @@ public final class MyrIncubator extends CardImpl {
|
|||
public MyrIncubator(UUID ownerId, CardSetInfo setInfo) {
|
||||
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.
|
||||
Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new MyrIncubatorEffect(), new ManaCostsImpl("{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.
|
||||
Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new MyrIncubatorEffect(), new GenericManaCost(6));
|
||||
ability.addCost(new TapSourceCost());
|
||||
ability.addCost(new SacrificeSourceCost());
|
||||
this.addAbility(ability);
|
||||
|
@ -56,32 +59,39 @@ class MyrIncubatorEffect extends SearchEffect {
|
|||
filter.add(CardType.ARTIFACT.getPredicate());
|
||||
}
|
||||
|
||||
int tokensToCreate = 0;
|
||||
int tokensToCreate;
|
||||
|
||||
MyrIncubatorEffect() {
|
||||
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) {
|
||||
super(effect);
|
||||
this.tokensToCreate = effect.tokensToCreate;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean apply(Game game, Ability source) {
|
||||
Player controller = game.getPlayer(source.getControllerId());
|
||||
if (controller != null
|
||||
&& controller.searchLibrary(target, source, game)) {
|
||||
if (!target.getTargets().isEmpty()) {
|
||||
tokensToCreate = target.getTargets().size();
|
||||
controller.moveCards(new CardsImpl(target.getTargets()), Zone.EXILED, source, game);
|
||||
}
|
||||
if (controller == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
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);
|
||||
effect.apply(game, source);
|
||||
controller.shuffleLibrary(source, game);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
controller.shuffleLibrary(source, game);
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -55,7 +55,6 @@ public final class NaturesBlessing extends CardImpl {
|
|||
class NaturesBlessingEffect extends OneShotEffect {
|
||||
|
||||
private static final Set<String> choices = new HashSet<>();
|
||||
private Ability gainedAbility;
|
||||
|
||||
static {
|
||||
choices.add("+1/+1 counter");
|
||||
|
@ -82,30 +81,33 @@ class NaturesBlessingEffect extends OneShotEffect {
|
|||
public boolean apply(Game game, Ability source) {
|
||||
Player controller = game.getPlayer(source.getControllerId());
|
||||
Permanent targetPermanent = game.getPermanent(this.getTargetPointer().getFirst(game, source));
|
||||
if (controller != null && targetPermanent != 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;
|
||||
if (controller == null || targetPermanent == null) {
|
||||
return false;
|
||||
}
|
||||
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) {
|
||||
super(cost);
|
||||
this.isZombieCard = cost.isZombieCard;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -46,6 +46,7 @@ class PredatoryFocusEffect extends AsThoughEffectImpl {
|
|||
|
||||
public PredatoryFocusEffect(PredatoryFocusEffect effect) {
|
||||
super(effect);
|
||||
this.choseUse = effect.choseUse;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -49,6 +49,7 @@ class PrimitiveEtchingsAbility extends TriggeredAbilityImpl {
|
|||
|
||||
PrimitiveEtchingsAbility(final PrimitiveEtchingsAbility ability) {
|
||||
super(ability);
|
||||
this.lastTriggeredTurn = ability.lastTriggeredTurn;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -87,6 +87,7 @@ class RaziaBorosArchangelEffect extends RedirectionEffect {
|
|||
|
||||
public RaziaBorosArchangelEffect(final RaziaBorosArchangelEffect effect) {
|
||||
super(effect);
|
||||
this.redirectToObject = effect.redirectToObject;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -47,8 +47,9 @@ class RowenAbility extends TriggeredAbilityImpl {
|
|||
super(Zone.BATTLEFIELD, new InfoEffect(""), false);
|
||||
}
|
||||
|
||||
RowenAbility(final RowenAbility ability) {
|
||||
private RowenAbility(final RowenAbility ability) {
|
||||
super(ability);
|
||||
this.lastTriggeredTurn = ability.lastTriggeredTurn;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -54,7 +54,7 @@ class ChooseNumberEffect extends OneShotEffect {
|
|||
staticText = "choose a number";
|
||||
}
|
||||
|
||||
public ChooseNumberEffect(final ChooseNumberEffect effect) {
|
||||
private ChooseNumberEffect(final ChooseNumberEffect effect) {
|
||||
super(effect);
|
||||
}
|
||||
|
||||
|
@ -83,14 +83,12 @@ class ChooseNumberEffect extends OneShotEffect {
|
|||
|
||||
class SanctumPrelateReplacementEffect extends ContinuousRuleModifyingEffectImpl {
|
||||
|
||||
Integer choiceValue;
|
||||
|
||||
public SanctumPrelateReplacementEffect() {
|
||||
super(Duration.WhileOnBattlefield, Outcome.Detriment);
|
||||
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);
|
||||
}
|
||||
|
||||
|
@ -120,7 +118,7 @@ class SanctumPrelateReplacementEffect extends ContinuousRuleModifyingEffectImpl
|
|||
|
||||
@Override
|
||||
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());
|
||||
|
||||
if (spell != null && !spell.isCreature(game)) {
|
||||
|
|
|
@ -12,6 +12,7 @@ import mage.constants.CardType;
|
|||
import mage.constants.SubType;
|
||||
import mage.constants.Zone;
|
||||
import mage.counters.CounterType;
|
||||
import mage.filter.StaticFilters;
|
||||
import mage.filter.common.FilterLandPermanent;
|
||||
import mage.game.Game;
|
||||
import mage.game.events.GameEvent;
|
||||
|
@ -45,8 +46,6 @@ public final class ScuteMob extends CardImpl {
|
|||
|
||||
class ScuteMobAbility extends TriggeredAbilityImpl {
|
||||
|
||||
private FilterLandPermanent filter = new FilterLandPermanent();
|
||||
|
||||
public ScuteMobAbility() {
|
||||
super(Zone.BATTLEFIELD, new AddCountersSourceEffect(CounterType.P1P1.createInstance(4)));
|
||||
}
|
||||
|
@ -72,7 +71,7 @@ class ScuteMobAbility extends TriggeredAbilityImpl {
|
|||
|
||||
@Override
|
||||
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
|
||||
|
|
|
@ -31,6 +31,7 @@ public final class SlumberingTora extends CardImpl {
|
|||
|
||||
public SlumberingTora(UUID ownerId, CardSetInfo setInfo) {
|
||||
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,
|
||||
// where X is the discarded card's converted mana cost.
|
||||
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 int convManaCosts = 0;
|
||||
private int convManaCosts;
|
||||
|
||||
private SlumberingToraEffect() {
|
||||
super(Duration.EndOfTurn, Outcome.BecomeCreature);
|
||||
|
@ -59,6 +60,7 @@ public final class SlumberingTora extends CardImpl {
|
|||
|
||||
private SlumberingToraEffect(final SlumberingToraEffect effect) {
|
||||
super(effect);
|
||||
this.convManaCosts = effect.convManaCosts;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -80,13 +80,24 @@ class SoulEchoOpponentsChoiceEffect extends OneShotEffect {
|
|||
Permanent permanent = game.getPermanentOrLKIBattlefield(source.getSourceId());
|
||||
Player controller = game.getPlayer(source.getControllerId());
|
||||
Player opponent = game.getPlayer(targetPointer.getFirst(game, source));
|
||||
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)) {
|
||||
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);
|
||||
}
|
||||
if (controller == null || opponent == null || permanent == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
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 false;
|
||||
}
|
||||
}
|
||||
|
@ -99,16 +110,15 @@ class SoulEchoReplacementEffect extends ReplacementEffectImpl {
|
|||
super(Duration.Custom, Outcome.PreventDamage);
|
||||
}
|
||||
|
||||
SoulEchoReplacementEffect(final SoulEchoReplacementEffect effect) {
|
||||
private SoulEchoReplacementEffect(final SoulEchoReplacementEffect effect) {
|
||||
super(effect);
|
||||
this.sameStep = effect.sameStep;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isInactive(Ability source, Game game) {
|
||||
if (game.getPhase().getStep().getType() == PhaseStep.UPKEEP) {
|
||||
if (!sameStep && game.isActivePlayer(source.getControllerId()) || game.getPlayer(source.getControllerId()).hasReachedNextTurnAfterLeaving()) {
|
||||
return true;
|
||||
}
|
||||
return !sameStep && game.isActivePlayer(source.getControllerId()) || game.getPlayer(source.getControllerId()).hasReachedNextTurnAfterLeaving();
|
||||
} else {
|
||||
sameStep = false;
|
||||
}
|
||||
|
@ -117,14 +127,18 @@ class SoulEchoReplacementEffect extends ReplacementEffectImpl {
|
|||
|
||||
@Override
|
||||
public boolean replaceEvent(GameEvent event, Ability source, Game game) {
|
||||
DamageEvent damageEvent = (DamageEvent) event;
|
||||
int damage = damageEvent.getAmount();
|
||||
|
||||
Permanent permanent = game.getPermanentOrLKIBattlefield(source.getSourceId());
|
||||
Player controller = game.getPlayer(source.getControllerId());
|
||||
if (permanent != null && controller != null) {
|
||||
permanent.removeCounters(CounterType.ECHO.createInstance(damage), source, game);
|
||||
game.informPlayers(controller.getLogName() + ": " + damage + " damage replaced with " + permanent.getLogName());
|
||||
if (permanent == null && controller == null) {
|
||||
return false;
|
||||
}
|
||||
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;
|
||||
}
|
||||
|
||||
|
|
|
@ -45,7 +45,7 @@ class CheeseStandsAloneContinuousEffect extends ContinuousRuleModifyingEffectImp
|
|||
|
||||
private static final FilterControlledPermanent filter = new FilterControlledPermanent();
|
||||
|
||||
private boolean wonAlready = false;
|
||||
private boolean wonAlready;
|
||||
|
||||
static {
|
||||
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";
|
||||
}
|
||||
|
||||
public CheeseStandsAloneContinuousEffect(final CheeseStandsAloneContinuousEffect effect) {
|
||||
private CheeseStandsAloneContinuousEffect(final CheeseStandsAloneContinuousEffect effect) {
|
||||
super(effect);
|
||||
this.wonAlready = effect.wonAlready;
|
||||
}
|
||||
|
||||
@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";
|
||||
}
|
||||
|
||||
public UrzasAvengerEffect(final UrzasAvengerEffect effect) {
|
||||
private UrzasAvengerEffect(final UrzasAvengerEffect effect) {
|
||||
super(effect);
|
||||
this.gainedAbility = effect.gainedAbility;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -100,8 +100,6 @@ class VerdantSuccessionTriggeredAbility extends TriggeredAbilityImpl {
|
|||
|
||||
class VerdantSuccessionEffect extends OneShotEffect {
|
||||
|
||||
private Permanent permanent;
|
||||
|
||||
VerdantSuccessionEffect() {
|
||||
super(Outcome.PutCardInPlay);
|
||||
}
|
||||
|
@ -118,26 +116,36 @@ class VerdantSuccessionEffect extends OneShotEffect {
|
|||
@Override
|
||||
public boolean apply(Game game, Ability source) {
|
||||
MageObject mageObject = game.getObject(source);
|
||||
if(mageObject != null) {
|
||||
permanent = (Permanent) game.getState().getValue("verdantSuccession" + mageObject);
|
||||
if (permanent != null) {
|
||||
Player controller = game.getPlayer(permanent.getControllerId());
|
||||
if (controller != null) {
|
||||
FilterCard filterCard = new FilterCard("Card named " + permanent.getName());
|
||||
filterCard.add(new NamePredicate(permanent.getName()));
|
||||
TargetCardInLibrary target = new TargetCardInLibrary(filterCard);
|
||||
controller.searchLibrary(target, source, game);
|
||||
if (!target.getTargets().isEmpty()) {
|
||||
Card card = game.getCard(target.getFirstTarget());
|
||||
if (card != null
|
||||
&& controller.moveCards(card, Zone.BATTLEFIELD, source, game)) {
|
||||
controller.shuffleLibrary(source, game);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
if (mageObject == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
Permanent permanent = (Permanent) game.getState().getValue("verdantSuccession" + mageObject);
|
||||
if (permanent == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
Player controller = game.getPlayer(permanent.getControllerId());
|
||||
if (controller == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
FilterCard filterCard = new FilterCard("Card named " + permanent.getName());
|
||||
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;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
import mage.Mana;
|
||||
import mage.abilities.Ability;
|
||||
import mage.abilities.common.SimpleActivatedAbility;
|
||||
import mage.abilities.costs.mana.ManaCost;
|
||||
import mage.abilities.costs.mana.ManaCostsImpl;
|
||||
import mage.abilities.dynamicvalue.DynamicValue;
|
||||
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}");
|
||||
|
||||
// {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) {
|
||||
super(effect);
|
||||
this.xCosts = effect.xCosts.copy();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean replaceEvent(GameEvent event, Ability source, Game game) {
|
||||
Player player = game.getPlayer(event.getPlayerId());
|
||||
if (player != null) {
|
||||
int amount = xCosts.calculate(game, source, this);
|
||||
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;
|
||||
}
|
||||
if (player == null) {
|
||||
return false;
|
||||
}
|
||||
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
|
||||
|
|
|
@ -54,6 +54,7 @@ class WarTaxCantAttackUnlessPaysEffect extends PayCostToAttackBlockEffectImpl {
|
|||
|
||||
WarTaxCantAttackUnlessPaysEffect(WarTaxCantAttackUnlessPaysEffect effect) {
|
||||
super(effect);
|
||||
this.xCosts = effect.xCosts.copy();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -54,9 +54,6 @@ public final class Woeleecher extends CardImpl {
|
|||
|
||||
class WoeleecherEffect extends OneShotEffect {
|
||||
|
||||
private int numberCountersOriginal = 0;
|
||||
private int numberCountersAfter = 0;
|
||||
|
||||
public WoeleecherEffect() {
|
||||
super(Outcome.ReturnToHand);
|
||||
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) {
|
||||
Permanent target = game.getPermanent(source.getFirstTarget());
|
||||
Player you = game.getPlayer(source.getControllerId());
|
||||
if (target != null && you != null) {
|
||||
numberCountersOriginal = target.getCounters(game).getCount(CounterType.M1M1);
|
||||
target.removeCounters(CounterType.M1M1.createInstance(), source, game);
|
||||
numberCountersAfter = target.getCounters(game).getCount(CounterType.M1M1);
|
||||
if (numberCountersAfter < numberCountersOriginal && you != null) {
|
||||
you.gainLife(2, game, source);
|
||||
return true;
|
||||
}
|
||||
if (target == null || you == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
int numberCountersOriginal = target.getCounters(game).getCount(CounterType.M1M1);
|
||||
target.removeCounters(CounterType.M1M1.createInstance(), source, game);
|
||||
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 {
|
||||
|
||||
private final boolean isSimulatedPlayer;
|
||||
private int actionCount = 0;
|
||||
private int actionCount;
|
||||
|
||||
protected PassAbility pass = new PassAbility();
|
||||
|
||||
|
@ -43,6 +43,8 @@ public class RandomPlayer extends ComputerPlayer {
|
|||
public RandomPlayer(final RandomPlayer player) {
|
||||
super(player);
|
||||
this.isSimulatedPlayer = player.isSimulatedPlayer;
|
||||
this.actionCount = player.actionCount;
|
||||
this.pass = player.pass.copy();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -83,7 +83,7 @@ public class TestPlayer implements Player {
|
|||
public static final String DIE_ROLL = "[die_roll]: ";
|
||||
|
||||
private int maxCallsWithoutAction = 400;
|
||||
private int foundNoAction = 0;
|
||||
private int foundNoAction;
|
||||
|
||||
// full playable AI, TODO: can be deleted?
|
||||
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 inner choice dialogs accessable by set up choices
|
||||
// (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.
|
||||
// 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.strictChooseMode = testPlayer.strictChooseMode;
|
||||
this.maxCallsWithoutAction = testPlayer.maxCallsWithoutAction;
|
||||
}
|
||||
|
||||
public void addChoice(String choice) {
|
||||
|
|
|
@ -23,10 +23,10 @@ public abstract class TriggeredAbilityImpl extends AbilityImpl implements Trigge
|
|||
|
||||
protected boolean optional;
|
||||
protected boolean leavesTheBattlefieldTrigger;
|
||||
private boolean triggersOnce = false;
|
||||
private boolean doOnlyOnce = false;
|
||||
private GameEvent triggerEvent = null;
|
||||
private String triggerPhrase = null;
|
||||
private boolean triggersOnce;
|
||||
private boolean doOnlyOnce;
|
||||
private GameEvent triggerEvent;
|
||||
private String triggerPhrase;
|
||||
|
||||
public TriggeredAbilityImpl(Zone zone, Effect effect) {
|
||||
this(zone, effect, false);
|
||||
|
@ -55,6 +55,7 @@ public abstract class TriggeredAbilityImpl extends AbilityImpl implements Trigge
|
|||
this.triggersOnce = ability.triggersOnce;
|
||||
this.doOnlyOnce = ability.doOnlyOnce;
|
||||
this.triggerPhrase = ability.triggerPhrase;
|
||||
this.triggerEvent = ability.triggerEvent;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -15,8 +15,8 @@ import mage.target.targetpointer.FixedTarget;
|
|||
*/
|
||||
public class BlocksAttachedTriggeredAbility extends TriggeredAbilityImpl {
|
||||
|
||||
private boolean setFixedTargetPointer;
|
||||
private String attachedDescription;
|
||||
private final boolean setFixedTargetPointer;
|
||||
private final String attachedDescription;
|
||||
private boolean setFixedTargetPointerToBlocked;
|
||||
|
||||
public BlocksAttachedTriggeredAbility(Effect effect, String attachedDescription, boolean optional) {
|
||||
|
@ -40,6 +40,7 @@ public class BlocksAttachedTriggeredAbility extends TriggeredAbilityImpl {
|
|||
super(ability);
|
||||
this.setFixedTargetPointer = ability.setFixedTargetPointer;
|
||||
this.attachedDescription = ability.attachedDescription;
|
||||
this.setFixedTargetPointerToBlocked = ability.setFixedTargetPointerToBlocked;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -16,13 +16,14 @@ import java.util.UUID;
|
|||
*/
|
||||
public class CyclingDiscardCost extends CostImpl {
|
||||
|
||||
private MageObjectReference cycledCard = null;
|
||||
private MageObjectReference cycledCard;
|
||||
|
||||
public CyclingDiscardCost() {
|
||||
}
|
||||
|
||||
private CyclingDiscardCost(CyclingDiscardCost cost) {
|
||||
super(cost);
|
||||
this.cycledCard = cost.cycledCard;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -49,6 +49,7 @@ public class ManaCostsImpl<T extends ManaCost> extends ArrayList<T> implements M
|
|||
this.add(cost.copy());
|
||||
}
|
||||
this.phyrexian = costs.phyrexian;
|
||||
this.phyrexianPaid = costs.phyrexianPaid;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -42,9 +42,7 @@ public abstract class EffectImpl implements Effect {
|
|||
if (effect.values != null) {
|
||||
values = new HashMap<>();
|
||||
Map<String, Object> map = effect.values;
|
||||
for (Map.Entry<String, Object> entry : map.entrySet()) {
|
||||
values.put(entry.getKey(), entry.getValue());
|
||||
}
|
||||
values.putAll(map);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -21,6 +21,7 @@ public class DontUntapInControllersNextUntapStepSourceEffect extends ContinuousR
|
|||
|
||||
public DontUntapInControllersNextUntapStepSourceEffect(final DontUntapInControllersNextUntapStepSourceEffect effect) {
|
||||
super(effect);
|
||||
this.validForTurnNum = effect.validForTurnNum;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -17,7 +17,6 @@ import mage.util.CardUtil;
|
|||
public class ExileCardsFromTopOfLibraryTargetEffect extends OneShotEffect {
|
||||
|
||||
int amount;
|
||||
String targetName;
|
||||
|
||||
public ExileCardsFromTopOfLibraryTargetEffect(int amount) {
|
||||
this(amount, null);
|
||||
|
|
|
@ -10,9 +10,10 @@ import mage.game.ExileZone;
|
|||
import mage.game.Game;
|
||||
import mage.players.Player;
|
||||
|
||||
// TODO: Remove this class? Nothing uses it.
|
||||
public class ReturnCreaturesFromExileEffect extends OneShotEffect {
|
||||
|
||||
private UUID exileId;
|
||||
private final UUID exileId;
|
||||
private boolean byOwner;
|
||||
|
||||
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);
|
||||
this.exileId = effect.exileId;
|
||||
this.byOwner = effect.byOwner;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -29,6 +29,7 @@ public class MustBeBlockedByAllAttachedEffect extends RequirementEffect {
|
|||
|
||||
public MustBeBlockedByAllAttachedEffect(final MustBeBlockedByAllAttachedEffect effect) {
|
||||
super(effect);
|
||||
this.attachmentType = effect.attachmentType;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -11,7 +11,7 @@ import mage.game.permanent.Permanent;
|
|||
*/
|
||||
public class BecomesCreatureIfVehicleEffect extends ContinuousEffectImpl {
|
||||
|
||||
private CardType addedType = CardType.CREATURE;
|
||||
private static final CardType addedType = CardType.CREATURE;
|
||||
|
||||
public BecomesCreatureIfVehicleEffect() {
|
||||
super(Duration.WhileOnBattlefield, Layer.TypeChangingEffects_4, SubLayer.NA, Outcome.Benefit);
|
||||
|
|
|
@ -22,7 +22,7 @@ public class BecomesCreatureTargetEffect extends ContinuousEffectImpl {
|
|||
protected boolean addStillALandText;
|
||||
protected boolean loseName;
|
||||
protected boolean keepAbilities;
|
||||
protected boolean removeSubtypes = false;
|
||||
protected boolean removeSubtypes;
|
||||
|
||||
|
||||
public BecomesCreatureTargetEffect(Token token, boolean loseAllAbilities, boolean stillALand, Duration duration) {
|
||||
|
@ -58,6 +58,7 @@ public class BecomesCreatureTargetEffect extends ContinuousEffectImpl {
|
|||
this.addStillALandText = effect.addStillALandText;
|
||||
this.loseName = effect.loseName;
|
||||
this.keepAbilities = effect.keepAbilities;
|
||||
this.removeSubtypes = effect.removeSubtypes;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -57,6 +57,7 @@ public class GainControlTargetEffect extends ContinuousEffectImpl {
|
|||
super(effect);
|
||||
this.controllingPlayerId = effect.controllingPlayerId;
|
||||
this.fixedControl = effect.fixedControl;
|
||||
this.firstControlChange = effect.firstControlChange;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -32,7 +32,7 @@ public class AmassEffect extends OneShotEffect {
|
|||
}
|
||||
|
||||
private final DynamicValue amassNumber;
|
||||
private UUID amassedCreatureId = null;
|
||||
private UUID amassedCreatureId;
|
||||
|
||||
public AmassEffect(int amassNumber) {
|
||||
this(StaticValue.get(amassNumber));
|
||||
|
@ -53,6 +53,7 @@ public class AmassEffect extends OneShotEffect {
|
|||
private AmassEffect(final AmassEffect effect) {
|
||||
super(effect);
|
||||
this.amassNumber = effect.amassNumber;
|
||||
this.amassedCreatureId = effect.amassedCreatureId;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -39,6 +39,7 @@ public class ProtectionChosenColorAttachedEffect extends ContinuousEffectImpl {
|
|||
this.protectionAbility = effect.protectionAbility.copy();
|
||||
}
|
||||
this.notRemoveItself = effect.notRemoveItself;
|
||||
this.notRemoveControlled = effect.notRemoveControlled;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -135,7 +135,7 @@ class ReturnAttackerToHandTargetCost extends CostImpl {
|
|||
filter.add(UnblockedPredicate.instance);
|
||||
}
|
||||
|
||||
private UUID defendingPlayerId = null;
|
||||
private UUID defendingPlayerId;
|
||||
|
||||
public ReturnAttackerToHandTargetCost() {
|
||||
this.addTarget(new TargetControlledPermanent(filter));
|
||||
|
@ -144,6 +144,7 @@ class ReturnAttackerToHandTargetCost extends CostImpl {
|
|||
|
||||
public ReturnAttackerToHandTargetCost(ReturnAttackerToHandTargetCost cost) {
|
||||
super(cost);
|
||||
this.defendingPlayerId = cost.defendingPlayerId;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -152,8 +153,7 @@ class ReturnAttackerToHandTargetCost extends CostImpl {
|
|||
for (UUID targetId : targets.get(0).getTargets()) {
|
||||
Permanent permanent = game.getPermanent(targetId);
|
||||
Player controller = game.getPlayer(controllerId);
|
||||
if (permanent == null
|
||||
|| controller == null) {
|
||||
if (permanent == null || controller == null) {
|
||||
return false;
|
||||
}
|
||||
defendingPlayerId = game.getCombat().getDefenderId(permanent.getId());
|
||||
|
|
|
@ -12,8 +12,8 @@ import mage.util.CardUtil;
|
|||
|
||||
public class VanishingUpkeepAbility extends BeginningOfUpkeepTriggeredAbility {
|
||||
|
||||
private int vanishingAmount;
|
||||
private String permanentType;
|
||||
private final int vanishingAmount;
|
||||
private final String permanentType;
|
||||
|
||||
public VanishingUpkeepAbility(int vanishingEffect) {
|
||||
super(new VanishingEffect(), TargetController.YOU, false);
|
||||
|
@ -27,9 +27,10 @@ public class VanishingUpkeepAbility extends BeginningOfUpkeepTriggeredAbility {
|
|||
this.permanentType = permanentType;
|
||||
}
|
||||
|
||||
public VanishingUpkeepAbility(final VanishingUpkeepAbility ability) {
|
||||
private VanishingUpkeepAbility(final VanishingUpkeepAbility ability) {
|
||||
super(ability);
|
||||
this.vanishingAmount = ability.vanishingAmount;
|
||||
this.permanentType = ability.permanentType;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -63,15 +64,16 @@ class VanishingEffect extends OneShotEffect {
|
|||
@Override
|
||||
public boolean apply(Game game, Ability source) {
|
||||
Permanent p = game.getPermanent(source.getSourceId());
|
||||
if (p != null) {
|
||||
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;
|
||||
if (p == null) {
|
||||
return false;
|
||||
}
|
||||
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
|
||||
|
|
|
@ -73,7 +73,7 @@ class AnyColorLandsProduceManaEffect extends ManaEffect {
|
|||
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 boolean inManaTypeCalculation = false;
|
||||
private boolean inManaTypeCalculation;
|
||||
|
||||
AnyColorLandsProduceManaEffect(TargetController targetController, boolean onlyColors, FilterPermanent filter) {
|
||||
super();
|
||||
|
@ -93,6 +93,7 @@ class AnyColorLandsProduceManaEffect extends ManaEffect {
|
|||
super(effect);
|
||||
this.filter = effect.filter.copy();
|
||||
this.onlyColors = effect.onlyColors;
|
||||
this.inManaTypeCalculation = effect.inManaTypeCalculation;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -57,7 +57,7 @@ class AnyColorPermanentTypesManaEffect extends ManaEffect {
|
|||
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 boolean inManaTypeCalculation = false;
|
||||
private boolean inManaTypeCalculation;
|
||||
|
||||
public AnyColorPermanentTypesManaEffect(TargetController targetController, boolean onlyColors, FilterPermanent permanentTypes) {
|
||||
super();
|
||||
|
@ -72,6 +72,7 @@ class AnyColorPermanentTypesManaEffect extends ManaEffect {
|
|||
super(effect);
|
||||
this.filter = effect.filter.copy();
|
||||
this.onlyColors = effect.onlyColors;
|
||||
this.inManaTypeCalculation = effect.inManaTypeCalculation;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -85,9 +85,9 @@ public class GameState implements Serializable, Copyable<GameState> {
|
|||
private Exile exile;
|
||||
private Battlefield battlefield;
|
||||
private int turnNum = 1;
|
||||
private int stepNum = 0;
|
||||
private UUID turnId = null;
|
||||
private boolean extraTurn = false;
|
||||
private int stepNum;
|
||||
private UUID turnId;
|
||||
private boolean extraTurn;
|
||||
private boolean legendaryRuleActive = true;
|
||||
private boolean gameOver;
|
||||
private boolean paused;
|
||||
|
@ -105,8 +105,8 @@ public class GameState implements Serializable, Copyable<GameState> {
|
|||
private int permanentOrderNumber;
|
||||
private final Map<UUID, FilterCreaturePermanent> usePowerInsteadOfToughnessForDamageLethalityFilters = new HashMap<>();
|
||||
private Set<MageObjectReference> commandersToStay = new HashSet<>(); // commanders that do not go back to command zone
|
||||
private boolean manaBurn = false;
|
||||
private boolean hasDayNight = false;
|
||||
private boolean manaBurn;
|
||||
private boolean hasDayNight;
|
||||
private boolean isDaytime = true;
|
||||
|
||||
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.turnNum = state.turnNum;
|
||||
this.stepNum = state.stepNum;
|
||||
this.turnId = state.turnId;
|
||||
this.extraTurn = state.extraTurn;
|
||||
this.legendaryRuleActive = state.legendaryRuleActive;
|
||||
this.effects = state.effects.copy();
|
||||
|
@ -199,6 +200,7 @@ public class GameState implements Serializable, Copyable<GameState> {
|
|||
this.commandersToStay.addAll(state.commandersToStay);
|
||||
this.hasDayNight = state.hasDayNight;
|
||||
this.isDaytime = state.isDaytime;
|
||||
this.manaBurn = state.manaBurn;
|
||||
}
|
||||
|
||||
public void clearOnGameRestart() {
|
||||
|
|
|
@ -39,6 +39,7 @@ public abstract class GameTinyLeadersImpl extends GameImpl {
|
|||
public GameTinyLeadersImpl(final GameTinyLeadersImpl game) {
|
||||
super(game);
|
||||
this.alsoHand = game.alsoHand;
|
||||
this.alsoLibrary = game.alsoLibrary;
|
||||
this.startingPlayerSkipsDraw = game.startingPlayerSkipsDraw;
|
||||
}
|
||||
|
||||
|
@ -50,35 +51,37 @@ public abstract class GameTinyLeadersImpl extends GameImpl {
|
|||
// move tiny leader to command zone
|
||||
for (UUID playerId : state.getPlayerList(startingPlayerId)) {
|
||||
Player player = getPlayer(playerId);
|
||||
if (player != null) {
|
||||
String commanderName = player.getMatchPlayer().getDeck().getName();
|
||||
Card commander = findCommander(this, player, commanderName);
|
||||
if (player == null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
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) {
|
||||
// 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);
|
||||
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 {
|
||||
// create new commander
|
||||
commander = getCommanderCard(commanderName, player.getId());
|
||||
if (commander != null) {
|
||||
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() + ']');
|
||||
}
|
||||
// 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 int classLevel = 1;
|
||||
protected final Set<UUID> goadingPlayers = new HashSet<>();
|
||||
// The UUID of the controller under who the permanent first entered the battelfield under.
|
||||
protected UUID originalControllerId;
|
||||
// The UUID of the current controller.
|
||||
protected UUID controllerId;
|
||||
protected UUID beforeResetControllerId;
|
||||
protected int damage;
|
||||
|
@ -129,6 +131,7 @@ public abstract class PermanentImpl extends CardImpl implements Permanent {
|
|||
this.flipped = permanent.flipped;
|
||||
this.originalControllerId = permanent.originalControllerId;
|
||||
this.controllerId = permanent.controllerId;
|
||||
this.beforeResetControllerId = permanent.controllerId;
|
||||
this.damage = permanent.damage;
|
||||
this.controlledFromStartOfControllerTurn = permanent.controlledFromStartOfControllerTurn;
|
||||
this.turnsOnBattlefield = permanent.turnsOnBattlefield;
|
||||
|
@ -141,11 +144,9 @@ public abstract class PermanentImpl extends CardImpl implements Permanent {
|
|||
this.deathtouched = permanent.deathtouched;
|
||||
this.markedLifelink = permanent.markedLifelink;
|
||||
|
||||
for (Map.Entry<String, List<UUID>> entry : permanent.connectedCards.entrySet()) {
|
||||
this.connectedCards.put(entry.getKey(), entry.getValue());
|
||||
}
|
||||
this.connectedCards.putAll(permanent.connectedCards);
|
||||
if (permanent.dealtDamageByThisTurn != null) {
|
||||
dealtDamageByThisTurn = new HashSet<>(permanent.dealtDamageByThisTurn);
|
||||
this.dealtDamageByThisTurn = new HashSet<>(permanent.dealtDamageByThisTurn);
|
||||
}
|
||||
if (permanent.markedDamage != null) {
|
||||
markedDamage = new ArrayList<>();
|
||||
|
@ -171,6 +172,7 @@ public abstract class PermanentImpl extends CardImpl implements Permanent {
|
|||
this.bandedCards.addAll(permanent.bandedCards);
|
||||
this.timesLoyaltyUsed = permanent.timesLoyaltyUsed;
|
||||
this.transformCount = permanent.transformCount;
|
||||
this.removedFromCombat = permanent.removedFromCombat;
|
||||
|
||||
this.morphed = permanent.morphed;
|
||||
this.manifested = permanent.manifested;
|
||||
|
@ -193,6 +195,14 @@ public abstract class PermanentImpl extends CardImpl implements Permanent {
|
|||
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
|
||||
public void setOriginalControllerId(UUID originalControllerId) {
|
||||
this.originalControllerId = originalControllerId;
|
||||
|
@ -764,6 +774,7 @@ public abstract class PermanentImpl extends CardImpl implements Permanent {
|
|||
|
||||
@Override
|
||||
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)) {
|
||||
this.removeFromCombat(game);
|
||||
this.controlledFromStartOfControllerTurn = false;
|
||||
|
@ -904,7 +915,7 @@ public abstract class PermanentImpl extends CardImpl implements Permanent {
|
|||
* @return
|
||||
*/
|
||||
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)) {
|
||||
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) {
|
||||
Zone fromZone = game.getState().getZone(objectId);
|
||||
Player controller = game.getPlayer(controllerId);
|
||||
if (controller != null) {
|
||||
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;
|
||||
if (controller == null) {
|
||||
return false;
|
||||
}
|
||||
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
|
||||
|
|
|
@ -81,6 +81,7 @@ public abstract class TokenImpl extends MageObjectImpl implements Token {
|
|||
this.expansionSetCodeChecked = token.expansionSetCodeChecked;
|
||||
this.copySourceCard = token.copySourceCard; // will never be changed
|
||||
this.availableImageSetCodes = token.availableImageSetCodes;
|
||||
this.tokenDescriptor = token.tokenDescriptor;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -30,6 +30,7 @@ public class SpellStack extends ArrayDeque<StackObject> {
|
|||
for (StackObject spell : stack) {
|
||||
this.addLast(spell.copy());
|
||||
}
|
||||
this.dateLastAdded = stack.dateLastAdded;
|
||||
}
|
||||
|
||||
//resolve top StackObject
|
||||
|
|
Loading…
Reference in a new issue