Merge origin/master

This commit is contained in:
fireshoes 2015-07-18 09:20:23 -05:00
commit eb0ce863e7
66 changed files with 1001 additions and 590 deletions

View file

@ -1,31 +1,30 @@
/* /*
* Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved.
* *
* Redistribution and use in source and binary forms, with or without modification, are * Redistribution and use in source and binary forms, with or without modification, are
* permitted provided that the following conditions are met: * permitted provided that the following conditions are met:
* *
* 1. Redistributions of source code must retain the above copyright notice, this list of * 1. Redistributions of source code must retain the above copyright notice, this list of
* conditions and the following disclaimer. * conditions and the following disclaimer.
* *
* 2. Redistributions in binary form must reproduce the above copyright notice, this list * 2. Redistributions in binary form must reproduce the above copyright notice, this list
* of conditions and the following disclaimer in the documentation and/or other materials * of conditions and the following disclaimer in the documentation and/or other materials
* provided with the distribution. * provided with the distribution.
* *
* THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
* *
* The views and conclusions contained in the software and documentation are those of the * The views and conclusions contained in the software and documentation are those of the
* authors and should not be interpreted as representing official policies, either expressed * authors and should not be interpreted as representing official policies, either expressed
* or implied, of BetaSteward_at_googlemail.com. * or implied, of BetaSteward_at_googlemail.com.
*/ */
package 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,27 +56,28 @@ 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) {
this.put(card.getId(), new CardView(card)); this.put(card.getId(), new CardView(card));
} }
} }
public CardsView(Game game, Collection<? extends Card> cards) { public CardsView(Game game, Collection<? extends Card> cards) {
for (Card card: cards) { for (Card card : cards) {
this.put(card.getId(), new CardView(card, game, false)); this.put(card.getId(), new CardView(card, game, false));
} }
} }
public CardsView ( Collection<? extends Ability> abilities, Game game ) { public CardsView(Collection<? extends Ability> abilities, Game game) {
for ( Ability ability : abilities ) { for (Ability ability : abilities) {
MageObject sourceObject = null; MageObject sourceObject = null;
AbilityView abilityView = null; AbilityView abilityView = null;
boolean isCard = false; boolean isCard = false;
boolean isPermanent = false; boolean isPermanent = false;
switch ( ability.getZone() ) { switch (ability.getZone()) {
case ALL: case ALL:
case EXILED: case EXILED:
case GRAVEYARD: case GRAVEYARD:
@ -86,7 +87,7 @@ public class CardsView extends LinkedHashMap<UUID, CardView> {
case BATTLEFIELD: case BATTLEFIELD:
sourceObject = game.getPermanent(ability.getSourceId()); sourceObject = game.getPermanent(ability.getSourceId());
if (sourceObject == null) { if (sourceObject == null) {
sourceObject = (Permanent)game.getLastKnownInformation(ability.getSourceId(), Zone.BATTLEFIELD); sourceObject = (Permanent) game.getLastKnownInformation(ability.getSourceId(), Zone.BATTLEFIELD);
} }
isPermanent = true; isPermanent = true;
break; break;
@ -99,14 +100,19 @@ public class CardsView extends LinkedHashMap<UUID, CardView> {
case COMMAND: case COMMAND:
sourceObject = game.getObject(ability.getSourceId()); sourceObject = game.getObject(ability.getSourceId());
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) {
abilityView = new AbilityView(ability, "Emblem " + planeswalkerCard.getName(), new CardView(new EmblemView((Emblem)sourceObject, planeswalkerCard))); 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.setName("Emblem " + planeswalkerCard.getName()); abilityView.setName("Emblem " + planeswalkerCard.getName());
abilityView.setExpansionSetCode(planeswalkerCard.getExpansionSetCode()); abilityView.setExpansionSetCode(planeswalkerCard.getExpansionSetCode());
} else { } else {
throw new IllegalArgumentException("Source card for emblem not found."); throw new IllegalArgumentException("Source card for emblem not found.");
} }
} }
break; break;
} }
@ -114,9 +120,9 @@ public class CardsView extends LinkedHashMap<UUID, CardView> {
if (abilityView == null) { if (abilityView == null) {
CardView sourceCardView; CardView sourceCardView;
if (isPermanent) { if (isPermanent) {
sourceCardView = new CardView((Permanent)sourceObject); sourceCardView = new CardView((Permanent) sourceObject);
} else if (isCard) { } else if (isCard) {
sourceCardView = new CardView((Card)sourceObject); sourceCardView = new CardView((Card) sourceObject);
} else { } else {
sourceCardView = new CardView(sourceObject); sourceCardView = new CardView(sourceObject);
} }
@ -153,7 +159,7 @@ public class CardsView extends LinkedHashMap<UUID, CardView> {
} }
public CardsView(Collection<? extends Ability> abilities, GameState state) { public CardsView(Collection<? extends Ability> abilities, GameState state) {
for (Ability ability: abilities) { for (Ability ability : abilities) {
Card sourceCard = state.getPermanent(ability.getSourceId()); Card sourceCard = state.getPermanent(ability.getSourceId());
if (sourceCard != null) { if (sourceCard != null) {
this.put(ability.getId(), new AbilityView(ability, sourceCard.getName(), new CardView(sourceCard))); this.put(ability.getId(), new AbilityView(ability, sourceCard.getName(), new CardView(sourceCard)));

View file

@ -1,36 +1,42 @@
/* /*
* Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved.
* *
* Redistribution and use in source and binary forms, with or without modification, are * Redistribution and use in source and binary forms, with or without modification, are
* permitted provided that the following conditions are met: * permitted provided that the following conditions are met:
* *
* 1. Redistributions of source code must retain the above copyright notice, this list of * 1. Redistributions of source code must retain the above copyright notice, this list of
* conditions and the following disclaimer. * conditions and the following disclaimer.
* *
* 2. Redistributions in binary form must reproduce the above copyright notice, this list * 2. Redistributions in binary form must reproduce the above copyright notice, this list
* of conditions and the following disclaimer in the documentation and/or other materials * of conditions and the following disclaimer in the documentation and/or other materials
* provided with the distribution. * provided with the distribution.
* *
* THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
* *
* The views and conclusions contained in the software and documentation are those of the * The views and conclusions contained in the software and documentation are those of the
* authors and should not be interpreted as representing official policies, either expressed * authors and should not be interpreted as representing official policies, either expressed
* or implied, of BetaSteward_at_googlemail.com. * or implied, of BetaSteward_at_googlemail.com.
*/ */
package 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,70 +86,73 @@ 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;
this.priorityTime = game.getPriorityTime(); this.priorityTime = game.getPriorityTime();
for (Player player: state.getPlayers().values()) { for (Player player : state.getPlayers().values()) {
players.add(new PlayerView(player, state, game, createdForPlayerId, watcherUserId)); players.add(new PlayerView(player, state, game, createdForPlayerId, watcherUserId));
if (player.getId().equals(createdForPlayerId)) { if (player.getId().equals(createdForPlayerId)) {
createdForPlayer = player; createdForPlayer = player;
} }
} }
for (StackObject stackObject: state.getStack()) { for (StackObject stackObject : state.getStack()) {
if (stackObject instanceof StackAbility) { if (stackObject instanceof StackAbility) {
// Stack Ability // Stack Ability
MageObject object = game.getObject(stackObject.getSourceId()); MageObject object = game.getObject(stackObject.getSourceId());
Card card = game.getCard(stackObject.getSourceId()); Card card = game.getCard(stackObject.getSourceId());
if (card != null) { if (card != null) {
if (object != null) { if (object != null) {
stack.put(stackObject.getId(), new StackAbilityView(game, (StackAbility)stackObject, card.getName(), new CardView(card))); stack.put(stackObject.getId(), new StackAbilityView(game, (StackAbility) stackObject, card.getName(), new CardView(card)));
} else { } else {
stack.put(stackObject.getId(), new StackAbilityView(game, (StackAbility)stackObject, "", new CardView(card))); stack.put(stackObject.getId(), new StackAbilityView(game, (StackAbility) stackObject, "", new CardView(card)));
} }
if (card.canTransform()) { if (card.canTransform()) {
updateLatestCardView(game, card, stackObject.getId()); updateLatestCardView(game, card, stackObject.getId());
} }
checkPaid(stackObject.getId(), (StackAbility)stackObject); checkPaid(stackObject.getId(), (StackAbility) stackObject);
} else if (object != null) { } else if (object != null) {
if (object instanceof PermanentToken) { if (object instanceof PermanentToken) {
PermanentToken token = (PermanentToken)object; PermanentToken token = (PermanentToken) object;
stack.put(stackObject.getId(), new StackAbilityView(game, (StackAbility)stackObject, token.getName(), new CardView(token))); stack.put(stackObject.getId(), new StackAbilityView(game, (StackAbility) stackObject, token.getName(), new CardView(token)));
checkPaid(stackObject.getId(), (StackAbility)stackObject); checkPaid(stackObject.getId(), (StackAbility) stackObject);
} 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) {
((StackAbility)stackObject).setName("Emblem " + sourceCard.getName()); if (!sourceCard.getCardType().contains(CardType.PLANESWALKER)) {
((StackAbility)stackObject).setExpansionSetCode(sourceCard.getExpansionSetCode()); if (sourceCard.getSecondCardFace() != null) {
sourceCard = sourceCard.getSecondCardFace();
}
}
((StackAbility) stackObject).setName("Emblem " + sourceCard.getName());
((StackAbility) stackObject).setExpansionSetCode(sourceCard.getExpansionSetCode());
} else { } else {
throw new IllegalArgumentException("Source card for emblem not found."); throw new IllegalArgumentException("Source card for emblem not found.");
} }
stack.put(stackObject.getId(), stack.put(stackObject.getId(),
new StackAbilityView(game, (StackAbility)stackObject, object.getName(), new CardView(new EmblemView(((Emblem)object),sourceCard)))); new StackAbilityView(game, (StackAbility) stackObject, object.getName(), new CardView(new EmblemView(((Emblem) object), sourceCard))));
checkPaid(stackObject.getId(), ((StackAbility)stackObject)); checkPaid(stackObject.getId(), ((StackAbility) stackObject));
} else { } else {
StackAbility stackAbility = ((StackAbility)object); StackAbility stackAbility = ((StackAbility) object);
stackAbility.newId(); stackAbility.newId();
stack.put(stackObject.getId(), new CardView(((StackAbility)stackObject))); stack.put(stackObject.getId(), new CardView(((StackAbility) stackObject)));
checkPaid(stackObject.getId(), ((StackAbility)stackObject)); checkPaid(stackObject.getId(), ((StackAbility) stackObject));
} }
} 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);
} }
//stackOrder.add(stackObject.getId()); //stackOrder.add(stackObject.getId());
} }
//Collections.reverse(stackOrder); //Collections.reverse(stackOrder);
for (ExileZone exileZone: state.getExile().getExileZones()) { for (ExileZone exileZone : state.getExile().getExileZones()) {
exiles.add(new ExileView(exileZone, game)); exiles.add(new ExileView(exileZone, game));
} }
for (String name: state.getRevealed().keySet()) { for (String name : state.getRevealed().keySet()) {
revealed.add(new RevealedView(name, state.getRevealed().get(name), game)); revealed.add(new RevealedView(name, state.getRevealed().get(name), game));
} }
this.phase = state.getTurn().getPhaseType(); this.phase = state.getTurn().getPhaseType();
@ -163,7 +169,7 @@ public class GameView implements Serializable {
} else { } else {
this.priorityPlayerName = ""; this.priorityPlayerName = "";
} }
for (CombatGroup combatGroup: state.getCombat().getGroups()) { for (CombatGroup combatGroup : state.getCombat().getGroups()) {
combat.add(new CombatGroupView(combatGroup, game)); combat.add(new CombatGroupView(combatGroup, game));
} }
if (isPlayer) { if (isPlayer) {
@ -174,13 +180,13 @@ public class GameView implements Serializable {
} else { } else {
this.special = false; this.special = false;
} }
CastSpellLastTurnWatcher watcher = (CastSpellLastTurnWatcher) game.getState().getWatchers().get("CastSpellLastTurnWatcher"); CastSpellLastTurnWatcher watcher = (CastSpellLastTurnWatcher) game.getState().getWatchers().get("CastSpellLastTurnWatcher");
if (watcher != null) { if (watcher != null) {
spellsCastCurrentTurn = watcher.getAmountOfSpellsAllPlayersCastOnCurrentTurn(); spellsCastCurrentTurn = watcher.getAmountOfSpellsAllPlayersCastOnCurrentTurn();
} else { } else {
spellsCastCurrentTurn = 0; spellsCastCurrentTurn = 0;
} }
rollbackTurnsAllowed = game.getOptions().rollbackTurnsAllowed; rollbackTurnsAllowed = game.getOptions().rollbackTurnsAllowed;
} }
@ -215,7 +221,7 @@ public class GameView implements Serializable {
} }
Permanent permanent = game.getPermanent(card.getId()); Permanent permanent = game.getPermanent(card.getId());
if (permanent == null) { if (permanent == null) {
permanent = (Permanent)game.getLastKnownInformation(card.getId(), Zone.BATTLEFIELD); permanent = (Permanent) game.getLastKnownInformation(card.getId(), Zone.BATTLEFIELD);
} }
if (permanent != null) { if (permanent != null) {
if (permanent.isTransformed()) { if (permanent.isTransformed()) {
@ -328,5 +334,5 @@ public class GameView implements Serializable {
public boolean isRollbackTurnsAllowed() { public boolean isRollbackTurnsAllowed() {
return rollbackTurnsAllowed; return rollbackTurnsAllowed;
} }
} }

View file

@ -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));
} }
} }

View file

@ -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<>();

View file

@ -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;
@ -54,9 +54,9 @@ import mage.target.TargetPlayer;
* @author jeffwadsworth * @author jeffwadsworth
*/ */
public class NecromancersCovenant extends CardImpl { public class NecromancersCovenant extends CardImpl {
private static final FilterControlledCreaturePermanent filter = new FilterControlledCreaturePermanent("Zombies you control"); private static final FilterControlledCreaturePermanent filter = new FilterControlledCreaturePermanent("Zombies you control");
static { static {
filter.add(new SubtypePredicate("Zombie")); filter.add(new SubtypePredicate("Zombie"));
} }
@ -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;
} }

View file

@ -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;

View file

@ -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) {

View file

@ -72,11 +72,11 @@ 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");
Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, effect, new ManaCostsImpl("{B}")); Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, effect, new ManaCostsImpl("{B}"));
ability.addCost(new TapSourceCost()); ability.addCost(new TapSourceCost());
ability.addCost(new SacrificeTargetCost(new TargetControlledCreaturePermanent(filter))); ability.addCost(new SacrificeTargetCost(new TargetControlledCreaturePermanent(filter)));
this.addAbility(ability); this.addAbility(ability);

View file

@ -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));

View file

@ -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}")));
} }

View file

@ -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)));

View file

@ -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));
} }

View file

@ -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));
} }

View file

@ -53,9 +53,9 @@ public class RakshasaGravecaller extends CardImpl {
// Exploit // Exploit
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) {

View file

@ -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))));
} }

View file

@ -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));

View file

@ -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());
} }
} }

View file

@ -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())));
} }

View file

@ -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));

View file

@ -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) {
@ -105,7 +105,7 @@ class UndeadAlchemistTriggeredAbility extends TriggeredAbilityImpl {
@Override @Override
public boolean checkTrigger(GameEvent event, Game game) { public boolean checkTrigger(GameEvent event, Game game) {
ZoneChangeEvent zEvent = (ZoneChangeEvent)event; ZoneChangeEvent zEvent = (ZoneChangeEvent) event;
if (zEvent.getFromZone() == Zone.LIBRARY && zEvent.getToZone() == Zone.GRAVEYARD && game.getOpponents(this.getControllerId()).contains(zEvent.getPlayerId())) { if (zEvent.getFromZone() == Zone.LIBRARY && zEvent.getToZone() == Zone.GRAVEYARD && game.getOpponents(this.getControllerId()).contains(zEvent.getPlayerId())) {
Card card = game.getCard(event.getTargetId()); Card card = game.getCard(event.getTargetId());
if (card != null && card.getCardType().contains(CardType.CREATURE)) { if (card != null && card.getCardType().contains(CardType.CREATURE)) {

View file

@ -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) {

View file

@ -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),

View file

@ -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}")));
@ -102,7 +102,7 @@ class PonybackBrigadeAbility extends TriggeredAbilityImpl {
if (event.getType() == EventType.TURNEDFACEUP && event.getTargetId().equals(this.getSourceId())) { if (event.getType() == EventType.TURNEDFACEUP && event.getTargetId().equals(this.getSourceId())) {
return true; return true;
} }
if (event.getType() == EventType.ENTERS_THE_BATTLEFIELD && event.getTargetId().equals(this.getSourceId()) ) { if (event.getType() == EventType.ENTERS_THE_BATTLEFIELD && event.getTargetId().equals(this.getSourceId())) {
Permanent sourcePermanent = game.getPermanent(getSourceId()); Permanent sourcePermanent = game.getPermanent(getSourceId());
if (sourcePermanent != null && !sourcePermanent.isFaceDown(game)) { if (sourcePermanent != null && !sourcePermanent.isFaceDown(game)) {
return true; return true;

View file

@ -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) {
@ -126,12 +126,12 @@ class SidisiBroodTyrantTriggeredAbility extends TriggeredAbilityImpl {
@Override @Override
public boolean checkTrigger(GameEvent event, Game game) { public boolean checkTrigger(GameEvent event, Game game) {
ZoneChangeGroupEvent zEvent = (ZoneChangeGroupEvent)event; ZoneChangeGroupEvent zEvent = (ZoneChangeGroupEvent) event;
if (Zone.LIBRARY == zEvent.getFromZone() && Zone.GRAVEYARD == zEvent.getToZone()) { if (Zone.LIBRARY == zEvent.getFromZone() && Zone.GRAVEYARD == zEvent.getToZone()) {
for (Card card: zEvent.getCards()) { for (Card card : zEvent.getCards()) {
if (card.getOwnerId().equals(getControllerId()) && card.getCardType().contains(CardType.CREATURE)) { if (card.getOwnerId().equals(getControllerId()) && card.getCardType().contains(CardType.CREATURE)) {
return true; return true;
} }
} }
} }
return false; return false;
@ -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.";

View file

@ -1,16 +1,16 @@
/* /*
* Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved.
* *
* Redistribution and use in source and binary forms, with or without modification, are * Redistribution and use in source and binary forms, with or without modification, are
* permitted provided that the following conditions are met: * permitted provided that the following conditions are met:
* *
* 1. Redistributions of source code must retain the above copyright notice, this list of * 1. Redistributions of source code must retain the above copyright notice, this list of
* conditions and the following disclaimer. * conditions and the following disclaimer.
* *
* 2. Redistributions in binary form must reproduce the above copyright notice, this list * 2. Redistributions in binary form must reproduce the above copyright notice, this list
* of conditions and the following disclaimer in the documentation and/or other materials * of conditions and the following disclaimer in the documentation and/or other materials
* provided with the distribution. * provided with the distribution.
* *
* THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR
@ -20,12 +20,11 @@
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
* *
* The views and conclusions contained in the software and documentation are those of the * The views and conclusions contained in the software and documentation are those of the
* authors and should not be interpreted as representing official policies, either expressed * authors and should not be interpreted as representing official policies, either expressed
* or implied, of BetaSteward_at_googlemail.com. * or implied, of BetaSteward_at_googlemail.com.
*/ */
package 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) {
@ -96,7 +95,7 @@ class GraveTitanAbility extends TriggeredAbilityImpl {
if (event.getType() == EventType.ATTACKER_DECLARED && event.getSourceId().equals(this.getSourceId())) { if (event.getType() == EventType.ATTACKER_DECLARED && event.getSourceId().equals(this.getSourceId())) {
return true; return true;
} }
if (event.getType() == EventType.ENTERS_THE_BATTLEFIELD && event.getTargetId().equals(this.getSourceId()) ) { if (event.getType() == EventType.ENTERS_THE_BATTLEFIELD && event.getTargetId().equals(this.getSourceId())) {
return true; return true;
} }
return false; return false;

View file

@ -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;
@ -55,7 +54,7 @@ import mage.target.common.TargetCardInGraveyard;
public class CemeteryReaper extends CardImpl { public class CemeteryReaper extends CardImpl {
private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("Zombie creatures"); private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("Zombie creatures");
static { static {
filter.add(new SubtypePredicate("Zombie")); filter.add(new SubtypePredicate("Zombie"));
} }
@ -66,14 +65,14 @@ public class CemeteryReaper extends CardImpl {
this.subtype.add("Zombie"); this.subtype.add("Zombie");
this.power = new MageInt(2); this.power = new MageInt(2);
this.toughness = new MageInt(2); this.toughness = new MageInt(2);
// Other Zombie creatures you control get +1/+1. // Other Zombie creatures you control get +1/+1.
this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new BoostControlledEffect(1, 1, Duration.WhileOnBattlefield, filter, true))); this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new BoostControlledEffect(1, 1, Duration.WhileOnBattlefield, filter, true)));
// {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);
} }

View file

@ -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);
} }

View file

@ -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) {

View file

@ -57,8 +57,8 @@ public class LilianasReaver extends CardImpl {
this.addAbility(DeathtouchAbility.getInstance()); this.addAbility(DeathtouchAbility.getInstance());
// 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);
} }

View file

@ -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);

View file

@ -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) {

View file

@ -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}"));
@ -97,7 +95,7 @@ class NecromancersStockpileDiscardTargetCost extends CostImpl {
public boolean pay(Ability ability, Game game, UUID sourceId, UUID controllerId, boolean noMana) { public boolean pay(Ability ability, Game game, UUID sourceId, UUID controllerId, boolean noMana) {
if (targets.choose(Outcome.Discard, controllerId, sourceId, game)) { if (targets.choose(Outcome.Discard, controllerId, sourceId, game)) {
Player player = game.getPlayer(controllerId); Player player = game.getPlayer(controllerId);
for (UUID targetId: targets.get(0).getTargets()) { for (UUID targetId : targets.get(0).getTargets()) {
Card card = player.getHand().get(targetId, game); Card card = player.getHand().get(targetId, game);
if (card == null) { if (card == null) {
return false; return false;
@ -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);
} }
} }

View file

@ -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);
} }

View file

@ -53,13 +53,12 @@ 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());
// Whenever an opponent discards a land card, add {B}{B} to your mana pool. // Whenever an opponent discards a land card, add {B}{B} to your mana pool.
this.addAbility(new WasteNotLandTriggeredAbility()); this.addAbility(new WasteNotLandTriggeredAbility());
// Whenever an opponent discards a noncreature, nonland card, draw a card. // Whenever an opponent discards a noncreature, nonland card, draw a card.
this.addAbility(new WasteNotOtherTriggeredAbility()); this.addAbility(new WasteNotOtherTriggeredAbility());
} }
@ -75,15 +74,15 @@ 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) {
super(ability); super(ability);
} }
@Override @Override
public WasteNotCreatureTriggeredAbility copy() { public WasteNotCreatureTriggeredAbility copy() {
return new WasteNotCreatureTriggeredAbility(this); return new WasteNotCreatureTriggeredAbility(this);
@ -93,7 +92,7 @@ class WasteNotCreatureTriggeredAbility extends TriggeredAbilityImpl {
public boolean checkEventType(GameEvent event, Game game) { public boolean checkEventType(GameEvent event, Game game) {
return event.getType() == EventType.DISCARDED_CARD; return event.getType() == EventType.DISCARDED_CARD;
} }
@Override @Override
public boolean checkTrigger(GameEvent event, Game game) { public boolean checkTrigger(GameEvent event, Game game) {
if (game.getOpponents(this.getControllerId()).contains(event.getPlayerId())) { if (game.getOpponents(this.getControllerId()).contains(event.getPlayerId())) {
@ -104,7 +103,7 @@ class WasteNotCreatureTriggeredAbility extends TriggeredAbilityImpl {
} }
return false; return false;
} }
@Override @Override
public String getRule() { public String getRule() {
return "Whenever an opponent discards a creature card, put a 2/2 black Zombie creature token onto the battlefield."; return "Whenever an opponent discards a creature card, put a 2/2 black Zombie creature token onto the battlefield.";
@ -112,15 +111,15 @@ class WasteNotCreatureTriggeredAbility extends TriggeredAbilityImpl {
} }
class WasteNotLandTriggeredAbility extends TriggeredAbilityImpl { class WasteNotLandTriggeredAbility extends TriggeredAbilityImpl {
WasteNotLandTriggeredAbility() { WasteNotLandTriggeredAbility() {
super(Zone.BATTLEFIELD, new BasicManaEffect(new Mana(0, 0, 0, 0, 2, 0, 0)), false); super(Zone.BATTLEFIELD, new BasicManaEffect(new Mana(0, 0, 0, 0, 2, 0, 0)), false);
} }
WasteNotLandTriggeredAbility(final WasteNotLandTriggeredAbility ability) { WasteNotLandTriggeredAbility(final WasteNotLandTriggeredAbility ability) {
super(ability); super(ability);
} }
@Override @Override
public WasteNotLandTriggeredAbility copy() { public WasteNotLandTriggeredAbility copy() {
return new WasteNotLandTriggeredAbility(this); return new WasteNotLandTriggeredAbility(this);
@ -130,7 +129,7 @@ class WasteNotLandTriggeredAbility extends TriggeredAbilityImpl {
public boolean checkEventType(GameEvent event, Game game) { public boolean checkEventType(GameEvent event, Game game) {
return event.getType() == EventType.DISCARDED_CARD; return event.getType() == EventType.DISCARDED_CARD;
} }
@Override @Override
public boolean checkTrigger(GameEvent event, Game game) { public boolean checkTrigger(GameEvent event, Game game) {
if (game.getOpponents(this.getControllerId()).contains(event.getPlayerId())) { if (game.getOpponents(this.getControllerId()).contains(event.getPlayerId())) {
@ -141,7 +140,7 @@ class WasteNotLandTriggeredAbility extends TriggeredAbilityImpl {
} }
return false; return false;
} }
@Override @Override
public String getRule() { public String getRule() {
return "Whenever an opponent discards a land card, add {B}{B} to your mana pool."; return "Whenever an opponent discards a land card, add {B}{B} to your mana pool.";
@ -149,15 +148,15 @@ class WasteNotLandTriggeredAbility extends TriggeredAbilityImpl {
} }
class WasteNotOtherTriggeredAbility extends TriggeredAbilityImpl { class WasteNotOtherTriggeredAbility extends TriggeredAbilityImpl {
WasteNotOtherTriggeredAbility() { WasteNotOtherTriggeredAbility() {
super(Zone.BATTLEFIELD, new DrawCardSourceControllerEffect(1), false); super(Zone.BATTLEFIELD, new DrawCardSourceControllerEffect(1), false);
} }
WasteNotOtherTriggeredAbility(final WasteNotOtherTriggeredAbility ability) { WasteNotOtherTriggeredAbility(final WasteNotOtherTriggeredAbility ability) {
super(ability); super(ability);
} }
@Override @Override
public WasteNotOtherTriggeredAbility copy() { public WasteNotOtherTriggeredAbility copy() {
return new WasteNotOtherTriggeredAbility(this); return new WasteNotOtherTriggeredAbility(this);
@ -167,7 +166,7 @@ class WasteNotOtherTriggeredAbility extends TriggeredAbilityImpl {
public boolean checkEventType(GameEvent event, Game game) { public boolean checkEventType(GameEvent event, Game game) {
return event.getType() == EventType.DISCARDED_CARD; return event.getType() == EventType.DISCARDED_CARD;
} }
@Override @Override
public boolean checkTrigger(GameEvent event, Game game) { public boolean checkTrigger(GameEvent event, Game game) {
if (game.getOpponents(this.getControllerId()).contains(event.getPlayerId())) { if (game.getOpponents(this.getControllerId()).contains(event.getPlayerId())) {
@ -178,9 +177,9 @@ class WasteNotOtherTriggeredAbility extends TriggeredAbilityImpl {
} }
return false; return false;
} }
@Override @Override
public String getRule() { public String getRule() {
return "Whenever an opponent discards a noncreature, nonland card, draw a card."; return "Whenever an opponent discards a noncreature, nonland card, draw a card.";
} }
} }

View file

@ -53,9 +53,9 @@ public class AspiringAeronaut extends CardImpl {
// Flying // Flying
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) {

View file

@ -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,8 +55,8 @@ 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());
this.addAbility(ability); this.addAbility(ability);

View file

@ -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);

View file

@ -66,10 +66,10 @@ public class HangarbackWalker extends CardImpl {
// Hangarback Walker enters the battlefield with X +1/+1 counters on it. // Hangarback Walker enters the battlefield with X +1/+1 counters on it.
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));
ability.addCost(new TapSourceCost()); ability.addCost(new TapSourceCost());
@ -88,33 +88,33 @@ public class HangarbackWalker extends CardImpl {
class HangarbackWalkerEffect extends OneShotEffect { class HangarbackWalkerEffect extends OneShotEffect {
public HangarbackWalkerEffect() { public HangarbackWalkerEffect() {
super(Outcome.BoostCreature); super(Outcome.BoostCreature);
staticText = "{this} enters the battlefield with X +1/+1 counters on it"; staticText = "{this} enters the battlefield with X +1/+1 counters on it";
} }
public HangarbackWalkerEffect(final HangarbackWalkerEffect effect) { public HangarbackWalkerEffect(final HangarbackWalkerEffect effect) {
super(effect); super(effect);
} }
@Override @Override
public boolean apply(Game game, Ability source) { public boolean apply(Game game, Ability source) {
Permanent permanent = game.getPermanent(source.getSourceId()); Permanent permanent = game.getPermanent(source.getSourceId());
if (permanent != null) { if (permanent != null) {
Object obj = getValue(EntersBattlefieldEffect.SOURCE_CAST_SPELL_ABILITY); Object obj = getValue(EntersBattlefieldEffect.SOURCE_CAST_SPELL_ABILITY);
if (obj != null && obj instanceof SpellAbility) { if (obj != null && obj instanceof SpellAbility) {
int amount = ((SpellAbility)obj).getManaCostsToPay().getX(); int amount = ((SpellAbility) obj).getManaCostsToPay().getX();
if (amount > 0) { if (amount > 0) {
permanent.addCounters(CounterType.P1P1.createInstance(amount), game); permanent.addCounters(CounterType.P1P1.createInstance(amount), game);
}
} }
} }
return true;
} }
return true;
}
@Override @Override
public HangarbackWalkerEffect copy() { public HangarbackWalkerEffect copy() {
return new HangarbackWalkerEffect(this); return new HangarbackWalkerEffect(this);
} }
} }

View file

@ -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);
} }

View file

@ -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) {

View file

@ -65,10 +65,10 @@ public class NissaSageAnimist extends CardImpl {
this.expansionSetCode = "ORI"; this.expansionSetCode = "ORI";
this.subtype.add("Nissa"); this.subtype.add("Nissa");
this.color.setGreen(true); this.color.setGreen(true);
this.nightCard = true; this.nightCard = true;
this.canTransform = true; this.canTransform = true;
this.addAbility(new EntersBattlefieldAbility(new AddCountersSourceEffect(CounterType.LOYALTY.createInstance(3)), false)); this.addAbility(new EntersBattlefieldAbility(new AddCountersSourceEffect(CounterType.LOYALTY.createInstance(3)), false));
// +1: Reveal the top card of your library. If it's a land card, put it onto the battlefield. Otherwise, put it into your hand. // +1: Reveal the top card of your library. If it's a land card, put it onto the battlefield. Otherwise, put it into your hand.
@ -95,21 +95,21 @@ public class NissaSageAnimist extends CardImpl {
} }
class NissaSageAnimistPlusOneEffect extends OneShotEffect { class NissaSageAnimistPlusOneEffect extends OneShotEffect {
NissaSageAnimistPlusOneEffect() { NissaSageAnimistPlusOneEffect() {
super(Outcome.Benefit); super(Outcome.Benefit);
this.staticText = "Reveal the top card of your library. If it's a land card, put it onto the battlefield. Otherwise, put it into your hand."; this.staticText = "Reveal the top card of your library. If it's a land card, put it onto the battlefield. Otherwise, put it into your hand.";
} }
NissaSageAnimistPlusOneEffect(final NissaSageAnimistPlusOneEffect effect) { NissaSageAnimistPlusOneEffect(final NissaSageAnimistPlusOneEffect effect) {
super(effect); super(effect);
} }
@Override @Override
public NissaSageAnimistPlusOneEffect copy() { public NissaSageAnimistPlusOneEffect copy() {
return new NissaSageAnimistPlusOneEffect(this); return new NissaSageAnimistPlusOneEffect(this);
} }
@Override @Override
public boolean apply(Game game, Ability source) { public boolean apply(Game game, Ability source) {
Player controller = game.getPlayer(source.getControllerId()); Player controller = game.getPlayer(source.getControllerId());
@ -195,4 +195,4 @@ class NissaSageAnimistMinusSevenEffect extends ContinuousEffectImpl {
public boolean hasLayer(Layer layer) { public boolean hasLayer(Layer layer) {
return layer == Layer.TypeChangingEffects_4 || layer == Layer.PTChangingEffects_7; return layer == Layer.TypeChangingEffects_4 || layer == Layer.PTChangingEffects_7;
} }
} }

View file

@ -61,11 +61,11 @@ 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}"));
ability.addCost(new SacrificeTargetCost(new TargetControlledPermanent(1,1, new FilterControlledArtifactPermanent("an artifact"),true))); ability.addCost(new SacrificeTargetCost(new TargetControlledPermanent(1, 1, new FilterControlledArtifactPermanent("an artifact"), true)));
ability.addTarget(new TargetCreatureOrPlayer()); ability.addTarget(new TargetCreatureOrPlayer());
this.addAbility(ability); this.addAbility(ability);
} }
@ -78,4 +78,4 @@ public class PiaAndKiranNalaar extends CardImpl {
public PiaAndKiranNalaar copy() { public PiaAndKiranNalaar copy() {
return new PiaAndKiranNalaar(this); return new PiaAndKiranNalaar(this);
} }
} }

View file

@ -56,7 +56,7 @@ public class ThopterSpyNetwork extends CardImpl {
// At the beginning of your upkeep, if you control an artifact, put a 1/1 colorless Thopter artifact creature token with flying onto the battlefield. // At the beginning of your upkeep, if you control an artifact, put a 1/1 colorless Thopter artifact creature token with flying onto the battlefield.
this.addAbility(new ThopterSpyNetworkUpkeepTriggeredAbility()); this.addAbility(new ThopterSpyNetworkUpkeepTriggeredAbility());
// Whenever one or more artifact creatures you control deals combat damage to a player, draw a card. // Whenever one or more artifact creatures you control deals combat damage to a player, draw a card.
this.addAbility(new ThopterSpyNetworkDamageTriggeredAbility()); this.addAbility(new ThopterSpyNetworkDamageTriggeredAbility());
} }
@ -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) {
@ -98,7 +98,7 @@ class ThopterSpyNetworkUpkeepTriggeredAbility extends TriggeredAbilityImpl {
@Override @Override
public boolean checkInterveningIfClause(Game game) { public boolean checkInterveningIfClause(Game game) {
return game.getBattlefield().countAll(new FilterArtifactPermanent(), this.controllerId, game) >= 1; return game.getBattlefield().countAll(new FilterArtifactPermanent(), this.controllerId, game) >= 1;
} }
@Override @Override
@ -108,7 +108,7 @@ class ThopterSpyNetworkUpkeepTriggeredAbility extends TriggeredAbilityImpl {
} }
class ThopterSpyNetworkDamageTriggeredAbility extends TriggeredAbilityImpl { class ThopterSpyNetworkDamageTriggeredAbility extends TriggeredAbilityImpl {
List<UUID> damagedPlayerIds = new ArrayList<>(); List<UUID> damagedPlayerIds = new ArrayList<>();
public ThopterSpyNetworkDamageTriggeredAbility() { public ThopterSpyNetworkDamageTriggeredAbility() {
@ -127,7 +127,7 @@ class ThopterSpyNetworkDamageTriggeredAbility extends TriggeredAbilityImpl {
@Override @Override
public boolean checkEventType(GameEvent event, Game game) { public boolean checkEventType(GameEvent event, Game game) {
return event.getType() == GameEvent.EventType.DAMAGED_PLAYER return event.getType() == GameEvent.EventType.DAMAGED_PLAYER
|| event.getType() == GameEvent.EventType.END_COMBAT_STEP_POST; || event.getType() == GameEvent.EventType.END_COMBAT_STEP_POST;
} }
@Override @Override
@ -135,14 +135,14 @@ class ThopterSpyNetworkDamageTriggeredAbility extends TriggeredAbilityImpl {
if (event.getType() == GameEvent.EventType.DAMAGED_PLAYER) { if (event.getType() == GameEvent.EventType.DAMAGED_PLAYER) {
if (((DamagedPlayerEvent) event).isCombatDamage()) { if (((DamagedPlayerEvent) event).isCombatDamage()) {
Permanent creature = game.getPermanent(event.getSourceId()); Permanent creature = game.getPermanent(event.getSourceId());
if (creature != null && creature.getControllerId().equals(controllerId) if (creature != null && creature.getControllerId().equals(controllerId)
&& creature.getCardType().contains(CardType.ARTIFACT) && !damagedPlayerIds.contains(event.getTargetId())) { && creature.getCardType().contains(CardType.ARTIFACT) && !damagedPlayerIds.contains(event.getTargetId())) {
damagedPlayerIds.add(event.getTargetId()); damagedPlayerIds.add(event.getTargetId());
return true; return true;
} }
} }
} }
if (event.getType().equals(GameEvent.EventType.END_COMBAT_STEP_POST)){ if (event.getType().equals(GameEvent.EventType.END_COMBAT_STEP_POST)) {
damagedPlayerIds.clear(); damagedPlayerIds.clear();
} }
return false; return false;
@ -152,4 +152,4 @@ class ThopterSpyNetworkDamageTriggeredAbility extends TriggeredAbilityImpl {
public String getRule() { public String getRule() {
return "Whenever one or more artifact creatures you control deals combat damage to a player, draw a card"; return "Whenever one or more artifact creatures you control deals combat damage to a player, draw a card";
} }
} }

View file

@ -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) {

View file

@ -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;
@ -47,7 +46,7 @@ import mage.game.permanent.token.ZombieToken;
*/ */
public class NestedGhoul extends CardImpl { public class NestedGhoul extends CardImpl {
public NestedGhoul (UUID ownerId) { public NestedGhoul(UUID ownerId) {
super(ownerId, 48, "Nested Ghoul", Rarity.UNCOMMON, new CardType[]{CardType.CREATURE}, "{3}{B}{B}"); super(ownerId, 48, "Nested Ghoul", Rarity.UNCOMMON, new CardType[]{CardType.CREATURE}, "{3}{B}{B}");
this.expansionSetCode = "MBS"; this.expansionSetCode = "MBS";
this.subtype.add("Zombie"); this.subtype.add("Zombie");
@ -58,7 +57,7 @@ public class NestedGhoul extends CardImpl {
this.addAbility(new NestedGhoulTriggeredAbility()); this.addAbility(new NestedGhoulTriggeredAbility());
} }
public NestedGhoul (final NestedGhoul card) { public NestedGhoul(final NestedGhoul card) {
super(card); super(card);
} }
@ -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) {
@ -97,4 +97,4 @@ class NestedGhoulTriggeredAbility extends TriggeredAbilityImpl {
public String getRule() { public String getRule() {
return "Whenever a source deals damage to {this}, put a 2/2 black Zombie creature token onto the battlefield."; return "Whenever a source deals damage to {this}, put a 2/2 black Zombie creature token onto the battlefield.";
} }
} }

View file

@ -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)));
} }

View file

@ -25,33 +25,32 @@
* 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 {
filter.add(new CardTypePredicate(CardType.ARTIFACT)); filter.add(new CardTypePredicate(CardType.ARTIFACT));
} }
public KuldothaRebirth (UUID ownerId) { public KuldothaRebirth(UUID ownerId) {
super(ownerId, 96, "Kuldotha Rebirth", Rarity.COMMON, new CardType[]{CardType.SORCERY}, "{R}"); super(ownerId, 96, "Kuldotha Rebirth", Rarity.COMMON, new CardType[]{CardType.SORCERY}, "{R}");
this.expansionSetCode = "SOM"; this.expansionSetCode = "SOM";
@ -59,7 +58,7 @@ public class KuldothaRebirth extends CardImpl {
this.getSpellAbility().addCost(new SacrificeTargetCost(new TargetControlledPermanent(filter))); this.getSpellAbility().addCost(new SacrificeTargetCost(new TargetControlledPermanent(filter)));
} }
public KuldothaRebirth (final KuldothaRebirth card) { public KuldothaRebirth(final KuldothaRebirth card) {
super(card); super(card);
} }
@ -68,4 +67,4 @@ public class KuldothaRebirth extends CardImpl {
return new KuldothaRebirth(this); return new KuldothaRebirth(this);
} }
} }

View file

@ -51,10 +51,11 @@ 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")));
} }
public ArchdemonOfUnx(UUID ownerId) { public ArchdemonOfUnx(UUID ownerId) {
super(ownerId, 64, "Archdemon of Unx", Rarity.RARE, new CardType[]{CardType.CREATURE}, "{5}{B}{B}"); super(ownerId, 64, "Archdemon of Unx", Rarity.RARE, new CardType[]{CardType.CREATURE}, "{5}{B}{B}");
this.expansionSetCode = "ALA"; this.expansionSetCode = "ALA";
@ -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);
} }

View file

@ -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;
/** /**

View file

@ -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;
@ -83,14 +82,14 @@ class MoggInfestationEffect extends OneShotEffect {
@Override @Override
public MoggInfestationEffect copy() { public MoggInfestationEffect copy() {
return new MoggInfestationEffect(this); return new MoggInfestationEffect(this);
} }
@Override @Override
public boolean apply(Game game, Ability source) { public boolean apply(Game game, Ability source) {
Player controller = game.getPlayer(source.getControllerId()); Player controller = game.getPlayer(source.getControllerId());
if (controller != null && getTargetPointer().getFirst(game, source) != null) { if (controller != null && getTargetPointer().getFirst(game, source) != null) {
for (Permanent permanent: game.getBattlefield().getAllActivePermanents(new FilterCreaturePermanent(), getTargetPointer().getFirst(game, source), game)) { for (Permanent permanent : game.getBattlefield().getAllActivePermanents(new FilterCreaturePermanent(), getTargetPointer().getFirst(game, source), game)) {
if (permanent.destroy(source.getSourceId(), game, false)) { if (permanent.destroy(source.getSourceId(), game, false)) {
Effect effect = new CreateTokenTargetEffect(new GoblinToken(), 2); Effect effect = new CreateTokenTargetEffect(new GoblinToken(), 2);
effect.setTargetPointer(getTargetPointer()); effect.setTargetPointer(getTargetPointer());

View file

@ -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

View file

@ -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();
}
}

View file

@ -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
* *

View file

@ -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;
} }
} }

View file

@ -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);
} }
} }

View file

@ -1,39 +1,40 @@
/* /*
* Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved.
* *
* Redistribution and use in source and binary forms, with or without modification, are * Redistribution and use in source and binary forms, with or without modification, are
* permitted provided that the following conditions are met: * permitted provided that the following conditions are met:
* *
* 1. Redistributions of source code must retain the above copyright notice, this list of * 1. Redistributions of source code must retain the above copyright notice, this list of
* conditions and the following disclaimer. * conditions and the following disclaimer.
* *
* 2. Redistributions in binary form must reproduce the above copyright notice, this list * 2. Redistributions in binary form must reproduce the above copyright notice, this list
* of conditions and the following disclaimer in the documentation and/or other materials * of conditions and the following disclaimer in the documentation and/or other materials
* provided with the distribution. * provided with the distribution.
* *
* THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
* *
* The views and conclusions contained in the software and documentation are those of the * The views and conclusions contained in the software and documentation are those of the
* authors and should not be interpreted as representing official policies, either expressed * authors and should not be interpreted as representing official policies, either expressed
* or implied, of BetaSteward_at_googlemail.com. * or implied, of BetaSteward_at_googlemail.com.
*/ */
package 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));
@ -63,7 +65,7 @@ public class CreateTokenEffect extends OneShotEffect {
public CreateTokenEffect(Token token, DynamicValue amount) { public CreateTokenEffect(Token token, DynamicValue amount) {
this(token, amount, false, false); this(token, amount, false, false);
} }
public CreateTokenEffect(Token token, int amount, boolean tapped, boolean attacking) { public CreateTokenEffect(Token token, int amount, boolean tapped, boolean attacking) {
this(token, new StaticValue(amount), tapped, attacking); this(token, new StaticValue(amount), tapped, attacking);
} }
@ -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,10 +108,18 @@ 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;
} }
public ArrayList<UUID> getLastAddedTokenIds() { public ArrayList<UUID> getLastAddedTokenIds() {
return lastAddedTokenIds; return lastAddedTokenIds;
} }

View file

@ -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());

View file

@ -1,31 +1,30 @@
/* /*
* Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved.
* *
* Redistribution and use in source and binary forms, with or without modification, are * Redistribution and use in source and binary forms, with or without modification, are
* permitted provided that the following conditions are met: * permitted provided that the following conditions are met:
* *
* 1. Redistributions of source code must retain the above copyright notice, this list of * 1. Redistributions of source code must retain the above copyright notice, this list of
* conditions and the following disclaimer. * conditions and the following disclaimer.
* *
* 2. Redistributions in binary form must reproduce the above copyright notice, this list * 2. Redistributions in binary form must reproduce the above copyright notice, this list
* of conditions and the following disclaimer in the documentation and/or other materials * of conditions and the following disclaimer in the documentation and/or other materials
* provided with the distribution. * provided with the distribution.
* *
* THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
* *
* The views and conclusions contained in the software and documentation are those of the * The views and conclusions contained in the software and documentation are those of the
* authors and should not be interpreted as representing official policies, either expressed * authors and should not be interpreted as representing official policies, either expressed
* or implied, of BetaSteward_at_googlemail.com. * or implied, of BetaSteward_at_googlemail.com.
*/ */
package 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,16 +108,15 @@ 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);
} }
ability.setSourceId(this.getId()); ability.setSourceId(this.getId());
abilities.add(ability); abilities.add(ability);
} }
this.usesVariousArt = Character.isDigit(this.getClass().getName().charAt(this.getClass().getName().length()-1)); this.usesVariousArt = Character.isDigit(this.getClass().getName().charAt(this.getClass().getName().length() - 1));
this.morphCard = false; this.morphCard = false;
} }
@ -206,8 +205,12 @@ 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() {
try { try {
@ -217,7 +220,7 @@ public abstract class CardImpl extends MageObjectImpl implements Card {
} }
return rulesError; return rulesError;
} }
@Override @Override
public List<String> getRules(Game game) { public List<String> getRules(Game game) {
try { try {
@ -228,7 +231,7 @@ public abstract class CardImpl extends MageObjectImpl implements Card {
for (String data : cardState.getInfo().values()) { for (String data : cardState.getInfo().values()) {
rules.add(data); rules.add(data);
} }
for (Ability ability: cardState.getAbilities()) { for (Ability ability : cardState.getAbilities()) {
rules.add(ability.getRule()); rules.add(ability.getRule());
} }
} }
@ -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,9 +255,10 @@ 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
*/ */
@Override @Override
@ -265,28 +270,28 @@ public abstract class CardImpl extends MageObjectImpl implements Card {
Abilities<Ability> all = new AbilitiesImpl<>(); Abilities<Ability> all = new AbilitiesImpl<>();
all.addAll(abilities); all.addAll(abilities);
all.addAll(otherAbilities); all.addAll(otherAbilities);
return all; return all;
} }
protected void addAbility(Ability ability) { protected void addAbility(Ability ability) {
ability.setSourceId(this.getId()); ability.setSourceId(this.getId());
abilities.add(ability); abilities.add(ability);
for (Ability subAbility: ability.getSubAbilities()) { for (Ability subAbility : ability.getSubAbilities()) {
abilities.add(subAbility); abilities.add(subAbility);
} }
} }
protected void addAbilities(List<Ability> abilities) { protected void addAbilities(List<Ability> abilities) {
for (Ability ability: abilities) { for (Ability ability : abilities) {
addAbility(ability); addAbility(ability);
} }
} }
protected void addAbility(Ability ability, Watcher watcher) { protected void addAbility(Ability ability, Watcher watcher) {
addAbility(ability); addAbility(ability);
ability.addWatcher(watcher); ability.addWatcher(watcher);
} }
@Override @Override
public SpellAbility getSpellAbility() { public SpellAbility getSpellAbility() {
if (spellAbility == null) { if (spellAbility == null) {
@ -322,9 +327,9 @@ public abstract class CardImpl extends MageObjectImpl implements Card {
public List<Mana> getMana() { public List<Mana> getMana() {
List<Mana> mana = new ArrayList<>(); List<Mana> mana = new ArrayList<>();
for (ManaAbility ability : this.abilities.getManaAbilities(Zone.BATTLEFIELD)) { for (ManaAbility ability : this.abilities.getManaAbilities(Zone.BATTLEFIELD)) {
for (Mana netMana: ability.getNetMana(null)) { for (Mana netMana : ability.getNetMana(null)) {
mana.add(netMana); mana.add(netMana);
} }
} }
return mana; return mana;
} }
@ -357,14 +362,14 @@ public abstract class CardImpl extends MageObjectImpl implements Card {
game.getPlayer(ownerId).getSideboard().remove(this); game.getPlayer(ownerId).getSideboard().remove(this);
break; break;
case COMMAND: case COMMAND:
game.getState().getCommand().remove((Commander)game.getObject(objectId)); game.getState().getCommand().remove((Commander) game.getObject(objectId));
break; break;
case STACK: case STACK:
StackObject stackObject = game.getStack().getSpell(getId()); StackObject stackObject = game.getStack().getSpell(getId());
if (stackObject == null && (this instanceof SplitCard)) { // handle if half od Split cast is on the stack if (stackObject == null && (this instanceof SplitCard)) { // handle if half od Split cast is on the stack
stackObject = game.getStack().getSpell(((SplitCard)this).getLeftHalfCard().getId()); stackObject = game.getStack().getSpell(((SplitCard) this).getLeftHalfCard().getId());
if (stackObject == null) { if (stackObject == null) {
stackObject = game.getStack().getSpell(((SplitCard)this).getRightHalfCard().getId()); stackObject = game.getStack().getSpell(((SplitCard) this).getRightHalfCard().getId());
} }
} }
if (stackObject != null) { if (stackObject != null) {
@ -379,12 +384,12 @@ public abstract class CardImpl extends MageObjectImpl implements Card {
logger.fatal(new StringBuilder("Invalid from zone [").append(fromZone) logger.fatal(new StringBuilder("Invalid from zone [").append(fromZone)
.append("] for card [").append(this.getName()) .append("] for card [").append(this.getName())
.append("] to zone [").append(toZone) .append("] to zone [").append(toZone)
.append("] source [").append(sourceCard != null ? sourceCard.getName():"null").append("]").toString()); .append("] source [").append(sourceCard != null ? sourceCard.getName() : "null").append("]").toString());
break; break;
} }
game.rememberLKI(objectId, event.getFromZone(), this); game.rememberLKI(objectId, event.getFromZone(), this);
} }
setFaceDown(false, game); setFaceDown(false, game);
updateZoneChangeCounter(game); updateZoneChangeCounter(game);
switch (event.getToZone()) { switch (event.getToZone()) {
@ -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;
@ -428,9 +432,9 @@ public abstract class CardImpl extends MageObjectImpl implements Card {
default: default:
Card sourceCard = game.getCard(sourceId); Card sourceCard = game.getCard(sourceId);
logger.fatal(new StringBuilder("Invalid to zone [").append(toZone) logger.fatal(new StringBuilder("Invalid to zone [").append(toZone)
.append("] for card [").append(this.getName()) .append("] for card [").append(this.getName())
.append("] to zone [").append(toZone) .append("] to zone [").append(toZone)
.append("] source [").append(sourceCard != null ? sourceCard.getName():"null").append("]").toString()); .append("] source [").append(sourceCard != null ? sourceCard.getName() : "null").append("]").toString());
return false; return false;
} }
game.setZone(objectId, event.getToZone()); game.setZone(objectId, event.getToZone());
@ -462,12 +466,12 @@ public abstract class CardImpl extends MageObjectImpl implements Card {
case OUTSIDE: case OUTSIDE:
game.getPlayer(ownerId).getSideboard().remove(mainCard); game.getPlayer(ownerId).getSideboard().remove(mainCard);
break; break;
case COMMAND: case COMMAND:
game.getState().getCommand().remove((Commander)game.getObject(mainCard.getId())); game.getState().getCommand().remove((Commander) game.getObject(mainCard.getId()));
break; break;
default: default:
//logger.warning("moveToZone, not fully implemented: from="+event.getFromZone() + ", to="+event.getToZone()); //logger.warning("moveToZone, not fully implemented: from="+event.getFromZone() + ", to="+event.getToZone());
} }
game.rememberLKI(mainCard.getId(), event.getFromZone(), this); game.rememberLKI(mainCard.getId(), event.getFromZone(), this);
} }
@ -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);
@ -514,7 +519,7 @@ public abstract class CardImpl extends MageObjectImpl implements Card {
break; break;
default: default:
MageObject object = game.getObject(sourceId); MageObject object = game.getObject(sourceId);
logger.warn(new StringBuilder("moveToExile, not fully implemented: from = ").append(fromZone).append(" - ").append(object != null ? object.getName():"null")); logger.warn(new StringBuilder("moveToExile, not fully implemented: from = ").append(fromZone).append(" - ").append(object != null ? object.getName() : "null"));
} }
game.rememberLKI(objectId, event.getFromZone(), this); game.rememberLKI(objectId, event.getFromZone(), this);
} }
@ -537,19 +542,19 @@ public abstract class CardImpl extends MageObjectImpl implements Card {
public boolean putOntoBattlefield(Game game, Zone fromZone, UUID sourceId, UUID controllerId) { public boolean putOntoBattlefield(Game game, Zone fromZone, UUID sourceId, UUID controllerId) {
return this.putOntoBattlefield(game, fromZone, sourceId, controllerId, false, false, null); return this.putOntoBattlefield(game, fromZone, sourceId, controllerId, false, false, null);
} }
@Override @Override
public boolean putOntoBattlefield(Game game, Zone fromZone, UUID sourceId, UUID controllerId, boolean tapped){ public boolean putOntoBattlefield(Game game, Zone fromZone, UUID sourceId, UUID controllerId, boolean tapped) {
return this.putOntoBattlefield(game, fromZone, sourceId, controllerId, tapped, false, null); return this.putOntoBattlefield(game, fromZone, sourceId, controllerId, tapped, false, null);
} }
@Override @Override
public boolean putOntoBattlefield(Game game, Zone fromZone, UUID sourceId, UUID controllerId, boolean tapped, boolean facedown){ public boolean putOntoBattlefield(Game game, Zone fromZone, UUID sourceId, UUID controllerId, boolean tapped, boolean facedown) {
return this.putOntoBattlefield(game, fromZone, sourceId, controllerId, tapped, facedown, null); return this.putOntoBattlefield(game, fromZone, sourceId, controllerId, tapped, facedown, null);
} }
@Override @Override
public boolean putOntoBattlefield(Game game, Zone fromZone, UUID sourceId, UUID controllerId, boolean tapped, boolean facedown, ArrayList<UUID> appliedEffects){ public boolean putOntoBattlefield(Game game, Zone fromZone, UUID sourceId, UUID controllerId, boolean tapped, boolean facedown, ArrayList<UUID> appliedEffects) {
ZoneChangeEvent event = new ZoneChangeEvent(this.objectId, sourceId, controllerId, fromZone, Zone.BATTLEFIELD, appliedEffects, tapped); ZoneChangeEvent event = new ZoneChangeEvent(this.objectId, sourceId, controllerId, fromZone, Zone.BATTLEFIELD, appliedEffects, tapped);
if (facedown) { if (facedown) {
this.setFaceDown(true, game); this.setFaceDown(true, game);
@ -582,7 +587,7 @@ public abstract class CardImpl extends MageObjectImpl implements Card {
removed = true; removed = true;
break; break;
default: default:
logger.warn("putOntoBattlefield, not fully implemented: fromZone="+fromZone); logger.warn("putOntoBattlefield, not fully implemented: fromZone=" + fromZone);
} }
game.rememberLKI(objectId, event.getFromZone(), this); game.rememberLKI(objectId, event.getFromZone(), this);
if (!removed) { if (!removed) {
@ -601,7 +606,7 @@ public abstract class CardImpl extends MageObjectImpl implements Card {
permanent.entersBattlefield(sourceId, game, event.getFromZone(), true); permanent.entersBattlefield(sourceId, game, event.getFromZone(), true);
game.setScopeRelevant(false); game.setScopeRelevant(false);
game.applyEffects(); game.applyEffects();
game.addSimultaneousEvent(new ZoneChangeEvent(permanent, event.getPlayerId(), fromZone, Zone.BATTLEFIELD)); game.addSimultaneousEvent(new ZoneChangeEvent(permanent, event.getPlayerId(), fromZone, Zone.BATTLEFIELD));
return true; return true;
} }
if (facedown) { if (facedown) {
@ -625,7 +630,7 @@ public abstract class CardImpl extends MageObjectImpl implements Card {
GameEvent event = GameEvent.getEvent(GameEvent.EventType.TURNFACEUP, getId(), playerId); GameEvent event = GameEvent.getEvent(GameEvent.EventType.TURNFACEUP, getId(), playerId);
if (!game.replaceEvent(event)) { if (!game.replaceEvent(event)) {
setFaceDown(false, game); setFaceDown(false, game);
for (Ability ability :abilities) { // abilities that were set to not visible face down must be set to visible again for (Ability ability : abilities) { // abilities that were set to not visible face down must be set to visible again
if (ability.getWorksFaceDown() && !ability.getRuleVisible()) { if (ability.getWorksFaceDown() && !ability.getRuleVisible()) {
ability.setRuleVisible(true); ability.setRuleVisible(true);
} }
@ -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() {

View file

@ -1,30 +1,30 @@
/* /*
* Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved.
* *
* Redistribution and use in source and binary forms, with or without modification, are * Redistribution and use in source and binary forms, with or without modification, are
* permitted provided that the following conditions are met: * permitted provided that the following conditions are met:
* *
* 1. Redistributions of source code must retain the above copyright notice, this list of * 1. Redistributions of source code must retain the above copyright notice, this list of
* conditions and the following disclaimer. * conditions and the following disclaimer.
* *
* 2. Redistributions in binary form must reproduce the above copyright notice, this list * 2. Redistributions in binary form must reproduce the above copyright notice, this list
* of conditions and the following disclaimer in the documentation and/or other materials * of conditions and the following disclaimer in the documentation and/or other materials
* provided with the distribution. * provided with the distribution.
* *
* THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
* *
* The views and conclusions contained in the software and documentation are those of the * The views and conclusions contained in the software and documentation are those of the
* authors and should not be interpreted as representing official policies, either expressed * authors and should not be interpreted as representing official policies, either expressed
* or implied, of BetaSteward_at_googlemail.com. * or implied, of BetaSteward_at_googlemail.com.
*/ */
package mage.game.command; package mage.game.command;
import java.util.ArrayList; import java.util.ArrayList;
@ -86,7 +86,7 @@ public class Emblem implements CommandObject {
} }
public void setControllerId(UUID controllerId) { public void setControllerId(UUID controllerId) {
this.controllerId = controllerId; this.controllerId = controllerId;
this.abilites.setControllerId(controllerId); this.abilites.setControllerId(controllerId);
} }
@ -101,9 +101,9 @@ public class Emblem implements CommandObject {
@Override @Override
public String getIdName() { public String getIdName() {
return getName() + " ["+getId().toString().substring(0,3) +"]"; return getName() + " [" + getId().toString().substring(0, 3) + "]";
} }
@Override @Override
public String getLogName() { public String getLogName() {
return GameLog.getColoredObjectIdName(this); return GameLog.getColoredObjectIdName(this);
@ -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
@ -219,5 +222,5 @@ public class Emblem implements CommandObject {
public void setZoneChangeCounter(int value, Game game) { public void setZoneChangeCounter(int value, Game game) {
throw new UnsupportedOperationException("Unsupported operation"); throw new UnsupportedOperationException("Unsupported operation");
} }
} }

View file

@ -1,35 +1,35 @@
/* /*
* Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved.
* *
* Redistribution and use in source and binary forms, with or without modification, are * Redistribution and use in source and binary forms, with or without modification, are
* permitted provided that the following conditions are met: * permitted provided that the following conditions are met:
* *
* 1. Redistributions of source code must retain the above copyright notice, this list of * 1. Redistributions of source code must retain the above copyright notice, this list of
* conditions and the following disclaimer. * conditions and the following disclaimer.
* *
* 2. Redistributions in binary form must reproduce the above copyright notice, this list * 2. Redistributions in binary form must reproduce the above copyright notice, this list
* of conditions and the following disclaimer in the documentation and/or other materials * of conditions and the following disclaimer in the documentation and/or other materials
* provided with the distribution. * provided with the distribution.
* *
* THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
* *
* The views and conclusions contained in the software and documentation are those of the * The views and conclusions contained in the software and documentation are those of the
* authors and should not be interpreted as representing official policies, either expressed * authors and should not be interpreted as representing official policies, either expressed
* or implied, of BetaSteward_at_googlemail.com. * or implied, of BetaSteward_at_googlemail.com.
*/ */
package 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,24 +39,24 @@ 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");
power = new MageInt(3); power = new MageInt(3);
toughness = new MageInt(3); toughness = new MageInt(3);
} }
@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);
}
}
} }

View file

@ -1,33 +1,33 @@
/* /*
* Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved.
* *
* Redistribution and use in source and binary forms, with or without modification, are * Redistribution and use in source and binary forms, with or without modification, are
* permitted provided that the following conditions are met: * permitted provided that the following conditions are met:
* *
* 1. Redistributions of source code must retain the above copyright notice, this list of * 1. Redistributions of source code must retain the above copyright notice, this list of
* conditions and the following disclaimer. * conditions and the following disclaimer.
* *
* 2. Redistributions in binary form must reproduce the above copyright notice, this list * 2. Redistributions in binary form must reproduce the above copyright notice, this list
* of conditions and the following disclaimer in the documentation and/or other materials * of conditions and the following disclaimer in the documentation and/or other materials
* provided with the distribution. * provided with the distribution.
* *
* THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
* *
* The views and conclusions contained in the software and documentation are those of the * The views and conclusions contained in the software and documentation are those of the
* authors and should not be interpreted as representing official policies, either expressed * authors and should not be interpreted as representing official policies, either expressed
* or implied, of BetaSteward_at_googlemail.com. * or implied, of BetaSteward_at_googlemail.com.
*/ */
package 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);
}
}
} }

View file

@ -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,22 +37,10 @@ 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");

View file

@ -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);
}
}
} }

View file

@ -1,35 +1,35 @@
/* /*
* Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved.
* *
* Redistribution and use in source and binary forms, with or without modification, are * Redistribution and use in source and binary forms, with or without modification, are
* permitted provided that the following conditions are met: * permitted provided that the following conditions are met:
* *
* 1. Redistributions of source code must retain the above copyright notice, this list of * 1. Redistributions of source code must retain the above copyright notice, this list of
* conditions and the following disclaimer. * conditions and the following disclaimer.
* *
* 2. Redistributions in binary form must reproduce the above copyright notice, this list * 2. Redistributions in binary form must reproduce the above copyright notice, this list
* of conditions and the following disclaimer in the documentation and/or other materials * of conditions and the following disclaimer in the documentation and/or other materials
* provided with the distribution. * provided with the distribution.
* *
* THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
* *
* The views and conclusions contained in the software and documentation are those of the * The views and conclusions contained in the software and documentation are those of the
* authors and should not be interpreted as representing official policies, either expressed * authors and should not be interpreted as representing official policies, either expressed
* or implied, of BetaSteward_at_googlemail.com. * or implied, of BetaSteward_at_googlemail.com.
*/ */
package 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 {
@ -56,22 +54,26 @@ public class Token extends MageObjectImpl {
private int originalCardNumber; private int originalCardNumber;
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);
int code; int code;
Type(int code) { Type(int code) {
this.code = code; this.code = code;
} }
int getCode() { int getCode() {
return this.code; return this.code;
} }
} }
public Token(String name, String description) { public Token(String name, String description) {
this.name = name; this.name = name;
this.description = description; this.description = description;
@ -95,7 +97,7 @@ public class Token extends MageObjectImpl {
this.tokenType = token.tokenType; this.tokenType = token.tokenType;
this.lastAddedTokenId = token.lastAddedTokenId; this.lastAddedTokenId = token.lastAddedTokenId;
this.lastAddedTokenIds.addAll(token.lastAddedTokenIds); this.lastAddedTokenIds.addAll(token.lastAddedTokenIds);
this.originalCardNumber = token.originalCardNumber; this.originalCardNumber = token.originalCardNumber;
this.originalExpansionSetCode = token.originalExpansionSetCode; this.originalExpansionSetCode = token.originalExpansionSetCode;
this.copySourceCard = token.copySourceCard; // will never be changed this.copySourceCard = token.copySourceCard; // will never be changed
} }
@ -165,7 +167,7 @@ public class Token extends MageObjectImpl {
} }
if (!game.isSimulation()) { if (!game.isSimulation()) {
game.informPlayers(controller.getLogName() + " puts a " + newToken.getLogName() + " token onto the battlefield"); game.informPlayers(controller.getLogName() + " puts a " + newToken.getLogName() + " token onto the battlefield");
} }
} }
return true; return true;
@ -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())));
}
}
}
} }

View file

@ -1,16 +1,16 @@
/* /*
* Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved.
* *
* Redistribution and use in source and binary forms, with or without modification, are * Redistribution and use in source and binary forms, with or without modification, are
* permitted provided that the following conditions are met: * permitted provided that the following conditions are met:
* *
* 1. Redistributions of source code must retain the above copyright notice, this list of * 1. Redistributions of source code must retain the above copyright notice, this list of
* conditions and the following disclaimer. * conditions and the following disclaimer.
* *
* 2. Redistributions in binary form must reproduce the above copyright notice, this list * 2. Redistributions in binary form must reproduce the above copyright notice, this list
* of conditions and the following disclaimer in the documentation and/or other materials * of conditions and the following disclaimer in the documentation and/or other materials
* provided with the distribution. * provided with the distribution.
* *
* THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR
@ -20,14 +20,14 @@
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
* *
* The views and conclusions contained in the software and documentation are those of the * The views and conclusions contained in the software and documentation are those of the
* authors and should not be interpreted as representing official policies, either expressed * authors and should not be interpreted as representing official policies, either expressed
* or implied, of BetaSteward_at_googlemail.com. * or implied, of BetaSteward_at_googlemail.com.
*/ */
package 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);
}
}
}

View file

@ -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();
}
} }