Merge branch 'master' into feature/implement-spdr-piloted-by-peni

This commit is contained in:
theelk801 2025-09-18 13:03:40 -04:00
commit 1c62f54888
245 changed files with 2782 additions and 1758 deletions

View file

@ -575,7 +575,7 @@ public class DragCardGrid extends JPanel implements DragCardSource, DragCardTarg
// Constants
private static final int DEFAULT_COUNT_LABEL_HEIGHT = 40; // can contain 1 or 2 lines
public static final int GRID_PADDING = 20;
public static final int GRID_PADDING = 12;
private static final ImageIcon INSERT_ROW_ICON = new ImageIcon(DragCardGrid.class.getClassLoader().getResource("editor_insert_row.png"));
private static final ImageIcon INSERT_COL_ICON = new ImageIcon(DragCardGrid.class.getClassLoader().getResource("editor_insert_col.png"));

View file

@ -2818,6 +2818,14 @@ public class ScryfallImageSupportTokens {
put("EOC/Shapeshifter", "https://api.scryfall.com/cards/teoc/2/en?format=image");
put("EOC/Thopter", "https://api.scryfall.com/cards/teoc/16/en?format=image");
// SPM
put("SPM/Food", "https://api.scryfall.com/cards/tspm/5?format=image");
put("SPM/Human", "https://api.scryfall.com/cards/tspm/4?format=image");
put("SPM/Illusion", "https://api.scryfall.com/cards/tspm/2?format=image");
put("SPM/Robot", "https://api.scryfall.com/cards/tspm/6?format=image");
put("SPM/Spider", "https://api.scryfall.com/cards/tspm/3?format=image");
put("SPM/Treasure", "https://api.scryfall.com/cards/tspm/7?format=image");
// JVC
put("JVC/Elemental Shaman", "https://api.scryfall.com/cards/tjvc/4?format=image");

View file

@ -27,9 +27,9 @@ public final class AlabornZealot extends CardImpl {
// When Alaborn Zealot blocks a creature, destroy that creature and Alaborn Zealot.
TriggeredAbility ability = new BlocksCreatureTriggeredAbility(
new DestroyTargetEffect().setText("destroy that creature")
new DestroyTargetEffect().setText("destroy both")
);
ability.addEffect(new DestroySourceEffect().setText("and {this}"));
ability.addEffect(new DestroySourceEffect().setText(" creatures"));
ability.setTriggerPhrase("When {this} blocks a creature, ");
this.addAbility(ability);
}

View file

@ -117,7 +117,7 @@ class AltairIbnLaAhadTokenEffect extends OneShotEffect {
public boolean apply(Game game, Ability source) {
Set<Card> cards = game
.getExile()
.getAllCards(game, source.getControllerId())
.getCardsOwned(game, source.getControllerId())
.stream()
.filter(card -> card.getCounters(game).containsKey(CounterType.MEMORY))
.filter(card -> card.isCreature(game))

View file

@ -28,7 +28,7 @@ import mage.target.common.TargetControlledPermanent;
*/
public final class AngelicFavor extends CardImpl {
private static final FilterPermanent filter = new FilterPermanent("If you control a Plains");
private static final FilterPermanent filter = new FilterPermanent("you control a Plains");
static {
filter.add(SubType.PLAINS.getPredicate());

View file

@ -95,7 +95,7 @@ enum OpponentSearchesLibCondition implements Condition {
@Override
public String toString() {
return "If an opponent searched their library this turn";
return "an opponent searched their library this turn";
}
}

View file

@ -5,7 +5,7 @@ import mage.abilities.Ability;
import mage.abilities.common.SimpleActivatedAbility;
import mage.abilities.costs.mana.GenericManaCost;
import mage.abilities.effects.common.GainsChoiceOfAbilitiesEffect;
import mage.abilities.effects.common.continuous.BoostTargetEffect;
import mage.abilities.effects.common.continuous.BoostSourceEffect;
import mage.abilities.keyword.DeathtouchAbility;
import mage.abilities.keyword.FlyingAbility;
import mage.abilities.keyword.HasteAbility;
@ -13,6 +13,7 @@ import mage.abilities.keyword.VigilanceAbility;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
import mage.constants.Duration;
import mage.constants.SubType;
import java.util.UUID;
@ -30,7 +31,7 @@ public final class ArgivianAvenger extends CardImpl {
this.toughness = new MageInt(5);
// {1}: Until end of turn, Argivian Avenger gets -1/-1 and gains your choice of flying, vigilance, deathtouch, or haste.
Ability ability = new SimpleActivatedAbility(new BoostTargetEffect(-1, -1)
Ability ability = new SimpleActivatedAbility(new BoostSourceEffect(-1, -1, Duration.EndOfTurn)
.setText("Until end of turn, {this} gets -1/-1"), new GenericManaCost(1));
ability.addEffect(new GainsChoiceOfAbilitiesEffect(GainsChoiceOfAbilitiesEffect.TargetType.Source, "", false,
FlyingAbility.getInstance(), VigilanceAbility.getInstance(), DeathtouchAbility.getInstance(), HasteAbility.getInstance())

View file

@ -52,6 +52,6 @@ enum ArrowVolleyTrapCondition implements Condition {
@Override
public String toString() {
return "If four or more creatures are attacking";
return "four or more creatures are attacking";
}
}

View file

@ -11,6 +11,7 @@ import mage.constants.*;
import mage.filter.FilterCard;
import mage.filter.StaticFilters;
import mage.filter.predicate.Predicates;
import mage.filter.predicate.card.FaceDownPredicate;
import mage.game.Game;
import mage.game.permanent.Permanent;
import mage.game.permanent.token.AshiokNightmareMuseToken;
@ -20,8 +21,6 @@ import mage.target.common.TargetNonlandPermanent;
import mage.util.CardUtil;
import java.util.UUID;
import mage.filter.predicate.card.FaceDownPredicate;
import mage.filter.predicate.card.OwnerIdPredicate;
/**
* @author TheElk801
@ -96,6 +95,10 @@ class AshiokNightmareMuseBounceEffect extends OneShotEffect {
class AshiokNightmareMuseCastEffect extends OneShotEffect {
private static final FilterCard filter = new FilterCard("face-up cards your opponents own from exile");
static {
filter.add(TargetController.OPPONENT.getOwnerPredicate());
filter.add(Predicates.not(FaceDownPredicate.instance));
}
AshiokNightmareMuseCastEffect() {
super(Outcome.Benefit);
@ -117,11 +120,10 @@ class AshiokNightmareMuseCastEffect extends OneShotEffect {
if (controller == null) {
return false;
}
// card is owned by an opponent and is face up
filter.add(Predicates.not(new OwnerIdPredicate(controller.getId())));
filter.add(Predicates.not(FaceDownPredicate.instance));
CardUtil.castMultipleWithAttributeForFree(
controller, source, game, new CardsImpl(game.getExile().getCards(filter, game)),
controller, source, game, new CardsImpl(
game.getExile().getCardsInRange(filter, controller.getId(), source, game)
),
StaticFilters.FILTER_CARD, 3
);
return true;

View file

@ -3,7 +3,7 @@ package mage.cards.a;
import mage.abilities.Ability;
import mage.abilities.common.SimpleStaticAbility;
import mage.abilities.dynamicvalue.DynamicValue;
import mage.abilities.effects.Effect;
import mage.abilities.dynamicvalue.common.PermanentsOnBattlefieldCount;
import mage.abilities.effects.common.AttachEffect;
import mage.abilities.effects.common.continuous.BoostEnchantedEffect;
import mage.abilities.effects.common.continuous.GainAbilityAttachedEffect;
@ -12,19 +12,25 @@ import mage.abilities.keyword.VigilanceAbility;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.*;
import mage.game.Game;
import mage.game.permanent.Permanent;
import mage.filter.FilterPermanent;
import mage.filter.predicate.permanent.AttachedToAttachedPredicate;
import mage.target.TargetPermanent;
import mage.target.common.TargetCreaturePermanent;
import java.util.Objects;
import java.util.Optional;
import java.util.UUID;
/**
* @author spjspj
*/
public final class AuramancersGuise extends CardImpl {
private static final FilterPermanent filter = new FilterPermanent("Aura attached to it");
static {
filter.add(SubType.AURA.getPredicate());
filter.add(AttachedToAttachedPredicate.instance);
}
private static final DynamicValue xValue = new PermanentsOnBattlefieldCount(filter, 2);
public AuramancersGuise(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{2}{U}{U}");
@ -39,7 +45,7 @@ public final class AuramancersGuise extends CardImpl {
// Enchanted creature gets +2/+2 for each Aura attached to it and has vigilance.
Ability ability = new SimpleStaticAbility(new BoostEnchantedEffect(
AuramancersGuiseValue.instance, AuramancersGuiseValue.instance, Duration.WhileOnBattlefield
xValue, xValue, Duration.WhileOnBattlefield
));
ability.addEffect(new GainAbilityAttachedEffect(
VigilanceAbility.getInstance(), AttachmentType.AURA
@ -57,40 +63,3 @@ public final class AuramancersGuise extends CardImpl {
}
}
enum AuramancersGuiseValue implements DynamicValue {
instance;
@Override
public int calculate(Game game, Ability sourceAbility, Effect effect) {
Permanent permanent = Optional
.ofNullable(sourceAbility.getSourcePermanentIfItStillExists(game))
.map(Permanent::getAttachedTo)
.map(game::getPermanent)
.orElse(null);
return permanent != null
? 2 * permanent
.getAttachments()
.stream()
.map(game::getPermanent)
.filter(Objects::nonNull)
.filter(p -> p.hasSubtype(SubType.AURA, game))
.mapToInt(x -> 1)
.sum()
: 0;
}
@Override
public AuramancersGuiseValue copy() {
return this;
}
@Override
public String getMessage() {
return "for each Aura attached to it";
}
@Override
public String toString() {
return "2";
}
}

View file

@ -68,6 +68,6 @@ enum BalothCageTrapCondition implements Condition {
@Override
public String toString() {
return "If an opponent had an artifact enter the battlefield under their control this turn";
return "an opponent had an artifact enter the battlefield under their control this turn";
}
}

View file

@ -1,17 +1,13 @@
package mage.cards.b;
import mage.abilities.Ability;
import mage.abilities.effects.OneShotEffect;
import mage.abilities.effects.common.TargetsDamageTargetsEffect;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
import mage.constants.Outcome;
import mage.filter.FilterPermanent;
import mage.filter.common.FilterControlledCreaturePermanent;
import mage.filter.common.FilterCreaturePermanent;
import mage.filter.predicate.other.AnotherTargetPredicate;
import mage.game.Game;
import mage.game.permanent.Permanent;
import mage.target.Target;
import mage.target.TargetPermanent;
@ -27,19 +23,19 @@ public final class BandTogether extends CardImpl {
static {
filter.add(new AnotherTargetPredicate(1));
filter2.add(new AnotherTargetPredicate(2));
filter2.add(new AnotherTargetPredicate(3));
}
public BandTogether(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{2}{G}");
// Up to two target creatures you control each deal damage equal to their power to another target creature.
this.getSpellAbility().addEffect(new BandTogetherEffect());
this.getSpellAbility().addEffect(new TargetsDamageTargetsEffect(true));
Target target = new TargetPermanent(0, 2, filter, false);
target.setTargetTag(1);
this.getSpellAbility().addTarget(target);
target = new TargetPermanent(1, 1, filter2, false);
target.setTargetTag(2);
target.setTargetTag(3);
this.getSpellAbility().addTarget(target);
}
@ -52,48 +48,3 @@ public final class BandTogether extends CardImpl {
return new BandTogether(this);
}
}
class BandTogetherEffect extends OneShotEffect {
BandTogetherEffect() {
super(Outcome.Benefit);
this.staticText = "Up to two target creatures you control each deal damage equal to their power to another target creature.";
}
private BandTogetherEffect(final BandTogetherEffect effect) {
super(effect);
}
@Override
public BandTogetherEffect copy() {
return new BandTogetherEffect(this);
}
@Override
public boolean apply(Game game, Ability source) {
if (source.getTargets().size() < 2) {
return false;
}
Target damageTarget = source.getTargets().get(0);
Target destTarget = source.getTargets().get(1);
if (damageTarget.getTargets().isEmpty() || destTarget.getTargets().isEmpty()) {
return false;
}
Permanent permanentDamage1 = damageTarget.getTargets().isEmpty() ? null : game.getPermanent(damageTarget.getTargets().get(0));
Permanent permanentDamage2 = damageTarget.getTargets().size() < 2 ? null : game.getPermanent(damageTarget.getTargets().get(1));
Permanent permanentDest = game.getPermanent(destTarget.getTargets().get(0));
if (permanentDest == null) {
return false;
}
if (permanentDamage1 != null) {
permanentDest.damage(permanentDamage1.getPower().getValue(), permanentDamage1.getId(), source, game, false, true);
}
if (permanentDamage2 != null) {
permanentDest.damage(permanentDamage2.getPower().getValue(), permanentDamage2.getId(), source, game, false, true);
}
return true;
}
}

View file

@ -2,26 +2,24 @@ package mage.cards.b;
import mage.abilities.Ability;
import mage.abilities.common.DealsCombatDamageTriggeredAbility;
import mage.abilities.common.EntersBattlefieldAbility;
import mage.abilities.common.EntersBattlefieldAttachToTarget;
import mage.abilities.common.SimpleStaticAbility;
import mage.abilities.dynamicvalue.common.PermanentsOnBattlefieldCount;
import mage.abilities.effects.common.AttachEffect;
import mage.abilities.effects.common.DrawCardSourceControllerEffect;
import mage.abilities.effects.common.continuous.BoostEquippedEffect;
import mage.abilities.effects.common.continuous.GainAbilityAttachedEffect;
import mage.abilities.keyword.EquipAbility;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.*;
import mage.constants.CardType;
import mage.constants.SubType;
import mage.filter.FilterPermanent;
import mage.filter.common.FilterControlledCreaturePermanent;
import mage.filter.predicate.permanent.ModifiedPredicate;
import mage.target.common.TargetControlledCreaturePermanent;
import java.util.UUID;
/**
*
* @author Jmlundeen
*/
public final class BiorganicCarapace extends CardImpl {
@ -38,9 +36,7 @@ public final class BiorganicCarapace extends CardImpl {
this.subtype.add(SubType.EQUIPMENT);
// When this Equipment enters, attach it to target creature you control.
Ability ability = new EntersBattlefieldAbility(new AttachEffect(Outcome.BoostCreature));
ability.addTarget(new TargetControlledCreaturePermanent());
this.addAbility(ability);
this.addAbility(new EntersBattlefieldAttachToTarget());
// Equipped creature gets +2/+2 and has "Whenever this creature deals combat damage to a player, draw a card for each modified creature you control."
Ability gainedAbility = new DealsCombatDamageTriggeredAbility(new DrawCardSourceControllerEffect(new PermanentsOnBattlefieldCount(filter)), false);

View file

@ -88,7 +88,7 @@ class BiotransferenceEffect extends ContinuousEffectImpl {
}
}
// in Exile
for (Card card : game.getState().getExile().getAllCards(game, source.getControllerId())) {
for (Card card : game.getState().getExile().getCardsOwned(game, source.getControllerId())) {
if (card.isCreature(game) && !card.isArtifact(game)) {
card.addCardType(game, CardType.ARTIFACT);
}

View file

@ -28,7 +28,7 @@ public final class BlasphemousEdict extends CardImpl {
// You may pay {B} rather than pay this spell's mana cost if there are thirteen or more creatures on the battlefield.
Ability ability = new AlternativeCostSourceAbility(new ManaCostsImpl<>("{B}"), new PermanentsOnTheBattlefieldCondition(
new FilterCreaturePermanent("If there are thirteen or more creatures on the battlefield"),
new FilterCreaturePermanent("there are thirteen or more creatures on the battlefield"),
ComparisonType.OR_GREATER,
13,
false

View file

@ -1,4 +1,3 @@
package mage.cards.b;
import java.util.UUID;
@ -34,7 +33,9 @@ public final class Blight extends CardImpl {
this.addAbility(ability);
// When enchanted land becomes tapped, destroy it.
this.addAbility(new BecomesTappedAttachedTriggeredAbility(new DestroyAttachedToEffect("it"), "enchanted land"));
this.addAbility(new BecomesTappedAttachedTriggeredAbility(
new DestroyAttachedToEffect("it"), "enchanted land"
).setTriggerPhrase("When enchanted land becomes tapped, "));
}
private Blight(final Blight card) {

View file

@ -1,8 +1,8 @@
package mage.cards.b;
import mage.abilities.Ability;
import mage.abilities.common.SimpleStaticAbility;
import mage.abilities.condition.Condition;
import mage.abilities.condition.common.PermanentsOnTheBattlefieldCondition;
import mage.abilities.decorator.ConditionalContinuousEffect;
import mage.abilities.effects.common.CastSourceTriggeredAbility;
import mage.abilities.effects.common.CopySourceSpellEffect;
@ -13,20 +13,25 @@ import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.AttachmentType;
import mage.constants.CardType;
import mage.constants.ComparisonType;
import mage.constants.SubType;
import mage.game.Game;
import mage.game.permanent.Permanent;
import mage.filter.FilterPermanent;
import mage.filter.predicate.permanent.AttachedToAttachedPredicate;
import java.util.Collection;
import java.util.Objects;
import java.util.Optional;
import java.util.UUID;
import java.util.stream.Stream;
/**
* @author TheElk801
*/
public final class BrassKnuckles extends CardImpl {
private static final FilterPermanent filter = new FilterPermanent("Equipment attached to it");
static {
filter.add(SubType.EQUIPMENT.getPredicate());
filter.add(AttachedToAttachedPredicate.instance);
}
private static final Condition twoEquipmentAttachedToAttached = new PermanentsOnTheBattlefieldCondition(filter, ComparisonType.OR_GREATER, 2);
public BrassKnuckles(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{4}");
@ -40,7 +45,7 @@ public final class BrassKnuckles extends CardImpl {
this.addAbility(new SimpleStaticAbility(new ConditionalContinuousEffect(
new GainAbilityAttachedEffect(
DoubleStrikeAbility.getInstance(), AttachmentType.EQUIPMENT
), BrassKnucklesCondition.instance, "equipped creature has double strike " +
), twoEquipmentAttachedToAttached, "equipped creature has double strike " +
"as long as two or more Equipment are attached to it"
)));
@ -57,23 +62,3 @@ public final class BrassKnuckles extends CardImpl {
return new BrassKnuckles(this);
}
}
enum BrassKnucklesCondition implements Condition {
instance;
@Override
public boolean apply(Game game, Ability source) {
return Optional
.ofNullable(source.getSourcePermanentIfItStillExists(game))
.map(Permanent::getAttachedTo)
.map(game::getPermanent)
.map(Permanent::getAttachments)
.map(Collection::stream)
.map(stream -> stream.map(game::getPermanent))
.map(stream -> stream.filter(Objects::nonNull))
.map(stream -> stream.filter(p -> p.hasSubtype(SubType.EQUIPMENT, game)))
.map(Stream::count)
.map(x -> x >= 2)
.orElse(false);
}
}

View file

@ -9,6 +9,7 @@ import mage.abilities.triggers.BeginningOfUpkeepTriggeredAbility;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
import mage.constants.ComparisonType;
import mage.constants.SubType;
import mage.constants.TargetController;
import mage.filter.common.FilterCreaturePermanent;
@ -28,7 +29,7 @@ public final class CallToTheGrave extends CardImpl {
}
private static final Condition condition = new PermanentsOnTheBattlefieldCondition(
new FilterCreaturePermanent("no creatures are on the battlefield"), false
new FilterCreaturePermanent("no creatures are on the battlefield"), ComparisonType.EQUAL_TO, 0, false
);
public CallToTheGrave(UUID ownerId, CardSetInfo setInfo) {

View file

@ -40,7 +40,7 @@ public final class CallousBloodmage extends CardImpl {
ability.addMode(mode);
// Exile target player's graveyard.
mode = new Mode(new ExileGraveyardAllTargetPlayerEffect().setText("exile target player's graveyard"));
mode = new Mode(new ExileGraveyardAllTargetPlayerEffect());
mode.addTarget(new TargetPlayer());
ability.addMode(mode);
this.addAbility(ability);

View file

@ -65,7 +65,7 @@ enum CandlekeepInspirationValue implements DynamicValue {
.getCards(game)
.stream(),
game.getExile()
.getAllCards(game, sourceAbility.getControllerId())
.getCardsOwned(game, sourceAbility.getControllerId())
.stream()
)
.filter(Objects::nonNull)

View file

@ -128,7 +128,7 @@ class CelestialDawnToWhiteEffect extends ContinuousEffectImpl {
}
}
// Exile
for (Card card : game.getExile().getAllCardsByRange(game, controller.getId())) {
for (Card card : game.getExile().getCardsInRange(game, controller.getId())) {
if (card.isOwnedBy(controller.getId())) {
setColor(card.getColor(game), game);
}

View file

@ -164,7 +164,7 @@ class ChissGoriaForgeTyrantAffinityEffect extends ContinuousEffectImpl {
return false;
}
for (Card card : game.getExile().getAllCardsByRange(game, source.getControllerId())) {
for (Card card : game.getExile().getCardsInRange(game, source.getControllerId())) {
if (morSet.contains(new MageObjectReference(card, game)) && card.isArtifact(game)) {
game.getState().addOtherAbility(card, new AffinityForArtifactsAbility());
}

View file

@ -41,7 +41,7 @@ public final class ChoArrimLegate extends CardImpl {
this.addAbility(ProtectionAbility.from(ObjectColor.BLACK));
// If an opponent controls a Swamp and you control a Plains, you may cast this spell without paying its mana cost.
Condition condition = new CompoundCondition("If an opponent controls a Swamp and you control a Plains",
Condition condition = new CompoundCondition("an opponent controls a Swamp and you control a Plains",
new OpponentControlsPermanentCondition(filterSwamp),
new PermanentsOnTheBattlefieldCondition(filterPlains));
this.addAbility(new AlternativeCostSourceAbility(null, condition));

View file

@ -60,7 +60,7 @@ enum CobraTrapCondition implements Condition {
@Override
public String toString() {
return "If a noncreature permanent under your control was destroyed this turn by a spell or ability an opponent controlled";
return "a noncreature permanent under your control was destroyed this turn by a spell or ability an opponent controlled";
}
}

View file

@ -1,15 +1,11 @@
package mage.cards.c;
import mage.abilities.Ability;
import mage.abilities.effects.OneShotEffect;
import mage.abilities.effects.common.TargetsDamageTargetsEffect;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
import mage.constants.Outcome;
import mage.filter.FilterPermanent;
import mage.filter.common.FilterTeamCreaturePermanent;
import mage.game.Game;
import mage.game.permanent.Permanent;
import mage.target.TargetPermanent;
import mage.target.common.TargetCreaturePermanent;
@ -26,9 +22,9 @@ public final class ComboAttack extends CardImpl {
super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{2}{G}");
// Two target creatures your team controls each deal damage equal to their power to target creature.
this.getSpellAbility().addEffect(new ComboAttackEffect());
this.getSpellAbility().addTarget(new TargetPermanent(2, filter));
this.getSpellAbility().addTarget(new TargetCreaturePermanent());
this.getSpellAbility().addEffect(new TargetsDamageTargetsEffect(true));
this.getSpellAbility().addTarget(new TargetPermanent(2, filter).setTargetTag(1));
this.getSpellAbility().addTarget(new TargetCreaturePermanent().setTargetTag(3));
}
private ComboAttack(final ComboAttack card) {
@ -40,41 +36,3 @@ public final class ComboAttack extends CardImpl {
return new ComboAttack(this);
}
}
class ComboAttackEffect extends OneShotEffect {
ComboAttackEffect() {
super(Outcome.Benefit);
this.staticText = "Two target creatures your team controls each deal damage equal to their power to target creature";
}
private ComboAttackEffect(final ComboAttackEffect effect) {
super(effect);
}
@Override
public ComboAttackEffect copy() {
return new ComboAttackEffect(this);
}
@Override
public boolean apply(Game game, Ability source) {
if (source.getTargets().size() < 2) {
return false;
}
Permanent permanent3 = game.getPermanent(source.getTargets().get(1).getFirstTarget());
if (permanent3 == null) {
return false;
}
// You cant cast Combo Attack without targeting two creatures your team controls.
// If one of those creatures is an illegal target as Combo Attack resolves,
// the other will still deal damage equal to its power. (2018-06-08)
for (UUID id : source.getTargets().get(0).getTargets()) {
Permanent permanent = game.getPermanent(id);
if (permanent != null) {
permanent3.damage(permanent.getPower().getValue(), permanent.getId(), source, game);
}
}
return true;
}
}

View file

@ -1,8 +1,7 @@
package mage.cards.c;
import mage.abilities.Ability;
import mage.abilities.common.delayed.CopyNextSpellDelayedTriggeredAbility;
import mage.abilities.effects.OneShotEffect;
import mage.abilities.common.delayed.CastNextSpellDelayedTriggeredAbility;
import mage.abilities.effects.common.CopyTargetStackObjectEffect;
import mage.abilities.effects.common.CreateDelayedTriggeredAbilityEffect;
import mage.abilities.effects.common.continuous.CastAsThoughItHadFlashAllEffect;
import mage.abilities.keyword.ConvokeAbility;
@ -10,11 +9,8 @@ import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
import mage.constants.Duration;
import mage.constants.Outcome;
import mage.filter.FilterCard;
import mage.filter.StaticFilters;
import mage.game.Game;
import mage.game.stack.Spell;
import java.util.UUID;
@ -40,10 +36,9 @@ public final class CompleteTheCircuit extends CardImpl {
// When you next cast an instant or sorcery spell this turn, copy that spell twice. You may choose new targets for the copies.
this.getSpellAbility().addEffect(new CreateDelayedTriggeredAbilityEffect(
new CopyNextSpellDelayedTriggeredAbility(
StaticFilters.FILTER_SPELL_AN_INSTANT_OR_SORCERY,
new CompleteTheCircuitEffect(), "When you next cast an instant or sorcery spell " +
"this turn, copy that spell twice. You may choose new targets for the copies."
new CastNextSpellDelayedTriggeredAbility(
new CopyTargetStackObjectEffect(false, true, true, 2, null),
StaticFilters.FILTER_SPELL_AN_INSTANT_OR_SORCERY, true
)
).concatBy("<br>"));
}
@ -57,29 +52,3 @@ public final class CompleteTheCircuit extends CardImpl {
return new CompleteTheCircuit(this);
}
}
class CompleteTheCircuitEffect extends OneShotEffect {
CompleteTheCircuitEffect() {
super(Outcome.Benefit);
}
private CompleteTheCircuitEffect(final CompleteTheCircuitEffect effect) {
super(effect);
}
@Override
public CompleteTheCircuitEffect copy() {
return new CompleteTheCircuitEffect(this);
}
@Override
public boolean apply(Game game, Ability source) {
Spell spell = (Spell) getValue("spellCast");
if (spell != null) {
spell.createCopyOnStack(game, source, source.getControllerId(), true, 2);
return true;
}
return false;
}
}

View file

@ -92,14 +92,14 @@ public final class Conspiracy extends CardImpl {
}
}
// in Exile
for (Card card : game.getState().getExile().getAllCards(game)) {
if (card.isOwnedBy(controller.getId()) && card.isCreature(game)) {
for (Card card : game.getState().getExile().getCardsOwned(game, controller.getId())) {
if (card.isCreature(game)) {
setCreatureSubtype(card, subType, game);
}
}
// in Library (e.g. for Mystical Teachings)
for (Card card : controller.getLibrary().getCards(game)) {
if (card.isOwnedBy(controller.getId()) && card.isCreature(game)) {
if (card.isCreature(game)) {
setCreatureSubtype(card, subType, game);
}
}

View file

@ -1,21 +1,15 @@
package mage.cards.c;
import mage.abilities.Ability;
import mage.abilities.effects.OneShotEffect;
import mage.abilities.effects.common.TapTargetEffect;
import mage.abilities.effects.common.TargetsDamageTargetsEffect;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
import mage.constants.Outcome;
import mage.filter.StaticFilters;
import mage.game.Game;
import mage.game.permanent.Permanent;
import mage.target.TargetPermanent;
import mage.target.common.TargetOpponentsCreaturePermanent;
import java.util.List;
import java.util.Objects;
import java.util.UUID;
import java.util.stream.Collectors;
/**
* @author TheElk801
@ -26,11 +20,12 @@ public final class CoordinatedClobbering extends CardImpl {
super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{G}");
// Tap one or two target untapped creatures you control. They each deal damage equal to their power to target creature an opponent controls.
this.getSpellAbility().addEffect(new CoordinatedClobberingEffect());
this.getSpellAbility().addEffect(new TapTargetEffect());
this.getSpellAbility().addEffect(new TargetsDamageTargetsEffect(false));
this.getSpellAbility().addTarget(new TargetPermanent(
1, 2, StaticFilters.FILTER_CONTROLLED_UNTAPPED_CREATURES
));
this.getSpellAbility().addTarget(new TargetOpponentsCreaturePermanent());
).setTargetTag(1));
this.getSpellAbility().addTarget(new TargetOpponentsCreaturePermanent().setTargetTag(3));
}
private CoordinatedClobbering(final CoordinatedClobbering card) {
@ -42,48 +37,4 @@ public final class CoordinatedClobbering extends CardImpl {
return new CoordinatedClobbering(this);
}
}
class CoordinatedClobberingEffect extends OneShotEffect {
CoordinatedClobberingEffect() {
super(Outcome.Benefit);
staticText = "tap one or two target untapped creatures you control. " +
"They each deal damage equal to their power to target creature an opponent controls";
}
private CoordinatedClobberingEffect(final CoordinatedClobberingEffect effect) {
super(effect);
}
@Override
public CoordinatedClobberingEffect copy() {
return new CoordinatedClobberingEffect(this);
}
@Override
public boolean apply(Game game, Ability source) {
List<Permanent> permanents = this
.getTargetPointer()
.getTargets(game, source)
.stream()
.map(game::getPermanent)
.filter(Objects::nonNull)
.collect(Collectors.toList());
if (permanents.isEmpty()) {
return false;
}
for (Permanent permanent : permanents) {
permanent.tap(source, game);
}
Permanent targetPermanent = game.getPermanent(source.getTargets().get(1).getFirstTarget());
if (targetPermanent == null) {
return true;
}
game.processAction();
for (Permanent permanent : permanents) {
targetPermanent.damage(permanent.getPower().getValue(), permanent.getId(), source, game);
}
return true;
}
}
// flame on!

View file

@ -56,7 +56,7 @@ enum CosmogoyfValue implements DynamicValue {
@Override
public int calculate(Game game, Ability sourceAbility, Effect effect) {
return game.getState().getExile().getAllCards(game, sourceAbility.getControllerId()).size();
return game.getState().getExile().getCardsOwned(game, sourceAbility.getControllerId()).size();
}
@Override

View file

@ -1,4 +1,3 @@
package mage.cards.d;
import mage.abilities.condition.Condition;
@ -13,7 +12,6 @@ import mage.constants.Duration;
import mage.constants.SubType;
import mage.filter.FilterPermanent;
import mage.filter.StaticFilters;
import mage.target.common.TargetControlledCreaturePermanent;
import java.util.UUID;
@ -23,7 +21,7 @@ import java.util.UUID;
public final class DarkTriumph extends CardImpl {
private static final Condition condition = new PermanentsOnTheBattlefieldCondition(
new FilterPermanent(SubType.SWAMP, "If you control a Swamp")
new FilterPermanent(SubType.SWAMP, "you control a Swamp")
);
public DarkTriumph(UUID ownerId, CardSetInfo setInfo) {

View file

@ -40,7 +40,7 @@ public final class DeepwoodLegate extends CardImpl {
this.toughness = new MageInt(1);
// If an opponent controls a Forest and you control a Swamp, you may cast this spell without paying its mana cost.
Condition condition = new CompoundCondition("If an opponent controls a Forest and you control a Swamp",
Condition condition = new CompoundCondition("an opponent controls a Forest and you control a Swamp",
new OpponentControlsPermanentCondition(filterForest),
new PermanentsOnTheBattlefieldCondition(filterSwamp));
this.addAbility(new AlternativeCostSourceAbility(null, condition));

View file

@ -161,7 +161,7 @@ class TargetControlledSource extends TargetSource {
possibleTargets.add(card.getId());
}
// 108.4a If anything asks for the controller of a card that doesn't have one (because it's not a permanent or spell), use its owner instead.
for (Card card : game.getExile().getAllCards(game)) {
for (Card card : game.getExile().getCardsInRange(game, sourceControllerId)) {
if (Objects.equals(card.getOwnerId(), sourceControllerId)) {
possibleTargets.add(card.getId());
}

View file

@ -35,13 +35,12 @@ public final class DiscipleOfPerdition extends CardImpl {
// When Disciple of Perdition dies, choose one. If you have exactly 13 life, you may choose both.
// * You draw a card and you lose 1 life.
Ability ability = new DiesSourceTriggeredAbility(new DrawCardSourceControllerEffect(1, true), false);
ability.getModes().setChooseText("choose one. If you have exactly 13 life, you may choose both.");
ability.getModes().setChooseText("choose one. If you have exactly 13 life, you may choose both instead.");
ability.getModes().setMoreCondition(2, new LifeCompareCondition(TargetController.YOU, ComparisonType.EQUAL_TO, 13));
ability.addEffect(new LoseLifeSourceControllerEffect(1).concatBy("and"));
// * Exile target opponent's graveyard. That player loses 1 life.
ability.addMode(new Mode(new ExileGraveyardAllTargetPlayerEffect()
.setText("Exile target opponent's graveyard"))
ability.addMode(new Mode(new ExileGraveyardAllTargetPlayerEffect())
.addEffect(new LoseLifeTargetEffect(1).setText("that player loses 1 life"))
.addTarget(new TargetOpponent()));
this.addAbility(ability);

View file

@ -79,7 +79,7 @@ class DragonKamisEggEffect extends OneShotEffect {
}
Cards cards = new CardsImpl();
game.getExile()
.getAllCards(game, player.getId())
.getCardsOwned(game, player.getId())
.stream()
.filter(Objects::nonNull)
.filter(card -> card.getCounters(game).containsKey(CounterType.HATCHLING))

View file

@ -82,6 +82,6 @@ class DredgingClawTriggeredAbility extends TriggeredAbilityImpl {
@Override
public String getRule() {
return "Whenever a creature enters the battlefield from your graveyard, you may attach {this} to it.";
return "Whenever a creature enters from your graveyard, you may attach {this} to it.";
}
}

View file

@ -115,7 +115,7 @@ class DuneChanterContinuousEffect extends ContinuousEffectImpl {
}
}
// in exile
for (Card card : game.getState().getExile().getAllCards(game, controllerId)) {
for (Card card : game.getState().getExile().getCardsOwned(game, controllerId)) {
if (filterCard.match(card, controllerId, source, game) && !card.hasSubtype(subType, game)) {
game.getState().getCreateMageObjectAttribute(card, game).getSubtype().add(subType);
}
@ -174,5 +174,3 @@ class DuneChanterEffect extends OneShotEffect {
return true;
}
}

View file

@ -83,7 +83,7 @@ class DustOfMomentsEffect extends OneShotEffect {
permanent.addCounters(CounterType.TIME.createInstance(2), source, game);
}
}
for (Card card : game.getExile().getCards(filter.getCardFilter(), game)) {
for (Card card : game.getExile().getCardsInRange(filter.getCardFilter(), source.getControllerId(), source, game)) {
if (remove) {
card.removeCounters(CounterType.TIME.createInstance(2), source, game);
} else {

View file

@ -58,8 +58,7 @@ public final class ElspethsNightmare extends CardImpl {
// III - Exile target opponent's graveyard.
sagaAbility.addChapterEffect(
this, SagaChapter.CHAPTER_III, SagaChapter.CHAPTER_III,
new ExileGraveyardAllTargetPlayerEffect()
.setText("exile target opponent's graveyard"),
new ExileGraveyardAllTargetPlayerEffect(),
new TargetOpponent()
);
this.addAbility(sagaAbility);

View file

@ -80,7 +80,7 @@ class EncroachingMycosynthEffect extends ContinuousEffectImpl {
}
}
// in Exile
for (Card card : game.getState().getExile().getAllCards(game, source.getControllerId())) {
for (Card card : game.getState().getExile().getCardsOwned(game, source.getControllerId())) {
if (card.isPermanent(game) && !card.isLand(game) && !card.isArtifact(game)) {
card.addCardType(game, CardType.ARTIFACT);
}

View file

@ -119,7 +119,7 @@ class EsperTerraEffect extends OneShotEffect {
.filter(amount -> amount > 0)
.ifPresent(amount -> token.addCounters(CounterType.LORE.createInstance(amount), source, game));
}
effect.sacrificeTokensCreatedAtNextEndStep(game, source);
effect.removeTokensCreatedAt(game, source, false, PhaseStep.END_TURN, TargetController.YOU);
return true;
}
}

View file

@ -32,7 +32,7 @@ public final class EternalScourge extends CardImpl {
// When Eternal Scourge becomes the target of a spell or ability an opponent controls, exile Eternal Scourge.
this.addAbility(new BecomesTargetSourceTriggeredAbility(new ExileSourceEffect(),
StaticFilters.FILTER_SPELL_OR_ABILITY_OPPONENTS));
StaticFilters.FILTER_SPELL_OR_ABILITY_OPPONENTS).withRuleTextReplacement(false));
}
private EternalScourge(final EternalScourge card) {

View file

@ -96,8 +96,8 @@ class EtrataTheSilencerEffect extends OneShotEffect {
if (card != null) {
card.addCounters(CounterType.HIT.createInstance(), source.getControllerId(), source, game);
}
int cardsFound = game.getExile().getAllCards(game).stream()
.filter(c -> c.getOwnerId().equals(player.getId()))
int cardsFound = game.getExile().getCardsOwned(game, player.getId())
.stream()
.filter(c -> c.getCounters(game).getCount(CounterType.HIT) > 0)
.mapToInt(x -> 1)
.sum();

View file

@ -85,7 +85,9 @@ class FalkenrathGorgerEffect extends ContinuousEffectImpl {
@Override
public boolean apply(Game game, Ability source) {
Player controller = game.getPlayer(source.getControllerId());
if (controller != null) {
if (controller == null) {
return false;
}
Map<UUID, MadnessAbility> usedMadnessAbilities = new HashMap<>();
// hand
for (Card card : controller.getHand().getCards(filter, game)) {
@ -96,19 +98,13 @@ class FalkenrathGorgerEffect extends ContinuousEffectImpl {
addMadnessToCard(game, card, usedMadnessAbilities);
}
// Exile
for (Card card : game.getExile().getAllCards(game)) {
if (filter.match(card, controller.getId(), source, game)) {
if (card.isOwnedBy(controller.getId())) {
for (Card card : game.getExile().getCardsOwned(filter, controller.getId(), source, game)) {
addMadnessToCard(game, card, usedMadnessAbilities);
}
}
}
madnessAbilities.clear();
madnessAbilities.putAll(usedMadnessAbilities);
return true;
}
return false;
}
private void addMadnessToCard(Game game, Card card, Map<UUID, MadnessAbility> usedMadnessAbilities) {

View file

@ -60,7 +60,7 @@ class FavorOfTheMightyEffect extends ContinuousEffectImpl {
FavorOfTheMightyEffect() {
super(Duration.WhileOnBattlefield, Layer.AbilityAddingRemovingEffects_6, SubLayer.NA, Outcome.AddAbility);
this.staticText = "Each creature with the highest mana value has protection from all colors.";
this.staticText = "Each creature with the greatest mana value has protection from each color.";
}
private FavorOfTheMightyEffect(final FavorOfTheMightyEffect effect) {

View file

@ -97,7 +97,7 @@ class FlamewarBrashVeteranEffect extends OneShotEffect {
}
Set<Card> cards = game
.getExile()
.getAllCards(game, source.getControllerId())
.getCardsOwned(game, source.getControllerId())
.stream()
.filter(card -> card.getCounters(game).containsKey(CounterType.INTEL))
.collect(Collectors.toSet());

View file

@ -1,24 +1,17 @@
package mage.cards.f;
import mage.abilities.Ability;
import mage.abilities.effects.OneShotEffect;
import mage.abilities.effects.common.TargetsDamageTargetsEffect;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
import mage.constants.Outcome;
import mage.constants.SuperType;
import mage.filter.FilterPermanent;
import mage.filter.StaticFilters;
import mage.filter.common.FilterControlledCreaturePermanent;
import mage.filter.predicate.other.AnotherTargetPredicate;
import mage.game.Game;
import mage.game.permanent.Permanent;
import mage.target.TargetPermanent;
import mage.target.common.TargetControlledCreaturePermanent;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.UUID;
/**
@ -37,7 +30,7 @@ public final class FriendlyRivalry extends CardImpl {
super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{R}{G}");
// Target creature you control and up to one other target legendary creature you control each deal damage equal to their power to target creature you don't control.
this.getSpellAbility().addEffect(new FriendlyRivalryEffect());
this.getSpellAbility().addEffect(new TargetsDamageTargetsEffect(true));
this.getSpellAbility().addTarget(new TargetControlledCreaturePermanent().setTargetTag(1).withChooseHint("to deal damage"));
this.getSpellAbility().addTarget(new TargetPermanent(0, 1, filter2).setTargetTag(2).withChooseHint("to deal damage"));
this.getSpellAbility().addTarget(new TargetPermanent(StaticFilters.FILTER_CREATURE_YOU_DONT_CONTROL).setTargetTag(3).withChooseHint("to take damage"));
@ -52,52 +45,3 @@ public final class FriendlyRivalry extends CardImpl {
return new FriendlyRivalry(this);
}
}
class FriendlyRivalryEffect extends OneShotEffect {
FriendlyRivalryEffect() {
super(Outcome.Benefit);
staticText = "Target creature you control and up to one other target legendary " +
"creature you control each deal damage equal to their power to target creature you don't control.";
}
private FriendlyRivalryEffect(final FriendlyRivalryEffect effect) {
super(effect);
}
@Override
public FriendlyRivalryEffect copy() {
return new FriendlyRivalryEffect(this);
}
@Override
public boolean apply(Game game, Ability source) {
int size = source.getTargets().size();
if (size < 3) {
throw new IllegalArgumentException("Wrong code usage. Lost targets list, must has 3, but found: " + source.getTargets());
}
List<Permanent> toDealDamage = new ArrayList<>();
source.getTargets().getTargetsByTag(1).stream()
.map(game::getPermanent)
.filter(Objects::nonNull)
.forEach(toDealDamage::add);
source.getTargets().getTargetsByTag(2).stream()
.map(game::getPermanent)
.filter(Objects::nonNull)
.forEach(toDealDamage::add);
Permanent toTakeDamage = source.getTargets().getTargetsByTag(3).stream()
.map(game::getPermanent)
.filter(Objects::nonNull)
.findFirst().orElse(null);
if (toDealDamage.isEmpty() || toTakeDamage == null) {
return false;
}
toDealDamage.forEach(permanent -> {
toTakeDamage.damage(permanent.getPower().getValue(), permanent.getId(), source, game, false, true);
});
return true;
}
}

View file

@ -1,27 +1,13 @@
package mage.cards.f;
import mage.MageObject;
import mage.abilities.Ability;
import mage.abilities.condition.common.FerociousCondition;
import mage.abilities.effects.AsThoughEffect;
import mage.abilities.effects.AsThoughEffectImpl;
import mage.abilities.effects.ContinuousEffect;
import mage.abilities.effects.OneShotEffect;
import mage.abilities.effects.common.ExileTopCardPlayUntilExileAnotherEffect;
import mage.abilities.hint.common.FerociousHint;
import mage.abilities.triggers.BeginningOfEndStepTriggeredAbility;
import mage.cards.Card;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.AsThoughEffectType;
import mage.constants.CardType;
import mage.constants.Duration;
import mage.constants.Outcome;
import mage.game.Game;
import mage.players.Player;
import mage.target.targetpointer.FixedTarget;
import mage.util.CardUtil;
import java.util.List;
import java.util.UUID;
/**
@ -34,7 +20,7 @@ public final class FuriousRise extends CardImpl {
// At the beginning of your end step, if you control a creature with power 4 or greater, exile the top card of your library.
// You may play that card until you exile another card with Furious Rise.
this.addAbility(new BeginningOfEndStepTriggeredAbility(new FuriousRiseEffect())
this.addAbility(new BeginningOfEndStepTriggeredAbility(new ExileTopCardPlayUntilExileAnotherEffect())
.withInterveningIf(FerociousCondition.instance).addHint(FerociousHint.instance));
}
@ -47,88 +33,3 @@ public final class FuriousRise extends CardImpl {
return new FuriousRise(this);
}
}
class FuriousRiseEffect extends OneShotEffect {
FuriousRiseEffect() {
super(Outcome.Benefit);
this.staticText = "exile the top card of your library. You may play that card until you exile another card with {this}";
}
private FuriousRiseEffect(final FuriousRiseEffect effect) {
super(effect);
}
@Override
public FuriousRiseEffect copy() {
return new FuriousRiseEffect(this);
}
@Override
public boolean apply(Game game, Ability source) {
Player controller = game.getPlayer(source.getControllerId());
MageObject mageObject = source.getSourceObject(game);
if (controller != null && mageObject != null) {
Card cardToExile = controller.getLibrary().getFromTop(game);
UUID exileId = CardUtil.getCardExileZoneId(game, source);
controller.moveCardsToExile(cardToExile, source, game, true, exileId, mageObject.getIdName() + " (" + source.getStackMomentSourceZCC() + ")");
Card cardToPlay = game.getCard(cardToExile.getId());
endPreviousEffect(game, source); // workaround for Furious Rise
ContinuousEffect effect = new FuriousRisePlayEffect();
effect.setTargetPointer(new FixedTarget(cardToPlay, game));
game.addEffect(effect, source);
return true;
}
return false;
}
private static boolean endPreviousEffect(Game game, Ability source) {
for (AsThoughEffect effect : game.getContinuousEffects().getApplicableAsThoughEffects(AsThoughEffectType.PLAY_FROM_NOT_OWN_HAND_ZONE, game)) {
if (effect instanceof FuriousRisePlayEffect) {
for (Ability ability : game.getContinuousEffects().getAsThoughEffectsAbility(effect)) {
if (ability.getSourceId().equals(source.getSourceId())
&& source.getStackMomentSourceZCC() == ability.getStackMomentSourceZCC()) {
effect.discard();
return true;
}
}
}
}
return false;
}
}
class FuriousRisePlayEffect extends AsThoughEffectImpl {
FuriousRisePlayEffect() {
super(AsThoughEffectType.PLAY_FROM_NOT_OWN_HAND_ZONE, Duration.Custom, Outcome.Benefit);
}
private FuriousRisePlayEffect(final FuriousRisePlayEffect effect) {
super(effect);
}
@Override
public boolean apply(Game game, Ability source) {
return true;
}
@Override
public FuriousRisePlayEffect copy() {
return new FuriousRisePlayEffect(this);
}
@Override
public boolean applies(UUID objectId, Ability source, UUID affectedControllerId, Game game) {
List<UUID> targets = getTargetPointer().getTargets(game, source);
if (targets.isEmpty()) {
this.discard();
return false;
}
return targets.contains(objectId)
&& affectedControllerId.equals(source.getControllerId());
}
}

View file

@ -9,10 +9,7 @@ import mage.abilities.effects.common.CreateTokenEffect;
import mage.abilities.keyword.HexproofAbility;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
import mage.constants.SubType;
import mage.constants.Outcome;
import mage.constants.SuperType;
import mage.constants.*;
import mage.game.Game;
import mage.game.permanent.token.AngelToken;
import mage.players.Player;
@ -65,7 +62,7 @@ class GeistOfSaintTraftEffect extends OneShotEffect {
Player controller = game.getPlayer(source.getControllerId());
if (controller != null && effect.apply(game, source)) {
effect.exileTokensCreatedAtEndOfCombat(game, source);
effect.removeTokensCreatedAt(game, source, true, PhaseStep.END_COMBAT, TargetController.ANY);
return true;
}
return false;

View file

@ -4,19 +4,15 @@ import mage.MageInt;
import mage.abilities.Ability;
import mage.abilities.Mode;
import mage.abilities.common.DealsCombatDamageToAPlayerTriggeredAbility;
import mage.abilities.effects.OneShotEffect;
import mage.abilities.effects.common.DestroyTargetEffect;
import mage.abilities.effects.common.DrawCardSourceControllerEffect;
import mage.abilities.effects.common.LoseLifeSourceControllerEffect;
import mage.abilities.effects.common.continuous.BoostSourceEffect;
import mage.abilities.effects.common.RemoveUpToAmountCountersEffect;
import mage.abilities.keyword.DeathtouchAbility;
import mage.abilities.keyword.FirstStrikeAbility;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.*;
import mage.game.Game;
import mage.game.permanent.Permanent;
import mage.players.Player;
import mage.target.TargetPermanent;
import mage.target.common.TargetEnchantmentPermanent;
@ -54,7 +50,7 @@ public final class GlissaSunslayer extends CardImpl {
ability.addMode(mode);
// Remove up to three counters from target permanent.
mode = new Mode(new GlissaSunslayerEffect());
mode = new Mode(new RemoveUpToAmountCountersEffect(3));
mode.addTarget(new TargetPermanent());
ability.addMode(mode);
@ -70,54 +66,3 @@ public final class GlissaSunslayer extends CardImpl {
return new GlissaSunslayer(this);
}
}
class GlissaSunslayerEffect extends OneShotEffect {
GlissaSunslayerEffect() {
super(Outcome.AIDontUseIt);
staticText = "Remove up to three counters from target permanent";
}
private GlissaSunslayerEffect(final GlissaSunslayerEffect effect) {
super(effect);
}
@Override
public GlissaSunslayerEffect copy() {
return new GlissaSunslayerEffect(this);
}
@Override
public boolean apply(Game game, Ability source) {
Player controller = game.getPlayer(source.getControllerId());
if (controller == null) {
return false;
}
Permanent permanent = game.getPermanent(source.getFirstTarget());
if (permanent != null) {
int toRemove = 3;
int removed = 0;
String[] counterNames = permanent.getCounters(game).keySet().toArray(new String[0]);
for (String counterName : counterNames) {
if (controller.chooseUse(Outcome.Neutral, "Remove " + counterName + " counters?", source, game)) {
if (permanent.getCounters(game).get(counterName).getCount() == 1 || (toRemove - removed == 1)) {
permanent.removeCounters(counterName, 1, source, game);
removed++;
} else {
int amount = controller.getAmount(1, Math.min(permanent.getCounters(game).get(counterName).getCount(), toRemove - removed), "How many?", source, game);
if (amount > 0) {
removed += amount;
permanent.removeCounters(counterName, amount, source, game);
}
}
}
if (removed >= toRemove) {
break;
}
}
game.addEffect(new BoostSourceEffect(removed, 0, Duration.EndOfTurn), source);
return true;
}
return true;
}
}

View file

@ -81,7 +81,7 @@ enum GolbezCrystalCollectorValue implements DynamicValue {
public int calculate(Game game, Ability sourceAbility, Effect effect) {
return Optional
.ofNullable(effect.getTargetPointer().getFirst(game, sourceAbility))
.map(game::getPermanent)
.map(game::getCard)
.map(MageObject::getPower)
.map(MageInt::getValue)
.orElse(0);

View file

@ -1,36 +1,44 @@
package mage.cards.g;
import mage.abilities.Ability;
import mage.abilities.common.SimpleStaticAbility;
import mage.abilities.costs.mana.GenericManaCost;
import mage.abilities.dynamicvalue.DynamicValue;
import mage.abilities.dynamicvalue.common.PermanentsOnBattlefieldCount;
import mage.abilities.dynamicvalue.common.StaticValue;
import mage.abilities.effects.Effect;
import mage.abilities.effects.common.continuous.BoostEquippedEffect;
import mage.abilities.keyword.EquipAbility;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.*;
import mage.game.Game;
import mage.game.permanent.Permanent;
import mage.constants.CardType;
import mage.constants.Outcome;
import mage.constants.SubType;
import mage.filter.FilterPermanent;
import mage.filter.predicate.permanent.AttachedToAttachedPredicate;
import java.util.List;
import java.util.UUID;
/**
*
* @author North
*/
public final class GolemSkinGauntlets extends CardImpl {
private static final FilterPermanent filter = new FilterPermanent("Equipment attached to it");
static {
filter.add(SubType.EQUIPMENT.getPredicate());
filter.add(AttachedToAttachedPredicate.instance);
}
private static final DynamicValue xValue = new PermanentsOnBattlefieldCount(filter);
public GolemSkinGauntlets(UUID ownerId, CardSetInfo setInfo) {
super(ownerId,setInfo,new CardType[]{CardType.ARTIFACT},"{1}");
super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{1}");
this.subtype.add(SubType.EQUIPMENT);
// Equipped creature gets +1/+0 for each Equipment attached to it.
this.addAbility(new SimpleStaticAbility(new BoostEquippedEffect(xValue, StaticValue.get(0))));
// Equip 2 (2: Attach to target creature you control. Equip only as a sorcery. This card enters the battlefield unattached and stays on the battlefield if the creature leaves.)
this.addAbility(new SimpleStaticAbility(new BoostEquippedEffect(new GolemSkinGauntletsAttachedCount(), StaticValue.get(0), Duration.WhileOnBattlefield)));
this.addAbility(new EquipAbility(Outcome.BoostCreature, new GenericManaCost(2)));
}
@ -43,49 +51,3 @@ public final class GolemSkinGauntlets extends CardImpl {
return new GolemSkinGauntlets(this);
}
}
// we can't use GolemSkinGauntletsAttachedCount
// compare to Goblin Gaveleer
class GolemSkinGauntletsAttachedCount implements DynamicValue {
GolemSkinGauntletsAttachedCount() {
}
private GolemSkinGauntletsAttachedCount(final GolemSkinGauntletsAttachedCount dynamicValue) {
}
@Override
public int calculate(Game game, Ability sourceAbility, Effect effect) {
int count = 0;
Permanent equipment = game.getPermanent(sourceAbility.getSourceId());
if (equipment != null) {
Permanent permanent = game.getPermanent(equipment.getAttachedTo());
if (permanent != null) {
List<UUID> attachments = permanent.getAttachments();
for (UUID attachmentId : attachments) {
Permanent attached = game.getPermanent(attachmentId);
if (attached != null && attached.hasSubtype(SubType.EQUIPMENT, game)) {
count++;
}
}
}
}
return count;
}
@Override
public GolemSkinGauntletsAttachedCount copy() {
return new GolemSkinGauntletsAttachedCount(this);
}
@Override
public String toString() {
return "1";
}
@Override
public String getMessage() {
return "Equipment attached to it";
}
}

View file

@ -1,36 +1,38 @@
package mage.cards.g;
import mage.abilities.Ability;
import mage.abilities.effects.OneShotEffect;
import mage.abilities.effects.common.TargetsDamageTargetsEffect;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
import mage.constants.Outcome;
import mage.filter.FilterPermanent;
import mage.filter.StaticFilters;
import mage.filter.common.FilterControlledCreaturePermanent;
import mage.filter.predicate.other.AnotherTargetPredicate;
import mage.filter.predicate.permanent.EnchantedPredicate;
import mage.game.Game;
import mage.game.permanent.Permanent;
import mage.target.TargetPermanent;
import java.util.List;
import java.util.Objects;
import java.util.UUID;
import java.util.stream.Collectors;
/**
* @author TheElk801
*/
public final class GracefulTakedown extends CardImpl {
private static final FilterPermanent filter = new FilterControlledCreaturePermanent("enchanted creatures you control");
private static final FilterControlledCreaturePermanent otherCreatureFilter = new FilterControlledCreaturePermanent("other target creature you control");
static {
filter.add(EnchantedPredicate.instance);
otherCreatureFilter.add(new AnotherTargetPredicate(2));
}
public GracefulTakedown(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{1}{G}");
// Any number of target enchanted creatures you control and up to one other target creature you control each deal damage equal to their power to target creature you don't control.
this.getSpellAbility().addEffect(new GracefulTakedownEffect());
this.getSpellAbility().addTarget(new GracefulTakedownTarget());
this.getSpellAbility().addTarget(new TargetPermanent(StaticFilters.FILTER_CREATURE_YOU_DONT_CONTROL));
this.getSpellAbility().addEffect(new TargetsDamageTargetsEffect(true));
this.getSpellAbility().addTarget(new TargetPermanent(0, Integer.MAX_VALUE, filter).setTargetTag(1).withChooseHint("enchanted"));
this.getSpellAbility().addTarget(new TargetPermanent(0, 1, otherCreatureFilter).setTargetTag(2));
this.getSpellAbility().addTarget(new TargetPermanent(StaticFilters.FILTER_CREATURE_YOU_DONT_CONTROL).setTargetTag(3));
}
private GracefulTakedown(final GracefulTakedown card) {
@ -42,78 +44,3 @@ public final class GracefulTakedown extends CardImpl {
return new GracefulTakedown(this);
}
}
class GracefulTakedownTarget extends TargetPermanent {
private static final FilterPermanent filter = new FilterControlledCreaturePermanent("enchanted creatures you control and up to one other creature you control");
GracefulTakedownTarget() {
super(0, Integer.MAX_VALUE, filter);
}
private GracefulTakedownTarget(final GracefulTakedownTarget target) {
super(target);
}
@Override
public GracefulTakedownTarget copy() {
return new GracefulTakedownTarget(this);
}
@Override
public boolean canTarget(UUID playerId, UUID id, Ability source, Game game) {
if (!super.canTarget(playerId, id, source, game)) {
return false;
}
Permanent permanent = game.getPermanent(id);
return permanent != null
&& (EnchantedPredicate.instance.apply(permanent, game)
|| this
.getTargets()
.stream()
.map(game::getPermanent)
.filter(Objects::nonNull)
.allMatch(p -> p.getId().equals(id) || EnchantedPredicate.instance.apply(p, game)));
}
}
class GracefulTakedownEffect extends OneShotEffect {
GracefulTakedownEffect() {
super(Outcome.Benefit);
staticText = "any number of target enchanted creatures you control and up to one other target creature " +
"you control each deal damage equal to their power to target creature you don't control";
}
private GracefulTakedownEffect(final GracefulTakedownEffect effect) {
super(effect);
}
@Override
public GracefulTakedownEffect copy() {
return new GracefulTakedownEffect(this);
}
@Override
public boolean apply(Game game, Ability source) {
List<Permanent> permanents = source
.getTargets()
.get(0)
.getTargets()
.stream()
.map(game::getPermanent)
.filter(Objects::nonNull)
.collect(Collectors.toList());
if (permanents.isEmpty()) {
return false;
}
Permanent creature = game.getPermanent(source.getTargets().get(1).getFirstTarget());
if (creature == null) {
return false;
}
for (Permanent permanent : permanents) {
creature.damage(permanent.getPower().getValue(), permanent.getId(), source, game);
}
return true;
}
}

View file

@ -48,6 +48,7 @@ public final class GrizzledAngler extends CardImpl {
new TransformSourceEffect(), condition,
"Then if there is a colorless creature card in your graveyard, transform {this}"
));
this.addAbility(ability);
}
private GrizzledAngler(final GrizzledAngler card) {

View file

@ -53,7 +53,7 @@ public final class GwenStacy extends ModalDoubleFacedCard {
// Remove two counters from Ghost-Spider: Exile the top card of your library. You may play that card this turn.
this.getRightHalfCard().addAbility(new SimpleActivatedAbility(
new ExileTopXMayPlayUntilEffect(1, Duration.EndOfTurn),
new RemoveCountersSourceCost(CounterType.P1P1.createInstance(2))));
new RemoveCountersSourceCost(2)));
}
private GwenStacy(final GwenStacy card) {

View file

@ -27,7 +27,7 @@ import java.util.UUID;
*/
public final class HakodaSelflessCommander extends CardImpl {
private static final FilterCard filter = new FilterCard(SubType.ALLY, "Ally spells");
private static final FilterCard filter = new FilterCard(SubType.ALLY, "cast Ally spells");
public HakodaSelflessCommander(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{W}");

View file

@ -1,21 +1,14 @@
package mage.cards.h;
import mage.abilities.Ability;
import mage.abilities.Mode;
import mage.abilities.effects.OneShotEffect;
import mage.abilities.effects.common.DestroyTargetEffect;
import mage.abilities.effects.common.continuous.BoostSourceEffect;
import mage.abilities.effects.common.RemoveUpToAmountCountersEffect;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
import mage.constants.Duration;
import mage.constants.Outcome;
import mage.filter.common.FilterCreaturePermanent;
import mage.filter.predicate.Predicates;
import mage.filter.predicate.permanent.CounterAnyPredicate;
import mage.game.Game;
import mage.game.permanent.Permanent;
import mage.players.Player;
import mage.target.TargetPermanent;
import mage.target.common.TargetCreaturePermanent;
@ -42,7 +35,7 @@ public final class HeartlessAct extends CardImpl {
this.getSpellAbility().addTarget(new TargetPermanent(filterWithoutCounters));
// Remove up to three counters from target creature.
Mode mode = new Mode(new HeartlessActEffect());
Mode mode = new Mode(new RemoveUpToAmountCountersEffect(3));
mode.addTarget(new TargetCreaturePermanent());
this.getSpellAbility().addMode(mode);
}
@ -56,54 +49,3 @@ public final class HeartlessAct extends CardImpl {
return new HeartlessAct(this);
}
}
class HeartlessActEffect extends OneShotEffect {
HeartlessActEffect() {
super(Outcome.AIDontUseIt);
staticText = "Remove up to three counters from target creature";
}
private HeartlessActEffect(final HeartlessActEffect effect) {
super(effect);
}
@Override
public HeartlessActEffect copy() {
return new HeartlessActEffect(this);
}
@Override
public boolean apply(Game game, Ability source) {
Player controller = game.getPlayer(source.getControllerId());
if (controller == null) {
return false;
}
Permanent permanent = game.getPermanent(source.getFirstTarget());
if (permanent != null) {
int toRemove = 3;
int removed = 0;
String[] counterNames = permanent.getCounters(game).keySet().toArray(new String[0]);
for (String counterName : counterNames) {
if (controller.chooseUse(Outcome.Neutral, "Remove " + counterName + " counters?", source, game)) {
if (permanent.getCounters(game).get(counterName).getCount() == 1 || (toRemove - removed == 1)) {
permanent.removeCounters(counterName, 1, source, game);
removed++;
} else {
int amount = controller.getAmount(1, Math.min(permanent.getCounters(game).get(counterName).getCount(), toRemove - removed), "How many?", source, game);
if (amount > 0) {
removed += amount;
permanent.removeCounters(counterName, amount, source, game);
}
}
}
if (removed >= toRemove) {
break;
}
}
game.addEffect(new BoostSourceEffect(removed, 0, Duration.EndOfTurn), source);
return true;
}
return true;
}
}

View file

@ -2,12 +2,12 @@ package mage.cards.h;
import mage.MageObject;
import mage.abilities.Ability;
import mage.abilities.triggers.BeginningOfUpkeepTriggeredAbility;
import mage.abilities.common.SimpleActivatedAbility;
import mage.abilities.costs.mana.ManaCostsImpl;
import mage.abilities.effects.OneShotEffect;
import mage.abilities.effects.keyword.ScryEffect;
import mage.abilities.keyword.HexproofAbility;
import mage.abilities.triggers.BeginningOfUpkeepTriggeredAbility;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.cards.Cards;
@ -15,7 +15,6 @@ import mage.cards.CardsImpl;
import mage.constants.CardType;
import mage.constants.Outcome;
import mage.constants.TargetController;
import mage.constants.Zone;
import mage.filter.FilterCard;
import mage.filter.FilterPermanent;
import mage.filter.predicate.mageobject.NamePredicate;
@ -93,9 +92,7 @@ class HedronAlignmentEffect extends OneShotEffect {
if (controller.getGraveyard().getCards(filterCard, controller.getId(), source, game).isEmpty()) {
return true;
}
Cards cardsToCheck = new CardsImpl();
cardsToCheck.addAllCards(game.getExile().getAllCards(game));
if (cardsToCheck.count(filterCard, controller.getId(), source, game) == 0) {
if (game.getExile().getCardsOwned(filterCard, controller.getId(), source, game).isEmpty()) {
return true;
}
controller.won(game);

View file

@ -87,7 +87,7 @@ class HenzieToolboxTorreGainBlitzEffect extends ContinuousEffectImpl {
controller.getLibrary().getCards(game).stream()
.filter(c -> filter.match(c, game))
.forEach(cardsToGainBlitz::add);
game.getExile().getAllCardsByRange(game, controller.getId()).stream()
game.getExile().getCardsInRange(game, controller.getId()).stream()
.filter(c -> filter.match(c, game))
.forEach(cardsToGainBlitz::add);
game.getCommanderCardsFromCommandZone(controller, CommanderCardType.ANY)

View file

@ -87,7 +87,7 @@ class HerigastEruptingNullkiteEffect extends ContinuousEffectImpl {
controller.getLibrary().getCards(game).stream()
.filter(c -> StaticFilters.FILTER_CARD_CREATURE.match(c, game))
.forEach(cardsToGainEmerge::add);
game.getExile().getAllCardsByRange(game, controller.getId()).stream()
game.getExile().getCardsInRange(game, controller.getId()).stream()
.filter(c -> StaticFilters.FILTER_CARD_CREATURE.match(c, game))
.forEach(cardsToGainEmerge::add);
game.getCommanderCardsFromCommandZone(controller, CommanderCardType.ANY)

View file

@ -59,7 +59,7 @@ enum HowlingGalefangCondition implements Condition {
public boolean apply(Game game, Ability source) {
return game
.getExile()
.getAllCards(game, source.getControllerId())
.getCardsOwned(game, source.getControllerId())
.stream()
.anyMatch(AdventureCard.class::isInstance);
}

View file

@ -77,13 +77,8 @@ enum HuskbursterSwarmValue implements DynamicValue {
}
return game
.getExile()
.getAllCards(game)
.stream()
.filter(card -> card.isCreature(game))
.map(Ownerable::getOwnerId)
.filter(sourceAbility::isControlledBy)
.mapToInt(x -> 1)
.sum()
.getCardsOwned(StaticFilters.FILTER_CARD_CREATURE, player.getId(), sourceAbility, game)
.size()
+ player
.getGraveyard()
.count(StaticFilters.FILTER_CARD_CREATURE, game);

View file

@ -63,7 +63,7 @@ enum InfernoTrapCondition implements Condition {
@Override
public String toString() {
return "If you've been dealt damage by two or more creatures this turn";
return "you've been dealt damage by two or more creatures this turn";
}
}

View file

@ -12,11 +12,7 @@ import mage.abilities.effects.common.continuous.GainAbilityAttachedEffect;
import mage.abilities.keyword.EnchantAbility;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.AttachmentType;
import mage.constants.CardType;
import mage.constants.SubType;
import mage.constants.Outcome;
import mage.constants.Zone;
import mage.constants.*;
import mage.game.Game;
import mage.game.permanent.token.AngelToken;
import mage.players.Player;
@ -72,7 +68,7 @@ class InvocationOfSaintTraftEffect extends OneShotEffect {
CreateTokenEffect effect = new CreateTokenEffect(new AngelToken(), 1, true, true);
Player controller = game.getPlayer(source.getControllerId());
if (controller != null && (effect.apply(game, source))) {
effect.exileTokensCreatedAtEndOfCombat(game, source);
effect.removeTokensCreatedAt(game, source, true, PhaseStep.END_COMBAT, TargetController.ANY);
return true;
}
return false;

View file

@ -7,7 +7,7 @@ import mage.abilities.Ability;
import mage.abilities.common.SimpleActivatedAbility;
import mage.abilities.costs.mana.ManaCostsImpl;
import mage.abilities.effects.common.GainsChoiceOfAbilitiesEffect;
import mage.abilities.effects.common.continuous.BoostTargetEffect;
import mage.abilities.effects.common.continuous.BoostSourceEffect;
import mage.abilities.keyword.DoubleStrikeAbility;
import mage.abilities.keyword.ProtectionAbility;
import mage.abilities.keyword.ShadowAbility;
@ -15,6 +15,7 @@ import mage.abilities.keyword.VigilanceAbility;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
import mage.constants.Duration;
import mage.constants.SubType;
import java.util.UUID;
@ -33,7 +34,7 @@ public final class JodahsAvenger extends CardImpl {
this.toughness = new MageInt(4);
// {0}: Until end of turn, Jodah's Avenger gets -1/-1 and gains your choice of double strike, protection from red, vigilance, or shadow.
Ability ability = new SimpleActivatedAbility(new BoostTargetEffect(-1, -1)
Ability ability = new SimpleActivatedAbility(new BoostSourceEffect(-1, -1, Duration.EndOfTurn)
.setText("Until end of turn, {this} gets -1/-1"), new ManaCostsImpl<>("{0}"));
ability.addEffect(new GainsChoiceOfAbilitiesEffect(GainsChoiceOfAbilitiesEffect.TargetType.Source, "", false,
DoubleStrikeAbility.getInstance(), ProtectionAbility.from(ObjectColor.RED), VigilanceAbility.getInstance(), ShadowAbility.getInstance())

View file

@ -11,10 +11,7 @@ import mage.abilities.keyword.FirstStrikeAbility;
import mage.abilities.keyword.MenaceAbility;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
import mage.constants.SubType;
import mage.constants.Outcome;
import mage.constants.SuperType;
import mage.constants.*;
import mage.game.Game;
import mage.game.permanent.token.RagavanToken;
import mage.players.Player;
@ -70,7 +67,7 @@ class KariZevSkyshipRaiderEffect extends OneShotEffect {
CreateTokenEffect effect = new CreateTokenEffect(new RagavanToken(), 1, true, true);
Player controller = game.getPlayer(source.getControllerId());
if (controller != null && effect.apply(game, source)) {
effect.exileTokensCreatedAtEndOfCombat(game, source);
effect.removeTokensCreatedAt(game, source, true, PhaseStep.END_COMBAT, TargetController.ANY);
return true;
}
return false;

View file

@ -18,10 +18,8 @@ import mage.target.TargetCard;
import mage.target.common.TargetCardInExile;
import mage.target.common.TargetOpponent;
import java.util.Objects;
import java.util.Set;
import java.util.UUID;
import java.util.stream.Collectors;
/**
* @author spjspj
@ -150,13 +148,7 @@ class KarnMinus1Effect extends OneShotEffect {
if (controller == null) {
return false;
}
Cards cards = new CardsImpl(game
.getExile()
.getCards(filter, game)
.stream()
.filter(Objects::nonNull)
.filter(card -> card.isOwnedBy(source.getControllerId()))
.collect(Collectors.toList()));
Cards cards = new CardsImpl(game.getExile().getCardsOwned(filter, controller.getId(), source, game));
Card card;
switch (cards.size()) {
case 0:
@ -173,6 +165,6 @@ class KarnMinus1Effect extends OneShotEffect {
if (card == null) {
return false;
}
return card != null && controller.moveCards(card, Zone.HAND, source, game);
return controller.moveCards(card, Zone.HAND, source, game);
}
}

View file

@ -44,7 +44,7 @@ public final class KataraWaterbendingMaster extends CardImpl {
// Whenever Katara attacks, you may draw a card for each experience counter you have. If you do, discard a card.
Ability ability = new AttacksTriggeredAbility(new DrawCardSourceControllerEffect(xValue)
.setText("draw a card for each experience counter you have"));
.setText("draw a card for each experience counter you have"), true);
ability.addEffect(new DiscardControllerEffect(1).concatBy("If you do,"));
this.addAbility(ability);
}

View file

@ -131,12 +131,7 @@ class KayaOrzhovUsurperDamageEffect extends OneShotEffect {
if (controller == null || player == null) {
return false;
}
int count = 0;
for (Card card : game.getExile().getAllCards(game)) {
if (card != null && card.getOwnerId().equals(player.getId())) {
count += 1;
}
}
int count = game.getExile().getCardsOwned(game, player.getId()).size();
player.damage(count, source.getSourceId(), source, game);
controller.gainLife(count, game, source);
return true;

View file

@ -127,10 +127,8 @@ enum KianneDeanOfSubstanceValue implements DynamicValue {
public int calculate(Game game, Ability sourceAbility, Effect effect) {
return game
.getExile()
.getAllCards(game)
.getCardsOwned(game, sourceAbility.getControllerId())
.stream()
.filter(Objects::nonNull)
.filter(card -> card.isOwnedBy(sourceAbility.getControllerId()))
.filter(card -> card.getCounters(game).containsKey(CounterType.STUDY))
.map(MageObject::getManaValue)
.distinct()
@ -155,10 +153,8 @@ enum KianneDeanOfSubstanceHint implements Hint {
@Override
public String getText(Game game, Ability ability) {
List<String> values = game.getExile()
.getAllCards(game)
.getCardsOwned(game, ability.getControllerId())
.stream()
.filter(Objects::nonNull)
.filter(card -> card.isOwnedBy(ability.getControllerId()))
.filter(card -> card.getCounters(game).containsKey(CounterType.STUDY))
.mapToInt(MageObject::getManaValue)
.distinct()
@ -166,7 +162,7 @@ enum KianneDeanOfSubstanceHint implements Hint {
.mapToObj(String::valueOf)
.collect(Collectors.toList());
return "Mana values of cards exiled with study counters: " + values.size()
+ (values.size() > 0 ? " (" + String.join(", ", values) + ')' : "");
+ (values.isEmpty() ? "" : " (" + String.join(", ", values) + ')');
}
@Override

View file

@ -29,8 +29,8 @@ public final class KinjallisSunwing extends CardImpl {
// Creatures your opponents control enter the battlefield tapped.
this.addAbility(new SimpleStaticAbility(new PermanentsEnterBattlefieldTappedEffect(
StaticFilters.FILTER_OPPONENTS_PERMANENT_CREATURE
).setText("creatures your opponents control enter the battlefield tapped")));
StaticFilters.FILTER_OPPONENTS_PERMANENT_CREATURES
)));
}
private KinjallisSunwing(final KinjallisSunwing card) {

View file

@ -39,7 +39,7 @@ public final class KyrenLegate extends CardImpl {
this.addAbility(HasteAbility.getInstance());
// If an opponent controls a Plains and you control a Mountain, you may cast this spell without paying its mana cost.
Condition condition = new CompoundCondition("If an opponent controls a Plains and you control a Mountain",
Condition condition = new CompoundCondition("an opponent controls a Plains and you control a Mountain",
new OpponentControlsPermanentCondition(filterPlains),
new PermanentsOnTheBattlefieldCondition(filterMountain));
this.addAbility(new AlternativeCostSourceAbility(null, condition));

View file

@ -31,7 +31,7 @@ import mage.target.common.TargetControlledPermanent;
*/
public final class Lashknife extends CardImpl {
private static final FilterControlledPermanent plainsFilter = new FilterControlledPermanent("If you control a Plains");
private static final FilterControlledPermanent plainsFilter = new FilterControlledPermanent("you control a Plains");
private static final FilterControlledCreaturePermanent creatureFilter = new FilterControlledCreaturePermanent("an untapped creature you control");
static {

View file

@ -78,6 +78,6 @@ enum LavaballTrapCondition implements Condition {
@Override
public String toString() {
return "If an opponent had two or more lands enter the battlefield under their control this turn";
return "an opponent had two or more lands enter the battlefield under their control this turn";
}
}

View file

@ -53,6 +53,6 @@ enum LethargyTrapCondition implements Condition {
@Override
public String toString() {
return "If three or more creatures are attacking";
return "three or more creatures are attacking";
}
}

View file

@ -125,7 +125,7 @@ class LivioOathswornSentinelReturnEffect extends OneShotEffect {
}
Set<Card> cards = game
.getExile()
.getAllCards(game)
.getCardsInRange(game, player.getId())
.stream()
.filter(Objects::nonNull)
.filter(card -> card.getCounters(game).containsKey(CounterType.AEGIS))

View file

@ -135,8 +135,7 @@ class MairsilThePretenderGainAbilitiesEffect extends ContinuousEffectImpl {
if (perm == null) {
return false;
}
for (Card card : game.getExile().getAllCards(game)) {
if (filter.match(card, game) && Objects.equals(card.getOwnerId(), perm.getControllerId())) {
for (Card card : game.getExile().getCardsOwned(filter, perm.getControllerId(), source, game)) {
for (Ability ability : card.getAbilities(game)) {
if (ability.isActivatedAbility()) {
ActivatedAbility copyAbility = (ActivatedAbility) ability.copy();
@ -145,7 +144,6 @@ class MairsilThePretenderGainAbilitiesEffect extends ContinuousEffectImpl {
}
}
}
}
return true;
}

View file

@ -18,12 +18,12 @@ import mage.cards.Cards;
import mage.constants.CardType;
import mage.constants.Outcome;
import mage.constants.SubType;
import mage.constants.TargetController;
import mage.filter.FilterPermanent;
import mage.filter.StaticFilters;
import mage.filter.common.FilterControlledCreaturePermanent;
import mage.filter.predicate.mageobject.AnotherPredicate;
import mage.game.Game;
import mage.game.GameState;
import mage.game.permanent.token.Token;
import mage.target.TargetCard;
import mage.target.TargetPermanent;
@ -100,12 +100,7 @@ class MarduSiegebreakerEffect extends OneShotEffect {
@Override
public boolean apply(Game game, Ability source) {
Cards cards = Optional
.ofNullable(game)
.map(Game::getState)
.map(GameState::getExile)
.map(exile -> exile.getExileZone(CardUtil.getExileZoneId(game, source)))
.orElse(null);
Cards cards = game.getState().getExile().getExileZone(CardUtil.getExileZoneId(game, source));
if (cards == null) {
return false;
}
@ -138,7 +133,7 @@ class MarduSiegebreakerEffect extends OneShotEffect {
.forEach(addedTokens::add);
}
game.addDelayedTriggeredAbility(new AtTheBeginOfNextEndStepDelayedTriggeredAbility(
new SacrificeTargetEffect().setTargetPointer(new FixedTargets(addedTokens))
new SacrificeTargetEffect().setTargetPointer(new FixedTargets(addedTokens)), TargetController.YOU
), source);
return true;
}

View file

@ -96,7 +96,7 @@ class MaskwoodNexusEffect extends ContinuousEffectImpl {
.forEach(affectedCards::add);
// in Exile
game.getState().getExile().getAllCards(game, controller.getId()).stream()
game.getState().getExile().getCardsOwned(game, controller.getId()).stream()
.filter(card -> card.isOwnedBy(controller.getId()))
.forEach(affectedCards::add);

View file

@ -34,7 +34,7 @@ public final class Massacre extends CardImpl {
// If an opponent controls a Plains and you control a Swamp, you may cast this spell without paying its mana cost.
Condition condition = new CompoundCondition("If an opponent controls a Plains and you control a Swamp",
Condition condition = new CompoundCondition("an opponent controls a Plains and you control a Swamp",
new OpponentControlsPermanentCondition(filterPlains),
new PermanentsOnTheBattlefieldCondition(filterSwamp));
this.addAbility(new AlternativeCostSourceAbility(null, condition));

View file

@ -2,7 +2,6 @@ package mage.cards.m;
import mage.Mana;
import mage.abilities.Ability;
import mage.abilities.common.EntersBattlefieldTriggeredAbility;
import mage.abilities.common.SagaAbility;
import mage.abilities.effects.RestrictionEffect;
import mage.abilities.effects.common.DamagePlayersEffect;
@ -11,7 +10,6 @@ import mage.abilities.effects.mana.AddManaToManaPoolSourceControllerEffect;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.*;
import mage.filter.StaticFilters;
import mage.filter.common.FilterOpponentsCreaturePermanent;
import mage.game.Game;
import mage.game.permanent.Permanent;
@ -19,7 +17,6 @@ import mage.game.permanent.Permanent;
import java.util.UUID;
/**
*
* @author Jmlundeen
*/
public final class MaximumCarnage extends CardImpl {
@ -42,6 +39,8 @@ public final class MaximumCarnage extends CardImpl {
// III -- This Saga deals 5 damage to each opponent.
sagaAbility.addChapterEffect(this, SagaChapter.CHAPTER_III, new DamagePlayersEffect(5, TargetController.OPPONENT));
this.addAbility(sagaAbility);
}
private MaximumCarnage(final MaximumCarnage card) {
@ -53,6 +52,7 @@ public final class MaximumCarnage extends CardImpl {
return new MaximumCarnage(this);
}
}
class MaximumCarnageEffect extends RestrictionEffect {
MaximumCarnageEffect() {

View file

@ -1,9 +1,5 @@
package mage.cards.m;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
import mage.abilities.Ability;
import mage.abilities.condition.common.PermanentsOnTheBattlefieldCondition;
import mage.abilities.costs.AlternativeCostSourceAbility;
@ -24,7 +20,10 @@ import mage.game.Game;
import mage.players.Player;
import mage.target.Target;
import mage.target.common.TargetCardInHand;
import mage.target.common.TargetControlledCreaturePermanent;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
/**
*
@ -32,7 +31,7 @@ import mage.target.common.TargetControlledCreaturePermanent;
*/
public final class MindSwords extends CardImpl {
private static final FilterLandPermanent filterSwamp = new FilterLandPermanent("If you control a Swamp");
private static final FilterLandPermanent filterSwamp = new FilterLandPermanent("you control a Swamp");
static {
filterSwamp.add(SubType.SWAMP.getPredicate());

View file

@ -65,7 +65,7 @@ enum MindbreakTrapCondition implements Condition {
@Override
public String toString() {
return "If an opponent cast three or more spells this turn";
return "an opponent cast three or more spells this turn";
}
}

View file

@ -82,7 +82,7 @@ class MiragePhalanxEffect extends OneShotEffect {
// Create the token(s)
tokenCopyEffect.apply(game, source);
// Exile it at the end of combat
tokenCopyEffect.exileTokensCreatedAtEndOfCombat(game, source);
tokenCopyEffect.removeTokensCreatedAt(game, source, true, PhaseStep.END_COMBAT, TargetController.ANY);
return !tokenCopyEffect.getAddedPermanents().isEmpty();
}

View file

@ -51,7 +51,7 @@ class MishrasWarMachineEffect extends OneShotEffect {
MishrasWarMachineEffect() {
super(Outcome.Sacrifice);
staticText = "{this} deals 3 damage to you unless you discard a card. If {this} deals damage to you this way, tap it";
staticText = "{this} deals 3 damage to you unless you discard a card. If it deals damage to you this way, tap it";
}
private MishrasWarMachineEffect(final MishrasWarMachineEffect effect) {

View file

@ -46,7 +46,7 @@ class MisthollowGriffinPlayEffect extends AsThoughEffectImpl {
MisthollowGriffinPlayEffect() {
super(AsThoughEffectType.CAST_FROM_NOT_OWN_HAND_ZONE, Duration.EndOfGame, Outcome.Benefit);
staticText = "You may cast {this} from exile";
staticText = "You may cast this card from exile";
}
private MisthollowGriffinPlayEffect(final MisthollowGriffinPlayEffect effect) {

View file

@ -33,7 +33,7 @@ public final class MoggSalvage extends CardImpl {
super(ownerId,setInfo,new CardType[]{CardType.INSTANT},"{2}{R}");
// If an opponent controls an Island and you control a Mountain, you may cast this spell without paying its mana cost.
Condition condition = new CompoundCondition("If an opponent controls an Island and you control a Mountain",
Condition condition = new CompoundCondition("an opponent controls an Island and you control a Mountain",
new OpponentControlsPermanentCondition(filterIsland),
new PermanentsOnTheBattlefieldCondition(filterMountain));
this.addAbility(new AlternativeCostSourceAbility(null, condition));

View file

@ -11,10 +11,7 @@ import mage.abilities.keyword.LifelinkAbility;
import mage.abilities.keyword.VigilanceAbility;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
import mage.constants.PutCards;
import mage.constants.SubType;
import mage.constants.SuperType;
import mage.constants.*;
import java.util.UUID;
@ -44,7 +41,7 @@ public final class MorbiusTheLivingVampire extends CardImpl {
this.addAbility(LifelinkAbility.getInstance());
// {U}{B}, Exile this card from your graveyard: Look at the top three cards of your library. Put one of them into your hand and the rest on the bottom of your library in any order.
Ability ability = new SimpleActivatedAbility(new LookLibraryAndPickControllerEffect(3, 1, PutCards.HAND, PutCards.BOTTOM_ANY),
Ability ability = new SimpleActivatedAbility(Zone.GRAVEYARD, new LookLibraryAndPickControllerEffect(3, 1, PutCards.HAND, PutCards.BOTTOM_ANY),
new ManaCostsImpl<>("{U}{B}"));
ability.addCost(new ExileSourceFromGraveCost());
this.addAbility(ability);

View file

@ -50,7 +50,7 @@ class MoxDiamondReplacementEffect extends ReplacementEffectImpl {
MoxDiamondReplacementEffect() {
super(Duration.WhileOnBattlefield, Outcome.Exile);
staticText = "If {this} would enter the battlefield, you may discard a land card instead. If you do, put {this} onto the battlefield. If you don't, put it into its owner's graveyard";
staticText = "If {this} would enter, you may discard a land card instead. If you do, put {this} onto the battlefield. If you don't, put it into its owner's graveyard";
}
private MoxDiamondReplacementEffect(final MoxDiamondReplacementEffect effect) {

View file

@ -107,7 +107,7 @@ class EverythingIsColorlessEffect extends ContinuousEffectImpl {
}
// exile
affectedCards.addAll(game.getExile().getAllCardsByRange(game, controller.getId()));
affectedCards.addAll(game.getExile().getCardsInRange(game, controller.getId()));
for (UUID playerId : game.getState().getPlayersInRange(controller.getId(), game)) {

View file

@ -64,6 +64,6 @@ enum NeedlebiteTrapCondition implements Condition {
@Override
public String toString() {
return "If an opponent gained life this turn";
return "an opponent gained life this turn";
}
}

View file

@ -32,7 +32,7 @@ import java.util.UUID;
*/
public final class NemesisTrap extends CardImpl {
private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("If a white creature is attacking");
private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("a white creature is attacking");
static {
filter.add(new ColorPredicate(ObjectColor.WHITE));

View file

@ -8,7 +8,7 @@ import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
import mage.constants.SubType;
import mage.game.permanent.token.CitizenGreenWhiteToken;
import mage.game.permanent.token.HumanCitizenToken;
import java.util.UUID;
@ -28,7 +28,7 @@ public final class NewsHelicopter extends CardImpl {
this.addAbility(FlyingAbility.getInstance());
// When this creature enters, create a 1/1 green and white Human Citizen creature token.
this.addAbility(new EntersBattlefieldTriggeredAbility(new CreateTokenEffect(new CitizenGreenWhiteToken())));
this.addAbility(new EntersBattlefieldTriggeredAbility(new CreateTokenEffect(new HumanCitizenToken())));
}
private NewsHelicopter(final NewsHelicopter card) {

View file

@ -1,7 +1,5 @@
package mage.cards.o;
import java.util.UUID;
import mage.MageInt;
import mage.abilities.Ability;
import mage.abilities.effects.OneShotEffect;
@ -12,19 +10,20 @@ import mage.cards.CardSetInfo;
import mage.cards.Cards;
import mage.cards.CardsImpl;
import mage.constants.CardType;
import mage.constants.SubType;
import mage.constants.Outcome;
import mage.constants.SubType;
import mage.constants.Zone;
import mage.filter.FilterCard;
import mage.filter.common.FilterLandCard;
import mage.filter.predicate.Predicates;
import mage.filter.predicate.card.FaceDownPredicate;
import mage.filter.predicate.card.OwnerIdPredicate;
import mage.game.Game;
import mage.players.Player;
import mage.target.TargetCard;
import mage.target.common.TargetOpponent;
import java.util.UUID;
/**
*
* @author LevelX2
@ -56,6 +55,11 @@ public final class OblivionSower extends CardImpl {
class OblivionSowerEffect extends OneShotEffect {
private static final FilterCard filter = new FilterLandCard();
static {
filter.add(Predicates.not(FaceDownPredicate.instance));
}
OblivionSowerEffect() {
super(Outcome.PutLandInPlay);
this.staticText = ", then you may put any number of land cards that player owns from exile onto the battlefield under your control";
@ -78,14 +82,12 @@ class OblivionSowerEffect extends OneShotEffect {
*/
Player controller = game.getPlayer(source.getControllerId());
Player targetPlayer = game.getPlayer(getTargetPointer().getFirst(game, source));
if (controller != null && targetPlayer != null) {
FilterLandCard filter = new FilterLandCard();
filter.add(new OwnerIdPredicate(targetPlayer.getId()));
filter.add(Predicates.not(FaceDownPredicate.instance));
Cards exiledCards = new CardsImpl();
exiledCards.addAllCards(game.getExile().getAllCards(game));
Cards exiledLands = new CardsImpl();
exiledLands.addAllCards(exiledCards.getCards(filter, controller.getId(), source, game));
if (controller == null || targetPlayer == null) {
return false;
}
Cards exiledLands = new CardsImpl(game.getExile()
.getCardsOwned(filter, targetPlayer.getId(), source, game)
);
if (!exiledLands.isEmpty() && controller.chooseUse(outcome, "Put lands into play?", source, game)) {
FilterCard filterToPlay = new FilterCard("land"
+ (exiledLands.size() > 1 ? "s" : "") + " from exile owned by "
@ -97,6 +99,4 @@ class OblivionSowerEffect extends OneShotEffect {
}
return true;
}
return false;
}
}

View file

@ -24,7 +24,7 @@ import mage.target.common.TargetAnyTarget;
*/
public final class OrimsCure extends CardImpl {
private static final FilterPermanent filter = new FilterPermanent("If you control a Plains");
private static final FilterPermanent filter = new FilterPermanent("you control a Plains");
private static final FilterControlledCreaturePermanent filterCreature = new FilterControlledCreaturePermanent("untapped creature you control");
static {

View file

@ -82,7 +82,7 @@ class PaintersServantEffect extends ContinuousEffectImpl {
}
// exile
affectedCards.addAll(game.getExile().getAllCardsByRange(game, controller.getId()));
affectedCards.addAll(game.getExile().getCardsInRange(game, controller.getId()));
for (UUID playerId : game.getState().getPlayersInRange(controller.getId(), game)) {
Player player = game.getPlayer(playerId);

View file

@ -1,4 +1,3 @@
package mage.cards.p;
import mage.ObjectColor;
@ -29,9 +28,8 @@ public final class PatriciansScorn extends CardImpl {
public PatriciansScorn(UUID ownerId, CardSetInfo setInfo) {
super(ownerId,setInfo,new CardType[]{CardType.INSTANT},"{3}{W}");
// If you've cast another white spell this turn, you may cast this spell without paying its mana cost.
this.addAbility(new AlternativeCostSourceAbility(new CastWhiteSpellThisTurnCondition()), new PatriciansScornWatcher());
this.addAbility(new AlternativeCostSourceAbility(PatriciansScornCondition.instance), new PatriciansScornWatcher());
// Destroy all enchantments.
this.getSpellAbility().addEffect(new DestroyAllEffect(StaticFilters.FILTER_PERMANENT_ENCHANTMENTS));
}
@ -46,8 +44,8 @@ public final class PatriciansScorn extends CardImpl {
}
}
class CastWhiteSpellThisTurnCondition implements Condition {
enum PatriciansScornCondition implements Condition {
instance;
@Override
public boolean apply(Game game, Ability source) {
@ -60,7 +58,7 @@ class CastWhiteSpellThisTurnCondition implements Condition {
@Override
public String toString() {
return "If you've cast another white spell this turn";
return "you've cast another white spell this turn";
}
}

View file

@ -72,6 +72,6 @@ enum PermafrostTrapCondition implements Condition {
@Override
public String toString() {
return "If an opponent had a green creature enter the battlefield under their control this turn";
return "an opponent had a green creature enter the battlefield under their control this turn";
}
}

View file

@ -106,7 +106,7 @@ class AmazingSpiderManEffect extends ContinuousEffectImpl {
controller.getLibrary().getCards(game).stream()
.filter(c -> filter.match(c, game))
.forEach(cardsToGainAbility::add);
game.getExile().getAllCardsByRange(game, controller.getId()).stream()
game.getExile().getCardsInRange(game, controller.getId()).stream()
.filter(c -> filter.match(c, game))
.forEach(cardsToGainAbility::add);
game.getCommanderCardsFromCommandZone(controller, CommanderCardType.ANY).stream()

View file

@ -12,7 +12,8 @@ import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.*;
import mage.counters.CounterType;
import mage.filter.common.FilterCreaturePermanent;
import mage.filter.FilterPermanent;
import mage.filter.common.FilterArtifactCreaturePermanent;
import mage.game.Game;
import mage.game.permanent.token.NalaarAetherjetToken;
import mage.game.permanent.token.Token;
@ -25,7 +26,7 @@ import java.util.UUID;
*/
public final class PiaNalaarChiefMechanic extends CardImpl {
private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("artifact creatures you control");
private static final FilterPermanent filter = new FilterArtifactCreaturePermanent("artifact creatures you control");
static {
filter.add(TargetController.YOU.getControllerPredicate());

View file

@ -21,7 +21,7 @@ public final class PillarLaunch extends CardImpl {
// Target creature gets +2/+2 and gains reach until end of turn. Untap it.
this.getSpellAbility().addEffect(new BoostTargetEffect(2, 2).setText("target creature gets +2/+2"));
this.getSpellAbility().addEffect(new GainAbilityTargetEffect(ReachAbility.getInstance()).setText("and gain reach until end of turn"));
this.getSpellAbility().addEffect(new GainAbilityTargetEffect(ReachAbility.getInstance()).setText("and gains reach until end of turn"));
this.getSpellAbility().addEffect(new UntapTargetEffect("Untap it"));
this.getSpellAbility().addTarget(new TargetCreaturePermanent());
}

Some files were not shown because too many files have changed in this diff Show more