mirror of
https://github.com/correl/mage.git
synced 2024-12-26 11:09:27 +00:00
Merge origin/master
This commit is contained in:
commit
eb0ce863e7
66 changed files with 1001 additions and 590 deletions
|
@ -25,7 +25,6 @@
|
||||||
* authors and should not be interpreted as representing official policies, either expressed
|
* authors and should not be interpreted as representing official policies, either expressed
|
||||||
* or implied, of BetaSteward_at_googlemail.com.
|
* or implied, of BetaSteward_at_googlemail.com.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package mage.view;
|
package mage.view;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
@ -37,6 +36,7 @@ import mage.MageObject;
|
||||||
import mage.abilities.Ability;
|
import mage.abilities.Ability;
|
||||||
import mage.abilities.effects.Effect;
|
import mage.abilities.effects.Effect;
|
||||||
import mage.cards.Card;
|
import mage.cards.Card;
|
||||||
|
import mage.constants.CardType;
|
||||||
import mage.constants.Zone;
|
import mage.constants.Zone;
|
||||||
import static mage.constants.Zone.ALL;
|
import static mage.constants.Zone.ALL;
|
||||||
import static mage.constants.Zone.BATTLEFIELD;
|
import static mage.constants.Zone.BATTLEFIELD;
|
||||||
|
@ -56,7 +56,8 @@ import mage.target.targetpointer.TargetPointer;
|
||||||
*/
|
*/
|
||||||
public class CardsView extends LinkedHashMap<UUID, CardView> {
|
public class CardsView extends LinkedHashMap<UUID, CardView> {
|
||||||
|
|
||||||
public CardsView() {}
|
public CardsView() {
|
||||||
|
}
|
||||||
|
|
||||||
public CardsView(Collection<? extends Card> cards) {
|
public CardsView(Collection<? extends Card> cards) {
|
||||||
for (Card card : cards) {
|
for (Card card : cards) {
|
||||||
|
@ -101,6 +102,11 @@ public class CardsView extends LinkedHashMap<UUID, CardView> {
|
||||||
if (sourceObject instanceof Emblem) {
|
if (sourceObject instanceof Emblem) {
|
||||||
Card planeswalkerCard = game.getCard(((Emblem) sourceObject).getSourceId());
|
Card planeswalkerCard = game.getCard(((Emblem) sourceObject).getSourceId());
|
||||||
if (planeswalkerCard != null) {
|
if (planeswalkerCard != null) {
|
||||||
|
if (!planeswalkerCard.getCardType().contains(CardType.PLANESWALKER)) {
|
||||||
|
if (planeswalkerCard.getSecondCardFace() != null) {
|
||||||
|
planeswalkerCard = planeswalkerCard.getSecondCardFace();
|
||||||
|
}
|
||||||
|
}
|
||||||
abilityView = new AbilityView(ability, "Emblem " + planeswalkerCard.getName(), new CardView(new EmblemView((Emblem) sourceObject, planeswalkerCard)));
|
abilityView = new AbilityView(ability, "Emblem " + planeswalkerCard.getName(), new CardView(new EmblemView((Emblem) sourceObject, planeswalkerCard)));
|
||||||
abilityView.setName("Emblem " + planeswalkerCard.getName());
|
abilityView.setName("Emblem " + planeswalkerCard.getName());
|
||||||
abilityView.setExpansionSetCode(planeswalkerCard.getExpansionSetCode());
|
abilityView.setExpansionSetCode(planeswalkerCard.getExpansionSetCode());
|
||||||
|
|
|
@ -25,12 +25,18 @@
|
||||||
* authors and should not be interpreted as representing official policies, either expressed
|
* authors and should not be interpreted as representing official policies, either expressed
|
||||||
* or implied, of BetaSteward_at_googlemail.com.
|
* or implied, of BetaSteward_at_googlemail.com.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package mage.view;
|
package mage.view;
|
||||||
|
|
||||||
|
import java.io.Serializable;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Set;
|
||||||
|
import java.util.UUID;
|
||||||
import mage.MageObject;
|
import mage.MageObject;
|
||||||
import mage.abilities.costs.Cost;
|
import mage.abilities.costs.Cost;
|
||||||
import mage.cards.Card;
|
import mage.cards.Card;
|
||||||
|
import mage.constants.CardType;
|
||||||
import mage.constants.PhaseStep;
|
import mage.constants.PhaseStep;
|
||||||
import mage.constants.TurnPhase;
|
import mage.constants.TurnPhase;
|
||||||
import mage.constants.Zone;
|
import mage.constants.Zone;
|
||||||
|
@ -45,18 +51,15 @@ import mage.game.stack.Spell;
|
||||||
import mage.game.stack.StackAbility;
|
import mage.game.stack.StackAbility;
|
||||||
import mage.game.stack.StackObject;
|
import mage.game.stack.StackObject;
|
||||||
import mage.players.Player;
|
import mage.players.Player;
|
||||||
import org.apache.log4j.Logger;
|
|
||||||
|
|
||||||
import java.io.Serializable;
|
|
||||||
import java.util.*;
|
|
||||||
import mage.watchers.common.CastSpellLastTurnWatcher;
|
import mage.watchers.common.CastSpellLastTurnWatcher;
|
||||||
|
import org.apache.log4j.Logger;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* @author BetaSteward_at_googlemail.com
|
* @author BetaSteward_at_googlemail.com
|
||||||
*/
|
*/
|
||||||
public class GameView implements Serializable {
|
public class GameView implements Serializable {
|
||||||
|
|
||||||
private static final long serialVersionUID = 1L;
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
private static final transient Logger logger = Logger.getLogger(GameView.class);
|
private static final transient Logger logger = Logger.getLogger(GameView.class);
|
||||||
|
@ -83,7 +86,6 @@ public class GameView implements Serializable {
|
||||||
private final int spellsCastCurrentTurn;
|
private final int spellsCastCurrentTurn;
|
||||||
private final boolean rollbackTurnsAllowed;
|
private final boolean rollbackTurnsAllowed;
|
||||||
|
|
||||||
|
|
||||||
public GameView(GameState state, Game game, UUID createdForPlayerId, UUID watcherUserId) {
|
public GameView(GameState state, Game game, UUID createdForPlayerId, UUID watcherUserId) {
|
||||||
Player createdForPlayer = null;
|
Player createdForPlayer = null;
|
||||||
this.isPlayer = createdForPlayerId != null;
|
this.isPlayer = createdForPlayerId != null;
|
||||||
|
@ -117,6 +119,11 @@ public class GameView implements Serializable {
|
||||||
} else if (object instanceof Emblem) {
|
} else if (object instanceof Emblem) {
|
||||||
Card sourceCard = game.getCard(((Emblem) object).getSourceId());
|
Card sourceCard = game.getCard(((Emblem) object).getSourceId());
|
||||||
if (sourceCard != null) {
|
if (sourceCard != null) {
|
||||||
|
if (!sourceCard.getCardType().contains(CardType.PLANESWALKER)) {
|
||||||
|
if (sourceCard.getSecondCardFace() != null) {
|
||||||
|
sourceCard = sourceCard.getSecondCardFace();
|
||||||
|
}
|
||||||
|
}
|
||||||
((StackAbility) stackObject).setName("Emblem " + sourceCard.getName());
|
((StackAbility) stackObject).setName("Emblem " + sourceCard.getName());
|
||||||
((StackAbility) stackObject).setExpansionSetCode(sourceCard.getExpansionSetCode());
|
((StackAbility) stackObject).setExpansionSetCode(sourceCard.getExpansionSetCode());
|
||||||
} else {
|
} else {
|
||||||
|
@ -134,8 +141,7 @@ public class GameView implements Serializable {
|
||||||
} else {
|
} else {
|
||||||
logger.error("Stack Object for stack ability not found: " + stackObject.getStackAbility().getRule());
|
logger.error("Stack Object for stack ability not found: " + stackObject.getStackAbility().getRule());
|
||||||
}
|
}
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
// Spell
|
// Spell
|
||||||
stack.put(stackObject.getId(), new CardView((Spell) stackObject, game, stackObject.getControllerId().equals(createdForPlayerId)));
|
stack.put(stackObject.getId(), new CardView((Spell) stackObject, game, stackObject.getControllerId().equals(createdForPlayerId)));
|
||||||
checkPaid(stackObject.getId(), (Spell) stackObject);
|
checkPaid(stackObject.getId(), (Spell) stackObject);
|
||||||
|
|
|
@ -34,6 +34,7 @@ import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
import mage.cards.Card;
|
import mage.cards.Card;
|
||||||
|
import mage.constants.CardType;
|
||||||
import mage.counters.CounterType;
|
import mage.counters.CounterType;
|
||||||
import mage.game.ExileZone;
|
import mage.game.ExileZone;
|
||||||
import mage.game.Game;
|
import mage.game.Game;
|
||||||
|
@ -125,6 +126,11 @@ public class PlayerView implements Serializable {
|
||||||
if (emblem.getControllerId().equals(this.playerId)) {
|
if (emblem.getControllerId().equals(this.playerId)) {
|
||||||
Card sourceCard = game.getCard(((CommandObject) emblem).getSourceId());
|
Card sourceCard = game.getCard(((CommandObject) emblem).getSourceId());
|
||||||
if (sourceCard != null) {
|
if (sourceCard != null) {
|
||||||
|
if (!sourceCard.getCardType().contains(CardType.PLANESWALKER)) {
|
||||||
|
if (sourceCard.getSecondCardFace() != null) {
|
||||||
|
sourceCard = sourceCard.getSecondCardFace();
|
||||||
|
}
|
||||||
|
}
|
||||||
commandList.add(new EmblemView(emblem, sourceCard));
|
commandList.add(new EmblemView(emblem, sourceCard));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -161,7 +161,7 @@ public class ComputerPlayer extends PlayerImpl implements Player {
|
||||||
private transient final static Logger log = Logger.getLogger(ComputerPlayer.class);
|
private transient final static Logger log = Logger.getLogger(ComputerPlayer.class);
|
||||||
|
|
||||||
protected int PASSIVITY_PENALTY = 5; // Penalty value for doing nothing if some actions are availble
|
protected int PASSIVITY_PENALTY = 5; // Penalty value for doing nothing if some actions are availble
|
||||||
protected boolean ALLOW_INTERRUPT = false; // change this for test / debugging purposes to false to switch off interrupts while debugging
|
protected boolean ALLOW_INTERRUPT = true; // change this for test / debugging purposes to false to switch off interrupts while debugging
|
||||||
|
|
||||||
private transient Map<Mana, Card> unplayable = new TreeMap<>();
|
private transient Map<Mana, Card> unplayable = new TreeMap<>();
|
||||||
private transient List<Card> playableNonInstant = new ArrayList<>();
|
private transient List<Card> playableNonInstant = new ArrayList<>();
|
||||||
|
|
|
@ -28,11 +28,6 @@
|
||||||
package mage.sets.alarareborn;
|
package mage.sets.alarareborn;
|
||||||
|
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
import mage.constants.CardType;
|
|
||||||
import mage.constants.Duration;
|
|
||||||
import mage.constants.Outcome;
|
|
||||||
import mage.constants.Rarity;
|
|
||||||
import mage.constants.Zone;
|
|
||||||
import mage.abilities.Ability;
|
import mage.abilities.Ability;
|
||||||
import mage.abilities.common.EntersBattlefieldTriggeredAbility;
|
import mage.abilities.common.EntersBattlefieldTriggeredAbility;
|
||||||
import mage.abilities.common.SimpleStaticAbility;
|
import mage.abilities.common.SimpleStaticAbility;
|
||||||
|
@ -41,6 +36,11 @@ import mage.abilities.effects.common.continuous.GainAbilityAllEffect;
|
||||||
import mage.abilities.keyword.LifelinkAbility;
|
import mage.abilities.keyword.LifelinkAbility;
|
||||||
import mage.cards.Card;
|
import mage.cards.Card;
|
||||||
import mage.cards.CardImpl;
|
import mage.cards.CardImpl;
|
||||||
|
import mage.constants.CardType;
|
||||||
|
import mage.constants.Duration;
|
||||||
|
import mage.constants.Outcome;
|
||||||
|
import mage.constants.Rarity;
|
||||||
|
import mage.constants.Zone;
|
||||||
import mage.filter.common.FilterControlledCreaturePermanent;
|
import mage.filter.common.FilterControlledCreaturePermanent;
|
||||||
import mage.filter.common.FilterCreatureCard;
|
import mage.filter.common.FilterCreatureCard;
|
||||||
import mage.filter.predicate.mageobject.SubtypePredicate;
|
import mage.filter.predicate.mageobject.SubtypePredicate;
|
||||||
|
@ -65,9 +65,6 @@ public class NecromancersCovenant extends CardImpl {
|
||||||
super(ownerId, 82, "Necromancer's Covenant", Rarity.RARE, new CardType[]{CardType.ENCHANTMENT}, "{3}{W}{B}{B}");
|
super(ownerId, 82, "Necromancer's Covenant", Rarity.RARE, new CardType[]{CardType.ENCHANTMENT}, "{3}{W}{B}{B}");
|
||||||
this.expansionSetCode = "ARB";
|
this.expansionSetCode = "ARB";
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// When Necromancer's Covenant enters the battlefield, exile all creature cards from target player's graveyard, then put a 2/2 black Zombie creature token onto the battlefield for each card exiled this way.
|
// When Necromancer's Covenant enters the battlefield, exile all creature cards from target player's graveyard, then put a 2/2 black Zombie creature token onto the battlefield for each card exiled this way.
|
||||||
Ability ability = new EntersBattlefieldTriggeredAbility(new NecromancersConvenantEffect(), false);
|
Ability ability = new EntersBattlefieldTriggeredAbility(new NecromancersConvenantEffect(), false);
|
||||||
ability.addTarget(new TargetPlayer());
|
ability.addTarget(new TargetPlayer());
|
||||||
|
@ -110,7 +107,7 @@ class NecromancersConvenantEffect extends OneShotEffect {
|
||||||
count += 1;
|
count += 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ZombieToken zombieToken = new ZombieToken("ALA");
|
ZombieToken zombieToken = new ZombieToken();
|
||||||
if (zombieToken.putOntoBattlefield(count, game, source.getSourceId(), source.getControllerId())) {
|
if (zombieToken.putOntoBattlefield(count, game, source.getSourceId(), source.getControllerId())) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
|
@ -163,7 +163,7 @@ class UnscytheEffect extends OneShotEffect {
|
||||||
if (controller != null) {
|
if (controller != null) {
|
||||||
Card card = game.getCard(targetPointer.getFirst(game, source));
|
Card card = game.getCard(targetPointer.getFirst(game, source));
|
||||||
if (card != null && game.getState().getZone(card.getId()).equals(Zone.GRAVEYARD) && controller.moveCardToExileWithInfo(card, null, "", source.getSourceId(), game, Zone.GRAVEYARD, true)) {
|
if (card != null && game.getState().getZone(card.getId()).equals(Zone.GRAVEYARD) && controller.moveCardToExileWithInfo(card, null, "", source.getSourceId(), game, Zone.GRAVEYARD, true)) {
|
||||||
ZombieToken zombie = new ZombieToken("ALA");
|
ZombieToken zombie = new ZombieToken();
|
||||||
return zombie.putOntoBattlefield(1, game, source.getSourceId(), source.getControllerId());
|
return zombie.putOntoBattlefield(1, game, source.getSourceId(), source.getControllerId());
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
|
|
|
@ -28,12 +28,12 @@
|
||||||
package mage.sets.avacynrestored;
|
package mage.sets.avacynrestored;
|
||||||
|
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
import mage.constants.CardType;
|
|
||||||
import mage.constants.Rarity;
|
|
||||||
import mage.MageInt;
|
import mage.MageInt;
|
||||||
import mage.abilities.common.DiesTriggeredAbility;
|
import mage.abilities.common.DiesTriggeredAbility;
|
||||||
import mage.abilities.effects.common.CreateTokenEffect;
|
import mage.abilities.effects.common.CreateTokenEffect;
|
||||||
import mage.cards.CardImpl;
|
import mage.cards.CardImpl;
|
||||||
|
import mage.constants.CardType;
|
||||||
|
import mage.constants.Rarity;
|
||||||
import mage.game.permanent.token.ZombieToken;
|
import mage.game.permanent.token.ZombieToken;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -51,7 +51,7 @@ public class MaalfeldTwins extends CardImpl {
|
||||||
this.toughness = new MageInt(4);
|
this.toughness = new MageInt(4);
|
||||||
|
|
||||||
// When Maalfeld Twins dies, put two 2/2 black Zombie creature tokens onto the battlefield.
|
// When Maalfeld Twins dies, put two 2/2 black Zombie creature tokens onto the battlefield.
|
||||||
this.addAbility(new DiesTriggeredAbility(new CreateTokenEffect(new ZombieToken("ALA"), 2)));
|
this.addAbility(new DiesTriggeredAbility(new CreateTokenEffect(new ZombieToken(), 2)));
|
||||||
}
|
}
|
||||||
|
|
||||||
public MaalfeldTwins(final MaalfeldTwins card) {
|
public MaalfeldTwins(final MaalfeldTwins card) {
|
||||||
|
|
|
@ -72,7 +72,7 @@ public class GhoulcallerGisa extends CardImpl {
|
||||||
|
|
||||||
// {B}, {tap}, Sacrifice another creature: Put X 2/2 black Zombie creature tokens onto the battlefield, where X is the sacrificed creature's power.
|
// {B}, {tap}, Sacrifice another creature: Put X 2/2 black Zombie creature tokens onto the battlefield, where X is the sacrificed creature's power.
|
||||||
DynamicValue xValue = new SacrificeCostCreaturesPower();
|
DynamicValue xValue = new SacrificeCostCreaturesPower();
|
||||||
Token zombie = new ZombieToken("C14");
|
Token zombie = new ZombieToken();
|
||||||
zombie.setTokenType(2);
|
zombie.setTokenType(2);
|
||||||
Effect effect = new CreateTokenEffect(zombie, xValue);
|
Effect effect = new CreateTokenEffect(zombie, xValue);
|
||||||
effect.setText("Put X 2/2 black Zombie creature tokens onto the battlefield, where X is the sacrificed creature's power");
|
effect.setText("Put X 2/2 black Zombie creature tokens onto the battlefield, where X is the sacrificed creature's power");
|
||||||
|
|
|
@ -75,7 +75,7 @@ public class OverseerOfTheDamned extends CardImpl {
|
||||||
ability.addTarget(new TargetCreaturePermanent());
|
ability.addTarget(new TargetCreaturePermanent());
|
||||||
this.addAbility(ability);
|
this.addAbility(ability);
|
||||||
// Whenever a nontoken creature an opponent controls dies, put a 2/2 black Zombie creature token onto the battlefield tapped.
|
// Whenever a nontoken creature an opponent controls dies, put a 2/2 black Zombie creature token onto the battlefield tapped.
|
||||||
Token zombie = new ZombieToken("C14");
|
Token zombie = new ZombieToken();
|
||||||
zombie.setTokenType(2);
|
zombie.setTokenType(2);
|
||||||
this.addAbility(new DiesCreatureTriggeredAbility(new CreateTokenEffect(zombie, 1, true, false), false, filter));
|
this.addAbility(new DiesCreatureTriggeredAbility(new CreateTokenEffect(zombie, 1, true, false), false, filter));
|
||||||
|
|
||||||
|
|
|
@ -25,21 +25,19 @@
|
||||||
* authors and should not be interpreted as representing official policies, either expressed
|
* authors and should not be interpreted as representing official policies, either expressed
|
||||||
* or implied, of BetaSteward_at_googlemail.com.
|
* or implied, of BetaSteward_at_googlemail.com.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package mage.sets.conflux;
|
package mage.sets.conflux;
|
||||||
|
|
||||||
import mage.constants.CardType;
|
import java.util.UUID;
|
||||||
import mage.constants.Rarity;
|
|
||||||
import mage.MageInt;
|
import mage.MageInt;
|
||||||
import mage.abilities.common.LeavesBattlefieldTriggeredAbility;
|
import mage.abilities.common.LeavesBattlefieldTriggeredAbility;
|
||||||
import mage.abilities.costs.mana.ManaCostsImpl;
|
import mage.abilities.costs.mana.ManaCostsImpl;
|
||||||
import mage.abilities.effects.common.CreateTokenEffect;
|
import mage.abilities.effects.common.CreateTokenEffect;
|
||||||
import mage.abilities.keyword.UnearthAbility;
|
import mage.abilities.keyword.UnearthAbility;
|
||||||
import mage.cards.CardImpl;
|
import mage.cards.CardImpl;
|
||||||
|
import mage.constants.CardType;
|
||||||
|
import mage.constants.Rarity;
|
||||||
import mage.game.permanent.token.ZombieToken;
|
import mage.game.permanent.token.ZombieToken;
|
||||||
|
|
||||||
import java.util.UUID;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author Loki
|
* @author Loki
|
||||||
*/
|
*/
|
||||||
|
@ -53,7 +51,7 @@ public class GrixisSlavedriver extends CardImpl {
|
||||||
this.subtype.add("Giant");
|
this.subtype.add("Giant");
|
||||||
this.power = new MageInt(4);
|
this.power = new MageInt(4);
|
||||||
this.toughness = new MageInt(4);
|
this.toughness = new MageInt(4);
|
||||||
this.addAbility(new LeavesBattlefieldTriggeredAbility(new CreateTokenEffect(new ZombieToken("ALA")), false));
|
this.addAbility(new LeavesBattlefieldTriggeredAbility(new CreateTokenEffect(new ZombieToken()), false));
|
||||||
this.addAbility(new UnearthAbility(new ManaCostsImpl("{3}{B}")));
|
this.addAbility(new UnearthAbility(new ManaCostsImpl("{3}{B}")));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -28,9 +28,6 @@
|
||||||
package mage.sets.darkascension;
|
package mage.sets.darkascension;
|
||||||
|
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
import mage.constants.CardType;
|
|
||||||
import mage.constants.Rarity;
|
|
||||||
import mage.constants.Zone;
|
|
||||||
import mage.MageInt;
|
import mage.MageInt;
|
||||||
import mage.abilities.common.SimpleActivatedAbility;
|
import mage.abilities.common.SimpleActivatedAbility;
|
||||||
import mage.abilities.costs.common.ExileFromGraveCost;
|
import mage.abilities.costs.common.ExileFromGraveCost;
|
||||||
|
@ -39,6 +36,9 @@ import mage.abilities.costs.mana.ManaCostsImpl;
|
||||||
import mage.abilities.effects.common.CreateTokenEffect;
|
import mage.abilities.effects.common.CreateTokenEffect;
|
||||||
import mage.abilities.effects.common.counter.AddCountersAllEffect;
|
import mage.abilities.effects.common.counter.AddCountersAllEffect;
|
||||||
import mage.cards.CardImpl;
|
import mage.cards.CardImpl;
|
||||||
|
import mage.constants.CardType;
|
||||||
|
import mage.constants.Rarity;
|
||||||
|
import mage.constants.Zone;
|
||||||
import mage.counters.CounterType;
|
import mage.counters.CounterType;
|
||||||
import mage.filter.common.FilterControlledCreaturePermanent;
|
import mage.filter.common.FilterControlledCreaturePermanent;
|
||||||
import mage.filter.common.FilterCreatureCard;
|
import mage.filter.common.FilterCreatureCard;
|
||||||
|
@ -71,7 +71,7 @@ public class HavengulRunebinder extends CardImpl {
|
||||||
// {2}{U}, {tap}, Exile a creature card from your graveyard: Put a 2/2 black Zombie creature token onto the battlefield,
|
// {2}{U}, {tap}, Exile a creature card from your graveyard: Put a 2/2 black Zombie creature token onto the battlefield,
|
||||||
// then put a +1/+1 counter on each Zombie creature you control.
|
// then put a +1/+1 counter on each Zombie creature you control.
|
||||||
SimpleActivatedAbility ability = new SimpleActivatedAbility(Zone.BATTLEFIELD,
|
SimpleActivatedAbility ability = new SimpleActivatedAbility(Zone.BATTLEFIELD,
|
||||||
new CreateTokenEffect(new ZombieToken("ISD")),
|
new CreateTokenEffect(new ZombieToken()),
|
||||||
new ManaCostsImpl("{2}{U}"));
|
new ManaCostsImpl("{2}{U}"));
|
||||||
ability.addCost(new TapSourceCost());
|
ability.addCost(new TapSourceCost());
|
||||||
ability.addCost(new ExileFromGraveCost(new TargetCardInYourGraveyard(filter)));
|
ability.addCost(new ExileFromGraveCost(new TargetCardInYourGraveyard(filter)));
|
||||||
|
|
|
@ -19,8 +19,7 @@ public class ReapTheSeagraf extends CardImpl {
|
||||||
super(ownerId, 72, "Reap the Seagraf", Rarity.COMMON, new CardType[]{CardType.SORCERY}, "{2}{B}");
|
super(ownerId, 72, "Reap the Seagraf", Rarity.COMMON, new CardType[]{CardType.SORCERY}, "{2}{B}");
|
||||||
this.expansionSetCode = "DKA";
|
this.expansionSetCode = "DKA";
|
||||||
|
|
||||||
|
this.getSpellAbility().addEffect(new CreateTokenEffect(new ZombieToken()));
|
||||||
this.getSpellAbility().addEffect(new CreateTokenEffect(new ZombieToken("ISD")));
|
|
||||||
this.addAbility(new FlashbackAbility(new ManaCostsImpl("{4}{U}"), TimingRule.SORCERY));
|
this.addAbility(new FlashbackAbility(new ManaCostsImpl("{4}{U}"), TimingRule.SORCERY));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -44,6 +44,7 @@ import mage.game.permanent.token.ZombieToken;
|
||||||
* @author Loki
|
* @author Loki
|
||||||
*/
|
*/
|
||||||
public class Wakedancer extends CardImpl {
|
public class Wakedancer extends CardImpl {
|
||||||
|
|
||||||
private static final String staticText = "Morbid - When {this} enters the battlefield, if a creature died this turn, put a 2/2 black Zombie creature token onto the battlefield.";
|
private static final String staticText = "Morbid - When {this} enters the battlefield, if a creature died this turn, put a 2/2 black Zombie creature token onto the battlefield.";
|
||||||
|
|
||||||
public Wakedancer(UUID ownerId) {
|
public Wakedancer(UUID ownerId) {
|
||||||
|
@ -57,7 +58,7 @@ public class Wakedancer extends CardImpl {
|
||||||
this.toughness = new MageInt(2);
|
this.toughness = new MageInt(2);
|
||||||
|
|
||||||
// Morbid - When Wakedancer enters the battlefield, if a creature died this turn, put a 2/2 black Zombie creature token onto the battlefield.
|
// Morbid - When Wakedancer enters the battlefield, if a creature died this turn, put a 2/2 black Zombie creature token onto the battlefield.
|
||||||
TriggeredAbility ability = new EntersBattlefieldTriggeredAbility(new CreateTokenEffect(new ZombieToken("ISD")));
|
TriggeredAbility ability = new EntersBattlefieldTriggeredAbility(new CreateTokenEffect(new ZombieToken()));
|
||||||
this.addAbility(new ConditionalTriggeredAbility(ability, MorbidCondition.getInstance(), staticText));
|
this.addAbility(new ConditionalTriggeredAbility(ability, MorbidCondition.getInstance(), staticText));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -55,7 +55,7 @@ public class RakshasaGravecaller extends CardImpl {
|
||||||
this.addAbility(new ExploitAbility());
|
this.addAbility(new ExploitAbility());
|
||||||
|
|
||||||
// When Rakshasa Gravecaller exploits a creature, put two 2/2 black Zombie creature tokens onto the battlefield.
|
// When Rakshasa Gravecaller exploits a creature, put two 2/2 black Zombie creature tokens onto the battlefield.
|
||||||
this.addAbility(new ExploitCreatureTriggeredAbility(new CreateTokenEffect(new ZombieToken("DTK"), 2), false));
|
this.addAbility(new ExploitCreatureTriggeredAbility(new CreateTokenEffect(new ZombieToken(), 2), false));
|
||||||
}
|
}
|
||||||
|
|
||||||
public RakshasaGravecaller(final RakshasaGravecaller card) {
|
public RakshasaGravecaller(final RakshasaGravecaller card) {
|
||||||
|
|
|
@ -86,7 +86,7 @@ public class IbHalfheartGoblinTactician extends CardImpl {
|
||||||
// Sacrifice two Mountains: Put two 1/1 red Goblin creature tokens onto the battlefield.
|
// Sacrifice two Mountains: Put two 1/1 red Goblin creature tokens onto the battlefield.
|
||||||
this.addAbility(new SimpleActivatedAbility(
|
this.addAbility(new SimpleActivatedAbility(
|
||||||
Zone.BATTLEFIELD,
|
Zone.BATTLEFIELD,
|
||||||
new CreateTokenEffect(new GoblinToken(expansionSetCode), 2),
|
new CreateTokenEffect(new GoblinToken(), 2),
|
||||||
new SacrificeTargetCost(new TargetControlledPermanent(2, 2, filter, true))));
|
new SacrificeTargetCost(new TargetControlledPermanent(2, 2, filter, true))));
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -37,7 +37,6 @@ import mage.constants.Rarity;
|
||||||
import mage.constants.TimingRule;
|
import mage.constants.TimingRule;
|
||||||
import mage.game.permanent.token.ZombieToken;
|
import mage.game.permanent.token.ZombieToken;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author nantuko
|
* @author nantuko
|
||||||
*/
|
*/
|
||||||
|
@ -47,9 +46,8 @@ public class ArmyOfTheDamned extends CardImpl {
|
||||||
super(ownerId, 87, "Army of the Damned", Rarity.MYTHIC, new CardType[]{CardType.SORCERY}, "{5}{B}{B}{B}");
|
super(ownerId, 87, "Army of the Damned", Rarity.MYTHIC, new CardType[]{CardType.SORCERY}, "{5}{B}{B}{B}");
|
||||||
this.expansionSetCode = "ISD";
|
this.expansionSetCode = "ISD";
|
||||||
|
|
||||||
|
|
||||||
// Put thirteen 2/2 black Zombie creature tokens onto the battlefield tapped.
|
// Put thirteen 2/2 black Zombie creature tokens onto the battlefield tapped.
|
||||||
this.getSpellAbility().addEffect(new CreateTokenEffect(new ZombieToken("ISD"), 13, true, false));
|
this.getSpellAbility().addEffect(new CreateTokenEffect(new ZombieToken(), 13, true, false));
|
||||||
|
|
||||||
// Flashback {7}{B}{B}{B}
|
// Flashback {7}{B}{B}{B}
|
||||||
this.addAbility(new FlashbackAbility(new ManaCostsImpl("{7}{B}{B}{B}"), TimingRule.SORCERY));
|
this.addAbility(new FlashbackAbility(new ManaCostsImpl("{7}{B}{B}{B}"), TimingRule.SORCERY));
|
||||||
|
|
|
@ -28,10 +28,6 @@
|
||||||
package mage.sets.innistrad;
|
package mage.sets.innistrad;
|
||||||
|
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
import mage.constants.CardType;
|
|
||||||
import mage.constants.Outcome;
|
|
||||||
import mage.constants.Rarity;
|
|
||||||
import mage.constants.Zone;
|
|
||||||
import mage.abilities.Ability;
|
import mage.abilities.Ability;
|
||||||
import mage.abilities.common.SimpleActivatedAbility;
|
import mage.abilities.common.SimpleActivatedAbility;
|
||||||
import mage.abilities.costs.common.TapSourceCost;
|
import mage.abilities.costs.common.TapSourceCost;
|
||||||
|
@ -39,6 +35,10 @@ import mage.abilities.costs.mana.GenericManaCost;
|
||||||
import mage.abilities.effects.OneShotEffect;
|
import mage.abilities.effects.OneShotEffect;
|
||||||
import mage.cards.Card;
|
import mage.cards.Card;
|
||||||
import mage.cards.CardImpl;
|
import mage.cards.CardImpl;
|
||||||
|
import mage.constants.CardType;
|
||||||
|
import mage.constants.Outcome;
|
||||||
|
import mage.constants.Rarity;
|
||||||
|
import mage.constants.Zone;
|
||||||
import mage.game.Game;
|
import mage.game.Game;
|
||||||
import mage.game.permanent.token.ZombieToken;
|
import mage.game.permanent.token.ZombieToken;
|
||||||
import mage.players.Player;
|
import mage.players.Player;
|
||||||
|
@ -95,7 +95,7 @@ class CellarDoorEffect extends OneShotEffect {
|
||||||
if (card != null) {
|
if (card != null) {
|
||||||
player.moveCards(card, Zone.LIBRARY, Zone.GRAVEYARD, source, game);
|
player.moveCards(card, Zone.LIBRARY, Zone.GRAVEYARD, source, game);
|
||||||
if (card.getCardType().contains(CardType.CREATURE)) {
|
if (card.getCardType().contains(CardType.CREATURE)) {
|
||||||
ZombieToken token = new ZombieToken("ISD");
|
ZombieToken token = new ZombieToken();
|
||||||
token.putOntoBattlefield(1, game, source.getSourceId(), source.getControllerId());
|
token.putOntoBattlefield(1, game, source.getSourceId(), source.getControllerId());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -27,6 +27,7 @@
|
||||||
*/
|
*/
|
||||||
package mage.sets.innistrad;
|
package mage.sets.innistrad;
|
||||||
|
|
||||||
|
import java.util.UUID;
|
||||||
import mage.abilities.Ability;
|
import mage.abilities.Ability;
|
||||||
import mage.abilities.common.OnEventTriggeredAbility;
|
import mage.abilities.common.OnEventTriggeredAbility;
|
||||||
import mage.abilities.dynamicvalue.DynamicValue;
|
import mage.abilities.dynamicvalue.DynamicValue;
|
||||||
|
@ -41,8 +42,6 @@ import mage.game.Game;
|
||||||
import mage.game.events.GameEvent.EventType;
|
import mage.game.events.GameEvent.EventType;
|
||||||
import mage.game.permanent.token.ZombieToken;
|
import mage.game.permanent.token.ZombieToken;
|
||||||
|
|
||||||
import java.util.UUID;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* @author BetaSteward
|
* @author BetaSteward
|
||||||
|
@ -53,11 +52,10 @@ public class EndlessRanksOfTheDead extends CardImpl {
|
||||||
super(ownerId, 99, "Endless Ranks of the Dead", Rarity.RARE, new CardType[]{CardType.ENCHANTMENT}, "{2}{B}{B}");
|
super(ownerId, 99, "Endless Ranks of the Dead", Rarity.RARE, new CardType[]{CardType.ENCHANTMENT}, "{2}{B}{B}");
|
||||||
this.expansionSetCode = "ISD";
|
this.expansionSetCode = "ISD";
|
||||||
|
|
||||||
|
|
||||||
// At the beginning of your upkeep, put X 2/2 black Zombie creature tokens onto the battlefield,
|
// At the beginning of your upkeep, put X 2/2 black Zombie creature tokens onto the battlefield,
|
||||||
// where X is half the number of Zombies you control, rounded down.
|
// where X is half the number of Zombies you control, rounded down.
|
||||||
this.addAbility(new OnEventTriggeredAbility(EventType.UPKEEP_STEP_PRE, "beginning of your upkeep",
|
this.addAbility(new OnEventTriggeredAbility(EventType.UPKEEP_STEP_PRE, "beginning of your upkeep",
|
||||||
new CreateTokenEffect(new ZombieToken("ISD"), new HalfZombiesCount())));
|
new CreateTokenEffect(new ZombieToken(), new HalfZombiesCount())));
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -47,9 +47,8 @@ public class MoanOfTheUnhallowed extends CardImpl {
|
||||||
super(ownerId, 109, "Moan of the Unhallowed", Rarity.UNCOMMON, new CardType[]{CardType.SORCERY}, "{2}{B}{B}");
|
super(ownerId, 109, "Moan of the Unhallowed", Rarity.UNCOMMON, new CardType[]{CardType.SORCERY}, "{2}{B}{B}");
|
||||||
this.expansionSetCode = "ISD";
|
this.expansionSetCode = "ISD";
|
||||||
|
|
||||||
|
|
||||||
// Put two 2/2 black Zombie creature tokens onto the battlefield.
|
// Put two 2/2 black Zombie creature tokens onto the battlefield.
|
||||||
this.getSpellAbility().addEffect(new CreateTokenEffect(new ZombieToken("ISD"), 2));
|
this.getSpellAbility().addEffect(new CreateTokenEffect(new ZombieToken(), 2));
|
||||||
|
|
||||||
// Flashback {5}{B}{B}
|
// Flashback {5}{B}{B}
|
||||||
this.addAbility(new FlashbackAbility(new ManaCostsImpl("{5}{B}{B}"), TimingRule.SORCERY));
|
this.addAbility(new FlashbackAbility(new ManaCostsImpl("{5}{B}{B}"), TimingRule.SORCERY));
|
||||||
|
|
|
@ -86,7 +86,7 @@ class UndeadAlchemistTriggeredAbility extends TriggeredAbilityImpl {
|
||||||
|
|
||||||
public UndeadAlchemistTriggeredAbility() {
|
public UndeadAlchemistTriggeredAbility() {
|
||||||
super(Zone.BATTLEFIELD, new ExileTargetEffect(), true);
|
super(Zone.BATTLEFIELD, new ExileTargetEffect(), true);
|
||||||
this.addEffect(new CreateTokenEffect(new ZombieToken("ISD")));
|
this.addEffect(new CreateTokenEffect(new ZombieToken()));
|
||||||
}
|
}
|
||||||
|
|
||||||
public UndeadAlchemistTriggeredAbility(final UndeadAlchemistTriggeredAbility ability) {
|
public UndeadAlchemistTriggeredAbility(final UndeadAlchemistTriggeredAbility ability) {
|
||||||
|
|
|
@ -44,9 +44,8 @@ public class HordelingOutburst extends CardImpl {
|
||||||
super(ownerId, 111, "Hordeling Outburst", Rarity.UNCOMMON, new CardType[]{CardType.SORCERY}, "{1}{R}{R}");
|
super(ownerId, 111, "Hordeling Outburst", Rarity.UNCOMMON, new CardType[]{CardType.SORCERY}, "{1}{R}{R}");
|
||||||
this.expansionSetCode = "KTK";
|
this.expansionSetCode = "KTK";
|
||||||
|
|
||||||
|
|
||||||
// Put 3 1/1 red Goblin creature tokens onto the battlefield.
|
// Put 3 1/1 red Goblin creature tokens onto the battlefield.
|
||||||
this.getSpellAbility().addEffect(new CreateTokenEffect(new GoblinToken(expansionSetCode), 3));
|
this.getSpellAbility().addEffect(new CreateTokenEffect(new GoblinToken(), 3));
|
||||||
}
|
}
|
||||||
|
|
||||||
public HordelingOutburst(final HordelingOutburst card) {
|
public HordelingOutburst(final HordelingOutburst card) {
|
||||||
|
|
|
@ -64,9 +64,8 @@ public class MarduAscendancy extends CardImpl {
|
||||||
super(ownerId, 185, "Mardu Ascendancy", Rarity.RARE, new CardType[]{CardType.ENCHANTMENT}, "{R}{W}{B}");
|
super(ownerId, 185, "Mardu Ascendancy", Rarity.RARE, new CardType[]{CardType.ENCHANTMENT}, "{R}{W}{B}");
|
||||||
this.expansionSetCode = "KTK";
|
this.expansionSetCode = "KTK";
|
||||||
|
|
||||||
|
|
||||||
// Whenever a nontoken creature you control attacks, put a 1/1 red Goblin creature token onto the battlefield tapped and attacking.
|
// Whenever a nontoken creature you control attacks, put a 1/1 red Goblin creature token onto the battlefield tapped and attacking.
|
||||||
this.addAbility(new AttacksCreatureYouControlTriggeredAbility(new CreateTokenEffect(new GoblinToken(expansionSetCode), 1, true, true), false, attackFilter));
|
this.addAbility(new AttacksCreatureYouControlTriggeredAbility(new CreateTokenEffect(new GoblinToken(), 1, true, true), false, attackFilter));
|
||||||
|
|
||||||
// Sacrifice Mardu Ascendancy: Creatures you control get +0/+3 until end of turn.
|
// Sacrifice Mardu Ascendancy: Creatures you control get +0/+3 until end of turn.
|
||||||
this.addAbility(new SimpleActivatedAbility(Zone.BATTLEFIELD, new BoostAllEffect(0, 3, Duration.EndOfTurn, filter, false),
|
this.addAbility(new SimpleActivatedAbility(Zone.BATTLEFIELD, new BoostAllEffect(0, 3, Duration.EndOfTurn, filter, false),
|
||||||
|
|
|
@ -60,7 +60,7 @@ public class PonybackBrigade extends CardImpl {
|
||||||
this.toughness = new MageInt(2);
|
this.toughness = new MageInt(2);
|
||||||
|
|
||||||
// When Ponyback Brigade enters the battlefield or is turned face up, put three 1/1 red Goblin creature tokens onto the battlefield.
|
// When Ponyback Brigade enters the battlefield or is turned face up, put three 1/1 red Goblin creature tokens onto the battlefield.
|
||||||
this.addAbility(new PonybackBrigadeAbility(new GoblinToken(expansionSetCode)));
|
this.addAbility(new PonybackBrigadeAbility(new GoblinToken()));
|
||||||
|
|
||||||
// Morph {2}{R}{W}{B}
|
// Morph {2}{R}{W}{B}
|
||||||
this.addAbility(new MorphAbility(this, new ManaCostsImpl("{2}{R}{W}{B}")));
|
this.addAbility(new MorphAbility(this, new ManaCostsImpl("{2}{R}{W}{B}")));
|
||||||
|
|
|
@ -112,7 +112,7 @@ class SidisiBroodTyrantAbility extends TriggeredAbilityImpl {
|
||||||
class SidisiBroodTyrantTriggeredAbility extends TriggeredAbilityImpl {
|
class SidisiBroodTyrantTriggeredAbility extends TriggeredAbilityImpl {
|
||||||
|
|
||||||
public SidisiBroodTyrantTriggeredAbility() {
|
public SidisiBroodTyrantTriggeredAbility() {
|
||||||
super(Zone.BATTLEFIELD, new CreateTokenEffect(new ZombieToken("KTK")), false);
|
super(Zone.BATTLEFIELD, new CreateTokenEffect(new ZombieToken()), false);
|
||||||
}
|
}
|
||||||
|
|
||||||
public SidisiBroodTyrantTriggeredAbility(final SidisiBroodTyrantTriggeredAbility ability) {
|
public SidisiBroodTyrantTriggeredAbility(final SidisiBroodTyrantTriggeredAbility ability) {
|
||||||
|
@ -142,7 +142,6 @@ class SidisiBroodTyrantTriggeredAbility extends TriggeredAbilityImpl {
|
||||||
return new SidisiBroodTyrantTriggeredAbility(this);
|
return new SidisiBroodTyrantTriggeredAbility(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getRule() {
|
public String getRule() {
|
||||||
return "Whenever one or more creature cards are put into your graveyard from your library, put a 2/2 black Zombie creature token onto the battlefield.";
|
return "Whenever one or more creature cards are put into your graveyard from your library, put a 2/2 black Zombie creature token onto the battlefield.";
|
||||||
|
|
|
@ -25,7 +25,6 @@
|
||||||
* authors and should not be interpreted as representing official policies, either expressed
|
* authors and should not be interpreted as representing official policies, either expressed
|
||||||
* or implied, of BetaSteward_at_googlemail.com.
|
* or implied, of BetaSteward_at_googlemail.com.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package mage.sets.magic2011;
|
package mage.sets.magic2011;
|
||||||
|
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
|
@ -74,7 +73,7 @@ public class GraveTitan extends CardImpl {
|
||||||
class GraveTitanAbility extends TriggeredAbilityImpl {
|
class GraveTitanAbility extends TriggeredAbilityImpl {
|
||||||
|
|
||||||
public GraveTitanAbility() {
|
public GraveTitanAbility() {
|
||||||
super(Zone.BATTLEFIELD, new CreateTokenEffect(new ZombieToken("M11"), 2), false);
|
super(Zone.BATTLEFIELD, new CreateTokenEffect(new ZombieToken(), 2), false);
|
||||||
}
|
}
|
||||||
|
|
||||||
public GraveTitanAbility(final GraveTitanAbility ability) {
|
public GraveTitanAbility(final GraveTitanAbility ability) {
|
||||||
|
|
|
@ -25,7 +25,6 @@
|
||||||
* authors and should not be interpreted as representing official policies, either expressed
|
* authors and should not be interpreted as representing official policies, either expressed
|
||||||
* or implied, of BetaSteward_at_googlemail.com.
|
* or implied, of BetaSteward_at_googlemail.com.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package mage.sets.magic2012;
|
package mage.sets.magic2012;
|
||||||
|
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
|
@ -73,7 +72,7 @@ public class CemeteryReaper extends CardImpl {
|
||||||
// {2}{B}, {T} : Exile target creature card from a graveyard. Put a 2/2 black Zombie creature token onto the battlefield.
|
// {2}{B}, {T} : Exile target creature card from a graveyard. Put a 2/2 black Zombie creature token onto the battlefield.
|
||||||
Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new ExileTargetEffect(), new ManaCostsImpl("{2}{B}"));
|
Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new ExileTargetEffect(), new ManaCostsImpl("{2}{B}"));
|
||||||
ability.addCost(new TapSourceCost());
|
ability.addCost(new TapSourceCost());
|
||||||
ability.addEffect(new CreateTokenEffect(new ZombieToken("M12")));
|
ability.addEffect(new CreateTokenEffect(new ZombieToken()));
|
||||||
ability.addTarget(new TargetCardInGraveyard(new FilterCreatureCard("creature card from a graveyard")));
|
ability.addTarget(new TargetCardInGraveyard(new FilterCreatureCard("creature card from a graveyard")));
|
||||||
this.addAbility(ability);
|
this.addAbility(ability);
|
||||||
}
|
}
|
||||||
|
|
|
@ -28,13 +28,13 @@
|
||||||
package mage.sets.magic2012;
|
package mage.sets.magic2012;
|
||||||
|
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
import mage.constants.CardType;
|
|
||||||
import mage.constants.Rarity;
|
|
||||||
import mage.constants.Zone;
|
|
||||||
import mage.abilities.common.SimpleActivatedAbility;
|
import mage.abilities.common.SimpleActivatedAbility;
|
||||||
import mage.abilities.costs.common.DiscardTargetCost;
|
import mage.abilities.costs.common.DiscardTargetCost;
|
||||||
import mage.abilities.effects.common.CreateTokenEffect;
|
import mage.abilities.effects.common.CreateTokenEffect;
|
||||||
import mage.cards.CardImpl;
|
import mage.cards.CardImpl;
|
||||||
|
import mage.constants.CardType;
|
||||||
|
import mage.constants.Rarity;
|
||||||
|
import mage.constants.Zone;
|
||||||
import mage.filter.FilterCard;
|
import mage.filter.FilterCard;
|
||||||
import mage.game.permanent.token.ZombieToken;
|
import mage.game.permanent.token.ZombieToken;
|
||||||
import mage.target.common.TargetCardInHand;
|
import mage.target.common.TargetCardInHand;
|
||||||
|
@ -49,10 +49,9 @@ public class ZombieInfestation extends CardImpl {
|
||||||
super(ownerId, 120, "Zombie Infestation", Rarity.UNCOMMON, new CardType[]{CardType.ENCHANTMENT}, "{1}{B}");
|
super(ownerId, 120, "Zombie Infestation", Rarity.UNCOMMON, new CardType[]{CardType.ENCHANTMENT}, "{1}{B}");
|
||||||
this.expansionSetCode = "M12";
|
this.expansionSetCode = "M12";
|
||||||
|
|
||||||
|
|
||||||
// Discard two cards: Put a 2/2 black Zombie creature token onto the battlefield.
|
// Discard two cards: Put a 2/2 black Zombie creature token onto the battlefield.
|
||||||
SimpleActivatedAbility ability = new SimpleActivatedAbility(Zone.BATTLEFIELD,
|
SimpleActivatedAbility ability = new SimpleActivatedAbility(Zone.BATTLEFIELD,
|
||||||
new CreateTokenEffect(new ZombieToken("M12")),
|
new CreateTokenEffect(new ZombieToken()),
|
||||||
new DiscardTargetCost(new TargetCardInHand(2, new FilterCard("two cards"))));
|
new DiscardTargetCost(new TargetCardInHand(2, new FilterCard("two cards"))));
|
||||||
this.addAbility(ability);
|
this.addAbility(ability);
|
||||||
}
|
}
|
||||||
|
|
|
@ -37,8 +37,6 @@ import mage.filter.common.FilterCreatureCard;
|
||||||
import mage.game.permanent.token.ZombieToken;
|
import mage.game.permanent.token.ZombieToken;
|
||||||
import mage.target.common.TargetCardInGraveyard;
|
import mage.target.common.TargetCardInGraveyard;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* @author North
|
* @author North
|
||||||
|
@ -49,13 +47,12 @@ public class VileRebirth extends CardImpl {
|
||||||
super(ownerId, 115, "Vile Rebirth", Rarity.COMMON, new CardType[]{CardType.INSTANT}, "{B}");
|
super(ownerId, 115, "Vile Rebirth", Rarity.COMMON, new CardType[]{CardType.INSTANT}, "{B}");
|
||||||
this.expansionSetCode = "M13";
|
this.expansionSetCode = "M13";
|
||||||
|
|
||||||
|
|
||||||
// Exile target creature card from a graveyard.
|
// Exile target creature card from a graveyard.
|
||||||
this.getSpellAbility().addEffect(new ExileTargetEffect());
|
this.getSpellAbility().addEffect(new ExileTargetEffect());
|
||||||
this.getSpellAbility().addTarget(new TargetCardInGraveyard(new FilterCreatureCard("creature card from a graveyard")));
|
this.getSpellAbility().addTarget(new TargetCardInGraveyard(new FilterCreatureCard("creature card from a graveyard")));
|
||||||
|
|
||||||
// Put a 2/2 black Zombie creature token onto the battlefield.
|
// Put a 2/2 black Zombie creature token onto the battlefield.
|
||||||
this.getSpellAbility().addEffect(new CreateTokenEffect(new ZombieToken("M13")));
|
this.getSpellAbility().addEffect(new CreateTokenEffect(new ZombieToken()));
|
||||||
}
|
}
|
||||||
|
|
||||||
public VileRebirth(final VileRebirth card) {
|
public VileRebirth(final VileRebirth card) {
|
||||||
|
|
|
@ -58,7 +58,7 @@ public class LilianasReaver extends CardImpl {
|
||||||
// Whenever Liliana's Reaver deals combat damage to a player, that player discards a card and you put a 2/2 black Zombie creature token onto the battlefield tapped.
|
// Whenever Liliana's Reaver deals combat damage to a player, that player discards a card and you put a 2/2 black Zombie creature token onto the battlefield tapped.
|
||||||
|
|
||||||
Ability ability = new DealsCombatDamageToAPlayerTriggeredAbility(new DiscardTargetEffect(1), false, true);
|
Ability ability = new DealsCombatDamageToAPlayerTriggeredAbility(new DiscardTargetEffect(1), false, true);
|
||||||
ability.addEffect(new CreateTokenEffect(new ZombieToken("M14"), 1, true, false));
|
ability.addEffect(new CreateTokenEffect(new ZombieToken(), 1, true, false));
|
||||||
this.addAbility(ability);
|
this.addAbility(ability);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -49,6 +49,7 @@ import mage.game.permanent.token.ZombieToken;
|
||||||
public class XathridNecromancer extends CardImpl {
|
public class XathridNecromancer extends CardImpl {
|
||||||
|
|
||||||
private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("Human creature you control");
|
private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("Human creature you control");
|
||||||
|
|
||||||
static {
|
static {
|
||||||
filter.add(new ControllerPredicate(TargetController.YOU));
|
filter.add(new ControllerPredicate(TargetController.YOU));
|
||||||
filter.add(new SubtypePredicate("Human"));
|
filter.add(new SubtypePredicate("Human"));
|
||||||
|
@ -64,7 +65,7 @@ public class XathridNecromancer extends CardImpl {
|
||||||
this.toughness = new MageInt(2);
|
this.toughness = new MageInt(2);
|
||||||
|
|
||||||
// Whenever Xathrid Necromancer or another Human creature you control dies, put a 2/2 black Zombie creature token onto the battlefield tapped.
|
// Whenever Xathrid Necromancer or another Human creature you control dies, put a 2/2 black Zombie creature token onto the battlefield tapped.
|
||||||
Effect effect = new CreateTokenEffect(new ZombieToken("M14"), 1, true, false);
|
Effect effect = new CreateTokenEffect(new ZombieToken(), 1, true, false);
|
||||||
Ability ability = new DiesThisOrAnotherCreatureTriggeredAbility(effect, false, filter);
|
Ability ability = new DiesThisOrAnotherCreatureTriggeredAbility(effect, false, filter);
|
||||||
this.addAbility(ability);
|
this.addAbility(ability);
|
||||||
|
|
||||||
|
|
|
@ -45,11 +45,10 @@ public class FeralIncarnation extends CardImpl {
|
||||||
super(ownerId, 174, "Feral Incarnation", Rarity.UNCOMMON, new CardType[]{CardType.SORCERY}, "{8}{G}");
|
super(ownerId, 174, "Feral Incarnation", Rarity.UNCOMMON, new CardType[]{CardType.SORCERY}, "{8}{G}");
|
||||||
this.expansionSetCode = "M15";
|
this.expansionSetCode = "M15";
|
||||||
|
|
||||||
|
|
||||||
// Convoke
|
// Convoke
|
||||||
this.addAbility(new ConvokeAbility());
|
this.addAbility(new ConvokeAbility());
|
||||||
// Put three 3/3 green Beast creature tokens onto the battlefield.
|
// Put three 3/3 green Beast creature tokens onto the battlefield.
|
||||||
this.getSpellAbility().addEffect(new CreateTokenEffect(new BeastToken("M15", 1), 3));
|
this.getSpellAbility().addEffect(new CreateTokenEffect(new BeastToken(), 3));
|
||||||
}
|
}
|
||||||
|
|
||||||
public FeralIncarnation(final FeralIncarnation card) {
|
public FeralIncarnation(final FeralIncarnation card) {
|
||||||
|
|
|
@ -27,6 +27,7 @@
|
||||||
*/
|
*/
|
||||||
package mage.sets.magic2015;
|
package mage.sets.magic2015;
|
||||||
|
|
||||||
|
import java.util.UUID;
|
||||||
import mage.abilities.Ability;
|
import mage.abilities.Ability;
|
||||||
import mage.abilities.common.SimpleActivatedAbility;
|
import mage.abilities.common.SimpleActivatedAbility;
|
||||||
import mage.abilities.costs.CostImpl;
|
import mage.abilities.costs.CostImpl;
|
||||||
|
@ -47,8 +48,6 @@ import mage.game.permanent.token.ZombieToken;
|
||||||
import mage.players.Player;
|
import mage.players.Player;
|
||||||
import mage.target.common.TargetCardInHand;
|
import mage.target.common.TargetCardInHand;
|
||||||
|
|
||||||
import java.util.UUID;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author noxx
|
* @author noxx
|
||||||
*/
|
*/
|
||||||
|
@ -60,7 +59,6 @@ public class NecromancersStockpile extends CardImpl {
|
||||||
super(ownerId, 108, "Necromancer's Stockpile", Rarity.RARE, new CardType[]{CardType.ENCHANTMENT}, "{1}{B}");
|
super(ownerId, 108, "Necromancer's Stockpile", Rarity.RARE, new CardType[]{CardType.ENCHANTMENT}, "{1}{B}");
|
||||||
this.expansionSetCode = "M15";
|
this.expansionSetCode = "M15";
|
||||||
|
|
||||||
|
|
||||||
// {1}{B}, Discard a creature card: Draw a card.
|
// {1}{B}, Discard a creature card: Draw a card.
|
||||||
// If the discarded card was a Zombie card, put a 2/2 black Zombie creature token onto the battlefield tapped.
|
// If the discarded card was a Zombie card, put a 2/2 black Zombie creature token onto the battlefield tapped.
|
||||||
Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new DrawCardSourceControllerEffect(1), new ManaCostsImpl("{1}{B}"));
|
Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new DrawCardSourceControllerEffect(1), new ManaCostsImpl("{1}{B}"));
|
||||||
|
@ -127,6 +125,7 @@ class NecromancersStockpileDiscardTargetCost extends CostImpl {
|
||||||
}
|
}
|
||||||
|
|
||||||
class NecromancersStockpilePutTokenEffect extends OneShotEffect {
|
class NecromancersStockpilePutTokenEffect extends OneShotEffect {
|
||||||
|
|
||||||
NecromancersStockpilePutTokenEffect() {
|
NecromancersStockpilePutTokenEffect() {
|
||||||
super(Outcome.Neutral);
|
super(Outcome.Neutral);
|
||||||
staticText = "If the discarded card was a Zombie card, put a 2/2 black Zombie creature token onto the battlefield tapped";
|
staticText = "If the discarded card was a Zombie card, put a 2/2 black Zombie creature token onto the battlefield tapped";
|
||||||
|
@ -140,7 +139,7 @@ class NecromancersStockpilePutTokenEffect extends OneShotEffect {
|
||||||
public boolean apply(Game game, Ability source) {
|
public boolean apply(Game game, Ability source) {
|
||||||
NecromancersStockpileDiscardTargetCost cost = (NecromancersStockpileDiscardTargetCost) source.getCosts().get(0);
|
NecromancersStockpileDiscardTargetCost cost = (NecromancersStockpileDiscardTargetCost) source.getCosts().get(0);
|
||||||
if (cost != null && cost.isZombieCard()) {
|
if (cost != null && cost.isZombieCard()) {
|
||||||
new CreateTokenEffect(new ZombieToken("M15"), 1, true, false).apply(game, source);
|
new CreateTokenEffect(new ZombieToken(), 1, true, false).apply(game, source);
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -150,4 +149,3 @@ class NecromancersStockpilePutTokenEffect extends OneShotEffect {
|
||||||
return new NecromancersStockpilePutTokenEffect(this);
|
return new NecromancersStockpilePutTokenEffect(this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -58,9 +58,9 @@ public class SoulOfZendikar extends CardImpl {
|
||||||
// Reach
|
// Reach
|
||||||
this.addAbility(ReachAbility.getInstance());
|
this.addAbility(ReachAbility.getInstance());
|
||||||
// {3}{G}{G}: Put a 3/3 green Beast creature token onto the battlefield.
|
// {3}{G}{G}: Put a 3/3 green Beast creature token onto the battlefield.
|
||||||
this.addAbility(new SimpleActivatedAbility(Zone.BATTLEFIELD, new CreateTokenEffect(new BeastToken("M15")), new ManaCostsImpl("{3}{G}{G}")));
|
this.addAbility(new SimpleActivatedAbility(Zone.BATTLEFIELD, new CreateTokenEffect(new BeastToken()), new ManaCostsImpl("{3}{G}{G}")));
|
||||||
// {3}{G}{G}, Exile Soul of Zendikar from your graveyard: Put a 3/3 green Beast creature token onto the battlefield.
|
// {3}{G}{G}, Exile Soul of Zendikar from your graveyard: Put a 3/3 green Beast creature token onto the battlefield.
|
||||||
Ability ability = new SimpleActivatedAbility(Zone.GRAVEYARD, new CreateTokenEffect(new BeastToken("M15")), new ManaCostsImpl("{3}{G}{G}"));
|
Ability ability = new SimpleActivatedAbility(Zone.GRAVEYARD, new CreateTokenEffect(new BeastToken()), new ManaCostsImpl("{3}{G}{G}"));
|
||||||
ability.addCost(new ExileSourceFromGraveCost());
|
ability.addCost(new ExileSourceFromGraveCost());
|
||||||
this.addAbility(ability);
|
this.addAbility(ability);
|
||||||
}
|
}
|
||||||
|
|
|
@ -53,7 +53,6 @@ public class WasteNot extends CardImpl {
|
||||||
super(ownerId, 122, "Waste Not", Rarity.RARE, new CardType[]{CardType.ENCHANTMENT}, "{1}{B}");
|
super(ownerId, 122, "Waste Not", Rarity.RARE, new CardType[]{CardType.ENCHANTMENT}, "{1}{B}");
|
||||||
this.expansionSetCode = "M15";
|
this.expansionSetCode = "M15";
|
||||||
|
|
||||||
|
|
||||||
// Whenever an opponent discards a creature card, put a 2/2 black Zombie creature token onto the battlefield.
|
// Whenever an opponent discards a creature card, put a 2/2 black Zombie creature token onto the battlefield.
|
||||||
this.addAbility(new WasteNotCreatureTriggeredAbility());
|
this.addAbility(new WasteNotCreatureTriggeredAbility());
|
||||||
|
|
||||||
|
@ -77,7 +76,7 @@ public class WasteNot extends CardImpl {
|
||||||
class WasteNotCreatureTriggeredAbility extends TriggeredAbilityImpl {
|
class WasteNotCreatureTriggeredAbility extends TriggeredAbilityImpl {
|
||||||
|
|
||||||
WasteNotCreatureTriggeredAbility() {
|
WasteNotCreatureTriggeredAbility() {
|
||||||
super(Zone.BATTLEFIELD, new CreateTokenEffect(new ZombieToken("M15")), false);
|
super(Zone.BATTLEFIELD, new CreateTokenEffect(new ZombieToken()), false);
|
||||||
}
|
}
|
||||||
|
|
||||||
WasteNotCreatureTriggeredAbility(final WasteNotCreatureTriggeredAbility ability) {
|
WasteNotCreatureTriggeredAbility(final WasteNotCreatureTriggeredAbility ability) {
|
||||||
|
|
|
@ -55,7 +55,7 @@ public class AspiringAeronaut extends CardImpl {
|
||||||
this.addAbility(FlyingAbility.getInstance());
|
this.addAbility(FlyingAbility.getInstance());
|
||||||
|
|
||||||
// When Aspiring Aeronaut enters the battlefield, put a 1/1 colorless Thopter artifact creature token with flying onto the battlefield.
|
// When Aspiring Aeronaut enters the battlefield, put a 1/1 colorless Thopter artifact creature token with flying onto the battlefield.
|
||||||
this.addAbility(new EntersBattlefieldTriggeredAbility(new CreateTokenEffect(new ThopterColorlessToken("ORI"))));
|
this.addAbility(new EntersBattlefieldTriggeredAbility(new CreateTokenEffect(new ThopterColorlessToken())));
|
||||||
}
|
}
|
||||||
|
|
||||||
public AspiringAeronaut(final AspiringAeronaut card) {
|
public AspiringAeronaut(final AspiringAeronaut card) {
|
||||||
|
|
|
@ -44,7 +44,7 @@ import mage.game.permanent.token.ThopterColorlessToken;
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* @author LoneFox
|
* @author LoneFox
|
||||||
|
*
|
||||||
*/
|
*/
|
||||||
public class FoundryOfTheConsuls extends CardImpl {
|
public class FoundryOfTheConsuls extends CardImpl {
|
||||||
|
|
||||||
|
@ -55,7 +55,7 @@ public class FoundryOfTheConsuls extends CardImpl {
|
||||||
// {T}: Add {1} to your mana pool.
|
// {T}: Add {1} to your mana pool.
|
||||||
this.addAbility(new ColorlessManaAbility());
|
this.addAbility(new ColorlessManaAbility());
|
||||||
// {5}, {T}, Sacrifice Foundry of the Consuls: Put two 1/1 colorless Thopter artifact creature tokens with flying onto the battlefield.
|
// {5}, {T}, Sacrifice Foundry of the Consuls: Put two 1/1 colorless Thopter artifact creature tokens with flying onto the battlefield.
|
||||||
Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new CreateTokenEffect(new ThopterColorlessToken("ORI"), 2),
|
Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new CreateTokenEffect(new ThopterColorlessToken(), 2),
|
||||||
new ManaCostsImpl("{5}"));
|
new ManaCostsImpl("{5}"));
|
||||||
ability.addCost(new TapSourceCost());
|
ability.addCost(new TapSourceCost());
|
||||||
ability.addCost(new SacrificeSourceCost());
|
ability.addCost(new SacrificeSourceCost());
|
||||||
|
|
|
@ -79,7 +79,7 @@ public class GideonsPhalanx extends CardImpl {
|
||||||
class GideonsPhalanxKnightToken extends Token {
|
class GideonsPhalanxKnightToken extends Token {
|
||||||
|
|
||||||
public GideonsPhalanxKnightToken() {
|
public GideonsPhalanxKnightToken() {
|
||||||
super("Soldier", "2/2 white Knight creature tokens with vigilance");
|
super("Knight", "2/2 white Knight creature tokens with vigilance");
|
||||||
this.setOriginalExpansionSetCode("ORI");
|
this.setOriginalExpansionSetCode("ORI");
|
||||||
cardType.add(CardType.CREATURE);
|
cardType.add(CardType.CREATURE);
|
||||||
color.setColor(ObjectColor.WHITE);
|
color.setColor(ObjectColor.WHITE);
|
||||||
|
|
|
@ -68,7 +68,7 @@ public class HangarbackWalker extends CardImpl {
|
||||||
this.addAbility(new EntersBattlefieldAbility(new HangarbackWalkerEffect(), "with X +1/+1 counters on it"));
|
this.addAbility(new EntersBattlefieldAbility(new HangarbackWalkerEffect(), "with X +1/+1 counters on it"));
|
||||||
|
|
||||||
// When Hangarback Walker dies, put a 1/1 colorless Thopter artifact creature token with flying onto the battlefield for each +1/+1 counter on Hangarback Walker.
|
// When Hangarback Walker dies, put a 1/1 colorless Thopter artifact creature token with flying onto the battlefield for each +1/+1 counter on Hangarback Walker.
|
||||||
this.addAbility(new DiesTriggeredAbility(new CreateTokenEffect(new ThopterColorlessToken("ORI"), new CountersCount(CounterType.P1P1)), false));
|
this.addAbility(new DiesTriggeredAbility(new CreateTokenEffect(new ThopterColorlessToken(), new CountersCount(CounterType.P1P1)), false));
|
||||||
|
|
||||||
// {1}, {t}: Put a +1/+1 counter on Hangarback Walker.
|
// {1}, {t}: Put a +1/+1 counter on Hangarback Walker.
|
||||||
Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new AddCountersSourceEffect(CounterType.P1P1.createInstance()), new GenericManaCost(1));
|
Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new AddCountersSourceEffect(CounterType.P1P1.createInstance()), new GenericManaCost(1));
|
||||||
|
|
|
@ -50,6 +50,7 @@ import mage.constants.Outcome;
|
||||||
import mage.constants.Rarity;
|
import mage.constants.Rarity;
|
||||||
import mage.constants.Zone;
|
import mage.constants.Zone;
|
||||||
import mage.counters.CounterType;
|
import mage.counters.CounterType;
|
||||||
|
import mage.filter.FilterSpell;
|
||||||
import mage.filter.common.FilterInstantOrSorceryCard;
|
import mage.filter.common.FilterInstantOrSorceryCard;
|
||||||
import mage.game.Game;
|
import mage.game.Game;
|
||||||
import mage.game.command.Emblem;
|
import mage.game.command.Emblem;
|
||||||
|
@ -212,7 +213,7 @@ class JaceTelepathUnboundEmblem extends Emblem {
|
||||||
this.setName("Emblem - Jace");
|
this.setName("Emblem - Jace");
|
||||||
Effect effect = new PutTopCardOfLibraryIntoGraveTargetEffect(5);
|
Effect effect = new PutTopCardOfLibraryIntoGraveTargetEffect(5);
|
||||||
effect.setText("target opponent puts the top five cards of his or her library into his or her graveyard");
|
effect.setText("target opponent puts the top five cards of his or her library into his or her graveyard");
|
||||||
Ability ability = new SpellCastControllerTriggeredAbility(effect, false);
|
Ability ability = new SpellCastControllerTriggeredAbility(Zone.COMMAND, effect, new FilterSpell("a spell"), false, false);
|
||||||
ability.addTarget(new TargetOpponent());
|
ability.addTarget(new TargetOpponent());
|
||||||
getAbilities().add(ability);
|
getAbilities().add(ability);
|
||||||
}
|
}
|
||||||
|
|
|
@ -77,7 +77,7 @@ public class LilianaHereticalHealer extends CardImpl {
|
||||||
|
|
||||||
// Whenever another nontoken creature you control dies, exile Liliana Heretical Healer, then return her to the battlefield transformed under her owner's control. If you do, put a 2/2 black Zombie creature token onto the battlefield.
|
// Whenever another nontoken creature you control dies, exile Liliana Heretical Healer, then return her to the battlefield transformed under her owner's control. If you do, put a 2/2 black Zombie creature token onto the battlefield.
|
||||||
this.addAbility(new DiesCreatureTriggeredAbility(new ExileAndReturnTransformedSourceEffect(ExileAndReturnTransformedSourceEffect.Gender.FEMAL,
|
this.addAbility(new DiesCreatureTriggeredAbility(new ExileAndReturnTransformedSourceEffect(ExileAndReturnTransformedSourceEffect.Gender.FEMAL,
|
||||||
new CreateTokenEffect(new ZombieToken(expansionSetCode))), false, filter));
|
new CreateTokenEffect(new ZombieToken())), false, filter));
|
||||||
}
|
}
|
||||||
|
|
||||||
public LilianaHereticalHealer(final LilianaHereticalHealer card) {
|
public LilianaHereticalHealer(final LilianaHereticalHealer card) {
|
||||||
|
|
|
@ -61,7 +61,7 @@ public class PiaAndKiranNalaar extends CardImpl {
|
||||||
this.toughness = new MageInt(2);
|
this.toughness = new MageInt(2);
|
||||||
|
|
||||||
// When Pia and Kiran Nalaar enters the battlefield put 2 1/1 colorless Thopter artifact creature tokens with flying onto the battlefield.
|
// When Pia and Kiran Nalaar enters the battlefield put 2 1/1 colorless Thopter artifact creature tokens with flying onto the battlefield.
|
||||||
this.addAbility(new EntersBattlefieldTriggeredAbility(new CreateTokenEffect(new ThopterColorlessToken("ORI"), 2)));
|
this.addAbility(new EntersBattlefieldTriggeredAbility(new CreateTokenEffect(new ThopterColorlessToken(), 2)));
|
||||||
|
|
||||||
// {2}{R}, Sacrifice an artifact: Pia and Kiran Nalaar deals 2 damage to target creature or player.
|
// {2}{R}, Sacrifice an artifact: Pia and Kiran Nalaar deals 2 damage to target creature or player.
|
||||||
Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new DamageTargetEffect(2), new ManaCostsImpl("{2}{R}"));
|
Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new DamageTargetEffect(2), new ManaCostsImpl("{2}{R}"));
|
||||||
|
|
|
@ -74,7 +74,7 @@ public class ThopterSpyNetwork extends CardImpl {
|
||||||
class ThopterSpyNetworkUpkeepTriggeredAbility extends TriggeredAbilityImpl {
|
class ThopterSpyNetworkUpkeepTriggeredAbility extends TriggeredAbilityImpl {
|
||||||
|
|
||||||
public ThopterSpyNetworkUpkeepTriggeredAbility() {
|
public ThopterSpyNetworkUpkeepTriggeredAbility() {
|
||||||
super(Zone.BATTLEFIELD, new CreateTokenEffect(new ThopterColorlessToken("ORI"), 1), false);
|
super(Zone.BATTLEFIELD, new CreateTokenEffect(new ThopterColorlessToken(), 1), false);
|
||||||
}
|
}
|
||||||
|
|
||||||
public ThopterSpyNetworkUpkeepTriggeredAbility(final ThopterSpyNetworkUpkeepTriggeredAbility ability) {
|
public ThopterSpyNetworkUpkeepTriggeredAbility(final ThopterSpyNetworkUpkeepTriggeredAbility ability) {
|
||||||
|
|
|
@ -59,7 +59,7 @@ public class UndeadServant extends CardImpl {
|
||||||
this.toughness = new MageInt(2);
|
this.toughness = new MageInt(2);
|
||||||
|
|
||||||
// When Undead Servant enters the battlefield, put a 2/2 black Zombie creature token onto the battlefield for each card named Undead Servant in your graveyard.
|
// When Undead Servant enters the battlefield, put a 2/2 black Zombie creature token onto the battlefield for each card named Undead Servant in your graveyard.
|
||||||
this.addAbility(new EntersBattlefieldTriggeredAbility(new CreateTokenEffect(new ZombieToken(expansionSetCode), new CardsInControllerGraveyardCount(filter))));
|
this.addAbility(new EntersBattlefieldTriggeredAbility(new CreateTokenEffect(new ZombieToken(), new CardsInControllerGraveyardCount(filter))));
|
||||||
}
|
}
|
||||||
|
|
||||||
public UndeadServant(final UndeadServant card) {
|
public UndeadServant(final UndeadServant card) {
|
||||||
|
|
|
@ -25,7 +25,6 @@
|
||||||
* authors and should not be interpreted as representing official policies, either expressed
|
* authors and should not be interpreted as representing official policies, either expressed
|
||||||
* or implied, of BetaSteward_at_googlemail.com.
|
* or implied, of BetaSteward_at_googlemail.com.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package mage.sets.mirrodinbesieged;
|
package mage.sets.mirrodinbesieged;
|
||||||
|
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
|
@ -70,8 +69,9 @@ public class NestedGhoul extends CardImpl {
|
||||||
}
|
}
|
||||||
|
|
||||||
class NestedGhoulTriggeredAbility extends TriggeredAbilityImpl {
|
class NestedGhoulTriggeredAbility extends TriggeredAbilityImpl {
|
||||||
|
|
||||||
NestedGhoulTriggeredAbility() {
|
NestedGhoulTriggeredAbility() {
|
||||||
super(Zone.BATTLEFIELD, new CreateTokenEffect(new ZombieToken("MBS")));
|
super(Zone.BATTLEFIELD, new CreateTokenEffect(new ZombieToken()));
|
||||||
}
|
}
|
||||||
|
|
||||||
NestedGhoulTriggeredAbility(final NestedGhoulTriggeredAbility ability) {
|
NestedGhoulTriggeredAbility(final NestedGhoulTriggeredAbility ability) {
|
||||||
|
|
|
@ -28,12 +28,12 @@
|
||||||
package mage.sets.planechase2012;
|
package mage.sets.planechase2012;
|
||||||
|
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
import mage.constants.CardType;
|
|
||||||
import mage.constants.Rarity;
|
|
||||||
import mage.MageInt;
|
import mage.MageInt;
|
||||||
import mage.abilities.common.EntersBattlefieldTriggeredAbility;
|
import mage.abilities.common.EntersBattlefieldTriggeredAbility;
|
||||||
import mage.abilities.effects.common.CreateTokenEffect;
|
import mage.abilities.effects.common.CreateTokenEffect;
|
||||||
import mage.cards.CardImpl;
|
import mage.cards.CardImpl;
|
||||||
|
import mage.constants.CardType;
|
||||||
|
import mage.constants.Rarity;
|
||||||
import mage.game.permanent.token.GoblinToken;
|
import mage.game.permanent.token.GoblinToken;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -52,7 +52,7 @@ public class BeetlebackChief extends CardImpl {
|
||||||
this.toughness = new MageInt(2);
|
this.toughness = new MageInt(2);
|
||||||
|
|
||||||
// When Beetleback Chief enters the battlefield, put two 1/1 red Goblin creature tokens onto the battlefield.
|
// When Beetleback Chief enters the battlefield, put two 1/1 red Goblin creature tokens onto the battlefield.
|
||||||
this.addAbility(new EntersBattlefieldTriggeredAbility(new CreateTokenEffect(new GoblinToken(expansionSetCode), 2)));
|
this.addAbility(new EntersBattlefieldTriggeredAbility(new CreateTokenEffect(new GoblinToken(), 2)));
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -25,26 +25,25 @@
|
||||||
* authors and should not be interpreted as representing official policies, either expressed
|
* authors and should not be interpreted as representing official policies, either expressed
|
||||||
* or implied, of BetaSteward_at_googlemail.com.
|
* or implied, of BetaSteward_at_googlemail.com.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package mage.sets.scarsofmirrodin;
|
package mage.sets.scarsofmirrodin;
|
||||||
|
|
||||||
import mage.constants.CardType;
|
import java.util.UUID;
|
||||||
import mage.constants.Rarity;
|
|
||||||
import mage.abilities.costs.common.SacrificeTargetCost;
|
import mage.abilities.costs.common.SacrificeTargetCost;
|
||||||
import mage.abilities.effects.common.CreateTokenEffect;
|
import mage.abilities.effects.common.CreateTokenEffect;
|
||||||
import mage.cards.CardImpl;
|
import mage.cards.CardImpl;
|
||||||
|
import mage.constants.CardType;
|
||||||
|
import mage.constants.Rarity;
|
||||||
import mage.filter.common.FilterControlledPermanent;
|
import mage.filter.common.FilterControlledPermanent;
|
||||||
import mage.filter.predicate.mageobject.CardTypePredicate;
|
import mage.filter.predicate.mageobject.CardTypePredicate;
|
||||||
import mage.game.permanent.token.GoblinToken;
|
import mage.game.permanent.token.GoblinToken;
|
||||||
import mage.target.common.TargetControlledPermanent;
|
import mage.target.common.TargetControlledPermanent;
|
||||||
|
|
||||||
import java.util.UUID;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* @author Loki
|
* @author Loki
|
||||||
*/
|
*/
|
||||||
public class KuldothaRebirth extends CardImpl {
|
public class KuldothaRebirth extends CardImpl {
|
||||||
|
|
||||||
private static final FilterControlledPermanent filter = new FilterControlledPermanent("an artifact");
|
private static final FilterControlledPermanent filter = new FilterControlledPermanent("an artifact");
|
||||||
|
|
||||||
static {
|
static {
|
||||||
|
|
|
@ -51,6 +51,7 @@ import mage.game.permanent.token.ZombieToken;
|
||||||
public class ArchdemonOfUnx extends CardImpl {
|
public class ArchdemonOfUnx extends CardImpl {
|
||||||
|
|
||||||
private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("non-Zombie creature");
|
private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("non-Zombie creature");
|
||||||
|
|
||||||
static {
|
static {
|
||||||
filter.add(Predicates.not(new SubtypePredicate("Zombie")));
|
filter.add(Predicates.not(new SubtypePredicate("Zombie")));
|
||||||
}
|
}
|
||||||
|
@ -69,7 +70,7 @@ public class ArchdemonOfUnx extends CardImpl {
|
||||||
this.addAbility(TrampleAbility.getInstance());
|
this.addAbility(TrampleAbility.getInstance());
|
||||||
// At the beginning of your upkeep, sacrifice a non-Zombie creature, then put a 2/2 black Zombie creature token onto the battlefield.
|
// At the beginning of your upkeep, sacrifice a non-Zombie creature, then put a 2/2 black Zombie creature token onto the battlefield.
|
||||||
Ability ability = new BeginningOfUpkeepTriggeredAbility(new SacrificeControllerEffect(filter, 1, ""), TargetController.YOU, false);
|
Ability ability = new BeginningOfUpkeepTriggeredAbility(new SacrificeControllerEffect(filter, 1, ""), TargetController.YOU, false);
|
||||||
ability.addEffect(new CreateTokenEffect(new ZombieToken("ALA")));
|
ability.addEffect(new CreateTokenEffect(new ZombieToken()));
|
||||||
this.addAbility(ability);
|
this.addAbility(ability);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -28,10 +28,10 @@
|
||||||
package mage.sets.shardsofalara;
|
package mage.sets.shardsofalara;
|
||||||
|
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
import mage.constants.CardType;
|
|
||||||
import mage.constants.Rarity;
|
|
||||||
import mage.abilities.effects.common.CreateTokenEffect;
|
import mage.abilities.effects.common.CreateTokenEffect;
|
||||||
import mage.cards.CardImpl;
|
import mage.cards.CardImpl;
|
||||||
|
import mage.constants.CardType;
|
||||||
|
import mage.constants.Rarity;
|
||||||
import mage.game.permanent.token.GoblinToken;
|
import mage.game.permanent.token.GoblinToken;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -31,7 +31,6 @@ import java.util.UUID;
|
||||||
import mage.abilities.Ability;
|
import mage.abilities.Ability;
|
||||||
import mage.abilities.effects.Effect;
|
import mage.abilities.effects.Effect;
|
||||||
import mage.abilities.effects.OneShotEffect;
|
import mage.abilities.effects.OneShotEffect;
|
||||||
import mage.abilities.effects.common.CreateTokenEffect;
|
|
||||||
import mage.abilities.effects.common.CreateTokenTargetEffect;
|
import mage.abilities.effects.common.CreateTokenTargetEffect;
|
||||||
import mage.cards.CardImpl;
|
import mage.cards.CardImpl;
|
||||||
import mage.constants.CardType;
|
import mage.constants.CardType;
|
||||||
|
|
|
@ -28,11 +28,11 @@
|
||||||
package mage.sets.timespiral;
|
package mage.sets.timespiral;
|
||||||
|
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
import mage.constants.CardType;
|
|
||||||
import mage.constants.Rarity;
|
|
||||||
import mage.abilities.effects.common.CreateTokenEffect;
|
import mage.abilities.effects.common.CreateTokenEffect;
|
||||||
import mage.abilities.keyword.StormAbility;
|
import mage.abilities.keyword.StormAbility;
|
||||||
import mage.cards.CardImpl;
|
import mage.cards.CardImpl;
|
||||||
|
import mage.constants.CardType;
|
||||||
|
import mage.constants.Rarity;
|
||||||
import mage.game.permanent.token.GoblinToken;
|
import mage.game.permanent.token.GoblinToken;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -45,7 +45,6 @@ public class EmptyTheWarrens extends CardImpl {
|
||||||
super(ownerId, 152, "Empty the Warrens", Rarity.COMMON, new CardType[]{CardType.SORCERY}, "{3}{R}");
|
super(ownerId, 152, "Empty the Warrens", Rarity.COMMON, new CardType[]{CardType.SORCERY}, "{3}{R}");
|
||||||
this.expansionSetCode = "TSP";
|
this.expansionSetCode = "TSP";
|
||||||
|
|
||||||
|
|
||||||
// Put two 1/1 red Goblin creature tokens onto the battlefield.
|
// Put two 1/1 red Goblin creature tokens onto the battlefield.
|
||||||
this.getSpellAbility().addEffect(new CreateTokenEffect(new GoblinToken(), 2));
|
this.getSpellAbility().addEffect(new CreateTokenEffect(new GoblinToken(), 2));
|
||||||
// Storm
|
// Storm
|
||||||
|
|
|
@ -0,0 +1,299 @@
|
||||||
|
package org.mage.test.cards.cost.modification;
|
||||||
|
|
||||||
|
import mage.abilities.keyword.HexproofAbility;
|
||||||
|
import mage.constants.PhaseStep;
|
||||||
|
import mage.constants.Zone;
|
||||||
|
import mage.game.permanent.Permanent;
|
||||||
|
import org.junit.Assert;
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.mage.test.serverside.base.CardTestPlayerBase;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Battlefield Thaumaturge:
|
||||||
|
* Creature - Human Wizard
|
||||||
|
* Each instant and sorcery spell you cast costs {1} less to cast for each creature it targets.
|
||||||
|
* Heroic - Whenever you cast a spell that targets Battlefield Thaumaturge, Battlefield Thaumaturge gains hexproof until end of turn.
|
||||||
|
*
|
||||||
|
* @author Simown
|
||||||
|
*/
|
||||||
|
public class BattlefieldThaumaturgeTest extends CardTestPlayerBase {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testSingleTargetReduction() {
|
||||||
|
|
||||||
|
addCard(Zone.BATTLEFIELD, playerA, "Battlefield Thaumaturge");
|
||||||
|
addCard(Zone.BATTLEFIELD, playerA, "Mountain");
|
||||||
|
addCard(Zone.BATTLEFIELD, playerA, "Island");
|
||||||
|
addCard(Zone.HAND, playerA, "Lightning Strike");
|
||||||
|
|
||||||
|
addCard(Zone.BATTLEFIELD, playerB, "Akroan Skyguard");
|
||||||
|
|
||||||
|
// Lightning Strike - {1}{R} - Lightning Strike deals 3 damage to target creature or player.
|
||||||
|
// Because Battlefield Thaumaturge is on the battlefield, and the creature is targeted by the
|
||||||
|
// Lightning Strike it will be payable with {R}.
|
||||||
|
castSpell(2, PhaseStep.POSTCOMBAT_MAIN, playerA, "Lightning Strike", "Akroan Skyguard");
|
||||||
|
setStopAt(2, PhaseStep.END_TURN);
|
||||||
|
execute();
|
||||||
|
|
||||||
|
// PlayerA still has the Battlefield Thaumaturge
|
||||||
|
assertPermanentCount(playerA, "Battlefield Thaumaturge", 1);
|
||||||
|
// The Akroan Skyguard has been killed by the Lightning Strike
|
||||||
|
assertPermanentCount(playerB, "Akroan Skyguard", 0);
|
||||||
|
assertGraveyardCount(playerB, "Akroan Skyguard", 1);
|
||||||
|
|
||||||
|
// Check {R} has been used to pay, and the other land remains untapped
|
||||||
|
assertTappedCount("Mountain", true, 1);
|
||||||
|
assertTappedCount("Island", false, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testStriveTargetingReduction1() {
|
||||||
|
|
||||||
|
addCard(Zone.BATTLEFIELD, playerA, "Battlefield Thaumaturge");
|
||||||
|
addCard(Zone.BATTLEFIELD, playerA, "Swamp", 3);
|
||||||
|
addCard(Zone.BATTLEFIELD, playerA, "Forest", 4);
|
||||||
|
addCard(Zone.BATTLEFIELD, playerA, "Pharika's Chosen");
|
||||||
|
addCard(Zone.HAND, playerA, "Silence the Believers");
|
||||||
|
|
||||||
|
addCard(Zone.BATTLEFIELD, playerB, "Battlewise Hoplite");
|
||||||
|
/**
|
||||||
|
* Silence the Believers - {2}{B}{B}
|
||||||
|
* Exile any number of target creatures and all Auras attached to them
|
||||||
|
* Strive - Silence the Believers costs {2}{B} more to cast for each target beyond the first.
|
||||||
|
* Targetting a creature on both sides of the battlefield.
|
||||||
|
*/
|
||||||
|
castSpell(2, PhaseStep.PRECOMBAT_MAIN, playerA, "Silence the Believers", "Pharika's Chosen^Battlewise Hoplite");
|
||||||
|
setStopAt(2, PhaseStep.END_TURN);
|
||||||
|
execute();
|
||||||
|
|
||||||
|
// Both creatures were exiled
|
||||||
|
assertExileCount("Pharika's Chosen", 1);
|
||||||
|
assertExileCount("Battlewise Hoplite", 1);
|
||||||
|
// Not still on the battlefield or in the graveyard
|
||||||
|
assertPermanentCount(playerA, "Pharika's Chosen", 0);
|
||||||
|
assertPermanentCount(playerB, "Battlewise Hoplite", 0);
|
||||||
|
assertGraveyardCount(playerA, "Pharika's Chosen", 0);
|
||||||
|
assertGraveyardCount(playerB, "Battlewise Hoplite", 0);
|
||||||
|
|
||||||
|
/* Cost to exile 2 permanents will be:
|
||||||
|
* + {2}{B}{B} for the base spell
|
||||||
|
* + {2}{B} for an additional target
|
||||||
|
* - {2} for Battlefield Thaumaturge cost reducing effect
|
||||||
|
* = {2}{B}{B}{B} to pay.
|
||||||
|
*/
|
||||||
|
// Check 3 Swamps have been tapped to pay the reduced cost
|
||||||
|
assertTappedCount("Swamp", true, 3);
|
||||||
|
// And 2 Forests for the colorless mana
|
||||||
|
assertTappedCount("Forest", true, 2);
|
||||||
|
// And the rest of the Forests remain untapped
|
||||||
|
assertTappedCount("Forest", false, 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testStriveTargetingReduction2() {
|
||||||
|
|
||||||
|
String [] creatures = {"Battlefield Thaumaturge", "Agent of Horizons", "Blood-Toll Harpy", "Anvilwrought Raptor", "Fleshmad Steed" };
|
||||||
|
for(String creature : creatures) {
|
||||||
|
addCard(Zone.BATTLEFIELD, playerA, creature);
|
||||||
|
}
|
||||||
|
addCard(Zone.BATTLEFIELD, playerA, "Plains", 1);
|
||||||
|
addCard(Zone.BATTLEFIELD, playerA, "Island", 5);
|
||||||
|
addCard(Zone.HAND, playerA, "Launch the Fleet");
|
||||||
|
|
||||||
|
// Launch the Fleet - {W}
|
||||||
|
// Strive - Launch the Fleet costs {1} more to cast for each target beyond the first.
|
||||||
|
// Until end of turn, any number of target creatures each gain "Whenever this creature attacks, put a 1/1 white Soldier token onto the battlefield tapped and attacking."
|
||||||
|
castSpell(3, PhaseStep.PRECOMBAT_MAIN, playerA, "Launch the Fleet", createTargetingString(creatures));
|
||||||
|
for(String creature : creatures) {
|
||||||
|
attack(3, playerA, creature);
|
||||||
|
}
|
||||||
|
setStopAt(3, PhaseStep.POSTCOMBAT_MAIN);
|
||||||
|
execute();
|
||||||
|
|
||||||
|
// 5 initial creatures + 5 soldier tokens + 6 lands
|
||||||
|
assertPermanentCount(playerA, 16);
|
||||||
|
// The initial creatures exist
|
||||||
|
for(String creature : creatures) {
|
||||||
|
assertPermanentCount(playerA, creature, 1);
|
||||||
|
}
|
||||||
|
// Each has a solider token generated while attacking
|
||||||
|
assertPermanentCount(playerA, "Soldier", 5);
|
||||||
|
// Battlefield Thaumaturge will have hexproof from heroic trigger
|
||||||
|
Permanent battlefieldThaumaturge = getPermanent("Battlefield Thaumaturge", playerA.getId());
|
||||||
|
Assert.assertTrue("Battlefield Thaumaturge must have hexproof", battlefieldThaumaturge.getAbilities().contains(HexproofAbility.getInstance()));
|
||||||
|
|
||||||
|
assertLife(playerA, 20);
|
||||||
|
// 5 initial creatures + 5 soldier tokens => 16 damage
|
||||||
|
assertLife(playerB, 4);
|
||||||
|
/* Cost to have 5 attackers generate soldier tokens
|
||||||
|
* + {W} for the base spell
|
||||||
|
* + {4} for an additional targets
|
||||||
|
* - {4} for Battlefield Thaumaturge cost reducing effect (reduce {1} per target)
|
||||||
|
* = {W} to pay.
|
||||||
|
*/
|
||||||
|
assertTappedCount("Plains", true, 1);
|
||||||
|
// No other mana has been tapped to pay costs
|
||||||
|
assertTappedCount("Island", false, 5);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testVariableCostReduction() {
|
||||||
|
addCard(Zone.BATTLEFIELD, playerA, "Battlefield Thaumaturge");
|
||||||
|
addCard(Zone.BATTLEFIELD, playerA, "Island", 2);
|
||||||
|
addCard(Zone.BATTLEFIELD, playerA, "Plains", 4);
|
||||||
|
addCard(Zone.HAND, playerA, "Curse of the Swine");
|
||||||
|
|
||||||
|
String [] opponentsCreatures = {"Fleecemane Lion", "Sedge Scorpion", "Boon Satyr", "Bronze Sable"};
|
||||||
|
for(String creature: opponentsCreatures) {
|
||||||
|
addCard(Zone.BATTLEFIELD, playerB, creature);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Curse of the Swine - {X}{U}{U}
|
||||||
|
* Exile X target creatures. For each creature exiled this way,
|
||||||
|
* its controller puts a 2/2 green Boar creature token onto the battlefield
|
||||||
|
*/
|
||||||
|
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Curse of the Swine");
|
||||||
|
setChoice(playerA, "X=4");
|
||||||
|
addTarget(playerA, createTargetingString(opponentsCreatures));
|
||||||
|
setStopAt(1, PhaseStep.POSTCOMBAT_MAIN);
|
||||||
|
execute();
|
||||||
|
|
||||||
|
// All the opponents creatures have been exiled from the battlefield
|
||||||
|
for(String creature: opponentsCreatures) {
|
||||||
|
assertPermanentCount(playerB, creature, 0);
|
||||||
|
assertGraveyardCount(playerB, creature, 0);
|
||||||
|
assertExileCount(creature, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
// All 4 creatures have been replaced by boars
|
||||||
|
assertPermanentCount(playerB, "Boar", 4);
|
||||||
|
|
||||||
|
/* Cost to target 4 permanents will be:
|
||||||
|
* + {4}{U}{U} for the base spell with X = 4
|
||||||
|
* - {4} for Battlefield Thaumaturge cost reducing effect as 4 creatures are targetted
|
||||||
|
* = {U}{U} to pay.
|
||||||
|
*/
|
||||||
|
// Check 2 islands have been tapped to pay the reduced cost
|
||||||
|
assertTappedCount("Island", true, 2);
|
||||||
|
// And the rest of the lands remain untapped
|
||||||
|
assertTappedCount("Plains", false, 4);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testMutipleTargetReduction() {
|
||||||
|
|
||||||
|
String [] playerACreatures = {"Battlefield Thaumaturge", "Sedge Scorpion", "Boon Satyr"};
|
||||||
|
String [] playerBCreatures = {"Agent of Horizons", "Blood-Toll Harpy", "Anvilwrought Raptor"};
|
||||||
|
|
||||||
|
addCard(Zone.BATTLEFIELD, playerA, "Mountain", 2);
|
||||||
|
addCard(Zone.BATTLEFIELD, playerA, "Swamp", 4);
|
||||||
|
// Creatures for player A
|
||||||
|
for(String creature: playerACreatures) {
|
||||||
|
addCard(Zone.BATTLEFIELD, playerA, creature);
|
||||||
|
}
|
||||||
|
addCard(Zone.HAND, playerA, "Descent of the Dragons");
|
||||||
|
// Creatures for player B
|
||||||
|
for(String creature: playerBCreatures) {
|
||||||
|
addCard(Zone.BATTLEFIELD, playerB, creature);
|
||||||
|
}
|
||||||
|
/* Descent of the Dragons - {4}{R}{R}
|
||||||
|
* Destroy any number of target creatures.
|
||||||
|
* For each creature destroyed this way, its controller puts a 4/4 red Dragon creature token with flying onto the battlefield.
|
||||||
|
* Battlefield Thaumaturge should reduce the cost of the spell when cast, before he is destroyed and replaced with a dragon.
|
||||||
|
*/
|
||||||
|
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Descent of the Dragons", createTargetingString(playerACreatures) + "^" + createTargetingString(playerBCreatures));
|
||||||
|
setStopAt(1, PhaseStep.END_TURN);
|
||||||
|
execute();
|
||||||
|
|
||||||
|
// All creatures have been put in the graveyard
|
||||||
|
for(String creature: playerACreatures) {
|
||||||
|
assertPermanentCount(playerA, creature, 0);
|
||||||
|
assertGraveyardCount(playerA, creature, 1);
|
||||||
|
}
|
||||||
|
for(String creature: playerBCreatures) {
|
||||||
|
assertPermanentCount(playerB, creature, 0);
|
||||||
|
assertGraveyardCount(playerB, creature, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
// And each player has 3 dragons
|
||||||
|
assertPermanentCount(playerA, "Dragon", 3);
|
||||||
|
assertPermanentCount(playerB, "Dragon", 3);
|
||||||
|
|
||||||
|
/* Cost to target 6 creatures will be
|
||||||
|
* + {4}{R}{R} for the fixed cost base spell
|
||||||
|
* - {4} for Battlefield Thaumaturge cost reducing effect
|
||||||
|
* each creature targeted will reduce the cost by {1} so the cost
|
||||||
|
* can only be reduced by {4} maximum using Battlefield Thaumaturge
|
||||||
|
* even though 6 creatures are targeted.
|
||||||
|
* = {R}{R} to pay.
|
||||||
|
*/
|
||||||
|
// Check 2 mountains have been tapped to pay the reduced cost
|
||||||
|
assertTappedCount("Mountain", true, 2);
|
||||||
|
// And the rest of the lands remain untapped
|
||||||
|
assertTappedCount("Swamp", false, 4);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testTargetNonCreature() {
|
||||||
|
|
||||||
|
addCard(Zone.BATTLEFIELD, playerA, "Battlefield Thaumaturge");
|
||||||
|
addCard(Zone.BATTLEFIELD, playerA, "Forest", 3);
|
||||||
|
addCard(Zone.HAND, playerA, "Fade into Antiquity");
|
||||||
|
|
||||||
|
addCard(Zone.BATTLEFIELD, playerB, "Heliod, God of the Sun");
|
||||||
|
|
||||||
|
// Fade into Antiquity - Sorcery - {2}{G} - Exile target artifact or enchantment.
|
||||||
|
// Battlefield Thaumaturge only reduces the cost instants and sorceries where the target is a creature
|
||||||
|
// No cost reduction for targeting an enchantment (devotion is too low for Heliod to be a creature)
|
||||||
|
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Fade into Antiquity", "Heliod, God of the Sun");
|
||||||
|
setStopAt(1, PhaseStep.END_TURN);
|
||||||
|
execute();
|
||||||
|
|
||||||
|
// PlayerA still has the Battlefield Thaumaturge
|
||||||
|
assertPermanentCount(playerA, "Battlefield Thaumaturge", 1);
|
||||||
|
// Heliod has been exiled
|
||||||
|
assertPermanentCount(playerB, "Heliod, God of the Sun", 0);
|
||||||
|
assertGraveyardCount(playerB, "Heliod, God of the Sun", 0);
|
||||||
|
assertExileCount("Heliod, God of the Sun", 1);
|
||||||
|
|
||||||
|
// Expect full amount paid, i.e. all lands are tapped. Cost was not reduced by Battlefield Thaumaturge, no creature was targeted.
|
||||||
|
assertTappedCount("Forest", true, 3);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testTargetWithAura() {
|
||||||
|
|
||||||
|
addCard(Zone.BATTLEFIELD, playerA, "Battlefield Thaumaturge");
|
||||||
|
addCard(Zone.BATTLEFIELD, playerA, "Plains", 5);
|
||||||
|
addCard(Zone.HAND, playerA, "Spectra Ward");
|
||||||
|
|
||||||
|
// Spectra Ward - {3}{W}{W} - Aura
|
||||||
|
// Enchanted creature gets +2/+2 and has protection from all colors. This effect doesn't remove auras.
|
||||||
|
// Battlefield Thaumaturge only reduces the cost instants and sorceries targeting creatures.
|
||||||
|
// No cost reduction for targeting a creature with an Aura.
|
||||||
|
castSpell(1, PhaseStep.POSTCOMBAT_MAIN, playerA, "Spectra Ward", "Battlefield Thaumaturge");
|
||||||
|
setStopAt(1, PhaseStep.END_TURN);
|
||||||
|
execute();
|
||||||
|
|
||||||
|
assertPermanentCount(playerA, "Battlefield Thaumaturge", 1);
|
||||||
|
assertPermanentCount(playerA, "Spectra Ward", 1);
|
||||||
|
// Battlefield Thaumaturge will have hexproof from heroic trigger
|
||||||
|
Permanent battlefieldThaumaturge = getPermanent("Battlefield Thaumaturge", playerA.getId());
|
||||||
|
Assert.assertTrue("Battlefield Thaumaturge must have hexproof", battlefieldThaumaturge.getAbilities().contains(HexproofAbility.getInstance()));
|
||||||
|
|
||||||
|
// No cost reduction from Battlefield Thaumaturge, full amount paid
|
||||||
|
assertTappedCount("Plains", true, 5);
|
||||||
|
}
|
||||||
|
|
||||||
|
private String createTargetingString(String [] targets) {
|
||||||
|
StringBuilder targetBuilder = new StringBuilder();
|
||||||
|
for (String target : targets) {
|
||||||
|
if (targetBuilder.length() > 0) {
|
||||||
|
targetBuilder.append('^');
|
||||||
|
}
|
||||||
|
targetBuilder.append(target);
|
||||||
|
}
|
||||||
|
return targetBuilder.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -711,6 +711,28 @@ public abstract class CardTestPlayerAPIImpl extends MageTestPlayerBase implement
|
||||||
Assert.assertEquals("(Battlefield) Tapped state is not equal (" + cardName + ")", tapped, found.isTapped());
|
Assert.assertEquals("(Battlefield) Tapped state is not equal (" + cardName + ")", tapped, found.isTapped());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Assert whether X permanents of the same name are tapped or not.
|
||||||
|
*
|
||||||
|
* @param cardName Name of the permanent that should be checked.
|
||||||
|
* @param tapped Whether the permanent is tapped or not
|
||||||
|
* @param count The amount of this permanents that should be tapped
|
||||||
|
*/
|
||||||
|
public void assertTappedCount(String cardName, boolean tapped, int count) throws AssertionError {
|
||||||
|
int tappedAmount = 0;
|
||||||
|
Permanent found = null;
|
||||||
|
for (Permanent permanent : currentGame.getBattlefield().getAllActivePermanents()) {
|
||||||
|
if (permanent.getName().equals(cardName)) {
|
||||||
|
if(permanent.isTapped() == tapped) {
|
||||||
|
tappedAmount++;
|
||||||
|
}
|
||||||
|
found = permanent;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Assert.assertNotNull("There is no such permanent on the battlefield, cardName=" + cardName, found);
|
||||||
|
Assert.assertEquals("(Battlefield) " + count + " permanents (" + cardName + ") are not " + ((tapped) ? "" : "un") + "tapped.", count, tappedAmount);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Assert whether a permanent is attacking or not
|
* Assert whether a permanent is attacking or not
|
||||||
*
|
*
|
||||||
|
|
|
@ -66,6 +66,22 @@ public class ManaUtilTest extends CardTestPlayerBase {
|
||||||
testManaToPayVsLand("{W/R}{R/G}", "Sacred Foundry", 2, 2); // can't auto choose to pay
|
testManaToPayVsLand("{W/R}{R/G}", "Sacred Foundry", 2, 2); // can't auto choose to pay
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testManaCondensing() {
|
||||||
|
Assert.assertEquals("{5}{W}", ManaUtil.condenseManaCostString(("{1}{1}{1}{2}{W}")));
|
||||||
|
Assert.assertEquals("{4}{B}{B}", ManaUtil.condenseManaCostString("{2}{B}{2}{B}"));
|
||||||
|
Assert.assertEquals("{6}{R}{R}{R}{U}", ManaUtil.condenseManaCostString("{R}{1}{R}{2}{R}{3}{U}"));
|
||||||
|
Assert.assertEquals("{5}{B}{U}{W}", ManaUtil.condenseManaCostString("{1}{B}{W}{4}{U}"));
|
||||||
|
Assert.assertEquals("{8}{B}{G}{G}{U}", ManaUtil.condenseManaCostString("{1}{G}{1}{2}{3}{G}{B}{U}{1}"));
|
||||||
|
Assert.assertEquals("{3}{R}{U}", ManaUtil.condenseManaCostString("{3}{R}{U}"));
|
||||||
|
Assert.assertEquals("{10}", ManaUtil.condenseManaCostString("{1}{2}{3}{4}"));
|
||||||
|
Assert.assertEquals("{B}{G}{R}{U}{W}", ManaUtil.condenseManaCostString("{B}{G}{R}{U}{W}"));
|
||||||
|
Assert.assertEquals("{R}{R}", ManaUtil.condenseManaCostString("{R}{R}"));
|
||||||
|
Assert.assertEquals("{U}", ManaUtil.condenseManaCostString("{U}"));
|
||||||
|
Assert.assertEquals("{2}", ManaUtil.condenseManaCostString("{2}"));
|
||||||
|
Assert.assertEquals("", ManaUtil.condenseManaCostString(""));
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Common way to test ManaUtil.tryToAutoPay
|
* Common way to test ManaUtil.tryToAutoPay
|
||||||
*
|
*
|
||||||
|
@ -133,4 +149,5 @@ public class ManaUtilTest extends CardTestPlayerBase {
|
||||||
}
|
}
|
||||||
return useableAbilities;
|
return useableAbilities;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -39,6 +39,7 @@ import mage.constants.Outcome;
|
||||||
import mage.constants.Zone;
|
import mage.constants.Zone;
|
||||||
import mage.game.Game;
|
import mage.game.Game;
|
||||||
import mage.target.Target;
|
import mage.target.Target;
|
||||||
|
import mage.util.ManaUtil;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
|
@ -50,7 +51,7 @@ public class StriveAbility extends SimpleStaticAbility {
|
||||||
private final String striveCost;
|
private final String striveCost;
|
||||||
|
|
||||||
public StriveAbility(String manaString) {
|
public StriveAbility(String manaString) {
|
||||||
super(Zone.STACK, new StriveCostIncreasementEffect(new ManaCostsImpl(manaString)));
|
super(Zone.STACK, new StriveCostIncreasingEffect(new ManaCostsImpl(manaString)));
|
||||||
setRuleAtTheTop(true);
|
setRuleAtTheTop(true);
|
||||||
this.striveCost = manaString;
|
this.striveCost = manaString;
|
||||||
}
|
}
|
||||||
|
@ -71,29 +72,32 @@ public class StriveAbility extends SimpleStaticAbility {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class StriveCostIncreasementEffect extends CostModificationEffectImpl {
|
class StriveCostIncreasingEffect extends CostModificationEffectImpl {
|
||||||
|
|
||||||
private ManaCostsImpl striveCosts = null;
|
private ManaCostsImpl striveCosts = null;
|
||||||
|
|
||||||
public StriveCostIncreasementEffect(ManaCostsImpl striveCosts) {
|
public StriveCostIncreasingEffect(ManaCostsImpl striveCosts) {
|
||||||
super(Duration.WhileOnStack, Outcome.Benefit, CostModificationType.INCREASE_COST);
|
super(Duration.WhileOnStack, Outcome.Benefit, CostModificationType.INCREASE_COST);
|
||||||
this.striveCosts = striveCosts;
|
this.striveCosts = striveCosts;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected StriveCostIncreasementEffect(StriveCostIncreasementEffect effect) {
|
protected StriveCostIncreasingEffect(StriveCostIncreasingEffect effect) {
|
||||||
super(effect);
|
super(effect);
|
||||||
this.striveCosts = effect.striveCosts;
|
this.striveCosts = effect.striveCosts;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean apply(Game game, Ability source, Ability abilityToModify) {
|
public boolean apply(Game game, Ability source, Ability abilityToModify) {
|
||||||
// Target target = abilityToModify.getTargets().get(0);
|
|
||||||
for (Target target : abilityToModify.getTargets()) {
|
for (Target target : abilityToModify.getTargets()) {
|
||||||
if (target.getMaxNumberOfTargets() == Integer.MAX_VALUE) {
|
if (target.getMaxNumberOfTargets() == Integer.MAX_VALUE) {
|
||||||
int additionalTargets = target.getTargets().size() - 1;
|
int additionalTargets = target.getTargets().size() - 1;
|
||||||
|
StringBuilder sb = new StringBuilder();
|
||||||
for (int i = 0; i < additionalTargets; i++) {
|
for (int i = 0; i < additionalTargets; i++) {
|
||||||
abilityToModify.getManaCostsToPay().add(striveCosts.copy());
|
// Build up a string of strive costs for each target
|
||||||
|
sb.append(striveCosts.getText());
|
||||||
}
|
}
|
||||||
|
String finalCost = ManaUtil.condenseManaCostString(sb.toString());
|
||||||
|
abilityToModify.getManaCostsToPay().add(new ManaCostsImpl(finalCost));
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -106,7 +110,7 @@ class StriveCostIncreasementEffect extends CostModificationEffectImpl {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public StriveCostIncreasementEffect copy() {
|
public StriveCostIncreasingEffect copy() {
|
||||||
return new StriveCostIncreasementEffect(this);
|
return new StriveCostIncreasingEffect(this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -25,15 +25,16 @@
|
||||||
* authors and should not be interpreted as representing official policies, either expressed
|
* authors and should not be interpreted as representing official policies, either expressed
|
||||||
* or implied, of BetaSteward_at_googlemail.com.
|
* or implied, of BetaSteward_at_googlemail.com.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package mage.abilities.effects.common;
|
package mage.abilities.effects.common;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
|
import mage.MageObject;
|
||||||
import mage.abilities.Ability;
|
import mage.abilities.Ability;
|
||||||
import mage.abilities.dynamicvalue.DynamicValue;
|
import mage.abilities.dynamicvalue.DynamicValue;
|
||||||
import mage.abilities.dynamicvalue.common.StaticValue;
|
import mage.abilities.dynamicvalue.common.StaticValue;
|
||||||
import mage.abilities.effects.OneShotEffect;
|
import mage.abilities.effects.OneShotEffect;
|
||||||
|
import mage.cards.Card;
|
||||||
import mage.constants.Outcome;
|
import mage.constants.Outcome;
|
||||||
import mage.game.Game;
|
import mage.game.Game;
|
||||||
import mage.game.permanent.token.Token;
|
import mage.game.permanent.token.Token;
|
||||||
|
@ -51,6 +52,7 @@ public class CreateTokenEffect extends OneShotEffect {
|
||||||
private boolean attacking;
|
private boolean attacking;
|
||||||
private UUID lastAddedTokenId;
|
private UUID lastAddedTokenId;
|
||||||
private ArrayList<UUID> lastAddedTokenIds = new ArrayList<>();
|
private ArrayList<UUID> lastAddedTokenIds = new ArrayList<>();
|
||||||
|
private boolean expansionSetCodeChecked;
|
||||||
|
|
||||||
public CreateTokenEffect(Token token) {
|
public CreateTokenEffect(Token token) {
|
||||||
this(token, new StaticValue(1));
|
this(token, new StaticValue(1));
|
||||||
|
@ -74,6 +76,7 @@ public class CreateTokenEffect extends OneShotEffect {
|
||||||
this.amount = amount.copy();
|
this.amount = amount.copy();
|
||||||
this.tapped = tapped;
|
this.tapped = tapped;
|
||||||
this.attacking = attacking;
|
this.attacking = attacking;
|
||||||
|
this.expansionSetCodeChecked = false;
|
||||||
setText();
|
setText();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -85,6 +88,7 @@ public class CreateTokenEffect extends OneShotEffect {
|
||||||
this.attacking = effect.attacking;
|
this.attacking = effect.attacking;
|
||||||
this.lastAddedTokenId = effect.lastAddedTokenId;
|
this.lastAddedTokenId = effect.lastAddedTokenId;
|
||||||
this.lastAddedTokenIds.addAll(effect.lastAddedTokenIds);
|
this.lastAddedTokenIds.addAll(effect.lastAddedTokenIds);
|
||||||
|
this.expansionSetCodeChecked = effect.expansionSetCodeChecked;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -94,6 +98,9 @@ public class CreateTokenEffect extends OneShotEffect {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean apply(Game game, Ability source) {
|
public boolean apply(Game game, Ability source) {
|
||||||
|
if (!expansionSetCodeChecked) {
|
||||||
|
updateExpansionSetCode(game, source);
|
||||||
|
}
|
||||||
int value = amount.calculate(game, source, this);
|
int value = amount.calculate(game, source, this);
|
||||||
token.putOntoBattlefield(value, game, source.getSourceId(), source.getControllerId(), tapped, attacking);
|
token.putOntoBattlefield(value, game, source.getSourceId(), source.getControllerId(), tapped, attacking);
|
||||||
this.lastAddedTokenId = token.getLastAddedToken();
|
this.lastAddedTokenId = token.getLastAddedToken();
|
||||||
|
@ -101,6 +108,14 @@ public class CreateTokenEffect extends OneShotEffect {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void updateExpansionSetCode(Game game, Ability source) {
|
||||||
|
MageObject sourceObject = source.getSourceObject(game);
|
||||||
|
if (sourceObject instanceof Card) {
|
||||||
|
token.setExpansionSetCodeForImage(((Card) sourceObject).getExpansionSetCode());
|
||||||
|
}
|
||||||
|
expansionSetCodeChecked = true;
|
||||||
|
}
|
||||||
|
|
||||||
public UUID getLastAddedTokenId() {
|
public UUID getLastAddedTokenId() {
|
||||||
return lastAddedTokenId;
|
return lastAddedTokenId;
|
||||||
}
|
}
|
||||||
|
|
|
@ -60,7 +60,7 @@ public class ExileAndReturnTransformedSourceEffect extends OneShotEffect {
|
||||||
// Creature has to be on the battlefield to get exiled and be able to return transformed
|
// Creature has to be on the battlefield to get exiled and be able to return transformed
|
||||||
Permanent sourceObject = game.getPermanent(source.getSourceId());
|
Permanent sourceObject = game.getPermanent(source.getSourceId());
|
||||||
Player controller = game.getPlayer(source.getControllerId());
|
Player controller = game.getPlayer(source.getControllerId());
|
||||||
if (sourceObject != null && controller != null) {
|
if (sourceObject != null && controller != null && sourceObject.getZoneChangeCounter(game) == source.getSourceObjectZoneChangeCounter()) {
|
||||||
Card card = (Card) sourceObject;
|
Card card = (Card) sourceObject;
|
||||||
if (controller.moveCards(card, Zone.BATTLEFIELD, Zone.EXILED, source, game)) {
|
if (controller.moveCards(card, Zone.BATTLEFIELD, Zone.EXILED, source, game)) {
|
||||||
Player owner = game.getPlayer(card.getOwnerId());
|
Player owner = game.getPlayer(card.getOwnerId());
|
||||||
|
|
|
@ -25,7 +25,6 @@
|
||||||
* authors and should not be interpreted as representing official policies, either expressed
|
* authors and should not be interpreted as representing official policies, either expressed
|
||||||
* or implied, of BetaSteward_at_googlemail.com.
|
* or implied, of BetaSteward_at_googlemail.com.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package mage.cards;
|
package mage.cards;
|
||||||
|
|
||||||
import java.lang.reflect.Constructor;
|
import java.lang.reflect.Constructor;
|
||||||
|
@ -74,13 +73,14 @@ import mage.watchers.Watcher;
|
||||||
import org.apache.log4j.Logger;
|
import org.apache.log4j.Logger;
|
||||||
|
|
||||||
public abstract class CardImpl extends MageObjectImpl implements Card {
|
public abstract class CardImpl extends MageObjectImpl implements Card {
|
||||||
|
|
||||||
private static final long serialVersionUID = 1L;
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
private static final Logger logger = Logger.getLogger(CardImpl.class);
|
private static final Logger logger = Logger.getLogger(CardImpl.class);
|
||||||
|
|
||||||
protected UUID ownerId;
|
protected UUID ownerId;
|
||||||
protected int cardNumber;
|
protected int cardNumber;
|
||||||
protected String expansionSetCode;
|
public String expansionSetCode;
|
||||||
protected String tokenSetCode;
|
protected String tokenSetCode;
|
||||||
protected Rarity rarity;
|
protected Rarity rarity;
|
||||||
protected boolean canTransform;
|
protected boolean canTransform;
|
||||||
|
@ -108,8 +108,7 @@ public abstract class CardImpl extends MageObjectImpl implements Card {
|
||||||
Ability ability = new PlayLandAbility(name);
|
Ability ability = new PlayLandAbility(name);
|
||||||
ability.setSourceId(this.getId());
|
ability.setSourceId(this.getId());
|
||||||
abilities.add(ability);
|
abilities.add(ability);
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
SpellAbility ability = new SpellAbility(manaCost, name, Zone.HAND, spellAbilityType);
|
SpellAbility ability = new SpellAbility(manaCost, name, Zone.HAND, spellAbilityType);
|
||||||
if (!cardType.contains(CardType.INSTANT)) {
|
if (!cardType.contains(CardType.INSTANT)) {
|
||||||
ability.setTiming(TimingRule.SORCERY);
|
ability.setTiming(TimingRule.SORCERY);
|
||||||
|
@ -206,7 +205,11 @@ public abstract class CardImpl extends MageObjectImpl implements Card {
|
||||||
game.getState().getCardState(objectId).addInfo(key, value);
|
game.getState().getCardState(objectId).addInfo(key, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected static final ArrayList<String> rulesError = new ArrayList<String>() {{add("Exception occured in rules generation");}};
|
protected static final ArrayList<String> rulesError = new ArrayList<String>() {
|
||||||
|
{
|
||||||
|
add("Exception occured in rules generation");
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<String> getRules() {
|
public List<String> getRules() {
|
||||||
|
@ -243,6 +246,7 @@ public abstract class CardImpl extends MageObjectImpl implements Card {
|
||||||
/**
|
/**
|
||||||
* Gets all base abilities - does not include additional abilities added by
|
* Gets all base abilities - does not include additional abilities added by
|
||||||
* other cards or effects
|
* other cards or effects
|
||||||
|
*
|
||||||
* @return A list of {@link Ability} - this collection is modifiable
|
* @return A list of {@link Ability} - this collection is modifiable
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
|
@ -251,8 +255,9 @@ public abstract class CardImpl extends MageObjectImpl implements Card {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets all current abilities - includes additional abilities added by
|
* Gets all current abilities - includes additional abilities added by other
|
||||||
* other cards or effects
|
* cards or effects
|
||||||
|
*
|
||||||
* @param game
|
* @param game
|
||||||
* @return A list of {@link Ability} - this collection is not modifiable
|
* @return A list of {@link Ability} - this collection is not modifiable
|
||||||
*/
|
*/
|
||||||
|
@ -406,8 +411,7 @@ public abstract class CardImpl extends MageObjectImpl implements Card {
|
||||||
case LIBRARY:
|
case LIBRARY:
|
||||||
if (flag) {
|
if (flag) {
|
||||||
game.getPlayer(ownerId).getLibrary().putOnTop(this, game);
|
game.getPlayer(ownerId).getLibrary().putOnTop(this, game);
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
game.getPlayer(ownerId).getLibrary().putOnBottom(this, game);
|
game.getPlayer(ownerId).getLibrary().putOnBottom(this, game);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
@ -479,6 +483,7 @@ public abstract class CardImpl extends MageObjectImpl implements Card {
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean moveToExile(UUID exileId, String name, UUID sourceId, Game game) {
|
public boolean moveToExile(UUID exileId, String name, UUID sourceId, Game game) {
|
||||||
return moveToExile(exileId, name, sourceId, game, null);
|
return moveToExile(exileId, name, sourceId, game, null);
|
||||||
|
@ -678,7 +683,8 @@ public abstract class CardImpl extends MageObjectImpl implements Card {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void build() {}
|
public void build() {
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean getUsesVariousArt() {
|
public boolean getUsesVariousArt() {
|
||||||
|
|
|
@ -170,13 +170,16 @@ public class Emblem implements CommandObject {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void adjustChoices(Ability ability, Game game) {}
|
public void adjustChoices(Ability ability, Game game) {
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void adjustCosts(Ability ability, Game game) {}
|
public void adjustCosts(Ability ability, Game game) {
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void adjustTargets(Ability ability, Game game) {}
|
public void adjustTargets(Ability ability, Game game) {
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public UUID getId() {
|
public UUID getId() {
|
||||||
|
@ -207,7 +210,7 @@ public class Emblem implements CommandObject {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int getZoneChangeCounter(Game game) {
|
public int getZoneChangeCounter(Game game) {
|
||||||
throw new UnsupportedOperationException("Unsupported operation");
|
return 1; // Emblems can't move zones until now so return always 1
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -25,11 +25,11 @@
|
||||||
* authors and should not be interpreted as representing official policies, either expressed
|
* authors and should not be interpreted as representing official policies, either expressed
|
||||||
* or implied, of BetaSteward_at_googlemail.com.
|
* or implied, of BetaSteward_at_googlemail.com.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package mage.game.permanent.token;
|
package mage.game.permanent.token;
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.Random;
|
||||||
import mage.MageInt;
|
import mage.MageInt;
|
||||||
import mage.ObjectColor;
|
|
||||||
import mage.constants.CardType;
|
import mage.constants.CardType;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -39,18 +39,8 @@ import mage.constants.CardType;
|
||||||
public class BeastToken extends Token {
|
public class BeastToken extends Token {
|
||||||
|
|
||||||
public BeastToken() {
|
public BeastToken() {
|
||||||
this("LRW");
|
|
||||||
}
|
|
||||||
public BeastToken(String setCode) {
|
|
||||||
this(setCode, Integer.MIN_VALUE);
|
|
||||||
}
|
|
||||||
|
|
||||||
public BeastToken(String setCode, int tokenType) {
|
|
||||||
super("Beast", "3/3 green Beast creature token");
|
super("Beast", "3/3 green Beast creature token");
|
||||||
setOriginalExpansionSetCode(setCode);
|
availableImageSetCodes.addAll(Arrays.asList("C14", "LRW", "M15", "M14", "DDL", "M13", "M12"));
|
||||||
if (tokenType != Integer.MIN_VALUE) {
|
|
||||||
setTokenType(tokenType);
|
|
||||||
}
|
|
||||||
cardType.add(CardType.CREATURE);
|
cardType.add(CardType.CREATURE);
|
||||||
color.setGreen(true);
|
color.setGreen(true);
|
||||||
subtype.add("Beast");
|
subtype.add("Beast");
|
||||||
|
@ -59,4 +49,14 @@ public class BeastToken extends Token {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setExpansionSetCodeForImage(String code) {
|
||||||
|
super.setExpansionSetCodeForImage(code);
|
||||||
|
if (getOriginalExpansionSetCode().equals("C14")) {
|
||||||
|
this.setTokenType(new Random().nextInt(2) + 1);
|
||||||
|
}
|
||||||
|
if (getOriginalExpansionSetCode().equals("M15")) {
|
||||||
|
this.setTokenType(2);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -25,9 +25,9 @@
|
||||||
* authors and should not be interpreted as representing official policies, either expressed
|
* authors and should not be interpreted as representing official policies, either expressed
|
||||||
* or implied, of BetaSteward_at_googlemail.com.
|
* or implied, of BetaSteward_at_googlemail.com.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package mage.game.permanent.token;
|
package mage.game.permanent.token;
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
import mage.MageInt;
|
import mage.MageInt;
|
||||||
import mage.constants.CardType;
|
import mage.constants.CardType;
|
||||||
|
|
||||||
|
@ -39,6 +39,7 @@ public class ElfToken extends Token {
|
||||||
|
|
||||||
public ElfToken() {
|
public ElfToken() {
|
||||||
super("Elf Warrior", "1/1 green Elf Warrior creature token");
|
super("Elf Warrior", "1/1 green Elf Warrior creature token");
|
||||||
|
availableImageSetCodes.addAll(Arrays.asList("C14", "SHM", "EVG", "LRW", "ORI"));
|
||||||
cardType.add(CardType.CREATURE);
|
cardType.add(CardType.CREATURE);
|
||||||
color.setGreen(true);
|
color.setGreen(true);
|
||||||
subtype.add("Elf");
|
subtype.add("Elf");
|
||||||
|
@ -47,4 +48,11 @@ public class ElfToken extends Token {
|
||||||
toughness = new MageInt(1);
|
toughness = new MageInt(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setExpansionSetCodeForImage(String code) {
|
||||||
|
super.setExpansionSetCodeForImage(code);
|
||||||
|
if (getOriginalExpansionSetCode().equals("SHM")) {
|
||||||
|
this.setTokenType(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -28,8 +28,6 @@
|
||||||
package mage.game.permanent.token;
|
package mage.game.permanent.token;
|
||||||
|
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.List;
|
|
||||||
import java.util.Random;
|
|
||||||
import mage.MageInt;
|
import mage.MageInt;
|
||||||
import mage.constants.CardType;
|
import mage.constants.CardType;
|
||||||
|
|
||||||
|
@ -39,21 +37,9 @@ import mage.constants.CardType;
|
||||||
*/
|
*/
|
||||||
public class GoblinToken extends Token {
|
public class GoblinToken extends Token {
|
||||||
|
|
||||||
static List<String> imageSetCodes = Arrays.asList(
|
|
||||||
"M10", "C14", "KTK", "EVG", "DTK"
|
|
||||||
);
|
|
||||||
|
|
||||||
public GoblinToken() {
|
public GoblinToken() {
|
||||||
this(imageSetCodes.get(new Random().nextInt(imageSetCodes.size())));
|
|
||||||
}
|
|
||||||
|
|
||||||
public GoblinToken(String originalExpansionSetCode) {
|
|
||||||
super("Goblin", "1/1 red Goblin creature token");
|
super("Goblin", "1/1 red Goblin creature token");
|
||||||
if (!imageSetCodes.contains(originalExpansionSetCode)) {
|
availableImageSetCodes.addAll(Arrays.asList("SOM", "M10", "C14", "KTK", "EVG", "DTK", "ORI"));
|
||||||
this.setOriginalExpansionSetCode(imageSetCodes.get(new Random().nextInt(imageSetCodes.size())));
|
|
||||||
} else {
|
|
||||||
this.setOriginalExpansionSetCode(originalExpansionSetCode);
|
|
||||||
}
|
|
||||||
|
|
||||||
cardType.add(CardType.CREATURE);
|
cardType.add(CardType.CREATURE);
|
||||||
subtype.add("Goblin");
|
subtype.add("Goblin");
|
||||||
|
|
|
@ -27,6 +27,8 @@
|
||||||
*/
|
*/
|
||||||
package mage.game.permanent.token;
|
package mage.game.permanent.token;
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.Random;
|
||||||
import mage.MageInt;
|
import mage.MageInt;
|
||||||
import mage.abilities.keyword.FlyingAbility;
|
import mage.abilities.keyword.FlyingAbility;
|
||||||
import mage.constants.CardType;
|
import mage.constants.CardType;
|
||||||
|
@ -38,12 +40,8 @@ import mage.constants.CardType;
|
||||||
public class ThopterColorlessToken extends Token {
|
public class ThopterColorlessToken extends Token {
|
||||||
|
|
||||||
public ThopterColorlessToken() {
|
public ThopterColorlessToken() {
|
||||||
this("EXO");
|
|
||||||
}
|
|
||||||
|
|
||||||
public ThopterColorlessToken(String expansionSetCode) {
|
|
||||||
super("Thopter", "1/1 colorless Thopter artifact creature token with flying");
|
super("Thopter", "1/1 colorless Thopter artifact creature token with flying");
|
||||||
this.setOriginalExpansionSetCode(expansionSetCode);
|
availableImageSetCodes.addAll(Arrays.asList("EXO", "ORI"));
|
||||||
cardType.add(CardType.ARTIFACT);
|
cardType.add(CardType.ARTIFACT);
|
||||||
cardType.add(CardType.CREATURE);
|
cardType.add(CardType.CREATURE);
|
||||||
subtype.add("Thopter");
|
subtype.add("Thopter");
|
||||||
|
@ -53,4 +51,11 @@ public class ThopterColorlessToken extends Token {
|
||||||
addAbility(FlyingAbility.getInstance());
|
addAbility(FlyingAbility.getInstance());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setExpansionSetCodeForImage(String code) {
|
||||||
|
super.setExpansionSetCodeForImage(code);
|
||||||
|
if (getOriginalExpansionSetCode().equals("ORI")) {
|
||||||
|
this.setTokenType(new Random().nextInt(2) + 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -25,11 +25,11 @@
|
||||||
* authors and should not be interpreted as representing official policies, either expressed
|
* authors and should not be interpreted as representing official policies, either expressed
|
||||||
* or implied, of BetaSteward_at_googlemail.com.
|
* or implied, of BetaSteward_at_googlemail.com.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package mage.game.permanent.token;
|
package mage.game.permanent.token;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Random;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
import mage.MageObjectImpl;
|
import mage.MageObjectImpl;
|
||||||
import mage.ObjectColor;
|
import mage.ObjectColor;
|
||||||
|
@ -44,8 +44,6 @@ import mage.game.events.GameEvent.EventType;
|
||||||
import mage.game.events.ZoneChangeEvent;
|
import mage.game.events.ZoneChangeEvent;
|
||||||
import mage.game.permanent.PermanentToken;
|
import mage.game.permanent.PermanentToken;
|
||||||
import mage.players.Player;
|
import mage.players.Player;
|
||||||
import mage.util.CardUtil;
|
|
||||||
|
|
||||||
|
|
||||||
public class Token extends MageObjectImpl {
|
public class Token extends MageObjectImpl {
|
||||||
|
|
||||||
|
@ -57,7 +55,11 @@ public class Token extends MageObjectImpl {
|
||||||
private String originalExpansionSetCode;
|
private String originalExpansionSetCode;
|
||||||
private Card copySourceCard; // the card the Token is a copy from
|
private Card copySourceCard; // the card the Token is a copy from
|
||||||
|
|
||||||
|
// list of set codes tokene images are available for
|
||||||
|
protected List<String> availableImageSetCodes = new ArrayList<>();
|
||||||
|
|
||||||
public enum Type {
|
public enum Type {
|
||||||
|
|
||||||
FIRST(1),
|
FIRST(1),
|
||||||
SECOND(2);
|
SECOND(2);
|
||||||
|
|
||||||
|
@ -207,5 +209,13 @@ public class Token extends MageObjectImpl {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void setExpansionSetCodeForImage(String code) {
|
||||||
|
if (availableImageSetCodes.size() > 0) {
|
||||||
|
if (availableImageSetCodes.contains(code)) {
|
||||||
|
setOriginalExpansionSetCode(code);
|
||||||
|
} else {
|
||||||
|
setOriginalExpansionSetCode(availableImageSetCodes.get(new Random().nextInt(availableImageSetCodes.size())));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -25,9 +25,9 @@
|
||||||
* authors and should not be interpreted as representing official policies, either expressed
|
* authors and should not be interpreted as representing official policies, either expressed
|
||||||
* or implied, of BetaSteward_at_googlemail.com.
|
* or implied, of BetaSteward_at_googlemail.com.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package mage.game.permanent.token;
|
package mage.game.permanent.token;
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
import java.util.Random;
|
import java.util.Random;
|
||||||
import mage.MageInt;
|
import mage.MageInt;
|
||||||
import mage.constants.CardType;
|
import mage.constants.CardType;
|
||||||
|
@ -39,15 +39,8 @@ import mage.constants.CardType;
|
||||||
public class ZombieToken extends Token {
|
public class ZombieToken extends Token {
|
||||||
|
|
||||||
public ZombieToken() {
|
public ZombieToken() {
|
||||||
this("10E");
|
|
||||||
}
|
|
||||||
|
|
||||||
public ZombieToken(String expansionSetCode) {
|
|
||||||
super("Zombie", "2/2 black Zombie creature token");
|
super("Zombie", "2/2 black Zombie creature token");
|
||||||
this.setOriginalExpansionSetCode(expansionSetCode);
|
availableImageSetCodes.addAll(Arrays.asList("10E", "M10", "M11", "M12", "M13", "M14", "M15", "MBS", "ALA", "ISD", "C14", "CNS", "MMA", "BNG", "KTK", "DTK", "ORI"));
|
||||||
if (expansionSetCode.equals("ISD")) {
|
|
||||||
this.setTokenType(new Random().nextInt(3) + 1);
|
|
||||||
}
|
|
||||||
cardType.add(CardType.CREATURE);
|
cardType.add(CardType.CREATURE);
|
||||||
color.setBlack(true);
|
color.setBlack(true);
|
||||||
subtype.add("Zombie");
|
subtype.add("Zombie");
|
||||||
|
@ -55,4 +48,12 @@ public class ZombieToken extends Token {
|
||||||
toughness = new MageInt(2);
|
toughness = new MageInt(2);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setExpansionSetCodeForImage(String code) {
|
||||||
|
super.setExpansionSetCodeForImage(code);
|
||||||
|
if (getOriginalExpansionSetCode().equals("ISD")) {
|
||||||
|
this.setTokenType(new Random().nextInt(3) + 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
|
@ -1,9 +1,7 @@
|
||||||
package mage.util;
|
package mage.util;
|
||||||
|
|
||||||
import java.util.HashSet;
|
import java.util.*;
|
||||||
import java.util.LinkedHashMap;
|
|
||||||
import java.util.Set;
|
|
||||||
import java.util.UUID;
|
|
||||||
import mage.MageObject;
|
import mage.MageObject;
|
||||||
import mage.Mana;
|
import mage.Mana;
|
||||||
import mage.ManaSymbol;
|
import mage.ManaSymbol;
|
||||||
|
@ -379,4 +377,46 @@ public class ManaUtil {
|
||||||
return unpaid.getText();
|
return unpaid.getText();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Converts a collection of mana symbols into a single condensed string
|
||||||
|
* e.g.
|
||||||
|
* {1}{1}{1}{1}{1}{W} = {5}{W}
|
||||||
|
* {2}{B}{2}{B}{2}{B} = {6}{B}{B}{B}
|
||||||
|
* {1}{2}{R}{U}{1}{1} = {5}{R}{U}
|
||||||
|
* {B}{G}{R} = {B}{G}{R}
|
||||||
|
* */
|
||||||
|
public static String condenseManaCostString(String rawCost) {
|
||||||
|
int total = 0;
|
||||||
|
int index = 0;
|
||||||
|
// Split the string in to an array of numbers and colored mana symbols
|
||||||
|
String[] splitCost = rawCost.replace("{", "").replace("}", " ").split(" ");
|
||||||
|
// Sort alphabetically which will push1 the numbers to the front before the colored mana symbols
|
||||||
|
Arrays.sort(splitCost);
|
||||||
|
for (String c : splitCost) {
|
||||||
|
// If the string is a representation of a number
|
||||||
|
if(c.matches("\\d+")) {
|
||||||
|
total += Integer.parseInt(c);
|
||||||
|
} else {
|
||||||
|
// First non-number we see we can finish as they are sorted
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
index++;
|
||||||
|
}
|
||||||
|
int splitCostLength = splitCost.length;
|
||||||
|
// No need to add {total} to the mana cost if total == 0
|
||||||
|
int shift = (total > 0) ? 1 : 0;
|
||||||
|
String [] finalCost = new String[shift + splitCostLength - index];
|
||||||
|
// Account for no colourless mana symbols seen
|
||||||
|
if(total > 0) {
|
||||||
|
finalCost[0] = String.valueOf(total);
|
||||||
|
}
|
||||||
|
System.arraycopy(splitCost, index, finalCost, shift, splitCostLength - index);
|
||||||
|
// Combine the cost back as a mana string
|
||||||
|
StringBuilder sb = new StringBuilder();
|
||||||
|
for(String s: finalCost) {
|
||||||
|
sb.append("{" + s + "}");
|
||||||
|
}
|
||||||
|
// Return the condensed string
|
||||||
|
return sb.toString();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue