Merge branch 'magefree:master' into github-actions

This commit is contained in:
Phred Lane 2021-10-05 09:09:55 -05:00 committed by GitHub
commit f71ce769cd
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
51 changed files with 204 additions and 121 deletions

View file

@ -32,8 +32,7 @@ public final class AccomplishedAlchemist extends CardImpl {
// {T}: Add X mana of any one color, where X is the amount of life you gained this turn.
this.addAbility(new DynamicManaAbility(
new Mana(0, 0, 0, 0, 0, 0, 1, 0),
ControllerGotLifeCount.instance, new TapSourceCost(), "Add X mana " +
Mana.AnyMana(1), ControllerGotLifeCount.instance, new TapSourceCost(), "Add X mana " +
"of any one color, where X is the amount of life you gained this turn", true
).addHint(ControllerGotLifeCount.getHint()), new PlayerGainedLifeWatcher());
}

View file

@ -41,7 +41,7 @@ public final class AmbitiousFarmhand extends CardImpl {
// When Ambitious Farmhand enters the battlefield, you may search your library for a basic Plains card, reveal it, put it into your hand, then shuffle.
this.addAbility(new EntersBattlefieldTriggeredAbility(
new SearchLibraryPutInHandEffect(new TargetCardInLibrary(filter)), true
new SearchLibraryPutInHandEffect(new TargetCardInLibrary(filter), true), true
));
// Coven{1}{W}{W}: Transform Ambitious Farmhand. Activate only if you control three or more creatures with different powers.

View file

@ -55,7 +55,7 @@ class AngelOfGlorysRiseEffect extends OneShotEffect {
public AngelOfGlorysRiseEffect() {
super(Outcome.PutCreatureInPlay);
staticText = "Exile all Zombies, then return all Human creature cards from your graveyard to the battlefield";
staticText = "exile all Zombies, then return all Human creature cards from your graveyard to the battlefield";
}
public AngelOfGlorysRiseEffect(final AngelOfGlorysRiseEffect effect) {

View file

@ -32,7 +32,7 @@ public final class BereavedSurvivor extends CardImpl {
this.addAbility(new DiesCreatureTriggeredAbility(
new TransformSourceEffect(true), false,
StaticFilters.FILTER_CONTROLLED_ANOTHER_CREATURE
));
).setTriggerPhrase("When another creature you control dies, "));
}
private BereavedSurvivor(final BereavedSurvivor card) {

View file

@ -1,8 +1,5 @@
package mage.cards.b;
import java.util.UUID;
import mage.abilities.effects.common.CreateTokenEffect;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
@ -11,18 +8,19 @@ import mage.game.permanent.token.ElephantToken;
import mage.game.permanent.token.SnakeToken;
import mage.game.permanent.token.WolfToken;
import java.util.UUID;
/**
*
* @author BetaSteward_at_googlemail.com
*/
public final class BestialMenace extends CardImpl {
public BestialMenace(UUID ownerId, CardSetInfo setInfo) {
super(ownerId,setInfo,new CardType[]{CardType.SORCERY},"{3}{G}{G}");
super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{3}{G}{G}");
this.getSpellAbility().addEffect(new CreateTokenEffect(new SnakeToken()));
this.getSpellAbility().addEffect(new CreateTokenEffect(new WolfToken()));
this.getSpellAbility().addEffect(new CreateTokenEffect(new ElephantToken()));
this.getSpellAbility().addEffect(new CreateTokenEffect(new WolfToken()).setText(", a 2/2 green Wolf creature token"));
this.getSpellAbility().addEffect(new CreateTokenEffect(new ElephantToken()).setText(", and a 3/3 green Elephant creature token"));
}
private BestialMenace(final BestialMenace card) {
@ -33,5 +31,4 @@ public final class BestialMenace extends CardImpl {
public BestialMenace copy() {
return new BestialMenace(this);
}
}

View file

@ -122,8 +122,8 @@ class CalixDestinysHandExileEffect extends OneShotEffect {
theirPerm.getId(), theirPerm.getZoneChangeCounter(game) + 1, game
);
MageObjectReference myMor = new MageObjectReference(myPerm, game);
UUID exileId = CardUtil.getExileZoneId(game, source);
controller.moveCardsToExile(theirPerm, source, game, true, exileId, myPerm.getLogName());
UUID exileId = CardUtil.getExileZoneId(myPerm.toString(), game);
controller.moveCardsToExile(theirPerm, source, game, true, exileId, myPerm.getIdName());
game.addDelayedTriggeredAbility(new CalixDestinysHandDelayedTriggeredAbility(theirMor, myMor), source);
return true;
}

View file

@ -1,42 +1,42 @@
package mage.cards.c;
import java.util.UUID;
import mage.MageInt;
import mage.abilities.Ability;
import mage.abilities.common.DiesSourceTriggeredAbility;
import mage.abilities.dynamicvalue.DynamicValue;
import mage.abilities.dynamicvalue.common.CardsInTargetPlayersGraveyardCount;
import mage.abilities.effects.Effect;
import mage.abilities.effects.common.DrawCardSourceControllerEffect;
import mage.abilities.effects.common.LoseLifeSourceControllerEffect;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
import mage.constants.SubType;
import mage.filter.common.FilterCreatureCard;
import mage.filter.StaticFilters;
import mage.target.TargetPlayer;
import java.util.UUID;
/**
*
* @author fireshoes
*/
public final class CorpseAugur extends CardImpl {
private static final DynamicValue dynamicValue
= new CardsInTargetPlayersGraveyardCount(StaticFilters.FILTER_CARD_CREATURE);
public CorpseAugur(UUID ownerId, CardSetInfo setInfo) {
super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{3}{B}");
super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{B}");
this.subtype.add(SubType.ZOMBIE);
this.subtype.add(SubType.WIZARD);
this.power = new MageInt(4);
this.toughness = new MageInt(2);
// When Corpse Augur dies, you draw X cards and you lose X life, where X is the number of creature cards in target player's graveyard.
CardsInTargetPlayersGraveyardCount dynamicValue = new CardsInTargetPlayersGraveyardCount(new FilterCreatureCard("the number of creature cards"));
Effect effect = new DrawCardSourceControllerEffect(dynamicValue);
effect.setText("You draw X cards");
Ability ability = new DiesSourceTriggeredAbility(effect, false);
effect = new LoseLifeSourceControllerEffect(dynamicValue);
effect.setText("and you lose X life, where X is the number of creature cards in target player's graveyard");
ability.addEffect(effect);
Ability ability = new DiesSourceTriggeredAbility(
new DrawCardSourceControllerEffect(dynamicValue).setText("you draw X cards"), false
);
ability.addEffect(new LoseLifeSourceControllerEffect(dynamicValue)
.setText("and you lose X life, where X is the number of creature cards in target player's graveyard"));
ability.addTarget(new TargetPlayer());
this.addAbility(ability);
}

View file

@ -33,7 +33,7 @@ public final class CurseOfUnbinding extends CardImpl {
// At the beginning of enchanted player's upkeep, that player reveals cards from the top of their library until they reveal a creature card. Put that card onto the battlefield under your control. That player puts the rest of the revealed cards into their graveyard.
this.addAbility(new BeginningOfUpkeepTriggeredAbility(
new CurseOfConformityEffect(), TargetController.ENCHANTED, false
new CurseOfUnbindingEffect(), TargetController.ENCHANTED, false
));
}

View file

@ -1,6 +1,7 @@
package mage.cards.d;
import mage.MageInt;
import mage.MageObject;
import mage.abilities.Ability;
import mage.abilities.common.SimpleStaticAbility;
import mage.abilities.effects.common.continuous.BoostControlledEffect;
@ -12,7 +13,9 @@ import mage.constants.CardType;
import mage.constants.Duration;
import mage.constants.SubType;
import mage.filter.common.FilterCreaturePermanent;
import mage.filter.predicate.Predicates;
import mage.filter.predicate.ObjectSourcePlayer;
import mage.filter.predicate.ObjectSourcePlayerPredicate;
import mage.game.Game;
import java.util.UUID;
@ -21,13 +24,11 @@ import java.util.UUID;
*/
public final class DeathBaron extends CardImpl {
private static final FilterCreaturePermanent filterSkeletons = new FilterCreaturePermanent();
private static final FilterCreaturePermanent filterZombie = new FilterCreaturePermanent();
private static final FilterCreaturePermanent filter
= new FilterCreaturePermanent("Skeletons you control and other Zombies");
static {
filterSkeletons.add(SubType.SKELETON.getPredicate());
filterZombie.add(SubType.ZOMBIE.getPredicate());
filterZombie.add(Predicates.not(SubType.SKELETON.getPredicate()));
filter.add(DeathBaronPredicate.instance);
}
public DeathBaron(UUID ownerId, CardSetInfo setInfo) {
@ -40,16 +41,10 @@ public final class DeathBaron extends CardImpl {
// Skeletons you control and other Zombies you control get +1/+1 and have deathtouch.
Ability ability = new SimpleStaticAbility(new BoostControlledEffect(
1, 1, Duration.WhileOnBattlefield, filterSkeletons, false
).setText("Skeletons you control"));
1, 1, Duration.WhileOnBattlefield, filter, false
));
ability.addEffect(new GainAbilityControlledEffect(
DeathtouchAbility.getInstance(), Duration.WhileOnBattlefield, filterSkeletons, false
).setText("and other Zombies you control"));
ability.addEffect(new BoostControlledEffect(
1, 1, Duration.WhileOnBattlefield, filterZombie, true
).setText("get +1/+1"));
ability.addEffect(new GainAbilityControlledEffect(
DeathtouchAbility.getInstance(), Duration.WhileOnBattlefield, filterZombie, true
DeathtouchAbility.getInstance(), Duration.WhileOnBattlefield, filter, true
).setText("and have deathtouch"));
this.addAbility(ability);
}
@ -63,3 +58,16 @@ public final class DeathBaron extends CardImpl {
return new DeathBaron(this);
}
}
enum DeathBaronPredicate implements ObjectSourcePlayerPredicate<MageObject> {
instance;
@Override
public boolean apply(ObjectSourcePlayer<MageObject> input, Game game) {
if (input.getObject().hasSubtype(SubType.SKELETON, game)) {
return true;
}
return !input.getObject().getId().equals(input.getSourceId())
&& input.getObject().hasSubtype(SubType.ZOMBIE, game);
}
}

View file

@ -12,6 +12,7 @@ import mage.constants.CardType;
import mage.constants.SubType;
import mage.constants.SuperType;
import mage.constants.TargetController;
import mage.filter.StaticFilters;
import java.util.UUID;
@ -36,7 +37,10 @@ public final class DennickPiousApparition extends CardImpl {
this.addAbility(FlyingAbility.getInstance());
// Whenever one or more creature cards are put into graveyards from anywhere, investigate. This ability triggers only once each turn.
this.addAbility(new PutCardIntoGraveFromAnywhereAllTriggeredAbility(new InvestigateEffect(1), false, TargetController.ANY).setTriggersOnce(true));
this.addAbility(new PutCardIntoGraveFromAnywhereAllTriggeredAbility(
new InvestigateEffect(1), false,
StaticFilters.FILTER_CARD_CREATURE, TargetController.ANY
).setTriggersOnce(true).setTriggerPhrase("Whenever one or more creature cards are put into graveyards from anywhere, "));
// If Dennick, Pious Apparition would be put into a graveyard from anywhere, exile it instead.
this.addAbility(new PutIntoGraveFromAnywhereSourceAbility(new ExileSourceEffect().setText("exile it instead")));

View file

@ -15,7 +15,6 @@ import mage.constants.Zone;
import mage.filter.common.FilterCreaturePermanent;
import mage.game.Game;
import mage.game.events.GameEvent;
import mage.game.events.GameEvent.EventType;
import mage.game.events.ZoneChangeEvent;
import mage.game.permanent.Permanent;
import mage.target.common.TargetOpponent;
@ -27,11 +26,8 @@ import java.util.UUID;
*/
public final class DiregrafCaptain extends CardImpl {
private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("Zombie");
static {
filter.add(SubType.ZOMBIE.getPredicate());
}
private static final FilterCreaturePermanent filter
= new FilterCreaturePermanent(SubType.ZOMBIE, "Zombie creatures");
public DiregrafCaptain(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{U}{B}");

View file

@ -27,7 +27,7 @@ import mage.target.common.TargetCreaturePermanent;
*/
public final class EaterOfHope extends CardImpl {
private static final FilterControlledCreaturePermanent destroyFilter = new FilterControlledCreaturePermanent("two other creatures");
private static final FilterControlledCreaturePermanent destroyFilter = new FilterControlledCreaturePermanent("other creatures");
static {
destroyFilter.add(AnotherPredicate.instance);

View file

@ -45,7 +45,7 @@ class FlareOfFaithEffect extends OneShotEffect {
FlareOfFaithEffect() {
super(Outcome.Benefit);
staticText = "target creature gets +2/+2 until end of turn. If it's a Human, " +
"it gets +3/+3 and gains indestructible until end of turn instead";
"instead it gets +3/+3 and gains indestructible until end of turn";
}
private FlareOfFaithEffect(final FlareOfFaithEffect effect) {

View file

@ -13,6 +13,7 @@ import mage.cards.CardSetInfo;
import mage.constants.CardType;
import mage.constants.SubType;
import mage.filter.FilterPermanent;
import mage.filter.StaticFilters;
import mage.filter.common.FilterArtifactOrEnchantmentPermanent;
import mage.filter.predicate.permanent.DefendingPlayerControlsPredicate;
import mage.target.TargetPermanent;
@ -44,6 +45,7 @@ public final class FrenziedTrapbreaker extends CardImpl {
// {1}, Sacrifice Frenzied Trapbreaker: Destroy target artifact or enchantment.
Ability ability = new SimpleActivatedAbility(new DestroyTargetEffect(), new GenericManaCost(1));
ability.addCost(new SacrificeSourceCost());
ability.addTarget(new TargetPermanent(StaticFilters.FILTER_PERMANENT_ARTIFACT_OR_ENCHANTMENT));
this.addAbility(ability);
// Whenever Frenzied Trapbreaker attacks, destroy target artifact or enchantment defending player controls.

View file

@ -58,7 +58,7 @@ class GisaAndGeralfCastFromGraveyardEffect extends AsThoughEffectImpl {
GisaAndGeralfCastFromGraveyardEffect() {
super(AsThoughEffectType.PLAY_FROM_NOT_OWN_HAND_ZONE, Duration.WhileOnBattlefield, Outcome.PutCreatureInPlay, true);
staticText = "During each of your turns, you may cast a Zombie creature card from your graveyard";
staticText = "During each of your turns, you may cast a Zombie creature spell from your graveyard";
}
GisaAndGeralfCastFromGraveyardEffect(final GisaAndGeralfCastFromGraveyardEffect effect) {

View file

@ -48,7 +48,7 @@ public final class HavengulRunebinder extends CardImpl {
new ManaCostsImpl("{2}{U}"));
ability.addCost(new TapSourceCost());
ability.addCost(new ExileFromGraveCost(new TargetCardInYourGraveyard(filter)));
ability.addEffect(new AddCountersAllEffect(CounterType.P1P1.createInstance(), filterPermanent));
ability.addEffect(new AddCountersAllEffect(CounterType.P1P1.createInstance(), filterPermanent).concatBy(", then"));
this.addAbility(ability);
}

View file

@ -55,7 +55,7 @@ class HeirloomMirrorEffect extends OneShotEffect {
HeirloomMirrorEffect() {
super(Outcome.Benefit);
staticText = "draw a card, mill a card, then put a ritual counter on {this}. " +
"Then if it has 3 or more ritual counters on it, remove them and transform it";
"Then if it has three or more ritual counters on it, remove them and transform it";
}
private HeirloomMirrorEffect(final HeirloomMirrorEffect effect) {

View file

@ -33,7 +33,7 @@ public final class HeraldOfWar extends CardImpl {
this.addAbility(FlyingAbility.getInstance());
// Whenever Herald of War attacks, put a +1/+1 counter on it.
this.addAbility(new AttacksTriggeredAbility(new AddCountersSourceEffect(CounterType.P1P1.createInstance()), false));
this.addAbility(new AttacksTriggeredAbility(new AddCountersSourceEffect(CounterType.P1P1.createInstance()).setText("put a +1/+1 counter on it"), false));
// Angel spells and Human spells you cast cost {1} less to cast for each +1/+1 counter on Herald of War.
this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new HeraldOfWarCostReductionEffect()));

View file

@ -1,13 +1,14 @@
package mage.cards.h;
import mage.MageInt;
import mage.Mana;
import mage.abilities.common.EntersBattlefieldControlledTriggeredAbility;
import mage.abilities.costs.common.TapSourceCost;
import mage.abilities.dynamicvalue.DynamicValue;
import mage.abilities.dynamicvalue.common.SourcePermanentPowerCount;
import mage.abilities.effects.common.counter.AddCountersSourceEffect;
import mage.abilities.keyword.VigilanceAbility;
import mage.abilities.mana.AnyColorManaAbility;
import mage.abilities.mana.DynamicManaAbility;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
@ -43,7 +44,10 @@ public final class HeronbladeElite extends CardImpl {
));
// {T}: Add X mana of any one color, where X is Heronblade Elite's power.
this.addAbility(new AnyColorManaAbility(new TapSourceCost(), xValue, false));
this.addAbility(new DynamicManaAbility(
Mana.AnyMana(1), xValue, new TapSourceCost(), "Add X mana " +
"of any one color, where X is {this}'s power", true
));
}
private HeronbladeElite(final HeronbladeElite card) {

View file

@ -44,7 +44,7 @@ public final class HeronsGraceChampion extends CardImpl {
// When Heron's Grace Champion enters the battlefield, other Humans you control get +1/+1 and gain lifelink until end of turn.
Effect effect = new BoostControlledEffect(1, 1, Duration.EndOfTurn, filter, true);
effect.setText("other Humans you control gets +1/+1");
effect.setText("other Humans you control get +1/+1");
Ability ability = new EntersBattlefieldTriggeredAbility(effect);
effect = new GainAbilityControlledEffect(LifelinkAbility.getInstance(), Duration.EndOfTurn, filter, true);
effect.setText("and gain lifelink until end of turn");

View file

@ -1,7 +1,5 @@
package mage.cards.j;
import java.util.UUID;
import mage.MageInt;
import mage.abilities.Ability;
import mage.abilities.common.EntersBattlefieldControlledTriggeredAbility;
@ -10,26 +8,29 @@ import mage.abilities.effects.common.counter.AddCountersTargetEffect;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
import mage.constants.SubType;
import mage.constants.SetTargetPointer;
import mage.constants.SubType;
import mage.constants.Zone;
import mage.counters.CounterType;
import mage.filter.StaticFilters;
import mage.filter.common.FilterCreaturePermanent;
import mage.filter.predicate.mageobject.AnotherPredicate;
import java.util.UUID;
/**
*
* @author emerald000
*/
public final class JuniperOrderRanger extends CardImpl {
private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("another creature");
static {
filter.add(AnotherPredicate.instance);
}
public JuniperOrderRanger(UUID ownerId, CardSetInfo setInfo) {
super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{3}{G}{W}");
super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{G}{W}");
this.subtype.add(SubType.HUMAN);
this.subtype.add(SubType.KNIGHT);
this.subtype.add(SubType.RANGER);
@ -38,12 +39,11 @@ public final class JuniperOrderRanger extends CardImpl {
// Whenever another creature enters the battlefield under your control, put a +1/+1 counter on that creature and a +1/+1 counter on Juniper Order Ranger.
Ability ability = new EntersBattlefieldControlledTriggeredAbility(
Zone.BATTLEFIELD,
new AddCountersTargetEffect(CounterType.P1P1.createInstance()),
filter,
false,
SetTargetPointer.PERMANENT,
"Whenever another creature enters the battlefield under your control, put a +1/+1 counter on that creature and a +1/+1 counter on Juniper Order Ranger");
Zone.BATTLEFIELD, new AddCountersTargetEffect(CounterType.P1P1.createInstance()),
StaticFilters.FILTER_CONTROLLED_ANOTHER_CREATURE, false,
SetTargetPointer.PERMANENT, "Whenever another creature enters the battlefield " +
"under your control, put a +1/+1 counter on that creature and a +1/+1 counter on {this}."
);
ability.addEffect(new AddCountersSourceEffect(CounterType.P1P1.createInstance()));
this.addAbility(ability);
}

View file

@ -47,7 +47,7 @@ class KessigCagebreakersEffect extends OneShotEffect {
public KessigCagebreakersEffect() {
super(Outcome.PutCreatureInPlay);
this.staticText = "create a 2/2 green Wolf creature token tapped and attacking for each creature card in your graveyard";
this.staticText = "create a 2/2 green Wolf creature token that's tapped and attacking for each creature card in your graveyard";
}
public KessigCagebreakersEffect(final KessigCagebreakersEffect effect) {

View file

@ -85,7 +85,7 @@ class LierDiscipleOfTheDrownedFlashbackEffect extends ContinuousEffectImpl {
public LierDiscipleOfTheDrownedFlashbackEffect() {
super(Duration.WhileOnBattlefield, Layer.AbilityAddingRemovingEffects_6, SubLayer.NA, Outcome.AddAbility);
this.staticText = "Each instant and sorcery card in your graveyard has flashback. " +
"The flashback cost is equal to its mana cost";
"The flashback cost is equal to that card's mana cost";
}
public LierDiscipleOfTheDrownedFlashbackEffect(final LierDiscipleOfTheDrownedFlashbackEffect effect) {

View file

@ -21,7 +21,7 @@ import mage.game.permanent.token.ZombieToken;
*/
public final class LilianasMastery extends CardImpl {
private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("Zombie creatures");
private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("Zombies");
static {
filter.add(SubType.ZOMBIE.getPredicate());

View file

@ -25,7 +25,7 @@ import mage.filter.common.FilterCreaturePermanent;
*/
public final class LordOfTheAccursed extends CardImpl {
private static final FilterCreaturePermanent filter = new FilterCreaturePermanent(SubType.ZOMBIE, "Zombie creatures");
private static final FilterCreaturePermanent filter = new FilterCreaturePermanent(SubType.ZOMBIE, "Zombies");
public LordOfTheAccursed(UUID ownerId, CardSetInfo setInfo) {
super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{2}{B}");
@ -41,7 +41,7 @@ public final class LordOfTheAccursed extends CardImpl {
Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new GainAbilityAllEffect(
new MenaceAbility(),
Duration.EndOfTurn,
filter, "All Zombies gains menace until end of turn."),
filter, "All Zombies gain menace until end of turn."),
new ManaCostsImpl("{1}{B}"));
ability.addCost(new TapSourceCost());
this.addAbility(ability);

View file

@ -80,7 +80,7 @@ class LordOfTheForsakenManaBuilder extends ConditionalManaBuilder {
@Override
public String getRule() {
return "Spend this mana only to cast a spell from a graveyard";
return "Spend this mana only to cast a spell from your graveyard";
}
}
@ -88,7 +88,7 @@ class LordOfTheForsakenConditionalMana extends ConditionalMana {
public LordOfTheForsakenConditionalMana(Mana mana) {
super(mana);
staticText = "Spend this mana only to cast a spell from a graveyard";
staticText = "Spend this mana only to cast a spell from your graveyard";
addCondition(LordOfTheForsakenManaCondition.instance);
}
}
@ -98,7 +98,8 @@ enum LordOfTheForsakenManaCondition implements Condition {
@Override
public boolean apply(Game game, Ability source) {
if (game == null || !game.inCheckPlayableState()) {
if (game == null || !game.inCheckPlayableState()
|| !source.isControlledBy(game.getOwnerId(source.getSourceId()))) {
return false;
}
if (game.getCard(source.getSourceId()) != null

View file

@ -10,7 +10,9 @@ import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
import mage.constants.SubType;
import mage.filter.StaticFilters;
import mage.filter.FilterPermanent;
import mage.filter.common.FilterControlledCreaturePermanent;
import mage.filter.predicate.mageobject.AnotherPredicate;
import java.util.UUID;
@ -19,6 +21,13 @@ import java.util.UUID;
*/
public final class LuminousPhantom extends CardImpl {
private static final FilterPermanent filter
= new FilterControlledCreaturePermanent("another creature you control");
static {
filter.add(AnotherPredicate.instance);
}
public LuminousPhantom(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "");
@ -34,9 +43,7 @@ public final class LuminousPhantom extends CardImpl {
this.addAbility(FlyingAbility.getInstance());
// Whenever another creature you control leaves the battlefield, you gain 1 life.
this.addAbility(new LeavesBattlefieldAllTriggeredAbility(
new GainLifeEffect(1), StaticFilters.FILTER_CONTROLLED_ANOTHER_CREATURE
));
this.addAbility(new LeavesBattlefieldAllTriggeredAbility(new GainLifeEffect(1), filter));
// If Luminous Phantom would be put into a graveyard from anywhere, exile it instead.
this.addAbility(new PutIntoGraveFromAnywhereSourceAbility(new ExileSourceEffect().setText("exile it instead")));

View file

@ -21,7 +21,7 @@ import mage.filter.predicate.permanent.TokenPredicate;
public final class MidnightReaper extends CardImpl {
private static final FilterCreaturePermanent filter
= new FilterCreaturePermanent("nontoken creature you control");
= new FilterCreaturePermanent("a nontoken creature you control");
static {
filter.add(TargetController.YOU.getControllerPredicate());

View file

@ -51,7 +51,7 @@ class OldStickfingersEffect extends OneShotEffect {
public OldStickfingersEffect() {
super(Outcome.Discard);
this.staticText = "reveal cards from the top of your library until you reveal X creature cards. Put all the creature cards revealed this way into your graveyard and the rest on the bottom of your library in a random order";
this.staticText = "reveal cards from the top of your library until you reveal X creature cards. Put all creature cards revealed this way into your graveyard, then put the rest on the bottom of your library in a random order";
}
public OldStickfingersEffect(final OldStickfingersEffect effect) {

View file

@ -17,7 +17,7 @@ import mage.game.permanent.token.ZombieToken;
*/
public final class OpenTheGraves extends CardImpl {
private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("nontoken creature you control");
private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("a nontoken creature you control");
static {
filter.add(TargetController.YOU.getControllerPredicate());

View file

@ -26,7 +26,7 @@ import mage.target.common.TargetCreaturePermanent;
*/
public final class OverseerOfTheDamned extends CardImpl {
private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("nontoken creature an opponent controls");
private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("a nontoken creature an opponent controls");
static {
filter.add(TargetController.OPPONENT.getControllerPredicate());

View file

@ -66,7 +66,7 @@ class PhantomCarriageEffect extends SearchEffect {
public PhantomCarriageEffect() {
super(new TargetCardInLibrary(StaticFilters.FILTER_CARD_CREATURE), Outcome.Neutral);
staticText = "search your library for a card with flashback or disturb, put that card into your graveyard, then shuffle";
staticText = "search your library for a card with flashback or disturb, put it into your graveyard, then shuffle";
}
public PhantomCarriageEffect(final PhantomCarriageEffect effect) {

View file

@ -71,10 +71,13 @@ class PraetorsGraspEffect extends OneShotEffect {
if (controller.searchLibrary(target, source, game, opponent.getId())) {
UUID targetId = target.getFirstTarget();
Card card = opponent.getLibrary().getCard(targetId, game);
UUID exileId = CardUtil.getExileZoneId(game, source.getSourceId(),
source.getSourceObjectZoneChangeCounter());
if (card != null
&& exileId != null) {
if (card == null) {
return false;
}
// account for card going into exile from the library
final int zcc = game.getState().getZoneChangeCounter(card.getId()) + 1;
UUID exileId = CardUtil.getExileZoneId(card.getId().toString() + zcc, game);
if (exileId != null) {
game.informPlayers(controller.getLogName() + " moves the searched "
+ "card face down to exile");
card.moveToExile(exileId, sourceObject.getIdName(), source, game);
@ -120,14 +123,15 @@ class PraetorsGraspPlayEffect extends AsThoughEffectImpl {
if (objectId.equals(cardId)
&& affectedControllerId.equals(source.getControllerId())) {
Player controller = game.getPlayer(source.getControllerId());
UUID exileId = CardUtil.getExileZoneId(game, source.getSourceId(),
source.getSourceObjectZoneChangeCounter());
UUID exileId = CardUtil.getExileZoneId(cardId.toString() + game.getState().getZoneChangeCounter(cardId), game);
if (exileId != null
&& controller != null) {
ExileZone exileZone = game.getExile().getExileZone(exileId);
if (exileZone != null
&& exileZone.contains(cardId)) {
return true;
} else {
discard();
}
}
}
@ -166,8 +170,7 @@ class PraetorsGraspRevealEffect extends AsThoughEffectImpl {
if (objectId.equals(cardId)
&& affectedControllerId.equals(source.getControllerId())) {
MageObject sourceObject = source.getSourceObject(game);
UUID exileId = CardUtil.getExileZoneId(game, source.getSourceId(),
source.getSourceObjectZoneChangeCounter());
UUID exileId = CardUtil.getExileZoneId(cardId.toString() + game.getState().getZoneChangeCounter(cardId), game);
if (exileId != null
&& sourceObject != null) {
ExileZone exileZone = game.getExile().getExileZone(exileId);

View file

@ -62,7 +62,7 @@ class PurifyingDragonEffect extends OneShotEffect {
PurifyingDragonEffect() {
super(Outcome.Benefit);
staticText = "it deals 1 damage to target creature defending player controls. " +
"If that creature is a Zombie, {this} deals 2 damage to that creature instead";
"If that creature is a Zombie, {this} deals 2 damage to it instead";
}
private PurifyingDragonEffect(final PurifyingDragonEffect effect) {

View file

@ -58,7 +58,7 @@ public final class RootcoilCreeper extends CardImpl {
// {G}{U}, {T}, Exile Rootcoil Creeper: Return target card with flashback you own in exile to your hand.
Ability ability = new SimpleActivatedAbility(
new ReturnToHandTargetEffect()
.setText("return target card with flashback you own in exile to your hand"),
.setText("return target card with flashback you own from exile to your hand"),
new ManaCostsImpl<>("{G}{U}")
);
ability.addCost(new TapSourceCost());

View file

@ -75,6 +75,6 @@ enum SeizeTheStormValue implements DynamicValue {
@Override
public String getMessage() {
return "instant and sorcery cards in your graveyard, plus the number of cards with flashback you own in exile";
return "instant and sorcery cards in your graveyard plus the number of cards with flashback you own in exile";
}
}

View file

@ -27,7 +27,7 @@ import mage.target.common.TargetCardInYourGraveyard;
*/
public final class SigardaHeronsGrace extends CardImpl {
private static final FilterControlledPermanent filter = new FilterControlledPermanent("Humans you control");
private static final FilterControlledPermanent filter = new FilterControlledPermanent("Humans");
static {
filter.add(SubType.HUMAN.getPredicate());
@ -45,10 +45,10 @@ public final class SigardaHeronsGrace extends CardImpl {
// You and Humans you control have hexproof.
Effect effect = new GainAbilityControllerEffect(HexproofAbility.getInstance(), Duration.WhileOnBattlefield);
effect.setText("You and");
effect.setText("You");
Ability ability =new SimpleStaticAbility(Zone.BATTLEFIELD, effect);
effect = new GainAbilityControlledEffect(HexproofAbility.getInstance(), Duration.WhileOnBattlefield, filter);
effect.setText("and Humans you control have hexproof");
effect.concatBy("and");
ability.addEffect(effect);
this.addAbility(ability);

View file

@ -32,7 +32,7 @@ public final class StormTheFestival extends CardImpl {
// Look at the top five cards of your library. Put up to two permanent cards with mana value 5 or less from among them onto the battlefield. Put the rest on the bottom of your library in a random order.
this.getSpellAbility().addEffect(new LookLibraryAndPickControllerEffect(
5, 2, filter, false, true, Zone.BATTLEFIELD, false
5, 2, filter, false, true, Zone.BATTLEFIELD, true
).setBackInRandomOrder(true));
// Flashback {7}{G}{G}{G}

View file

@ -74,7 +74,7 @@ class StranglingGraspEffect extends OneShotEffect {
StranglingGraspEffect() {
super(Outcome.Benefit);
staticText = "enchanted permanent's controller sacrifices a nonland permanent and loses 1 life";
staticText = "enchanted permanent's controller sacrifices a nonland permanent, then that player loses 1 life";
}
private StranglingGraspEffect(final StranglingGraspEffect effect) {

View file

@ -37,7 +37,7 @@ public final class SunstreakPhoenix extends CardImpl {
this.addAbility(new BecomesDayOrNightTriggeredAbility(
Zone.GRAVEYARD,
new DoIfCostPaid(
new ReturnSourceFromGraveyardToBattlefieldEffect(true),
new ReturnSourceFromGraveyardToBattlefieldEffect(true, false),
new ManaCostsImpl<>("{1}{R}")
)
));

View file

@ -59,7 +59,7 @@ class TaintedAdversaryEffect extends OneShotEffect {
TaintedAdversaryEffect() {
super(Outcome.Benefit);
staticText = "put that many +1/+1 counters on {this}, " +
"then create twice that many black 2/2 Zombie creature tokens with decayed";
"then create twice that many 2/2 black Zombie creature tokens with decayed";
}
private TaintedAdversaryEffect(final TaintedAdversaryEffect effect) {

View file

@ -70,7 +70,7 @@ public final class TombTyrant extends CardImpl {
new ManaCostsImpl<>("{2}{B}"), condition
);
ability.addCost(new TapSourceCost());
ability.addCost(new SacrificeTargetCost(StaticFilters.FILTER_CONTROLLED_ANOTHER_CREATURE));
ability.addCost(new SacrificeTargetCost(StaticFilters.FILTER_CONTROLLED_CREATURE_SHORT_TEXT));
this.addAbility(ability.addHint(MyTurnHint.instance).addHint(hint));
}

View file

@ -30,8 +30,8 @@ public final class TrostanisSummoner extends CardImpl {
// When Trostani's Summoner enters the battlefield, create a 2/2 white Knight creature token with vigilance, a 3/3 green Centaur creature token, and a 4/4 green Rhino creature token with trample.
Ability ability = new EntersBattlefieldTriggeredAbility(new CreateTokenEffect(new KnightToken()));
ability.addEffect(new CreateTokenEffect(new CentaurToken()));
ability.addEffect(new CreateTokenEffect(new RhinoToken()));
ability.addEffect(new CreateTokenEffect(new CentaurToken()).setText(", a 3/3 green Centaur creature token"));
ability.addEffect(new CreateTokenEffect(new RhinoToken()).setText(", and a 4/4 green Rhino creature token with trample"));
this.addAbility(ability);
}

View file

@ -29,7 +29,7 @@ public final class UnbreakableFormation extends CardImpl {
// Creatures you control gain indestructible until end of turn.
this.getSpellAbility().addEffect(new GainAbilityControlledEffect(
IndestructibleAbility.getInstance(), Duration.EndOfTurn,
StaticFilters.FILTER_PERMANENT_CREATURE
StaticFilters.FILTER_PERMANENT_CREATURES
));
// Addendum If you cast this spell during your main phase, put a +1/+1 counter on each of those creatures, and they also gain vigilance until end of turn.

View file

@ -29,7 +29,7 @@ import java.util.UUID;
public final class WilheltTheRotcleaver extends CardImpl {
private static final FilterPermanent filter
= new FilterControlledPermanent(SubType.ZOMBIE);
= new FilterControlledPermanent(SubType.ZOMBIE, "another Zombie you control");
private static final FilterControlledPermanent filter2
= new FilterControlledPermanent(SubType.ZOMBIE, "a Zombie");
@ -49,7 +49,7 @@ public final class WilheltTheRotcleaver extends CardImpl {
// Whenever another Zombie you control dies, if it didn't have decayed, create a 2/2 black Zombie creature token with decayed.
this.addAbility(new DiesCreatureTriggeredAbility(
new CreateTokenEffect(new ZombieDecayedToken())
.concatBy(", if it didn't have decayed, "),
.setText("if it didn't have decayed, create a 2/2 black Zombie creature token with decayed"),
false, filter
));

View file

@ -0,0 +1,61 @@
/*
* 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.abilities.flicker;
import mage.constants.PhaseStep;
import mage.constants.Zone;
import org.junit.Test;
import org.mage.test.serverside.base.CardTestPlayerBase;
/**
*
* @author jeffwadsworth
*/
public class GisaGloriousResurrectorBlinkedTest extends CardTestPlayerBase {
@Test
public void testNormalCastAndRetrieve() {
setStrictChooseMode(true);
addCard(Zone.BATTLEFIELD, playerB, "Memnite");
addCard(Zone.BATTLEFIELD, playerA, "Gisa, Glorious Resurrector");
addCard(Zone.HAND, playerA, "Lightning Bolt");
addCard(Zone.BATTLEFIELD, playerA, "Mountain"); // mana for Lightning Bolt
// The Memnite dies and gets exiled. It should be put onto the battlefield under playerA's control during the next upkeep
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Lightning Bolt", "Memnite");
setStopAt(3, PhaseStep.PRECOMBAT_MAIN);
execute();
assertAllCommandsUsed();
// should be under playerA control
assertPermanentCount(playerA, "Memnite", 1);
}
@Test
public void testBlinkedGisa() {
setStrictChooseMode(true);
addCard(Zone.BATTLEFIELD, playerB, "Memnite");
addCard(Zone.BATTLEFIELD, playerA, "Gisa, Glorious Resurrector");
addCard(Zone.HAND, playerA, "Lightning Bolt");
addCard(Zone.HAND, playerA, "Flicker");
addCard(Zone.BATTLEFIELD, playerA, "Mountain", 2); // mana for Lightning Bolt
addCard(Zone.BATTLEFIELD, playerA, "Plains", 2); // mana for Flicker
// The Memnite dies and gets exiled.
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Lightning Bolt", "Memnite");
// Blink the Gisa, Glorious Resurrector
castSpell(1, PhaseStep.POSTCOMBAT_MAIN, playerA, "Flicker", "Gisa, Glorious Resurrector");
setStopAt(3, PhaseStep.PRECOMBAT_MAIN);
execute();
assertAllCommandsUsed();
// exiled Memnite stays in exile zone
assertPermanentCount(playerA, "Memnite", 0);
}
}

View file

@ -115,7 +115,7 @@ public class BeginningOfEndStepTriggeredAbility extends TriggeredAbilityImpl {
case CONTROLLER_ATTACHED_TO:
return "At the beginning of the end step of enchanted permanent's controller, " + generateConditionString();
case ENCHANTED:
return "At the beginning of enchanted player's draw step, " + generateConditionString();
return "At the beginning of enchanted player's end step, " + generateConditionString();
}
return "";
}

View file

@ -1,4 +1,3 @@
package mage.abilities.effects.common;
import mage.MageObject;
@ -10,11 +9,9 @@ import mage.filter.FilterObject;
import mage.filter.FilterSpell;
import mage.game.Game;
import mage.game.events.GameEvent;
import mage.game.events.GameEvent.EventType;
import mage.game.stack.Spell;
/**
*
* @author BetaSteward_at_googlemail.com
*/
public class CantBeCounteredControlledEffect extends ContinuousRuleModifyingEffectImpl {
@ -77,7 +74,11 @@ public class CantBeCounteredControlledEffect extends ContinuousRuleModifyingEffe
private void setText() {
StringBuilder sb = new StringBuilder();
sb.append(filterTarget.getMessage()).append(" can't be countered");
sb.append(filterTarget.getMessage());
if (!filterTarget.getMessage().contains("you control")) {
sb.append(" you control");
}
sb.append(" can't be countered");
if (filterSource != null) {
sb.append(" by ").append(filterSource.getMessage());
}

View file

@ -164,7 +164,7 @@ public class FlashbackAbility extends SpellAbility {
sbRule.append('.');
}
if (abilityName != null) {
sbRule.append(' ');
sbRule.append(". ");
sbRule.append(abilityName);
}
sbRule.append(" <i>(You may cast this card from your graveyard for its flashback cost. Then exile it.)</i>");

View file

@ -16,7 +16,7 @@ import mage.game.Game;
public final class ConsumingBlobToken extends TokenImpl {
public ConsumingBlobToken() {
super("Ooze", "green Ooze creature token with \"This creature's power is equal to the number of card types among cards in your graveyard and its toughness is equal to that number plus 1\".");
super("Ooze", "green Ooze creature token with \"This creature's power is equal to the number of card types among cards in your graveyard and its toughness is equal to that number plus 1.\"");
setOriginalExpansionSetCode("MID");
cardType.add(CardType.CREATURE);
subtype.add(SubType.OOZE);

View file

@ -18,7 +18,7 @@ public final class SeizeTheStormToken extends TokenImpl {
public SeizeTheStormToken(DynamicValue xValue, Hint hint) {
super("Elemental", "red Elemental creature token with trample and " +
"\"This creature's power and toughness are each equal to the number of instant " +
"and sorcery cards in your graveyard, plus the number of cards with flashback you own in exile.\"");
"and sorcery cards in your graveyard plus the number of cards with flashback you own in exile.\"");
cardType.add(CardType.CREATURE);
color.setRed(true);
subtype.add(SubType.ELEMENTAL);