diff --git a/Mage.Server/src/main/java/mage/server/ChatManager.java b/Mage.Server/src/main/java/mage/server/ChatManager.java
index e30923010bd..c8d95300c5c 100644
--- a/Mage.Server/src/main/java/mage/server/ChatManager.java
+++ b/Mage.Server/src/main/java/mage/server/ChatManager.java
@@ -122,20 +122,28 @@ public class ChatManager {
}
}
+ private static final String COMMANDS_LIST =
+ "
List of commands:" +
+ "
\\history or \\h [username] - shows the history of a player" +
+ "
\\me - shows the history of the current player" +
+ "
\\list or \\l - Show a list of commands" +
+ "
\\whisper or \\w [player name] [text] - whisper to the player with the given name";
+
private boolean performUserCommand(User user, String message, UUID chatId, boolean doError) {
String command = message.substring(1).trim().toUpperCase(Locale.ENGLISH);
if (doError) {
- message += new StringBuilder("
Invalid User Command '" + message + "'.")
- .append("
List of commands:")
- .append("
\\history or \\h [username] - shows the history of a player")
- .append("
\\list or \\l - Show a list of commands")
- .append("
\\whisper or \\w [player name] [text] - whisper to the player with the given name").toString();
+ message += new StringBuilder("
Invalid User Command '" + message + "'.").append(COMMANDS_LIST).toString();
chatSessions.get(chatId).broadcastInfoToUser(user, message);
return true;
}
if (command.startsWith("H ") || command.startsWith("HISTORY ")) {
- message = UserManager.getInstance().getUserHistory(message.substring(command.startsWith("H ") ? 3 : 9));
+ message += "
" + UserManager.getInstance().getUserHistory(message.substring(command.startsWith("H ") ? 3 : 9));
+ chatSessions.get(chatId).broadcastInfoToUser(user, message);
+ return true;
+ }
+ if (command.equals("ME")) {
+ message += "
" + UserManager.getInstance().getUserHistory(user.getName());
chatSessions.get(chatId).broadcastInfoToUser(user, message);
return true;
}
@@ -159,10 +167,7 @@ public class ChatManager {
}
}
if (command.equals("L") || command.equals("LIST")) {
- message += new StringBuilder("
List of commands:")
- .append("
\\history or \\h [username] - shows the history of a player")
- .append("
\\list or \\l - Show a list of commands")
- .append("
\\whisper or \\w [player name] [text] - whisper to the player with the given name").toString();
+ message += COMMANDS_LIST;
chatSessions.get(chatId).broadcastInfoToUser(user, message);
return true;
}
diff --git a/Mage.Sets/src/mage/sets/eldritchmoon/CropSigil.java b/Mage.Sets/src/mage/sets/eldritchmoon/CropSigil.java
index d6e8eb05eb4..66e8358a08b 100644
--- a/Mage.Sets/src/mage/sets/eldritchmoon/CropSigil.java
+++ b/Mage.Sets/src/mage/sets/eldritchmoon/CropSigil.java
@@ -34,7 +34,6 @@ import mage.abilities.condition.common.DeliriumCondition;
import mage.abilities.costs.common.SacrificeSourceCost;
import mage.abilities.costs.mana.ManaCostsImpl;
import mage.abilities.decorator.ConditionalActivatedAbility;
-import mage.abilities.effects.Effect;
import mage.abilities.effects.common.PutTopCardOfLibraryIntoGraveControllerEffect;
import mage.abilities.effects.common.ReturnToHandTargetEffect;
import mage.cards.CardImpl;
@@ -44,7 +43,7 @@ import mage.constants.Zone;
import mage.filter.FilterCard;
import mage.filter.predicate.mageobject.CardTypePredicate;
import mage.game.events.GameEvent;
-import mage.target.common.TargetCardInGraveyard;
+import mage.target.common.TargetCardInYourGraveyard;
/**
*
@@ -69,12 +68,13 @@ public class CropSigil extends CardImpl {
// Delirium — {2}{G}, Sacrifice Crop Sigil: Return up to one target creature card and up to one target land card from your graveyard to your hand.
// Activate this ability only if there are four or more card types among cards in your graveyard.
- Effect effect = new ReturnToHandTargetEffect(true, true);
- effect.setText("Return up to one target creature card and up to one target land card from your graveyard to your hand");
- Ability ability = new ConditionalActivatedAbility(Zone.BATTLEFIELD, effect, new ManaCostsImpl<>("{2}{G}"), DeliriumCondition.getInstance());
+ Ability ability = new ConditionalActivatedAbility(Zone.BATTLEFIELD, new ReturnToHandTargetEffect(true, true), new ManaCostsImpl<>("{2}{G}"),
+ DeliriumCondition.getInstance(),
+ "Delirium — {2}{G}, Sacrifice {this}: Return up to one target creature card and up to one target land card from your graveyard to your hand. "
+ + "Activate this ability only if there are four or more card types among cards in your graveyard");
ability.addCost(new SacrificeSourceCost());
- ability.addTarget(new TargetCardInGraveyard(0, 1, filterCreature));
- ability.addTarget(new TargetCardInGraveyard(0, 1, filterLand));
+ ability.addTarget(new TargetCardInYourGraveyard(0, 1, filterCreature));
+ ability.addTarget(new TargetCardInYourGraveyard(0, 1, filterLand));
this.addAbility(ability);
}
diff --git a/Mage.Sets/src/mage/sets/eldritchmoon/EmrakulsEvangel.java b/Mage.Sets/src/mage/sets/eldritchmoon/EmrakulsEvangel.java
index 75243bc5060..515d0160b6d 100644
--- a/Mage.Sets/src/mage/sets/eldritchmoon/EmrakulsEvangel.java
+++ b/Mage.Sets/src/mage/sets/eldritchmoon/EmrakulsEvangel.java
@@ -33,6 +33,7 @@ import mage.abilities.Ability;
import mage.abilities.common.SimpleActivatedAbility;
import mage.abilities.costs.Cost;
import mage.abilities.costs.CostImpl;
+import mage.abilities.costs.common.TapSourceCost;
import mage.abilities.effects.OneShotEffect;
import mage.cards.CardImpl;
import mage.constants.CardType;
@@ -54,7 +55,7 @@ import mage.target.common.TargetControlledCreaturePermanent;
* @author escplan9 (Derek Monturo - dmontur1 at gmail dot com)
*/
public class EmrakulsEvangel extends CardImpl {
-
+
public EmrakulsEvangel(UUID ownerId) {
super(ownerId, 156, "Emrakul's Evangel", Rarity.RARE, new CardType[]{CardType.CREATURE}, "{2}{G}");
this.expansionSetCode = "EMN";
@@ -63,9 +64,11 @@ public class EmrakulsEvangel extends CardImpl {
this.power = new MageInt(3);
this.toughness = new MageInt(2);
- // {T}, Sacrifice Emrakul's Evangel and any number of other non-Eldrazi creatures:
+ // {T}, Sacrifice Emrakul's Evangel and any number of other non-Eldrazi creatures:
// Put a 3/2 colorless Eldrazi Horror creature token onto the battlefield for each creature sacrificed this way.
- this.addAbility(new SimpleActivatedAbility(Zone.BATTLEFIELD, new EmrakulsEvangelEffect(), new EmrakulsEvangelCost()));
+ Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new EmrakulsEvangelEffect(), new TapSourceCost());
+ ability.addCost(new EmrakulsEvangelCost());
+ this.addAbility(ability);
}
public EmrakulsEvangel(final EmrakulsEvangel card) {
@@ -79,14 +82,14 @@ public class EmrakulsEvangel extends CardImpl {
}
class EmrakulsEvangelCost extends CostImpl {
-
+
private static final FilterControlledCreaturePermanent filter = new FilterControlledCreaturePermanent("non-Eldrazi creatures you control");
-
+
static {
filter.add(new AnotherPredicate());
filter.add(Predicates.not(new SubtypePredicate("Eldrazi")));
- }
-
+ }
+
private int numSacrificed = 1; // always sacrifices self at least
public EmrakulsEvangelCost() {
@@ -117,7 +120,7 @@ class EmrakulsEvangelCost extends CostImpl {
}
return paid;
}
-
+
public int getNumSacrificed() {
return numSacrificed;
}
@@ -125,7 +128,7 @@ class EmrakulsEvangelCost extends CostImpl {
@Override
public boolean canPay(Ability ability, UUID sourceId, UUID controllerId, Game game) {
Permanent permanent = game.getPermanent(sourceId);
-
+
return permanent != null && game.getPlayer(controllerId).canPaySacrificeCost(permanent, sourceId, controllerId, game);
}
@@ -136,25 +139,25 @@ class EmrakulsEvangelCost extends CostImpl {
}
class EmrakulsEvangelEffect extends OneShotEffect {
-
+
EmrakulsEvangelEffect() {
super(Outcome.Sacrifice);
- this.staticText = "Sacrifice {this} and any number of other non-Eldrazi creatures: Put a 3/2 colorless Eldrazi Horror creature token onto the battlefield for each creature sacrificed this way.";
+ this.staticText = "Put a 3/2 colorless Eldrazi Horror creature token onto the battlefield for each creature sacrificed this way.";
}
-
+
EmrakulsEvangelEffect(final EmrakulsEvangelEffect effect) {
super(effect);
}
-
+
@Override
public EmrakulsEvangelEffect copy() {
return new EmrakulsEvangelEffect(this);
}
-
+
@Override
public boolean apply(Game game, Ability source) {
Player player = game.getPlayer(source.getControllerId());
- if (player != null) {
+ if (player != null) {
int tokensToCreate = 0;
for (Cost cost : source.getCosts()) {
if (cost instanceof EmrakulsEvangelCost) {
diff --git a/Mage.Sets/src/mage/sets/eldritchmoon/GeierReachSanitarium.java b/Mage.Sets/src/mage/sets/eldritchmoon/GeierReachSanitarium.java
index 84e493f7388..f0bdff485f2 100644
--- a/Mage.Sets/src/mage/sets/eldritchmoon/GeierReachSanitarium.java
+++ b/Mage.Sets/src/mage/sets/eldritchmoon/GeierReachSanitarium.java
@@ -32,6 +32,7 @@ import mage.abilities.Ability;
import mage.abilities.common.SimpleActivatedAbility;
import mage.abilities.costs.common.TapSourceCost;
import mage.abilities.costs.mana.GenericManaCost;
+import mage.abilities.effects.Effect;
import mage.abilities.effects.common.DrawCardAllEffect;
import mage.abilities.effects.common.discard.DiscardEachPlayerEffect;
import mage.abilities.mana.ColorlessManaAbility;
@@ -56,7 +57,9 @@ public class GeierReachSanitarium extends CardImpl {
// {2}, {T}: Each player draws a card, then discards a card.
Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new DrawCardAllEffect(1), new GenericManaCost(2));
- ability.addEffect(new DiscardEachPlayerEffect());
+ Effect effect = new DiscardEachPlayerEffect();
+ effect.setText(", then discards a card");
+ ability.addEffect(effect);
ability.addCost(new TapSourceCost());
this.addAbility(ability);
}
diff --git a/Mage.Sets/src/mage/sets/eldritchmoon/GrimFlayer.java b/Mage.Sets/src/mage/sets/eldritchmoon/GrimFlayer.java
index f9776940cc2..1cd7057e746 100644
--- a/Mage.Sets/src/mage/sets/eldritchmoon/GrimFlayer.java
+++ b/Mage.Sets/src/mage/sets/eldritchmoon/GrimFlayer.java
@@ -66,7 +66,7 @@ public class GrimFlayer extends CardImpl {
// and the rest back on top of your library in any order.
Effect effect = new LookLibraryAndPickControllerEffect(
new StaticValue(3), false, new StaticValue(3), new FilterCard(), Zone.LIBRARY, true, false, true, Zone.GRAVEYARD, false);
- effect.setText("look at the top three cards of your library. Put any number of them into your graveyard and the rest on top of your library in any order");
+ effect.setText("look at the top three cards of your library. Put any number of them into your graveyard and the rest back on top of your library in any order");
this.addAbility(new DealsCombatDamageToAPlayerTriggeredAbility(effect, false));
// Delirium — Grim Flayer gets +2/+2 as long as there are four or more card types among cards in your graveyard.
diff --git a/Mage.Sets/src/mage/sets/eldritchmoon/IshkanahGrafwidow.java b/Mage.Sets/src/mage/sets/eldritchmoon/IshkanahGrafwidow.java
index 82d5d9d19f2..bc9cdc5cd9f 100644
--- a/Mage.Sets/src/mage/sets/eldritchmoon/IshkanahGrafwidow.java
+++ b/Mage.Sets/src/mage/sets/eldritchmoon/IshkanahGrafwidow.java
@@ -54,7 +54,7 @@ import mage.target.common.TargetOpponent;
*/
public class IshkanahGrafwidow extends CardImpl {
- private static final FilterControlledCreaturePermanent filter = new FilterControlledCreaturePermanent("each Spider you control");
+ private static final FilterControlledCreaturePermanent filter = new FilterControlledCreaturePermanent("Spider you control");
static {
filter.add(new SubtypePredicate("Spider"));
diff --git a/Mage.Sets/src/mage/sets/eldritchmoon/MindsDilation.java b/Mage.Sets/src/mage/sets/eldritchmoon/MindsDilation.java
index ca777a1c688..06354f26ebe 100644
--- a/Mage.Sets/src/mage/sets/eldritchmoon/MindsDilation.java
+++ b/Mage.Sets/src/mage/sets/eldritchmoon/MindsDilation.java
@@ -32,15 +32,11 @@ import java.util.UUID;
import mage.MageObject;
import mage.abilities.Ability;
import mage.abilities.common.SpellCastOpponentTriggeredAbility;
-import mage.abilities.effects.AsThoughEffectImpl;
-import mage.abilities.effects.ContinuousEffect;
import mage.abilities.effects.Effect;
import mage.abilities.effects.OneShotEffect;
import mage.cards.Card;
import mage.cards.CardImpl;
-import mage.constants.AsThoughEffectType;
import mage.constants.CardType;
-import mage.constants.Duration;
import mage.constants.Outcome;
import mage.constants.Rarity;
import mage.constants.Zone;
@@ -64,8 +60,7 @@ public class MindsDilation extends CardImpl {
// Whenever an opponent casts his or her first spell each turn, that player exiles the top card of his or her library. If it's a nonland card,
// you may cast it without paying its mana cost.
- Ability ability = new MindsDilationTriggeredAbility(new MindsDilationEffect(), false);
- this.addAbility(ability, new SpellsCastWatcher());
+ this.addAbility(new MindsDilationTriggeredAbility(new MindsDilationEffect(), false), new SpellsCastWatcher());
}
public MindsDilation(final MindsDilation card) {
@@ -113,7 +108,7 @@ class MindsDilationTriggeredAbility extends SpellCastOpponentTriggeredAbility {
@Override
public String getRule() {
return "Whenever an opponent casts his or her first spell each turn, that player exiles the top card of his or her library."
- + " If it's a nonland card, you may cast it without paying its mana cost";
+ + " If it's a nonland card, you may cast it without paying its mana cost.";
}
}
@@ -121,7 +116,7 @@ class MindsDilationEffect extends OneShotEffect {
MindsDilationEffect() {
super(Outcome.Benefit);
- this.staticText = "that player exiles the top card of his or her library. If it's a nonland card, you may cast it without paying its mana cost.";
+ this.staticText = "that player exiles the top card of his or her library. If it's a nonland card, you may cast it without paying its mana cost";
}
MindsDilationEffect(final MindsDilationEffect effect) {
@@ -140,12 +135,13 @@ class MindsDilationEffect extends OneShotEffect {
Player opponent = game.getPlayer(getTargetPointer().getFirst(game, source));
if (controller != null && sourceObject != null && opponent != null) {
if (opponent.getLibrary().size() > 0) {
- Card card = opponent.getLibrary().removeFromTop(game);
- if (card != null) {
- opponent.moveCardToExileWithInfo(card, source.getSourceId(), sourceObject.getIdName(), source.getSourceId(), game, Zone.LIBRARY, true);
- ContinuousEffect effect = new MindsDilationCastFromExileEffect();
- effect.setTargetPointer(new FixedTarget(card.getId()));
- game.addEffect(effect, source);
+ Card card = opponent.getLibrary().getFromTop(game);
+ if (card != null && opponent.moveCards(card, Zone.EXILED, source, game)) {
+ if (!card.getCardType().contains(CardType.LAND)) {
+ if (controller.chooseUse(outcome, "Cast " + card.getLogName() + " without paying its mana cost from exile?", source, game)) {
+ controller.cast(card.getSpellAbility(), game, true);
+ }
+ }
}
}
return true;
@@ -153,41 +149,3 @@ class MindsDilationEffect extends OneShotEffect {
return false;
}
}
-
-class MindsDilationCastFromExileEffect extends AsThoughEffectImpl {
-
- MindsDilationCastFromExileEffect() {
- super(AsThoughEffectType.PLAY_FROM_NOT_OWN_HAND_ZONE, Duration.EndOfTurn, Outcome.Benefit);
- staticText = "If it's a nonland card, you may cast it without paying its mana cost";
- }
-
- MindsDilationCastFromExileEffect(final MindsDilationCastFromExileEffect effect) {
- super(effect);
- }
-
- @Override
- public boolean apply(Game game, Ability source) {
- return true;
- }
-
- @Override
- public MindsDilationCastFromExileEffect copy() {
- return new MindsDilationCastFromExileEffect(this);
- }
-
- @Override
- public boolean applies(UUID sourceId, Ability source, UUID affectedControllerId, Game game) {
- UUID targetId = getTargetPointer().getFirst(game, source);
- Player controller = game.getPlayer(source.getControllerId());
- if (targetId != null && controller != null) {
- Card card = game.getCard(targetId);
- if (card != null && !card.getCardType().contains(CardType.LAND) && game.getState().getZone(targetId) == Zone.EXILED) {
- if (controller.chooseUse(outcome, "Cast " + card.getLogName() + "?", source, game)) {
- controller.cast(card.getSpellAbility(), game, true);
- }
- return true;
- }
- }
- return false;
- }
-}
\ No newline at end of file
diff --git a/Mage.Sets/src/mage/sets/eldritchmoon/PrimalDruid.java b/Mage.Sets/src/mage/sets/eldritchmoon/PrimalDruid.java
index 48e367f5ab1..3792e57a92c 100644
--- a/Mage.Sets/src/mage/sets/eldritchmoon/PrimalDruid.java
+++ b/Mage.Sets/src/mage/sets/eldritchmoon/PrimalDruid.java
@@ -30,6 +30,7 @@ package mage.sets.eldritchmoon;
import java.util.UUID;
import mage.MageInt;
import mage.abilities.common.DiesTriggeredAbility;
+import mage.abilities.effects.Effect;
import mage.abilities.effects.common.search.SearchLibraryPutInPlayEffect;
import mage.cards.CardImpl;
import mage.constants.CardType;
@@ -52,7 +53,9 @@ public class PrimalDruid extends CardImpl {
this.toughness = new MageInt(3);
// When Primal Druid dies, you may search your library for a basic land card, put it onto the battlefield tapped, then shuffle your library.
- this.addAbility(new DiesTriggeredAbility(new SearchLibraryPutInPlayEffect(new TargetCardInLibrary(new FilterBasicLandCard()), true), true));
+ Effect effect = new SearchLibraryPutInPlayEffect(new TargetCardInLibrary(new FilterBasicLandCard()), true);
+ effect.setText("you may search your library for a basic land card, put it onto the battlefield tapped, then shuffle your library");
+ this.addAbility(new DiesTriggeredAbility(effect, true));
}
diff --git a/Mage.Sets/src/mage/sets/eldritchmoon/SpiritOfTheHunt.java b/Mage.Sets/src/mage/sets/eldritchmoon/SpiritOfTheHunt.java
index 7a9a50b9d27..04dc445bd5e 100644
--- a/Mage.Sets/src/mage/sets/eldritchmoon/SpiritOfTheHunt.java
+++ b/Mage.Sets/src/mage/sets/eldritchmoon/SpiritOfTheHunt.java
@@ -30,6 +30,7 @@ package mage.sets.eldritchmoon;
import java.util.UUID;
import mage.MageInt;
import mage.abilities.common.EntersBattlefieldTriggeredAbility;
+import mage.abilities.effects.Effect;
import mage.abilities.effects.common.continuous.BoostControlledEffect;
import mage.abilities.keyword.FlashAbility;
import mage.cards.CardImpl;
@@ -65,7 +66,9 @@ public class SpiritOfTheHunt extends CardImpl {
this.addAbility(FlashAbility.getInstance());
// When Spirit of the Hunt enters the battlefield, each other creature you control that's a Wolf or a Werewolf gets +0/+3 until end of turn.
- this.addAbility(new EntersBattlefieldTriggeredAbility(new BoostControlledEffect(0, 3, Duration.EndOfTurn, filter, true), false));
+ Effect effect = new BoostControlledEffect(0, 3, Duration.EndOfTurn, filter, true);
+ effect.setText("each other creature you control that's a Wolf or a Werewolf gets +0/+3 until end of turn");
+ this.addAbility(new EntersBattlefieldTriggeredAbility(effect, false));
}
public SpiritOfTheHunt(final SpiritOfTheHunt card) {
diff --git a/Mage.Sets/src/mage/sets/eldritchmoon/StitchersGraft.java b/Mage.Sets/src/mage/sets/eldritchmoon/StitchersGraft.java
index 65876b2e08f..33f3f77342d 100644
--- a/Mage.Sets/src/mage/sets/eldritchmoon/StitchersGraft.java
+++ b/Mage.Sets/src/mage/sets/eldritchmoon/StitchersGraft.java
@@ -45,8 +45,8 @@ import mage.constants.Outcome;
import mage.constants.Rarity;
import mage.constants.Zone;
import mage.game.Game;
-import mage.game.events.GameEvent.EventType;
import mage.game.events.GameEvent;
+import mage.game.events.GameEvent.EventType;
/**
*
@@ -68,7 +68,9 @@ public class StitchersGraft extends CardImpl {
this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, effect));
// Whenever Stitcher's Graft becomes unattached from a permanent, sacrifice that permanent.
- this.addAbility(new UnattachedTriggeredAbility(new SacrificeEquippedEffect(), false));
+ effect = new SacrificeEquippedEffect();
+ effect.setText("sacrifice that permanent");
+ this.addAbility(new UnattachedTriggeredAbility(effect, false));
// Equip {2}
this.addAbility(new EquipAbility(Outcome.AddAbility, new GenericManaCost(2)));
diff --git a/Mage.Sets/src/mage/sets/eldritchmoon/TamiyoFieldResearcher.java b/Mage.Sets/src/mage/sets/eldritchmoon/TamiyoFieldResearcher.java
index 2e8464303c2..c79567d3a14 100644
--- a/Mage.Sets/src/mage/sets/eldritchmoon/TamiyoFieldResearcher.java
+++ b/Mage.Sets/src/mage/sets/eldritchmoon/TamiyoFieldResearcher.java
@@ -157,7 +157,7 @@ class TamiyoFieldResearcherDelayedTriggeredAbility extends DelayedTriggeredAbili
private List creatures;
public TamiyoFieldResearcherDelayedTriggeredAbility(List creatures) {
- super(new DrawCardSourceControllerEffect(1), Duration.UntilYourNextTurn);
+ super(new DrawCardSourceControllerEffect(1), Duration.UntilYourNextTurn, false);
this.creatures = creatures;
}
diff --git a/Mage.Sets/src/mage/sets/eldritchmoon/WaxingMoon.java b/Mage.Sets/src/mage/sets/eldritchmoon/WaxingMoon.java
index 480cb9fa307..3a7e5d9f774 100644
--- a/Mage.Sets/src/mage/sets/eldritchmoon/WaxingMoon.java
+++ b/Mage.Sets/src/mage/sets/eldritchmoon/WaxingMoon.java
@@ -28,6 +28,7 @@
package mage.sets.eldritchmoon;
import java.util.UUID;
+import mage.abilities.effects.Effect;
import mage.abilities.effects.common.TransformTargetEffect;
import mage.abilities.effects.common.continuous.GainAbilityAllEffect;
import mage.abilities.keyword.TrampleAbility;
@@ -60,8 +61,11 @@ public class WaxingMoon extends CardImpl {
this.expansionSetCode = "EMN";
// Transform up to one target Werewolf you control.
- this.getSpellAbility().addEffect(new TransformTargetEffect(false));
+ Effect effect = new TransformTargetEffect(false);
+ effect.setText("Transform up to one target Werewolf you control");
+ this.getSpellAbility().addEffect(effect);
this.getSpellAbility().addTarget(new TargetCreaturePermanent(0, 1, filter, false));
+
// Creatures you control gain trample until end of turn.
this.getSpellAbility().addEffect(new GainAbilityAllEffect(TrampleAbility.getInstance(), Duration.EndOfTurn, new FilterControlledCreaturePermanent(), "Creatures you control gain trample until end of turn"));
}
diff --git a/Mage.Sets/src/mage/sets/gatecrash/GideonChampionOfJustice.java b/Mage.Sets/src/mage/sets/gatecrash/GideonChampionOfJustice.java
index debb217f509..ca21e65092f 100644
--- a/Mage.Sets/src/mage/sets/gatecrash/GideonChampionOfJustice.java
+++ b/Mage.Sets/src/mage/sets/gatecrash/GideonChampionOfJustice.java
@@ -32,13 +32,12 @@ import mage.MageInt;
import mage.abilities.Ability;
import mage.abilities.LoyaltyAbility;
import mage.abilities.common.PlanswalkerEntersWithLoyalityCountersAbility;
-import mage.abilities.common.SimpleStaticAbility;
+import mage.abilities.dynamicvalue.LockedInDynamicValue;
import mage.abilities.dynamicvalue.common.CountersCount;
import mage.abilities.dynamicvalue.common.PermanentsTargetOpponentControlsCount;
import mage.abilities.effects.OneShotEffect;
import mage.abilities.effects.common.PreventAllDamageToSourceEffect;
import mage.abilities.effects.common.continuous.BecomesCreatureSourceEffect;
-import mage.abilities.effects.common.continuous.SetPowerToughnessSourceEffect;
import mage.abilities.effects.common.counter.AddCountersSourceEffect;
import mage.abilities.keyword.IndestructibleAbility;
import mage.cards.CardImpl;
@@ -46,7 +45,6 @@ import mage.constants.CardType;
import mage.constants.Duration;
import mage.constants.Outcome;
import mage.constants.Rarity;
-import mage.constants.Zone;
import mage.counters.CounterType;
import mage.filter.common.FilterCreaturePermanent;
import mage.game.Game;
@@ -74,7 +72,9 @@ public class GideonChampionOfJustice extends CardImpl {
this.addAbility(ability1);
// 0: Until end of turn, Gideon becomes an indestructible Human Soldier creature with power and toughness each equal to the number of loyalty counters on him. He's still a planeswalker. Prevent all damage that would be dealt to him this turn.
- LoyaltyAbility ability2 = new LoyaltyAbility(new BecomesCreatureSourceEffect(new GideonChampionOfJusticeToken(), "planeswalker", Duration.EndOfTurn), 0);
+ LockedInDynamicValue loyaltyCount = new LockedInDynamicValue(new CountersCount(CounterType.LOYALTY));
+ LoyaltyAbility ability2 = new LoyaltyAbility(new BecomesCreatureSourceEffect(
+ new GideonChampionOfJusticeToken(), "planeswalker", Duration.EndOfTurn, false, false, loyaltyCount, loyaltyCount), 0);
ability2.addEffect(new PreventAllDamageToSourceEffect(Duration.EndOfTurn));
this.addAbility(ability2);
@@ -131,7 +131,7 @@ class GideonChampionOfJusticeToken extends Token {
toughness = new MageInt(0);
this.addAbility(IndestructibleAbility.getInstance());
- this.addAbility(new SimpleStaticAbility(Zone.ALL, new SetPowerToughnessSourceEffect(new CountersCount(CounterType.LOYALTY), Duration.WhileOnBattlefield)));
+
}
}
diff --git a/Mage.Sets/src/mage/sets/shadowsoverinnistrad/DevilsPlayground.java b/Mage.Sets/src/mage/sets/shadowsoverinnistrad/DevilsPlayground.java
index 6f5bee35e38..6c04fd98126 100644
--- a/Mage.Sets/src/mage/sets/shadowsoverinnistrad/DevilsPlayground.java
+++ b/Mage.Sets/src/mage/sets/shadowsoverinnistrad/DevilsPlayground.java
@@ -42,7 +42,7 @@ import mage.game.permanent.token.DevilToken;
public class DevilsPlayground extends CardImpl {
public DevilsPlayground(UUID ownerId) {
- super(ownerId, 151, "Devil's Playground", Rarity.RARE, new CardType[]{CardType.SORCERY}, "{4}{R}{R}");
+ super(ownerId, 151, "Devils' Playground", Rarity.RARE, new CardType[]{CardType.SORCERY}, "{4}{R}{R}");
this.expansionSetCode = "SOI";
// Put four 1/1 red Devil creature tokens onto the battlefield. They have "When this creature dies, it deals 1 damage to target creature or player."
diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/abilities/keywords/EscalateTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/abilities/keywords/EscalateTest.java
new file mode 100644
index 00000000000..22626a912a5
--- /dev/null
+++ b/Mage.Tests/src/test/java/org/mage/test/cards/abilities/keywords/EscalateTest.java
@@ -0,0 +1,65 @@
+/*
+ * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification, are
+ * permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this list of
+ * conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice, this list
+ * of conditions and the following disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * The views and conclusions contained in the software and documentation are those of the
+ * authors and should not be interpreted as representing official policies, either expressed
+ * or implied, of BetaSteward_at_googlemail.com.
+ */
+package org.mage.test.cards.abilities.keywords;
+
+import mage.constants.PhaseStep;
+import mage.constants.Zone;
+import org.junit.Test;
+import org.mage.test.serverside.base.CardTestPlayerBase;
+
+/**
+ *
+ * @author LevelX2
+ */
+public class EscalateTest extends CardTestPlayerBase {
+
+ @Test
+ public void testUseOneMode() {
+
+ addCard(Zone.BATTLEFIELD, playerA, "Mountain", 3);
+ // Escalate {1} (Pay this cost for each mode chosen beyond the first.)
+ // Choose one or more —
+ // Creatures target player controls gain trample until end of turn.
+ // Savage Alliance deals 2 damage to target creature;
+ // Savage Alliance deals 1 damage to each creature target opponent controls.
+ addCard(Zone.HAND, playerA, "Savage Alliance"); // Instant {2}{R}
+
+ addCard(Zone.BATTLEFIELD, playerB, "Silvercoat Lion", 1);
+
+ castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Savage Alliance", "mode=2Silvercoat Lion");
+ setModeChoice(playerA, "2");
+
+ setStopAt(1, PhaseStep.POSTCOMBAT_MAIN);
+ execute();
+
+ assertGraveyardCount(playerB, "Silvercoat Lion", 1);
+ assertGraveyardCount(playerA, "Savage Alliance", 1);
+
+ }
+
+}
diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/enchantments/MindsDilationTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/enchantments/MindsDilationTest.java
new file mode 100644
index 00000000000..5088a35ffdd
--- /dev/null
+++ b/Mage.Tests/src/test/java/org/mage/test/cards/enchantments/MindsDilationTest.java
@@ -0,0 +1,72 @@
+/*
+ * To change this license header, choose License Headers in Project Properties.
+ * To change this template file, choose Tools | Templates
+ * and open the template in the editor.
+ */
+package org.mage.test.cards.enchantments;
+
+import mage.constants.PhaseStep;
+import mage.constants.Zone;
+import org.junit.Test;
+import org.mage.test.serverside.base.CardTestPlayerBase;
+
+/**
+ *
+ * @author escplan9 (Derek Monturo - dmontur1 at gmail dot com)
+ */
+public class MindsDilationTest extends CardTestPlayerBase {
+
+ @Test
+ public void testExileNonLandCardAndCastIt() {
+
+ /**
+ * Mind's Dilation {5}{U}{U} Enchantment Whenever an opponent casts his
+ * or her first spell each turn, that player exiles the top card of his
+ * or her library. If it's a nonland card, you may cast it without
+ * paying its mana cost.
+ */
+ addCard(Zone.BATTLEFIELD, playerB, "Mind's Dilation", 1);
+ addCard(Zone.BATTLEFIELD, playerA, "Mountain", 1);
+ addCard(Zone.HAND, playerA, "Lightning Bolt", 1);
+ addCard(Zone.LIBRARY, playerA, "Divination", 1); // draw 2 cards
+
+ skipInitShuffling();
+
+ castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Lightning Bolt", playerB);
+ setChoice(playerB, "Yes");
+
+ setStopAt(1, PhaseStep.BEGIN_COMBAT);
+ execute();
+
+ assertLife(playerB, 17);
+ assertExileCount("Divination", 0);
+ assertHandCount(playerB, 2); // free divination!
+ }
+
+ @Test
+ public void testExileNonLandCardDontCastIt() {
+
+ removeAllCardsFromLibrary(playerA);
+
+ /**
+ * Mind's Dilation {5}{U}{U} Enchantment Whenever an opponent casts his
+ * or her first spell each turn, that player exiles the top card of his
+ * or her library. If it's a nonland card, you may cast it without
+ * paying its mana cost.
+ */
+ addCard(Zone.BATTLEFIELD, playerB, "Mind's Dilation", 1);
+ addCard(Zone.BATTLEFIELD, playerA, "Mountain", 1);
+ addCard(Zone.HAND, playerA, "Lightning Bolt", 1);
+ addCard(Zone.LIBRARY, playerA, "Divination", 1); // draw 2 cards
+
+ castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Lightning Bolt", playerB);
+ setChoice(playerB, "No"); // no, I don't want my free 2 cards
+
+ setStopAt(1, PhaseStep.BEGIN_COMBAT);
+ execute();
+
+ assertLife(playerB, 17);
+ assertExileCount("Divination", 1);
+ assertHandCount(playerB, 0); // Divination never cast
+ }
+}
diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/planeswalker/GideonTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/planeswalker/GideonTest.java
index 850f102ffb5..ef3fe0da492 100644
--- a/Mage.Tests/src/test/java/org/mage/test/cards/planeswalker/GideonTest.java
+++ b/Mage.Tests/src/test/java/org/mage/test/cards/planeswalker/GideonTest.java
@@ -76,4 +76,43 @@ public class GideonTest extends CardTestPlayerBase {
assertAbility(playerB, "Silvercoat Lion", IndestructibleAbility.getInstance(), false);
}
+ /*
+ * Reported bug: When Gideon, Champion of Justice uses his +0 ability to become a creature,
+ * he is immediately sent to the grave instead.
+ */
+ @Test
+ public void testGideonChampionOfJusticeSecondAbility() {
+ addCard(Zone.BATTLEFIELD, playerA, "Plains", 4);
+ /*
+ Gideon, Champion of Justice {2}{W}{W} - 4 Loyalty
+ +1: Put a loyalty counter on Gideon, Champion of Justice for each creature target opponent controls.
+
+ 0: Until end of turn, Gideon, Champion of Justice becomes a Human Soldier creature with power and toughness
+ each equal to the number of loyalty counters on him and gains indestructible. He's still a planeswalker.
+ Prevent all damage that would be dealt to him this turn.
+ LoyaltyAbility ability1 = new LoyaltyAbility(
+
+ -15: Exile all other permanents.
+ */
+ addCard(Zone.HAND, playerA, "Gideon, Champion of Justice", 1);
+
+ addCard(Zone.BATTLEFIELD, playerB, "Silvercoat Lion", 2);
+
+ castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Gideon, Champion of Justice");
+ activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "+0: Until end of turn");
+
+ activateAbility(3, PhaseStep.PRECOMBAT_MAIN, playerA, "+1: Put a loyalty counter on", playerB);
+
+ activateAbility(5, PhaseStep.PRECOMBAT_MAIN, playerA, "+0: Until end of turn");
+
+ setStopAt(5, PhaseStep.BEGIN_COMBAT);
+ execute();
+
+ assertGraveyardCount(playerA, "Gideon, Champion of Justice", 0);
+ assertPermanentCount(playerA, "Gideon, Champion of Justice", 1);
+ assertCounterCount(playerA, "Gideon, Champion of Justice", CounterType.LOYALTY, 7);
+ assertPowerToughness(playerA, "Gideon, Champion of Justice", 7, 7);
+
+ }
+
}
diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/planeswalker/TamiyoTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/planeswalker/TamiyoTest.java
index a22a34506d8..bc7b5689323 100644
--- a/Mage.Tests/src/test/java/org/mage/test/cards/planeswalker/TamiyoTest.java
+++ b/Mage.Tests/src/test/java/org/mage/test/cards/planeswalker/TamiyoTest.java
@@ -29,7 +29,6 @@ package org.mage.test.cards.planeswalker;
import mage.constants.PhaseStep;
import mage.constants.Zone;
-import org.junit.Ignore;
import org.junit.Test;
import org.mage.test.serverside.base.CardTestPlayerBase;
@@ -40,120 +39,120 @@ import org.mage.test.serverside.base.CardTestPlayerBase;
public class TamiyoTest extends CardTestPlayerBase {
/*
- * Reported bug: I activated Tamiyo's +1 ability on a 5/5 Gideon and his 2/2 Knight Ally, but when they both attacked
+ * Reported bug: I activated Tamiyo's +1 ability on a 5/5 Gideon and his 2/2 Knight Ally, but when they both attacked
* and dealt damage I only drew one card when I'm pretty sure I was supposed to draw for each of the two.
*/
@Test
public void testFieldResearcherFirstEffectOnGideon() {
-
+
// Tamiyo, Field Researcher {1}{G}{W}{U} - 4 loyalty
- // +1: Choose up to two target creatures. Until your next turn,
+ // +1: Choose up to two target creatures. Until your next turn,
// whenever either of those creatures deals combat damage, you draw a card.
addCard(Zone.BATTLEFIELD, playerA, "Tamiyo, Field Researcher", 1);
-
+
/* Gideon, Ally of Zendikar {2}{W}{W} - 4 loyalty
- * +1: Until end of turn, Gideon, Ally of Zendikar becomes a 5/5 Human Soldier Ally creature with indestructible
+ * +1: Until end of turn, Gideon, Ally of Zendikar becomes a 5/5 Human Soldier Ally creature with indestructible
* that's still a planeswalker. Prevent all damage that would be dealt to him this turn.
* 0: Put a 2/2 white Knight Ally creature token onto the battlefield.
**/
addCard(Zone.BATTLEFIELD, playerA, "Gideon, Ally of Zendikar", 1);
-
+
// put 2/2 knight ally token on battlefield
activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "+0: Put a");
-
+
// next, activate Gideon to make him a 5/5 human soldier ally creature
activateAbility(3, PhaseStep.PRECOMBAT_MAIN, playerA, "+1: Until end of turn");
// finally, use Tamiyo +1 on both creatures
activateAbility(3, PhaseStep.PRECOMBAT_MAIN, playerA, "+1: Choose up to two");
addTarget(playerA, "Knight Ally^Gideon, Ally of Zendikar"); // both token and Gideon as creature
-
+
// attack with both unblocked
- attack(3, playerA, "Knight Ally");
+ attack(3, playerA, "Knight Ally");
attack(3, playerA, "Gideon, Ally of Zendikar");
-
+
setStopAt(3, PhaseStep.END_COMBAT);
- execute();
-
+ execute();
+
assertLife(playerB, 13); // 5 + 2 damage, 20 - 7 = 13
assertPermanentCount(playerA, "Tamiyo, Field Researcher", 1);
assertPermanentCount(playerA, "Gideon, Ally of Zendikar", 1);
assertPermanentCount(playerA, "Knight Ally", 1);
assertHandCount(playerA, 3); // two cards drawn from each creature dealing damage + 1 card drawn on turn
}
-
+
/*
* Testing more basic scenario with Tamiyo, Field of Researcher +1 effect
*/
@Test
public void testFieldResearcherFirstEffectSimpleCreatureAttacks() {
-
+
// Tamiyo, Field Researcher {1}{G}{W}{U} - 4 loyalty
- // +1: Choose up to two target creatures. Until your next turn,
+ // +1: Choose up to two target creatures. Until your next turn,
// whenever either of those creatures deals combat damage, you draw a card.
addCard(Zone.BATTLEFIELD, playerA, "Tamiyo, Field Researcher", 1);
-
+
addCard(Zone.BATTLEFIELD, playerA, "Bronze Sable", 1); // 2/1
activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "+1: Choose up to two");
addTarget(playerA, "Bronze Sable");
-
+
attack(1, playerA, "Bronze Sable");
-
+
setStopAt(1, PhaseStep.END_COMBAT);
execute();
-
+
assertLife(playerB, 18);
assertHandCount(playerA, 1);
}
-
+
/*
* Testing more basic scenario with Tamiyo, Field of Researcher +1 effect
*/
@Test
public void testFieldResearcherFirstEffectSimpleCreaturesAttacks() {
-
+
// Tamiyo, Field Researcher {1}{G}{W}{U} - 4 loyalty
- // +1: Choose up to two target creatures. Until your next turn,
+ // +1: Choose up to two target creatures. Until your next turn,
// whenever either of those creatures deals combat damage, you draw a card.
addCard(Zone.BATTLEFIELD, playerA, "Tamiyo, Field Researcher", 1);
-
+
addCard(Zone.BATTLEFIELD, playerA, "Bronze Sable", 1); // 2/1
addCard(Zone.BATTLEFIELD, playerA, "Sylvan Advocate", 1); // 2/3
activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "+1: Choose up to two");
addTarget(playerA, "Bronze Sable^Sylvan Advocate");
-
+
attack(1, playerA, "Bronze Sable");
attack(1, playerA, "Sylvan Advocate");
-
+
setStopAt(1, PhaseStep.END_COMBAT);
execute();
-
+
assertLife(playerB, 16);
assertHandCount(playerA, 2);
}
-
+
/*
* Testing more basic scenarios with Tamiyo, Field of Researcher +1 effect
*/
@Test
public void testFieldResearcherFirstEffectAttackAndBlock() {
-
+
// Tamiyo, Field Researcher {1}{G}{W}{U} - 4 loyalty
- // +1: Choose up to two target creatures. Until your next turn,
+ // +1: Choose up to two target creatures. Until your next turn,
// whenever either of those creatures deals combat damage, you draw a card.
addCard(Zone.BATTLEFIELD, playerA, "Tamiyo, Field Researcher", 1);
-
+
addCard(Zone.BATTLEFIELD, playerA, "Sylvan Advocate", 1); // 2/3
addCard(Zone.BATTLEFIELD, playerB, "Memnite", 1);
activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "+1: Choose up to two");
addTarget(playerA, "Sylvan Advocate");
-
+
attack(1, playerA, "Sylvan Advocate");
attack(2, playerB, "Memnite");
block(2, playerA, "Sylvan Advocate", "Memnite");
-
+
setStopAt(2, PhaseStep.END_COMBAT);
execute();
-
+
assertLife(playerB, 18);
assertHandCount(playerA, 2); // Sylvan Advocate dealt combat damage twice
}
diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/replacement/KalitasTraitorOfGhetTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/replacement/KalitasTraitorOfGhetTest.java
new file mode 100644
index 00000000000..5191c1ae612
--- /dev/null
+++ b/Mage.Tests/src/test/java/org/mage/test/cards/replacement/KalitasTraitorOfGhetTest.java
@@ -0,0 +1,55 @@
+/*
+ * To change this license header, choose License Headers in Project Properties.
+ * To change this template file, choose Tools | Templates
+ * and open the template in the editor.
+ */
+package org.mage.test.cards.replacement;
+
+import mage.constants.PhaseStep;
+import mage.constants.Zone;
+import org.junit.Test;
+import org.mage.test.serverside.base.CardTestPlayerBase;
+
+/**
+ *
+ * @author escplan9 (Derek Monturo - dmontur1 at gmail dot com)
+ */
+public class KalitasTraitorOfGhetTest extends CardTestPlayerBase {
+
+ /*
+ * Reported bug: Damnation with Kalitas, Traitor of Ghet on my side and 3 opponent creatures, it only exiled 1 creature giving me only 1 zombie instead of 3.
+ */
+ @Test
+ public void testDamnation() {
+
+ /*
+ Kalitas, Traitor of Ghet {2}{B}{B} 3/4 lifelink - Legendary Vampire
+ If a nontoken creature an opponent controls would die, instead exile that card and put a 2/2 black Zombie creature token onto the battlefield.
+ */
+ addCard(Zone.BATTLEFIELD, playerA, "Kalitas, Traitor of Ghet", 1);
+ /*
+ Damnation {2}{B}{B} - Sorcery
+ Destroy all creatures. They can't be regenerated.
+ */
+ addCard(Zone.HAND, playerA, "Damnation", 1);
+
+ addCard(Zone.BATTLEFIELD, playerA, "Swamp", 4);
+
+ addCard(Zone.BATTLEFIELD, playerB, "Bronze Sable", 1);
+ addCard(Zone.BATTLEFIELD, playerB, "Wall of Roots", 1);
+ addCard(Zone.BATTLEFIELD, playerB, "Sigiled Starfish", 1);
+
+ castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Damnation");
+ setStopAt(1, PhaseStep.BEGIN_COMBAT);
+ execute();
+
+ assertGraveyardCount(playerA, "Kalitas, Traitor of Ghet", 1);
+ assertGraveyardCount(playerA, "Damnation", 1);
+ assertExileCount("Bronze Sable", 1);
+ assertExileCount("Wall of Roots", 1);
+ assertExileCount("Sigiled Starfish", 1);
+ assertGraveyardCount(playerB, 0); // all 3 creatures of playerB should be exiled not in graveyard
+ assertExileCount("Kalitas, Traitor of Ghet", 0); // player controlled, not opponent so not exiled
+ assertPermanentCount(playerA, "Zombie", 3); // 3 tokens generated from exiling 3 opponent's creatures
+ }
+}
diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/single/UrzasIncubatorTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/single/UrzasIncubatorTest.java
new file mode 100644
index 00000000000..86daec971b9
--- /dev/null
+++ b/Mage.Tests/src/test/java/org/mage/test/cards/single/UrzasIncubatorTest.java
@@ -0,0 +1,95 @@
+/*
+ * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification, are
+ * permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this list of
+ * conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice, this list
+ * of conditions and the following disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * The views and conclusions contained in the software and documentation are those of the
+ * authors and should not be interpreted as representing official policies, either expressed
+ * or implied, of BetaSteward_at_googlemail.com.
+ */
+package org.mage.test.cards.single;
+
+import mage.constants.PhaseStep;
+import mage.constants.Zone;
+import org.junit.Test;
+import org.mage.test.serverside.base.CardTestPlayerBase;
+
+/**
+ *
+ * @author escplan9 (Derek Monturo - dmontur1 at gmail dot com)
+ */
+public class UrzasIncubatorTest extends CardTestPlayerBase {
+
+ /*
+ * Reported bug: Urza's Incubator does not reduce the cost of Eldrazi creatures
+ */
+ @Test
+ public void testEldraziCostReduction() {
+
+ /*
+ Urza's Incubator (3) Artifact
+ As Urza's Incubator enters the battlefield, choose a creature type.
+ Creature spells of the chosen type cost 2 less to cast.
+ */
+ addCard(Zone.HAND, playerA, "Urza's Incubator", 1);
+ addCard(Zone.HAND, playerA, "Eldrazi Displacer", 1); // {2}{W} eldrazi 3/3
+ addCard(Zone.HAND, playerA, "Eldrazi Mimic", 2); // {2} eldrazi 2/1
+ addCard(Zone.BATTLEFIELD, playerA, "Plains", 4);
+
+ castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Urza's Incubator"); // taps 3 plains
+ setChoice(playerA, "Eldrazi");
+ castSpell(1, PhaseStep.POSTCOMBAT_MAIN, playerA, "Eldrazi Displacer"); // taps last plains
+ castSpell(1, PhaseStep.POSTCOMBAT_MAIN, playerA, "Eldrazi Mimic"); // both mimics should be free
+ castSpell(1, PhaseStep.POSTCOMBAT_MAIN, playerA, "Eldrazi Mimic");
+ setStopAt(1, PhaseStep.END_TURN);
+ execute();
+
+ assertPermanentCount(playerA, "Urza's Incubator", 1);
+ assertPermanentCount(playerA, "Eldrazi Displacer", 1);
+ assertPermanentCount(playerA, "Eldrazi Mimic", 2);
+ }
+
+ /*
+ * Test to make sure incubator only reduces generic cost. Cards with <> requirement
+ * still require specific colorless mana to cast.
+ */
+ @Test
+ public void testEldraziCostReductionWastesRequirement() {
+
+ /*
+ Urza's Incubator (3) Artifact
+ As Urza's Incubator enters the battlefield, choose a creature type.
+ Creature spells of the chosen type cost 2 less to cast.
+ */
+ addCard(Zone.HAND, playerA, "Urza's Incubator", 1);
+ addCard(Zone.HAND, playerA, "Thought-Knot Seer", 1); // {3}{<>} eldrazi 4/4
+ addCard(Zone.BATTLEFIELD, playerA, "Plains", 5);
+
+ castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Urza's Incubator"); // taps 3 plains
+ setChoice(playerA, "Eldrazi");
+ castSpell(1, PhaseStep.POSTCOMBAT_MAIN, playerA, "Thought-Knot Seer"); // 2 plains remaining, but <> required
+ setStopAt(1, PhaseStep.END_TURN);
+ execute();
+
+ assertPermanentCount(playerA, "Urza's Incubator", 1);
+ assertPermanentCount(playerA, "Thought-Knot Seer", 0); // should not be able to cast
+ }
+}
diff --git a/Mage.Tests/src/test/java/org/mage/test/player/TestPlayer.java b/Mage.Tests/src/test/java/org/mage/test/player/TestPlayer.java
index 44ce17cfbb8..97c83236776 100644
--- a/Mage.Tests/src/test/java/org/mage/test/player/TestPlayer.java
+++ b/Mage.Tests/src/test/java/org/mage/test/player/TestPlayer.java
@@ -574,6 +574,9 @@ public class TestPlayer implements Player {
i++;
}
}
+ if (modes.getMinModes() <= modes.getSelectedModes().size()) {
+ return null;
+ }
return computerPlayer.chooseMode(modes, source, game); //To change body of generated methods, choose Tools | Templates.
}
@@ -1734,7 +1737,7 @@ public class TestPlayer implements Player {
public boolean canPaySacrificeCost(Permanent permanent, UUID sourceId, UUID controllerId, Game game) {
return computerPlayer.canPaySacrificeCost(permanent, sourceId, controllerId, game);
}
-
+
@Override
public FilterPermanent getSacrificeCostFilter() {
return computerPlayer.getSacrificeCostFilter();
diff --git a/Mage/src/main/java/mage/abilities/dynamicvalue/LockedInDynamicValue.java b/Mage/src/main/java/mage/abilities/dynamicvalue/LockedInDynamicValue.java
new file mode 100644
index 00000000000..81e2a9a1b51
--- /dev/null
+++ b/Mage/src/main/java/mage/abilities/dynamicvalue/LockedInDynamicValue.java
@@ -0,0 +1,77 @@
+/*
+ * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification, are
+ * permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this list of
+ * conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice, this list
+ * of conditions and the following disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * The views and conclusions contained in the software and documentation are those of the
+ * authors and should not be interpreted as representing official policies, either expressed
+ * or implied, of BetaSteward_at_googlemail.com.
+ */
+package mage.abilities.dynamicvalue;
+
+import mage.abilities.Ability;
+import mage.abilities.effects.Effect;
+import mage.game.Game;
+
+/**
+ * The first calculated value is used as long as the class instance is in use
+ *
+ * IMPORTANT: If used the ability / effect that uses a locked in dynamic value
+ * has to really copy the dnamic value in its copy method (not reference)
+ *
+ * @author LevelX2
+ */
+public class LockedInDynamicValue implements DynamicValue {
+
+ private boolean valueChecked = false;
+ private int lockedInValue;
+ private final DynamicValue basicDynamicValue;
+
+ public LockedInDynamicValue(DynamicValue dynamicValue) {
+ this.basicDynamicValue = dynamicValue;
+ }
+
+ public LockedInDynamicValue(LockedInDynamicValue dynamicValue, final boolean copy) {
+ this.basicDynamicValue = dynamicValue.basicDynamicValue;
+ this.lockedInValue = dynamicValue.lockedInValue;
+ this.valueChecked = dynamicValue.valueChecked;
+ }
+
+ @Override
+ public int calculate(Game game, Ability sourceAbility, Effect effect) {
+ if (!valueChecked) {
+ lockedInValue = basicDynamicValue.calculate(game, sourceAbility, effect);
+ valueChecked = true;
+ }
+ return lockedInValue;
+ }
+
+ @Override
+ public LockedInDynamicValue copy() {
+ return new LockedInDynamicValue(this, true);
+ }
+
+ @Override
+ public String getMessage() {
+ return basicDynamicValue.getMessage();
+ }
+
+}
diff --git a/Mage/src/main/java/mage/abilities/effects/common/DontUntapInControllersNextUntapStepTargetEffect.java b/Mage/src/main/java/mage/abilities/effects/common/DontUntapInControllersNextUntapStepTargetEffect.java
index 54df18dd219..f59773e1e4e 100644
--- a/Mage/src/main/java/mage/abilities/effects/common/DontUntapInControllersNextUntapStepTargetEffect.java
+++ b/Mage/src/main/java/mage/abilities/effects/common/DontUntapInControllersNextUntapStepTargetEffect.java
@@ -159,7 +159,7 @@ public class DontUntapInControllersNextUntapStepTargetEffect extends ContinuousR
return staticText;
}
if (targetName != null && targetName.length() > 0) {
- if (targetName.equals("Those creatures")) {
+ if (targetName.equals("Those creatures") || targetName.equals("They")) {
return targetName + " don't untap during their controller's next untap step";
} else
return targetName + " doesn't untap during its controller's next untap step";
diff --git a/Mage/src/main/java/mage/abilities/effects/common/continuous/BecomesCreatureSourceEffect.java b/Mage/src/main/java/mage/abilities/effects/common/continuous/BecomesCreatureSourceEffect.java
index c8606d07b8b..99399d7c278 100644
--- a/Mage/src/main/java/mage/abilities/effects/common/continuous/BecomesCreatureSourceEffect.java
+++ b/Mage/src/main/java/mage/abilities/effects/common/continuous/BecomesCreatureSourceEffect.java
@@ -27,9 +27,9 @@
*/
package mage.abilities.effects.common.continuous;
-import mage.MageInt;
import mage.MageObjectReference;
import mage.abilities.Ability;
+import mage.abilities.dynamicvalue.DynamicValue;
import mage.abilities.effects.ContinuousEffectImpl;
import mage.cards.repository.CardRepository;
import mage.constants.CardType;
@@ -50,17 +50,25 @@ public class BecomesCreatureSourceEffect extends ContinuousEffectImpl implements
protected Token token;
protected String type;
protected boolean losePreviousTypes;
+ protected DynamicValue power = null;
+ protected DynamicValue toughness = null;
public BecomesCreatureSourceEffect(Token token, String type, Duration duration) {
this(token, type, duration, false, false);
}
public BecomesCreatureSourceEffect(Token token, String type, Duration duration, boolean losePreviousTypes, boolean characterDefining) {
+ this(token, type, duration, losePreviousTypes, characterDefining, null, null);
+ }
+
+ public BecomesCreatureSourceEffect(Token token, String type, Duration duration, boolean losePreviousTypes, boolean characterDefining, DynamicValue power, DynamicValue toughness) {
super(duration, Outcome.BecomeCreature);
this.characterDefining = characterDefining;
this.token = token;
this.type = type;
this.losePreviousTypes = losePreviousTypes;
+ this.power = power;
+ this.toughness = toughness;
setText();
}
@@ -69,6 +77,12 @@ public class BecomesCreatureSourceEffect extends ContinuousEffectImpl implements
this.token = effect.token.copy();
this.type = effect.type;
this.losePreviousTypes = effect.losePreviousTypes;
+ if (effect.power != null) {
+ this.power = effect.power.copy();
+ }
+ if (effect.toughness != null) {
+ this.toughness = effect.toughness.copy();
+ }
}
@Override
@@ -133,19 +147,21 @@ public class BecomesCreatureSourceEffect extends ContinuousEffectImpl implements
case PTChangingEffects_7:
if ((sublayer == SubLayer.CharacteristicDefining_7a && isCharacterDefining())
|| (sublayer == SubLayer.SetPT_7b && !isCharacterDefining())) {
- MageInt power = token.getPower();
- MageInt toughness = token.getToughness();
- if (power != null && toughness != null) {
- permanent.getPower().setValue(power.getValue());
- permanent.getToughness().setValue(toughness.getValue());
+ if (power != null) {
+ permanent.getPower().setValue(power.calculate(game, source, this));
+ } else if (token.getPower() != null) {
+ permanent.getPower().setValue(token.getPower().getValue());
+ }
+ if (toughness != null) {
+ permanent.getToughness().setValue(toughness.calculate(game, source, this));
+ } else if (token.getToughness() != null) {
+ permanent.getToughness().setValue(token.getToughness().getValue());
}
}
}
return true;
- } else {
- if (duration.equals(Duration.Custom)) {
- this.discard();
- }
+ } else if (duration.equals(Duration.Custom)) {
+ this.discard();
}
return false;
}
diff --git a/Mage/src/main/java/mage/target/TargetCard.java b/Mage/src/main/java/mage/target/TargetCard.java
index 92d00489275..04885dd42e5 100644
--- a/Mage/src/main/java/mage/target/TargetCard.java
+++ b/Mage/src/main/java/mage/target/TargetCard.java
@@ -24,21 +24,19 @@
* The views and conclusions contained in the software and documentation are those of the
* authors and should not be interpreted as representing official policies, either expressed
* or implied, of BetaSteward_at_googlemail.com.
-*/
-
+ */
package mage.target;
-import mage.constants.Zone;
-import mage.cards.Card;
-import mage.cards.Cards;
-import mage.filter.FilterCard;
-import mage.game.Game;
-import mage.players.Player;
-
import java.util.HashSet;
import java.util.Set;
import java.util.UUID;
+import mage.cards.Card;
+import mage.cards.Cards;
+import mage.constants.Zone;
+import mage.filter.FilterCard;
+import mage.game.Game;
import mage.game.events.GameEvent;
+import mage.players.Player;
/**
*
@@ -87,9 +85,12 @@ public class TargetCard extends TargetObject {
@Override
public boolean canChoose(UUID sourceId, UUID sourceControllerId, Game game) {
int possibleTargets = 0;
- for (UUID playerId: game.getState().getPlayersInRange(sourceControllerId, game)) {
+ for (UUID playerId : game.getState().getPlayersInRange(sourceControllerId, game)) {
Player player = game.getPlayer(playerId);
if (player != null) {
+ if (this.minNumberOfTargets == 0) {
+ return true;
+ }
switch (zone) {
case HAND:
for (Card card : player.getHand().getCards(filter, sourceId, sourceControllerId, game)) {
@@ -200,7 +201,7 @@ public class TargetCard extends TargetObject {
public Set possibleTargets(UUID sourceControllerId, Cards cards, Game game) {
Set possibleTargets = new HashSet<>();
- for (Card card: cards.getCards(filter, game)) {
+ for (Card card : cards.getCards(filter, game)) {
possibleTargets.add(card.getId());
}
return possibleTargets;
diff --git a/Mage/src/main/java/mage/target/Targets.java b/Mage/src/main/java/mage/target/Targets.java
index c29f1932d90..be2bbe1d6e8 100644
--- a/Mage/src/main/java/mage/target/Targets.java
+++ b/Mage/src/main/java/mage/target/Targets.java
@@ -121,7 +121,7 @@ public class Targets extends ArrayList {
}
}
// it is legal when either there is no target or not all targets are illegal
- return this.size() == 0 || this.size() != illegalCount;
+ return this.isEmpty() || this.size() != illegalCount;
}
/**
diff --git a/Mage/src/main/java/mage/target/common/TargetCardInYourGraveyard.java b/Mage/src/main/java/mage/target/common/TargetCardInYourGraveyard.java
index eba50fb268d..de6b3863873 100644
--- a/Mage/src/main/java/mage/target/common/TargetCardInYourGraveyard.java
+++ b/Mage/src/main/java/mage/target/common/TargetCardInYourGraveyard.java
@@ -30,10 +30,10 @@ package mage.target.common;
import java.util.HashSet;
import java.util.Set;
import java.util.UUID;
-import mage.constants.Zone;
import mage.abilities.Ability;
import mage.cards.Card;
import mage.cards.Cards;
+import mage.constants.Zone;
import mage.filter.FilterCard;
import mage.game.Game;
import mage.game.events.GameEvent;
@@ -122,10 +122,7 @@ public class TargetCardInYourGraveyard extends TargetCard {
*/
@Override
public boolean canChoose(UUID sourceControllerId, Game game) {
- if (game.getPlayer(sourceControllerId).getGraveyard().count(filter, game) >= this.minNumberOfTargets) {
- return true;
- }
- return false;
+ return game.getPlayer(sourceControllerId).getGraveyard().count(filter, game) >= this.minNumberOfTargets;
}
@Override
diff --git a/Mage/src/main/java/mage/watchers/common/SpellsCastWatcher.java b/Mage/src/main/java/mage/watchers/common/SpellsCastWatcher.java
index a175971151e..f0309d0ff89 100644
--- a/Mage/src/main/java/mage/watchers/common/SpellsCastWatcher.java
+++ b/Mage/src/main/java/mage/watchers/common/SpellsCastWatcher.java
@@ -32,6 +32,7 @@ public class SpellsCastWatcher extends Watcher {
public SpellsCastWatcher(final SpellsCastWatcher watcher) {
super(watcher);
+ this.spellsCast.putAll(watcher.spellsCast);
}
@Override