This commit is contained in:
Jeff 2022-06-03 20:26:55 -05:00
commit 36fdebef7f
43 changed files with 475 additions and 64 deletions

View file

@ -30,7 +30,7 @@ public final class AltarOfBhaal extends AdventureCard {
new ReturnFromGraveyardToBattlefieldTargetEffect(), new ManaCostsImpl<>("{2}{B}")
);
ability.addCost(new TapSourceCost());
ability.addCost(new ExileTargetCost(new TargetControlledPermanent(StaticFilters.FILTER_CONTROLLED_CREATURE)));
ability.addCost(new ExileTargetCost(new TargetControlledPermanent(StaticFilters.FILTER_CONTROLLED_A_CREATURE)));
ability.addTarget(new TargetCardInYourGraveyard(StaticFilters.FILTER_CARD_CREATURE_YOUR_GRAVEYARD));
this.addAbility(ability);

View file

@ -1,11 +1,11 @@
package mage.cards.a;
import mage.abilities.effects.common.continuous.BoostTargetEffect;
import mage.abilities.effects.common.continuous.BoostAllEffect;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
import mage.constants.Duration;
import mage.constants.TargetController;
import mage.filter.FilterPermanent;
import mage.filter.common.FilterCreaturePermanent;
import mage.target.TargetPlayer;
@ -16,7 +16,7 @@ import java.util.UUID;
*/
public final class ArmsOfHadar extends CardImpl {
private static final FilterPermanent filter = new FilterCreaturePermanent("creatures target player controls");
private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("creatures target player controls");
static {
filter.add(TargetController.SOURCE_TARGETS.getControllerPredicate());
@ -26,7 +26,9 @@ public final class ArmsOfHadar extends CardImpl {
super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{3}{B}");
// Creatures target player controls get -2/-2 until end of turn.
this.getSpellAbility().addEffect(new BoostTargetEffect(-2, -2));
this.getSpellAbility().addEffect(new BoostAllEffect(
-2, -2, Duration.EndOfTurn, filter, false
));
this.getSpellAbility().addTarget(new TargetPlayer());
}

View file

@ -47,7 +47,8 @@ public final class BaldursGate extends CardImpl {
// {2}, {T}: Add X mana of any one color, where X is the number of other Gates you control.
Ability ability = new DynamicManaAbility(
Mana.AnyMana(1), xValue, new GenericManaCost(2), null, true
Mana.AnyMana(1), xValue, new GenericManaCost(2), "Add X mana of any one color, " +
"where X is the number of other Gates you control.", true
);
ability.addCost(new TapSourceCost());
this.addAbility(ability.addHint(hint));

View file

@ -32,7 +32,7 @@ public final class DungeoneersPack extends CardImpl {
Ability ability = new ActivateAsSorceryActivatedAbility(new TakeTheInitiativeEffect(), new GenericManaCost(2));
ability.addCost(new TapSourceCost());
ability.addCost(new SacrificeSourceCost());
ability.addEffect(new GainLifeEffect(3).concatBy(", you"));
ability.addEffect(new GainLifeEffect(3).setText("gain 3 life"));
ability.addEffect(new DrawCardSourceControllerEffect(1).concatBy(","));
ability.addEffect(new CreateTokenEffect(new TreasureToken()).concatBy(", and"));
this.addAbility(ability);

View file

@ -30,7 +30,7 @@ public final class FlamingFist extends CardImpl {
this.addAbility(new SimpleStaticAbility(new GainAbilityAllEffect(
new AttacksTriggeredAbility(new GainAbilitySourceEffect(
DoubleStrikeAbility.getInstance(), Duration.EndOfTurn
).setText("it gains double strike until end of turn")),
).setText("it gains double strike until end of turn")).setTriggerPhrase("Whenever this creature attacks, "),
Duration.WhileOnBattlefield, StaticFilters.FILTER_CREATURES_OWNED_COMMANDER
)));
}

View file

@ -8,7 +8,9 @@ import mage.cards.CardSetInfo;
import mage.constants.CardType;
import mage.constants.SubType;
import mage.counters.CounterType;
import mage.filter.StaticFilters;
import mage.filter.FilterPermanent;
import mage.filter.common.FilterControlledCreaturePermanent;
import mage.filter.predicate.mageobject.AnotherPredicate;
import java.util.UUID;
@ -17,6 +19,13 @@ import java.util.UUID;
*/
public final class FlamingFistOfficer extends CardImpl {
private static final FilterPermanent filter
= new FilterControlledCreaturePermanent("another creature you control");
static {
filter.add(AnotherPredicate.instance);
}
public FlamingFistOfficer(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{W}");
@ -27,8 +36,7 @@ public final class FlamingFistOfficer extends CardImpl {
// Whenever another creature you control leaves the battlefield, put a +1/+1 counter on Flaming Fist Officer.
this.addAbility(new LeavesBattlefieldAllTriggeredAbility(
new AddCountersSourceEffect(CounterType.P1P1.createInstance()),
StaticFilters.FILTER_CONTROLLED_ANOTHER_CREATURE
new AddCountersSourceEffect(CounterType.P1P1.createInstance()), filter
));
}

View file

@ -45,7 +45,7 @@ public final class FrayingLine extends CardImpl {
// At the beginning of each player's upkeep, that player may pay {2}. If they do, they put a rope counter on a creature they control. Otherwise, exile Fraying Line and each creature without a rope counter on it, then remove all rope counters from all creatures.
this.addAbility(new BeginningOfUpkeepTriggeredAbility(
new FrayingLineEffect(), TargetController.ACTIVE, true
new FrayingLineEffect(), TargetController.ACTIVE, false
));
}

View file

@ -2,7 +2,7 @@ package mage.cards.g;
import mage.MageInt;
import mage.abilities.Ability;
import mage.abilities.common.EntersBattlefieldAllTriggeredAbility;
import mage.abilities.common.EntersBattlefieldControlledTriggeredAbility;
import mage.abilities.common.SimpleStaticAbility;
import mage.abilities.dynamicvalue.common.GateYouControlCount;
import mage.abilities.effects.common.PutOnLibrarySourceEffect;
@ -41,7 +41,7 @@ public final class GateColossus extends CardImpl {
this.addAbility(new DauntAbility());
// Whenever a Gate enters the battlefield under your control, you may put Gate Colossus from your graveyard on top of your library.
this.addAbility(new EntersBattlefieldAllTriggeredAbility(
this.addAbility(new EntersBattlefieldControlledTriggeredAbility(
Zone.GRAVEYARD,
new PutOnLibrarySourceEffect(
true, "put {this} from your graveyard on top of your library"

View file

@ -43,7 +43,7 @@ public final class GiantAnkheg extends CardImpl {
ability.addEffect(new GainAbilityControlledEffect(
new WardAbility(new GenericManaCost(2), false), Duration.WhileOnBattlefield,
StaticFilters.FILTER_PERMANENT_CREATURES, true
));
).setText("and ward {2}"));
this.addAbility(ability);
}

View file

@ -40,7 +40,7 @@ public final class GorionWiseMentor extends CardImpl {
// Whenever you cast an Adventure spell, you may copy it. You may choose new targets for the copy.
this.addAbility(new SpellCastControllerTriggeredAbility(
new CopyTargetSpellEffect(true).withSpellName("it"),
filter, false, true
filter, true, true
));
}

View file

@ -43,6 +43,7 @@ public final class GraySlaad extends AdventureCard {
ability.addEffect(new ConditionalContinuousEffect(new GainAbilitySourceEffect(
DeathtouchAbility.getInstance(), Duration.WhileOnBattlefield
), condition, "and deathtouch"));
this.addAbility(ability);
// Entropic Decay
// Mill four cards.

View file

@ -17,8 +17,6 @@ import mage.constants.SubType;
import mage.filter.FilterObject;
import mage.filter.FilterStackObject;
import mage.filter.StaticFilters;
import mage.filter.common.FilterControlledArtifactPermanent;
import mage.filter.predicate.Predicates;
import mage.game.Game;
import mage.game.events.GameEvent;
import mage.game.permanent.Permanent;
@ -33,12 +31,10 @@ import java.util.UUID;
public final class GuardianBeast extends CardImpl {
private static final FilterObject filterAura = new FilterStackObject("auras");
private static final FilterControlledArtifactPermanent filter = new FilterControlledArtifactPermanent("Noncreature artifacts");
static {
filterAura.add(CardType.ENCHANTMENT.getPredicate());
filterAura.add(SubType.AURA.getPredicate());
filter.add(Predicates.not(CardType.CREATURE.getPredicate()));
}
public GuardianBeast(UUID ownerId, CardSetInfo setInfo) {
@ -51,7 +47,8 @@ public final class GuardianBeast extends CardImpl {
// This effect doesn't remove Auras already attached to those artifacts.
Ability ability = new SimpleStaticAbility(new ConditionalContinuousEffect(
new GainAbilityControlledEffect(
IndestructibleAbility.getInstance(), Duration.WhileOnBattlefield, filter
IndestructibleAbility.getInstance(), Duration.WhileOnBattlefield,
StaticFilters.FILTER_ARTIFACT_NON_CREATURE
), SourceTappedCondition.UNTAPPED, "As long as {this} is untapped, " +
"noncreature artifacts you control can't be enchanted, they're indestructible"
));
@ -113,7 +110,7 @@ class GuardianBeastConditionalEffect extends ContinuousRuleModifyingEffectImpl {
|| ((event.getType() == GameEvent.EventType.ATTACH
|| event.getType() == GameEvent.EventType.TARGET)
&& spell != null && spell.isEnchantment(game) && spell.hasSubtype(SubType.AURA, game))) {
for (Permanent perm : game.getBattlefield().getAllActivePermanents(StaticFilters.FILTER_ARTIFACTS_NON_CREATURE, source.getControllerId(), game)) {
for (Permanent perm : game.getBattlefield().getAllActivePermanents(StaticFilters.FILTER_ARTIFACT_NON_CREATURE, source.getControllerId(), game)) {
if (perm != null && Objects.equals(perm.getId(), targetPermanent.getId()) && !perm.isCreature(game)) {
return true;
}

View file

@ -30,7 +30,7 @@ public final class InspiringLeader extends CardImpl {
2, 2, Duration.WhileOnBattlefield,
StaticFilters.FILTER_CREATURE_TOKENS
)), Duration.WhileOnBattlefield, StaticFilters.FILTER_CREATURES_OWNED_COMMANDER
)));
).withForceQuotes()));
}
private InspiringLeader(final InspiringLeader card) {

View file

@ -41,7 +41,7 @@ public final class JavelinOfLightning extends CardImpl {
"as long as it's your turn, equipped creature gets +2/+0"));
ability.addEffect(new ConditionalContinuousEffect(new GainAbilityAttachedEffect(
FirstStrikeAbility.getInstance(), AttachmentType.EQUIPMENT
), MyTurnCondition.instance, "and first strike"));
), MyTurnCondition.instance, "and has first strike"));
this.addAbility(ability.addHint(MyTurnHint.instance));
// Equip {4}

View file

@ -50,7 +50,7 @@ public final class KenkuArtificer extends CardImpl {
.withAbility(FlyingAbility.getInstance()),
false, false, Duration.EndOfTurn
).setText("That artifact becomes a 0/0 Homunculus artifact creature with flying"));
ability.addTarget(new TargetPermanent(0, 1, StaticFilters.FILTER_ARTIFACTS_NON_CREATURE));
ability.addTarget(new TargetPermanent(0, 1, StaticFilters.FILTER_ARTIFACT_NON_CREATURE));
this.addAbility(ability.withFlavorWord("Homunculus Servant"));
}

View file

@ -34,7 +34,7 @@ public final class MahadiEmporiumMaster extends CardImpl {
this.addAbility(new BeginningOfEndStepTriggeredAbility(
new CreateTokenEffect(
new TreasureToken(), CreaturesDiedThisTurnCount.instance
), TargetController.YOU, false
).setText("create a Treasure token for each creature that died this turn"), TargetController.YOU, false
).addHint(CreaturesDiedThisTurnHint.instance), new CreaturesDiedWatcher());
}

View file

@ -15,10 +15,11 @@ import mage.cards.CardSetInfo;
import mage.constants.CardType;
import mage.constants.SubType;
import mage.constants.WatcherScope;
import mage.filter.StaticFilters;
import mage.game.Game;
import mage.game.events.DamagedEvent;
import mage.game.events.GameEvent;
import mage.target.common.TargetCreaturePermanent;
import mage.target.TargetPermanent;
import mage.watchers.Watcher;
import java.util.HashSet;
@ -51,7 +52,9 @@ public final class MoonshaePixie extends AdventureCard {
// Pixie Dust
// Up to three target creatures gain flying until end of turn.
this.getSpellCard().getSpellAbility().addEffect(new GainAbilityTargetEffect(FlyingAbility.getInstance()));
this.getSpellCard().getSpellAbility().addTarget(new TargetCreaturePermanent(0, 3));
this.getSpellCard().getSpellAbility().addTarget(new TargetPermanent(
0, 3, StaticFilters.FILTER_PERMANENT_CREATURES
));
}
private MoonshaePixie(final MoonshaePixie card) {

View file

@ -38,7 +38,7 @@ public final class MyrkulsInvoker extends CardImpl {
ability.addEffect(new GainAbilityControlledEffect(
new MenaceAbility(false), Duration.EndOfTurn,
StaticFilters.FILTER_CONTROLLED_CREATURE
).setText("and gain menace until end of turn " +
).setText("and gain menace until end of turn. " +
"<i>(A creature with menace can't be blocked except by two or more creatures.)</i>"));
this.addAbility(ability.withFlavorWord("Psychic Blades"));
}

View file

@ -28,7 +28,7 @@ public final class MysteryKey extends CardImpl {
new DrawCardSourceControllerEffect(3),
new SacrificeSourceCost(), null, false
), "equipped", false
));
).setTriggerPhrase("When equipped creature deals combat damage to a player, "));
// Equip {1}
this.addAbility(new EquipAbility(1));

View file

@ -37,7 +37,8 @@ public final class NemesisPhoenix extends CardImpl {
// {2}{R}: Return Nemesis Phoenix from your graveyard to the battlefield tapped and attacking. Activate only during the declare attackers step and only if you're attacking two or more opponents.
this.addAbility(new ActivateIfConditionActivatedAbility(
Zone.GRAVEYARD,
new ReturnToBattlefieldUnderOwnerControlSourceEffect(true, true, -1),
new ReturnToBattlefieldUnderOwnerControlSourceEffect(true, true, -1)
.setText("return {this} from your graveyard to the battlefield tapped and attacking"),
new ManaCostsImpl<>("{2}{R}"), NemesisPhoenixCondition.instance
));
}

View file

@ -33,7 +33,7 @@ public final class OjiTheExquisiteBlade extends CardImpl {
// When Oji, the Exquisite Blade enters the battlefield, you gain 2 life and scry 2.
Ability ability = new EntersBattlefieldTriggeredAbility(new GainLifeEffect(2));
ability.addEffect(new ScryEffect(2, false));
ability.addEffect(new ScryEffect(2, false).concatBy("and"));
this.addAbility(ability);
// Whenever you cast your second spell each turn, exile up to one target creature you control, then return it to the battlefield under its owner's control.

View file

@ -39,7 +39,7 @@ public final class RasaadYnBashir extends CardImpl {
// Each creature you control assigns combat damage equal to its toughness rather than its power.
this.addAbility(new SimpleStaticAbility(new CombatDamageByToughnessEffect(
StaticFilters.FILTER_PERMANENT_CREATURE, false
StaticFilters.FILTER_PERMANENT_CREATURE, true
)));
// Whenever Rasaad yn Bashir attacks, if you have the initiative, double the toughness of each creature you control until end of turn.

View file

@ -5,8 +5,8 @@ import mage.abilities.effects.common.RollDieWithResultTableEffect;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
import mage.game.permanent.token.KnightToken;
import mage.game.permanent.token.SoldierToken;
import mage.game.permanent.token.WaylayToken;
import java.util.UUID;
@ -25,10 +25,10 @@ public final class RecruitmentDrive extends CardImpl {
effect.addTableEntry(1, 9, new CreateTokenEffect(new SoldierToken(), 2));
// 10-19 | Create two 2/2 white Knight creature tokens.
effect.addTableEntry(10, 19, new CreateTokenEffect(new KnightToken(), 2));
effect.addTableEntry(10, 19, new CreateTokenEffect(new WaylayToken(), 2));
// 20 | Create three 2/2 white Knight creature tokens.
effect.addTableEntry(20, 20, new CreateTokenEffect(new KnightToken(), 3));
effect.addTableEntry(20, 20, new CreateTokenEffect(new WaylayToken(), 3));
this.getSpellAbility().addEffect(effect);
}

View file

@ -0,0 +1,111 @@
package mage.cards.s;
import mage.abilities.Ability;
import mage.abilities.effects.OneShotEffect;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.cards.Cards;
import mage.cards.CardsImpl;
import mage.constants.CardType;
import mage.constants.ComparisonType;
import mage.constants.Outcome;
import mage.constants.Zone;
import mage.filter.FilterPermanent;
import mage.filter.StaticFilters;
import mage.filter.common.FilterControlledCreaturePermanent;
import mage.filter.predicate.mageobject.PowerPredicate;
import mage.game.Game;
import mage.game.permanent.Permanent;
import mage.players.Player;
import mage.target.TargetPermanent;
import mage.target.common.TargetControlledCreaturePermanent;
import java.util.HashSet;
import java.util.Set;
import java.util.UUID;
/**
* @author TheElk801
*/
public final class SculptedSunburst extends CardImpl {
public SculptedSunburst(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{3}{W}{W}");
// Choose a creature you control, then each opponent chooses a creature they control with equal or lesser power. If you chose a creature this way, exile each creature not chosen by any player this way.
this.getSpellAbility().addEffect(new SculptedSunburstEffect());
}
private SculptedSunburst(final SculptedSunburst card) {
super(card);
}
@Override
public SculptedSunburst copy() {
return new SculptedSunburst(this);
}
}
class SculptedSunburstEffect extends OneShotEffect {
SculptedSunburstEffect() {
super(Outcome.Benefit);
staticText = "choose a creature you control, then each opponent chooses " +
"a creature they control with equal or lesser power. If you chose a creature this way, " +
"exile each creature not chosen by any player this way";
}
private SculptedSunburstEffect(final SculptedSunburstEffect effect) {
super(effect);
}
@Override
public SculptedSunburstEffect copy() {
return new SculptedSunburstEffect(this);
}
@Override
public boolean apply(Game game, Ability source) {
if (!game.getBattlefield().contains(StaticFilters.FILTER_CONTROLLED_CREATURE, source, game, 1)) {
return false;
}
Player player = game.getPlayer(source.getControllerId());
if (player == null) {
return false;
}
TargetPermanent target = new TargetControlledCreaturePermanent();
target.setNotTarget(true);
player.choose(outcome, target, source, game);
Permanent permanent = game.getPermanent(target.getFirstTarget());
if (permanent == null) {
return false;
}
Set<UUID> set = new HashSet<>();
set.add(permanent.getId());
int power = permanent.getPower().getValue();
FilterPermanent filter = new FilterControlledCreaturePermanent(
"creature you control with power " + power + " or less"
);
filter.add(new PowerPredicate(ComparisonType.FEWER_THAN, power + 1));
for (UUID opponentId : game.getOpponents(source.getControllerId())) {
if (!game.getBattlefield().contains(filter, source, game, 1)) {
continue;
}
Player opponent = game.getPlayer(opponentId);
if (opponent == null) {
continue;
}
TargetPermanent targetPermanent = new TargetPermanent(filter);
targetPermanent.setNotTarget(true);
opponent.choose(outcome, targetPermanent, source, game);
set.add(targetPermanent.getFirstTarget());
}
Cards cards = new CardsImpl(game.getBattlefield().getActivePermanents(
StaticFilters.FILTER_PERMANENT_CREATURE,
source.getControllerId(), source, game
));
cards.removeIf(set::contains);
player.moveCards(cards, Zone.EXILED, source, game);
return true;
}
}

View file

@ -59,6 +59,7 @@ public final class SharpshooterElf extends CardImpl {
new DamageTargetEffect(xValue, "it"), true
);
ability.addTarget(new TargetPermanent(filter));
this.addAbility(ability);
}
private SharpshooterElf(final SharpshooterElf card) {

View file

@ -46,7 +46,8 @@ public final class SkanosDragonheart extends CardImpl {
// Whenever Skanos Dragonheart attacks, it gets +X/+X until end of turn, where X is the greatest power among Dragon cards in your graveyard or other Dragons you control.
this.addAbility(new AttacksTriggeredAbility(new BoostSourceEffect(
SkanosDragonheartValue.instance, SkanosDragonheartValue.instance, Duration.EndOfTurn
SkanosDragonheartValue.instance, SkanosDragonheartValue.instance,
Duration.EndOfTurn, true, "it"
)).addHint(hint));
// Choose a Background

View file

@ -14,6 +14,7 @@ import mage.constants.Duration;
import mage.constants.SubType;
import mage.constants.SuperType;
import mage.filter.StaticFilters;
import mage.target.common.TargetAnyTarget;
import java.util.UUID;
@ -33,6 +34,7 @@ public final class StreetUrchin extends CardImpl {
new DamageTargetEffect(1, "this creature"), new GenericManaCost(1)
);
ability.addCost(new SacrificeTargetCost(StaticFilters.FILTER_CONTROLLED_ARTIFACT_OR_OTHER_CREATURE));
ability.addTarget(new TargetAnyTarget());
this.addAbility(new SimpleStaticAbility(new GainAbilityAllEffect(
ability, Duration.WhileOnBattlefield,
StaticFilters.FILTER_CREATURES_OWNED_COMMANDER

View file

@ -0,0 +1,106 @@
package mage.cards.s;
import mage.abilities.Ability;
import mage.abilities.common.EntersBattlefieldTriggeredAbility;
import mage.abilities.common.SimpleStaticAbility;
import mage.abilities.condition.Condition;
import mage.abilities.condition.common.AttachedToMatchesFilterCondition;
import mage.abilities.decorator.ConditionalContinuousEffect;
import mage.abilities.effects.OneShotEffect;
import mage.abilities.effects.common.AttachEffect;
import mage.abilities.effects.common.DontUntapInControllersUntapStepEnchantedEffect;
import mage.abilities.keyword.EnchantAbility;
import mage.abilities.keyword.FlashAbility;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
import mage.constants.Outcome;
import mage.constants.SubType;
import mage.constants.SuperType;
import mage.filter.FilterPermanent;
import mage.filter.predicate.Predicates;
import mage.game.Game;
import mage.game.permanent.Permanent;
import mage.target.TargetPermanent;
import mage.target.common.TargetCreaturePermanent;
import java.util.Objects;
import java.util.Optional;
import java.util.UUID;
/**
* @author TheElk801
*/
public final class StunningStrike extends CardImpl {
private static final FilterPermanent filter = new FilterPermanent();
static {
filter.add(Predicates.not(SuperType.LEGENDARY.getPredicate()));
}
private static final Condition condition = new AttachedToMatchesFilterCondition(filter);
public StunningStrike(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{2}{U}");
this.subtype.add(SubType.AURA);
// Flash
this.addAbility(FlashAbility.getInstance());
// Enchant creature
TargetPermanent auraTarget = new TargetCreaturePermanent();
this.getSpellAbility().addTarget(auraTarget);
this.getSpellAbility().addEffect(new AttachEffect(Outcome.BoostCreature));
this.addAbility(new EnchantAbility(auraTarget.getTargetName()));
// When Stunning Strike enters the battlefield, tap enchanted creature and remove it from combat.
this.addAbility(new EntersBattlefieldTriggeredAbility(new StunningStrikeEffect()));
// As long as enchanted creature isn't legendary, it doesn't untap during its controller's untap step.
this.addAbility(new SimpleStaticAbility(new ConditionalContinuousEffect(
new DontUntapInControllersUntapStepEnchantedEffect(), condition, "as long as " +
"enchanted creature isn't legendary, it doesn't untap during its controller's untap step"
)));
}
private StunningStrike(final StunningStrike card) {
super(card);
}
@Override
public StunningStrike copy() {
return new StunningStrike(this);
}
}
class StunningStrikeEffect extends OneShotEffect {
StunningStrikeEffect() {
super(Outcome.Benefit);
staticText = "tap enchanted creature and remove it from combat";
}
private StunningStrikeEffect(final StunningStrikeEffect effect) {
super(effect);
}
@Override
public StunningStrikeEffect copy() {
return new StunningStrikeEffect(this);
}
@Override
public boolean apply(Game game, Ability source) {
Optional.of(source.getSourcePermanentOrLKI(game))
.filter(Objects::nonNull)
.map(Permanent::getAttachedTo)
.map(game::getPermanent)
.ifPresent(permanent -> {
permanent.tap(source, game);
permanent.removeFromCombat(game);
});
return true;
}
}

View file

@ -36,6 +36,8 @@ public final class Thunderwave extends CardImpl {
// 20 | Thunderwave deals 6 damage to each creature your opponents control.
effect.addTableEntry(20, 20, new DamageAllEffect(6, StaticFilters.FILTER_OPPONENTS_PERMANENT_CREATURE));
this.getSpellAbility().addEffect(effect);
}
private Thunderwave(final Thunderwave card) {

View file

@ -0,0 +1,65 @@
package mage.cards.u;
import mage.abilities.Ability;
import mage.abilities.common.AttacksWithCreaturesTriggeredAbility;
import mage.abilities.common.EntersBattlefieldTriggeredAbility;
import mage.abilities.condition.Condition;
import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility;
import mage.abilities.effects.common.CreateTokenEffect;
import mage.abilities.effects.common.TakeTheInitiativeEffect;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
import mage.game.Game;
import mage.game.permanent.token.SoldierToken;
import java.util.UUID;
/**
* @author TheElk801
*/
public final class UndercellarSweep extends CardImpl {
public UndercellarSweep(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{4}{W}");
// When Undercellar Sweep enters the battlefield, you take the initiative.
this.addAbility(new EntersBattlefieldTriggeredAbility(new TakeTheInitiativeEffect()));
// Whenever you attack, if you or a player you're attacking has the initiative, you create two 1/1 white Soldier creature token that are tapped and attacking.
this.addAbility(new ConditionalInterveningIfTriggeredAbility(
new AttacksWithCreaturesTriggeredAbility(
new CreateTokenEffect(new SoldierToken(), 2, true, true), 1
), UndercellarSweepCondition.instance, "Whenever you attack, if you or a player you're attacking " +
"has the initiative, you create two 1/1 white Soldier creature token that are tapped and attacking."
));
}
private UndercellarSweep(final UndercellarSweep card) {
super(card);
}
@Override
public UndercellarSweep copy() {
return new UndercellarSweep(this);
}
}
enum UndercellarSweepCondition implements Condition {
instance;
@Override
public boolean apply(Game game, Ability source) {
if (game.getInitiativeId() == null) {
return false;
}
return source.isControlledBy(game.getInitiativeId())
|| game
.getCombat()
.getAttackers()
.stream()
.filter(uuid -> source.isControlledBy(game.getControllerId(uuid)))
.map(game.getCombat()::getDefenderId)
.anyMatch(game.getInitiativeId()::equals);
}
}

View file

@ -0,0 +1,86 @@
package mage.cards.v;
import mage.abilities.Ability;
import mage.abilities.costs.mana.ManaCostsImpl;
import mage.abilities.dynamicvalue.common.StaticValue;
import mage.abilities.effects.OneShotEffect;
import mage.abilities.effects.common.ExileSpellEffect;
import mage.abilities.effects.common.counter.AddCountersSourceEffect;
import mage.abilities.keyword.SuspendAbility;
import mage.cards.*;
import mage.constants.CardType;
import mage.constants.Outcome;
import mage.constants.Zone;
import mage.counters.CounterType;
import mage.game.Game;
import mage.players.Player;
import mage.target.TargetPermanent;
import java.util.UUID;
/**
* @author TheElk801
*/
public final class VentureForth extends CardImpl {
public VentureForth(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{3}{G}");
// Exile cards from the top of your library until you exile a land card. Put that onto the battlefield and the rest on the bottom of your library in a random order. Exile Venture Forth with three time counters on it.
this.getSpellAbility().addEffect(new VentureForthEffect());
this.getSpellAbility().addEffect(new ExileSpellEffect());
this.getSpellAbility().addEffect(new AddCountersSourceEffect(
CounterType.TIME.createInstance(), StaticValue.get(3), false, true
).setText("with three time counters on it"));
this.getSpellAbility().addTarget(new TargetPermanent());
// Suspend 3{1}{G}
this.addAbility(new SuspendAbility(3, new ManaCostsImpl<>("{1}{G}"), this));
}
private VentureForth(final VentureForth card) {
super(card);
}
@Override
public VentureForth copy() {
return new VentureForth(this);
}
}
class VentureForthEffect extends OneShotEffect {
VentureForthEffect() {
super(Outcome.Benefit);
staticText = "exile cards from the top of your library until you exile a land card. Put that card " +
"onto the battlefield and the rest on the bottom of your library in a random order";
}
private VentureForthEffect(final VentureForthEffect effect) {
super(effect);
}
@Override
public VentureForthEffect copy() {
return new VentureForthEffect(this);
}
@Override
public boolean apply(Game game, Ability source) {
Player player = game.getPlayer(source.getControllerId());
if (player == null) {
return false;
}
Cards cards = new CardsImpl();
for (Card card : player.getLibrary().getCards(game)) {
player.moveCards(card, Zone.EXILED, source, game);
if (card.isLand(game)) {
player.moveCards(card, Zone.BATTLEFIELD, source, game);
break;
}
cards.add(card);
}
player.putCardsOnBottomOfLibrary(cards, game, source, false);
return true;
}
}

View file

@ -10,6 +10,7 @@ import mage.abilities.effects.common.ExileTopXMayPlayUntilEndOfTurnEffect;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
import mage.constants.Duration;
import mage.constants.SubType;
import mage.filter.common.FilterControlledPermanent;
import mage.filter.predicate.Predicates;
@ -40,7 +41,7 @@ public final class WarehouseThief extends CardImpl {
// {2}, {T}, Sacrifice an artifact or creature: Exile the top card of your library. Until the end of your next turn, you may play that card.
Ability ability = new SimpleActivatedAbility(
new ExileTopXMayPlayUntilEndOfTurnEffect(1), new GenericManaCost(2)
new ExileTopXMayPlayUntilEndOfTurnEffect(1, false, Duration.UntilEndOfYourNextTurn), new GenericManaCost(2)
);
ability.addCost(new TapSourceCost());
ability.addCost(new SacrificeTargetCost(filter));

View file

@ -3,7 +3,7 @@ package mage.cards.y;
import mage.abilities.Ability;
import mage.abilities.Mode;
import mage.abilities.effects.RequirementEffect;
import mage.abilities.effects.common.PreventAllNonCombatDamageToAllEffect;
import mage.abilities.effects.common.PreventAllDamageToAllEffect;
import mage.abilities.effects.common.continuous.BoostTargetEffect;
import mage.abilities.effects.common.continuous.GainAbilityTargetEffect;
import mage.abilities.keyword.IndestructibleAbility;
@ -11,7 +11,10 @@ import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
import mage.constants.Duration;
import mage.constants.TargetController;
import mage.filter.FilterPlayer;
import mage.filter.StaticFilters;
import mage.filter.common.FilterPermanentOrPlayer;
import mage.game.Game;
import mage.game.permanent.Permanent;
import mage.target.common.TargetCreaturePermanent;
@ -23,14 +26,21 @@ import java.util.UUID;
*/
public final class YouLookUponTheTarrasque extends CardImpl {
private static final FilterPermanentOrPlayer filter = new FilterPermanentOrPlayer(
"you and creatures you control",
StaticFilters.FILTER_CONTROLLED_CREATURES, new FilterPlayer()
);
static {
filter.getPlayerFilter().add(TargetController.YOU.getPlayerPredicate());
}
public YouLookUponTheTarrasque(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{4}{G}");
// Choose one
// Run and Hide Prevent all combat damage that would be dealt to you and creatures you control this turn.
this.getSpellAbility().addEffect(new PreventAllNonCombatDamageToAllEffect(
Duration.EndOfTurn, StaticFilters.FILTER_CONTROLLED_CREATURES, true
));
this.getSpellAbility().addEffect(new PreventAllDamageToAllEffect(Duration.EndOfTurn, filter, true));
this.getSpellAbility().withFirstModeFlavorWord("Run and Hide");
// Gather Your Courage Target creature gets +5/+5 and gains indestructible until end of turn. All creatures your opponents control able to block that creature this turn do so.

View file

@ -33,7 +33,7 @@ public final class YouveBeenCaughtStealing extends CardImpl {
// Bribe the Guards You create a Treasure token for each opponent who was dealt damage this turn.
this.getSpellAbility().addMode(new Mode(new CreateTokenEffect(
new TreasureToken(), YouveBeenCaughtStealingValue.instance
)).withFlavorWord("Bribe the Guards"));
).setText("you create a Treasure token for each opponent who was dealt damage this turn")).withFlavorWord("Bribe the Guards"));
}
private YouveBeenCaughtStealing(final YouveBeenCaughtStealing card) {

View file

@ -123,7 +123,7 @@ class ZevlorElturelExileTriggeredAbility extends DelayedTriggeredAbility {
@Override
public String getRule() {
return "When you next cast an instant or sorcery spell that targets only a single opponent or a single permanent an opponent controls this turn, for each other opponent, choose that player or a permanent they control, copy that spell, and the copy targets the chosen permanent.";
return "When you next cast an instant or sorcery spell that targets only a single opponent or a single permanent an opponent controls this turn, for each other opponent, choose that player or a permanent they control, copy that spell, and the copy targets the chosen player or permanent.";
}
}

View file

@ -465,6 +465,7 @@ public final class CommanderLegendsBattleForBaldursGate extends ExpansionSet {
cards.add(new SetCardInfo("Sarevok, Deathbringer", 144, Rarity.UNCOMMON, mage.cards.s.SarevokDeathbringer.class));
cards.add(new SetCardInfo("Scaled Nurturer", 252, Rarity.COMMON, mage.cards.s.ScaledNurturer.class));
cards.add(new SetCardInfo("Scouting Hawk", 41, Rarity.COMMON, mage.cards.s.ScoutingHawk.class));
cards.add(new SetCardInfo("Sculpted Sunburst", 42, Rarity.RARE, mage.cards.s.SculptedSunburst.class));
cards.add(new SetCardInfo("Sea Gate", 359, Rarity.COMMON, mage.cards.s.SeaGate.class));
cards.add(new SetCardInfo("Sea Hag", 95, Rarity.COMMON, mage.cards.s.SeaHag.class));
cards.add(new SetCardInfo("Sea of Clouds", 360, Rarity.RARE, mage.cards.s.SeaOfClouds.class));
@ -511,6 +512,7 @@ public final class CommanderLegendsBattleForBaldursGate extends ExpansionSet {
cards.add(new SetCardInfo("Stonespeaker Crystal", 338, Rarity.UNCOMMON, mage.cards.s.StonespeakerCrystal.class));
cards.add(new SetCardInfo("Street Urchin", 197, Rarity.UNCOMMON, mage.cards.s.StreetUrchin.class));
cards.add(new SetCardInfo("Stuffy Doll", 875, Rarity.RARE, mage.cards.s.StuffyDoll.class));
cards.add(new SetCardInfo("Stunning Strike", 97, Rarity.COMMON, mage.cards.s.StunningStrike.class));
cards.add(new SetCardInfo("Summon Undead", 151, Rarity.COMMON, mage.cards.s.SummonUndead.class));
cards.add(new SetCardInfo("Sunken Hollow", 918, Rarity.RARE, mage.cards.s.SunkenHollow.class));
cards.add(new SetCardInfo("Swamp", 459, Rarity.LAND, mage.cards.basiclands.Swamp.class, NON_FULL_USE_VARIOUS));
@ -557,6 +559,7 @@ public final class CommanderLegendsBattleForBaldursGate extends ExpansionSet {
cards.add(new SetCardInfo("Uchuulon", 673, Rarity.RARE, mage.cards.u.Uchuulon.class));
cards.add(new SetCardInfo("Unbreakable Formation", 710, Rarity.RARE, mage.cards.u.UnbreakableFormation.class));
cards.add(new SetCardInfo("Undercellar Myconid", 259, Rarity.COMMON, mage.cards.u.UndercellarMyconid.class));
cards.add(new SetCardInfo("Undercellar Sweep", 47, Rarity.UNCOMMON, mage.cards.u.UndercellarSweep.class));
cards.add(new SetCardInfo("Underdark Explorer", 154, Rarity.COMMON, mage.cards.u.UnderdarkExplorer.class));
cards.add(new SetCardInfo("Undermountain Adventurer", 260, Rarity.RARE, mage.cards.u.UndermountainAdventurer.class));
cards.add(new SetCardInfo("Universal Solvent", 342, Rarity.COMMON, mage.cards.u.UniversalSolvent.class));
@ -564,6 +567,7 @@ public final class CommanderLegendsBattleForBaldursGate extends ExpansionSet {
cards.add(new SetCardInfo("Valiant Changeling", 711, Rarity.UNCOMMON, mage.cards.v.ValiantChangeling.class));
cards.add(new SetCardInfo("Vault of the Archangel", 927, Rarity.RARE, mage.cards.v.VaultOfTheArchangel.class));
cards.add(new SetCardInfo("Vengeful Ancestor", 812, Rarity.RARE, mage.cards.v.VengefulAncestor.class));
cards.add(new SetCardInfo("Venture Forth", 683, Rarity.RARE, mage.cards.v.VentureForth.class));
cards.add(new SetCardInfo("Veteran Soldier", 48, Rarity.UNCOMMON, mage.cards.v.VeteranSoldier.class));
cards.add(new SetCardInfo("Vexing Puzzlebox", 343, Rarity.MYTHIC, mage.cards.v.VexingPuzzlebox.class));
cards.add(new SetCardInfo("Vicious Battlerager", 155, Rarity.COMMON, mage.cards.v.ViciousBattlerager.class));

View file

@ -60,7 +60,7 @@ public class VerifyCardDataTest {
private static final Logger logger = Logger.getLogger(VerifyCardDataTest.class);
private static final String FULL_ABILITIES_CHECK_SET_CODE = "ELD"; // check all abilities and output cards with wrong abilities texts;
private static final String FULL_ABILITIES_CHECK_SET_CODE = "CLB"; // check all abilities and output cards with wrong abilities texts;
private static final boolean AUTO_FIX_SAMPLE_DECKS = false; // debug only: auto-fix sample decks by test_checkSampleDecks test run
private static final boolean ONLY_TEXT = false; // use when checking text locally, suppresses unnecessary checks and output messages
@ -83,7 +83,7 @@ public class VerifyCardDataTest {
private static final List<String> evergreenKeywords = Arrays.asList(
"flying", "lifelink", "menace", "trample", "haste", "first strike", "hexproof", "fear",
"deathtouch", "double strike", "indestructible", "reach", "flash", "defender", "vigilance",
"plainswalk", "islandwalk", "swampwalk", "mountainwalk", "forestwalk"
"plainswalk", "islandwalk", "swampwalk", "mountainwalk", "forestwalk", "myriad"
);
static {

View file

@ -1,5 +1,6 @@
package mage.abilities.effects.common;
import mage.MageItem;
import mage.abilities.Ability;
import mage.abilities.effects.PreventionEffectImpl;
import mage.constants.Duration;
@ -10,10 +11,9 @@ import mage.filter.predicate.other.PlayerIdPredicate;
import mage.filter.predicate.permanent.PermanentIdPredicate;
import mage.game.Game;
import mage.game.events.GameEvent;
import mage.game.events.GameEvent.EventType;
import java.util.UUID;
import mage.MageItem;
import mage.game.events.GameEvent.EventType;
/**
* @author BetaSteward_at_googlemail.com
@ -41,7 +41,8 @@ public class PreventAllDamageToAllEffect extends PreventionEffectImpl {
+ (onlyCombat ? "combat " : "")
+ "damage that would be dealt to "
+ filter.getMessage()
+ (duration.toString().isEmpty() ? "" : ' ' + duration.toString());
+ (duration.toString().isEmpty() ? "" : ' ')
+ (duration == Duration.EndOfTurn ? "this turn" : duration.toString());
}
public PreventAllDamageToAllEffect(final PreventAllDamageToAllEffect effect) {
@ -85,12 +86,12 @@ public class PreventAllDamageToAllEffect extends PreventionEffectImpl {
@Override
public boolean applies(GameEvent event, Ability source, Game game) {
if (super.applies(event, source, game)) {
MageItem object ;
if(EventType.DAMAGE_PLAYER.equals(event.getType())) {
object = game.getPlayer(event.getTargetId());
MageItem object;
if (EventType.DAMAGE_PLAYER.equals(event.getType())) {
object = game.getPlayer(event.getTargetId());
} else {
object = game.getObject(event.getTargetId());
}
}
if (object != null) {
return filter.match(object, source.getControllerId(), source, game);
}

View file

@ -68,7 +68,10 @@ public class UntapTargetEffect extends OneShotEffect {
if (target.getMaxNumberOfTargets() > 1 || target.getNumberOfTargets() == 0) {
sb.append(CardUtil.numberToText(target.getMaxNumberOfTargets()));
sb.append(haveTargetWord ? " " : " target ");
sb.append(target.getTargetName()).append('s');
sb.append(target.getTargetName());
if (!target.getTargetName().endsWith("s")) {
sb.append('s');
}
} else {
sb.append(haveTargetWord ? "" : "target ");
sb.append(target.getTargetName());

View file

@ -7,10 +7,14 @@ import mage.abilities.TriggeredAbility;
import mage.abilities.common.SimpleActivatedAbility;
import mage.abilities.effects.ContinuousEffectImpl;
import mage.abilities.mana.ActivatedManaAbilityImpl;
import mage.constants.*;
import mage.constants.Duration;
import mage.constants.Layer;
import mage.constants.Outcome;
import mage.constants.SubLayer;
import mage.filter.FilterPermanent;
import mage.game.Game;
import mage.game.permanent.Permanent;
import mage.util.CardUtil;
import java.util.Iterator;
import java.util.Locale;
@ -136,7 +140,7 @@ public class GainAbilityAllEffect extends ContinuousEffectImpl {
boolean quotes = forceQuotes
|| ability instanceof SimpleActivatedAbility
||ability instanceof ActivatedManaAbilityImpl
|| ability instanceof ActivatedManaAbilityImpl
|| ability instanceof TriggeredAbility;
boolean each = filter.getMessage().toLowerCase(Locale.ENGLISH).startsWith("each");
if (excludeSource && !each) {
@ -150,10 +154,10 @@ public class GainAbilityAllEffect extends ContinuousEffectImpl {
}
if (quotes) {
sb.append('"');
}
sb.append(ability.getRule());
if (quotes) {
sb.append(CardUtil.getTextWithFirstCharUpperCase(ability.getRule()));
sb.append('"');
} else {
sb.append(ability.getRule());
}
if (!duration.toString().isEmpty()) {
sb.append(' ').append(duration.toString());

View file

@ -9,6 +9,7 @@ import mage.constants.*;
import mage.game.Game;
import mage.game.permanent.Permanent;
import mage.target.Target;
import mage.util.CardUtil;
import java.util.*;
@ -218,7 +219,7 @@ public class GainAbilityTargetEffect extends ContinuousEffectImpl {
if (target.getNumberOfTargets() < target.getMaxNumberOfTargets()) {
sb.append("up to ");
}
sb.append(target.getMaxNumberOfTargets()).append(" target ").append(target.getTargetName()).append(" gain ");
sb.append(CardUtil.numberToText(target.getMaxNumberOfTargets())).append(" target ").append(target.getTargetName()).append(" gain ");
} else {
if (!target.getTargetName().toLowerCase(Locale.ENGLISH).startsWith("another")) {
sb.append("target ");

View file

@ -23,7 +23,7 @@ public class MyriadAbility extends AttacksTriggeredAbility {
public MyriadAbility() {
super(new MyriadEffect(), false,
"Myriad <i>(Whenever this creature attacks, for each opponent other than the defending player, "
"myriad <i>(Whenever this creature attacks, for each opponent other than the defending player, "
+ "put a token that's a copy of this creature onto the battlefield tapped and attacking "
+ "that player or a planeswalker they control. Exile those tokens at the end of combat.)</i>",
SetTargetPointer.PLAYER

View file

@ -301,11 +301,11 @@ public final class StaticFilters {
FILTER_PERMANENTS_ARTIFACT_CREATURE.setLockedFilter(true);
}
public static final FilterControlledArtifactPermanent FILTER_ARTIFACTS_NON_CREATURE = new FilterControlledArtifactPermanent("Noncreature artifacts");
public static final FilterControlledArtifactPermanent FILTER_ARTIFACT_NON_CREATURE = new FilterControlledArtifactPermanent("noncreature artifact");
static {
FILTER_ARTIFACTS_NON_CREATURE.add(Predicates.not(CardType.CREATURE.getPredicate()));
FILTER_ARTIFACTS_NON_CREATURE.setLockedFilter(true);
FILTER_ARTIFACT_NON_CREATURE.add(Predicates.not(CardType.CREATURE.getPredicate()));
FILTER_ARTIFACT_NON_CREATURE.setLockedFilter(true);
}
public static final FilterPermanent FILTER_PERMANENT_ARTIFACT_OR_CREATURE = new FilterPermanent("artifact or creature");