mirror of
https://github.com/magefree/mage.git
synced 2026-01-18 09:19:56 -08:00
Merge remote-tracking branch 'refs/remotes/magefree/master'
This commit is contained in:
commit
153f2a82b0
28 changed files with 563 additions and 162 deletions
|
|
@ -122,20 +122,28 @@ public class ChatManager {
|
|||
}
|
||||
}
|
||||
|
||||
private static final String COMMANDS_LIST =
|
||||
"<br/>List of commands:" +
|
||||
"<br/>\\history or \\h [username] - shows the history of a player" +
|
||||
"<br/>\\me - shows the history of the current player" +
|
||||
"<br/>\\list or \\l - Show a list of commands" +
|
||||
"<br/>\\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("<br/>Invalid User Command '" + message + "'.")
|
||||
.append("<br/>List of commands:")
|
||||
.append("<br/>\\history or \\h [username] - shows the history of a player")
|
||||
.append("<br/>\\list or \\l - Show a list of commands")
|
||||
.append("<br/>\\whisper or \\w [player name] [text] - whisper to the player with the given name").toString();
|
||||
message += new StringBuilder("<br/>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 += "<br/>" + UserManager.getInstance().getUserHistory(message.substring(command.startsWith("H ") ? 3 : 9));
|
||||
chatSessions.get(chatId).broadcastInfoToUser(user, message);
|
||||
return true;
|
||||
}
|
||||
if (command.equals("ME")) {
|
||||
message += "<br/>" + 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("<br/>List of commands:")
|
||||
.append("<br/>\\history or \\h [username] - shows the history of a player")
|
||||
.append("<br/>\\list or \\l - Show a list of commands")
|
||||
.append("<br/>\\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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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 {
|
|||
|
||||
// <i>Delirium</i> — {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(),
|
||||
"<i>Delirium</i> — {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);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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) {
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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));
|
||||
|
||||
// <i>Delirium</i> — Grim Flayer gets +2/+2 as long as there are four or more card types among cards in your graveyard.
|
||||
|
|
|
|||
|
|
@ -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"));
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
@ -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));
|
||||
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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) {
|
||||
|
|
|
|||
|
|
@ -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)));
|
||||
|
|
|
|||
|
|
@ -157,7 +157,7 @@ class TamiyoFieldResearcherDelayedTriggeredAbility extends DelayedTriggeredAbili
|
|||
private List<MageObjectReference> creatures;
|
||||
|
||||
public TamiyoFieldResearcherDelayedTriggeredAbility(List<MageObjectReference> creatures) {
|
||||
super(new DrawCardSourceControllerEffect(1), Duration.UntilYourNextTurn);
|
||||
super(new DrawCardSourceControllerEffect(1), Duration.UntilYourNextTurn, false);
|
||||
this.creatures = creatures;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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"));
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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)));
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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."
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -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
|
||||
}
|
||||
}
|
||||
|
|
@ -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);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
}
|
||||
}
|
||||
|
|
@ -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
|
||||
}
|
||||
}
|
||||
|
|
@ -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();
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -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";
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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<UUID> possibleTargets(UUID sourceControllerId, Cards cards, Game game) {
|
||||
Set<UUID> possibleTargets = new HashSet<>();
|
||||
for (Card card: cards.getCards(filter, game)) {
|
||||
for (Card card : cards.getCards(filter, game)) {
|
||||
possibleTargets.add(card.getId());
|
||||
}
|
||||
return possibleTargets;
|
||||
|
|
|
|||
|
|
@ -121,7 +121,7 @@ public class Targets extends ArrayList<Target> {
|
|||
}
|
||||
}
|
||||
// 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;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -32,6 +32,7 @@ public class SpellsCastWatcher extends Watcher {
|
|||
|
||||
public SpellsCastWatcher(final SpellsCastWatcher watcher) {
|
||||
super(watcher);
|
||||
this.spellsCast.putAll(watcher.spellsCast);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue