refactor: new predicate for mana value equal to counters on source

This commit is contained in:
xenohedron 2025-05-31 16:01:36 -04:00
parent 00084bfd7d
commit fc1d5ce4cf
9 changed files with 128 additions and 290 deletions

View file

@ -8,21 +8,16 @@ import mage.abilities.costs.common.TapSourceCost;
import mage.abilities.costs.mana.GenericManaCost;
import mage.abilities.costs.mana.ManaCostsImpl;
import mage.abilities.dynamicvalue.common.GetXValue;
import mage.abilities.effects.OneShotEffect;
import mage.abilities.effects.common.DestroyAllEffect;
import mage.abilities.effects.common.counter.AddCountersSourceEffect;
import mage.abilities.mana.ColorlessManaAbility;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
import mage.constants.ComparisonType;
import mage.constants.Outcome;
import mage.counters.CounterType;
import mage.filter.FilterPermanent;
import mage.filter.common.FilterNonlandPermanent;
import mage.filter.predicate.mageobject.ManaValuePredicate;
import mage.game.Game;
import mage.game.permanent.Permanent;
import mage.filter.predicate.mageobject.ManaValueEqualToCountersSourceCountPredicate;
import java.util.UUID;
@ -31,6 +26,13 @@ import java.util.UUID;
*/
public final class BlastZone extends CardImpl {
private static final FilterPermanent filter = new FilterNonlandPermanent(
"each nonland permanent with mana value equal to the number of charge counters on {this}"
);
static {
filter.add(new ManaValueEqualToCountersSourceCountPredicate(CounterType.CHARGE));
}
public BlastZone(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.LAND}, "");
@ -52,7 +54,7 @@ public final class BlastZone extends CardImpl {
this.addAbility(ability);
// {3}, {T}, Sacrifice Blast Zone: Destroy each nonland permanent with converted mana cost equal to the number of charge counters on Blast Zone.
ability = new SimpleActivatedAbility(new BlastZoneEffect(), new GenericManaCost(3));
ability = new SimpleActivatedAbility(new DestroyAllEffect(filter), new GenericManaCost(3));
ability.addCost(new TapSourceCost());
ability.addCost(new SacrificeSourceCost());
this.addAbility(ability);
@ -67,30 +69,3 @@ public final class BlastZone extends CardImpl {
return new BlastZone(this);
}
}
class BlastZoneEffect extends OneShotEffect {
BlastZoneEffect() {
super(Outcome.Benefit);
staticText = "Destroy each nonland permanent with mana value " +
"equal to the number of charge counters on {this}";
}
private BlastZoneEffect(final BlastZoneEffect effect) {
super(effect);
}
@Override
public BlastZoneEffect copy() {
return new BlastZoneEffect(this);
}
@Override
public boolean apply(Game game, Ability source) {
Permanent permanent = game.getPermanentOrLKIBattlefield(source.getSourceId());
int xValue = permanent.getCounters(game).getCount(CounterType.CHARGE);
FilterPermanent filter = new FilterNonlandPermanent();
filter.add(new ManaValuePredicate(ComparisonType.EQUAL_TO, xValue));
return new DestroyAllEffect(filter).apply(game, source);
}
}

View file

@ -1,23 +1,20 @@
package mage.cards.e;
import java.util.UUID;
import mage.MageObject;
import mage.abilities.Ability;
import mage.abilities.common.SimpleActivatedAbility;
import mage.abilities.costs.common.SacrificeSourceCost;
import mage.abilities.costs.mana.ManaCostsImpl;
import mage.abilities.effects.OneShotEffect;
import mage.abilities.effects.common.DestroyAllEffect;
import mage.abilities.keyword.SunburstAbility;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
import mage.constants.Outcome;
import mage.constants.Zone;
import mage.counters.CounterType;
import mage.filter.FilterPermanent;
import mage.filter.common.FilterNonlandPermanent;
import mage.game.Game;
import mage.game.permanent.Permanent;
import mage.filter.predicate.mageobject.ManaValueEqualToCountersSourceCountPredicate;
import java.util.UUID;
/**
*
@ -25,14 +22,21 @@ import mage.game.permanent.Permanent;
*/
public final class EngineeredExplosives extends CardImpl {
private static final FilterPermanent filter = new FilterNonlandPermanent(
"each nonland permanent with mana value equal to the number of charge counters on {this}"
);
static {
filter.add(new ManaValueEqualToCountersSourceCountPredicate(CounterType.CHARGE));
}
public EngineeredExplosives(UUID ownerId, CardSetInfo setInfo) {
super(ownerId,setInfo,new CardType[]{CardType.ARTIFACT},"{X}");
// Sunburst
this.addAbility(new SunburstAbility(this));
// {2}, Sacrifice Engineered Explosives: Destroy each nonland permanent with converted mana cost equal to the number of charge counters on Engineered Explosives.
Ability ability = new SimpleActivatedAbility(new EngineeredExplosivesEffect(), new ManaCostsImpl<>("{2}"));
Ability ability = new SimpleActivatedAbility(new DestroyAllEffect(filter), new ManaCostsImpl<>("{2}"));
ability.addCost(new SacrificeSourceCost());
this.addAbility(ability);
}
@ -46,40 +50,3 @@ public final class EngineeredExplosives extends CardImpl {
return new EngineeredExplosives(this);
}
}
class EngineeredExplosivesEffect extends OneShotEffect {
private static final FilterNonlandPermanent filter = new FilterNonlandPermanent();
public EngineeredExplosivesEffect() {
super(Outcome.DestroyPermanent);
staticText = "Destroy each nonland permanent with mana value equal to the number of charge counters on Engineered Explosives";
}
private EngineeredExplosivesEffect(final EngineeredExplosivesEffect effect) {
super(effect);
}
@Override
public EngineeredExplosivesEffect copy() {
return new EngineeredExplosivesEffect(this);
}
@Override
public boolean apply(Game game, Ability source) {
MageObject engineeredExplosives = game.getLastKnownInformation(source.getSourceId(), Zone.BATTLEFIELD);
if(engineeredExplosives instanceof Permanent){
int count = ((Permanent)engineeredExplosives).getCounters(game).getCount(CounterType.CHARGE);
for (Permanent permanent : game.getBattlefield().getActivePermanents(filter, source.getControllerId(), source, game)) {
if(permanent.getManaValue() == count){
permanent.destroy(source, game, false);
}
}
return true;
}
return false;
}
}

View file

@ -1,26 +1,21 @@
package mage.cards.n;
import java.util.UUID;
import mage.MageInt;
import mage.abilities.Ability;
import mage.abilities.triggers.BeginningOfEndStepTriggeredAbility;
import mage.abilities.triggers.BeginningOfUpkeepTriggeredAbility;
import mage.abilities.effects.OneShotEffect;
import mage.abilities.effects.common.DestroyAllEffect;
import mage.abilities.effects.common.counter.AddCountersSourceEffect;
import mage.abilities.keyword.DredgeAbility;
import mage.abilities.triggers.BeginningOfEndStepTriggeredAbility;
import mage.abilities.triggers.BeginningOfUpkeepTriggeredAbility;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
import mage.constants.SubType;
import mage.constants.ComparisonType;
import mage.constants.Outcome;
import mage.counters.CounterType;
import mage.filter.FilterPermanent;
import mage.filter.common.FilterCreaturePermanent;
import mage.filter.predicate.mageobject.ManaValuePredicate;
import mage.game.Game;
import mage.game.permanent.Permanent;
import mage.players.Player;
import mage.filter.predicate.mageobject.ManaValueEqualToCountersSourceCountPredicate;
import java.util.UUID;
/**
*
@ -28,6 +23,13 @@ import mage.players.Player;
*/
public final class Necroplasm extends CardImpl {
private static final FilterPermanent filter = new FilterCreaturePermanent(
"each creature with mana value equal to the number of +1/+1 counters on {this}"
);
static {
filter.add(new ManaValueEqualToCountersSourceCountPredicate(CounterType.P1P1));
}
public Necroplasm(UUID ownerId, CardSetInfo setInfo) {
super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{1}{B}{B}");
this.subtype.add(SubType.OOZE);
@ -39,7 +41,7 @@ public final class Necroplasm extends CardImpl {
this.addAbility(new BeginningOfUpkeepTriggeredAbility(new AddCountersSourceEffect(CounterType.P1P1.createInstance())));
// At the beginning of your end step, destroy each creature with converted mana cost equal to the number of +1/+1 counters on Necroplasm.
this.addAbility(new BeginningOfEndStepTriggeredAbility(new NecroplasmEffect()));
this.addAbility(new BeginningOfEndStepTriggeredAbility(new DestroyAllEffect(filter)));
// Dredge 2
this.addAbility(new DredgeAbility(2));
@ -54,38 +56,3 @@ public final class Necroplasm extends CardImpl {
return new Necroplasm(this);
}
}
class NecroplasmEffect extends OneShotEffect {
NecroplasmEffect() {
super(Outcome.DestroyPermanent);
this.staticText = "destroy each creature with mana value equal to the number of +1/+1 counters on {this}.";
}
private NecroplasmEffect(final NecroplasmEffect effect) {
super(effect);
}
@Override
public NecroplasmEffect copy() {
return new NecroplasmEffect(this);
}
@Override
public boolean apply(Game game, Ability source) {
Player player = game.getPlayer(source.getControllerId());
Permanent sourcePermanent = game.getPermanentOrLKIBattlefield(source.getSourceId());
if (player != null && sourcePermanent != null) {
int numCounters = sourcePermanent.getCounters(game).getCount(CounterType.P1P1);
FilterCreaturePermanent filter = new FilterCreaturePermanent();
filter.add(new ManaValuePredicate(ComparisonType.EQUAL_TO, numCounters));
for (Permanent permanent : game.getBattlefield().getActivePermanents(filter, source.getControllerId(), source, game)) {
if(permanent != null) {
permanent.destroy(source, game, false);
}
}
return true;
}
return false;
}
}

View file

@ -1,26 +1,21 @@
package mage.cards.p;
import java.util.UUID;
import mage.abilities.Ability;
import mage.abilities.triggers.BeginningOfUpkeepTriggeredAbility;
import mage.abilities.common.SimpleActivatedAbility;
import mage.abilities.costs.common.SacrificeSourceCost;
import mage.abilities.costs.common.TapSourceCost;
import mage.abilities.effects.OneShotEffect;
import mage.abilities.effects.common.DestroyAllEffect;
import mage.abilities.effects.common.counter.AddCountersSourceEffect;
import mage.abilities.triggers.BeginningOfUpkeepTriggeredAbility;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
import mage.constants.ComparisonType;
import mage.constants.Outcome;
import mage.constants.Zone;
import mage.counters.CounterType;
import mage.filter.FilterPermanent;
import mage.filter.predicate.Predicates;
import mage.filter.predicate.mageobject.ManaValuePredicate;
import mage.game.Game;
import mage.game.permanent.Permanent;
import mage.filter.predicate.mageobject.ManaValueEqualToCountersSourceCountPredicate;
import java.util.UUID;
/**
*
@ -28,6 +23,17 @@ import mage.game.permanent.Permanent;
*/
public final class PowderKeg extends CardImpl {
private static final FilterPermanent filter = new FilterPermanent(
"each artifact and creature with mana value equal to the number of fuse counters on {this}"
);
static {
filter.add(Predicates.or(
CardType.ARTIFACT.getPredicate(),
CardType.CREATURE.getPredicate()
));
filter.add(new ManaValueEqualToCountersSourceCountPredicate(CounterType.FUSE));
}
public PowderKeg(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{2}");
@ -35,7 +41,7 @@ public final class PowderKeg extends CardImpl {
this.addAbility(new BeginningOfUpkeepTriggeredAbility(new AddCountersSourceEffect(CounterType.FUSE.createInstance(), true), true));
// {T}, Sacrifice Powder Keg: Destroy each artifact and creature with converted mana cost equal to the number of fuse counters on Powder Keg.
Ability ability = new SimpleActivatedAbility(new PowderKegEffect(), new TapSourceCost());
Ability ability = new SimpleActivatedAbility(new DestroyAllEffect(filter), new TapSourceCost());
ability.addCost(new SacrificeSourceCost());
this.addAbility(ability);
}
@ -49,37 +55,3 @@ public final class PowderKeg extends CardImpl {
return new PowderKeg(this);
}
}
class PowderKegEffect extends OneShotEffect {
PowderKegEffect() {
super(Outcome.DestroyPermanent);
staticText = "Destroy each artifact and creature with mana value equal to the number of fuse counters on {this}";
}
private PowderKegEffect(final PowderKegEffect effect) {
super(effect);
}
@Override
public boolean apply(Game game, Ability source) {
Permanent sourcePermanent = game.getPermanentOrLKIBattlefield(source.getSourceId());
if (sourcePermanent == null) {
return false;
}
int count = sourcePermanent.getCounters(game).getCount(CounterType.FUSE);
FilterPermanent filter = new FilterPermanent();
filter.add(Predicates.or(CardType.ARTIFACT.getPredicate(), CardType.CREATURE.getPredicate()));
filter.add(new ManaValuePredicate(ComparisonType.EQUAL_TO, count));
for (Permanent perm : game.getBattlefield().getActivePermanents(filter, source.getControllerId(), source, game)) {
perm.destroy(source, game, false);
}
return true;
}
@Override
public PowderKegEffect copy() {
return new PowderKegEffect(this);
}
}

View file

@ -1,21 +1,20 @@
package mage.cards.r;
import java.util.UUID;
import mage.abilities.Ability;
import mage.abilities.common.SimpleActivatedAbility;
import mage.abilities.costs.common.SacrificeSourceCost;
import mage.abilities.costs.common.TapSourceCost;
import mage.abilities.effects.OneShotEffect;
import mage.abilities.effects.common.DestroyAllEffect;
import mage.abilities.effects.common.counter.AddCountersSourceEffect;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
import mage.constants.Outcome;
import mage.constants.Zone;
import mage.counters.CounterType;
import mage.filter.StaticFilters;
import mage.game.Game;
import mage.game.permanent.Permanent;
import mage.filter.FilterPermanent;
import mage.filter.common.FilterNonlandPermanent;
import mage.filter.predicate.mageobject.ManaValueEqualToCountersSourceCountPredicate;
import java.util.UUID;
/**
*
@ -23,6 +22,13 @@ import mage.game.permanent.Permanent;
*/
public final class RatchetBomb extends CardImpl {
private static final FilterPermanent filter = new FilterNonlandPermanent(
"each nonland permanent with mana value equal to the number of charge counters on {this}"
);
static {
filter.add(new ManaValueEqualToCountersSourceCountPredicate(CounterType.CHARGE));
}
public RatchetBomb (UUID ownerId, CardSetInfo setInfo) {
super(ownerId,setInfo,new CardType[]{CardType.ARTIFACT},"{2}");
@ -30,7 +36,7 @@ public final class RatchetBomb extends CardImpl {
this.addAbility(new SimpleActivatedAbility(new AddCountersSourceEffect(CounterType.CHARGE.createInstance()), new TapSourceCost()));
// {T}, Sacrifice Ratchet Bomb: Destroy each nonland permanent with a converted mana cost equal to the number of charge counters on Ratchet Bomb.
Ability ability = new SimpleActivatedAbility(new RatchetBombEffect(), new TapSourceCost());
Ability ability = new SimpleActivatedAbility(new DestroyAllEffect(filter), new TapSourceCost());
ability.addCost(new SacrificeSourceCost());
this.addAbility(ability);
}
@ -45,39 +51,3 @@ public final class RatchetBomb extends CardImpl {
}
}
class RatchetBombEffect extends OneShotEffect {
RatchetBombEffect() {
super(Outcome.DestroyPermanent);
staticText = "Destroy each nonland permanent with mana value equal to the number of charge counters on {this}";
}
private RatchetBombEffect(final RatchetBombEffect effect) {
super(effect);
}
@Override
public boolean apply(Game game, Ability source) {
Permanent p = game.getPermanent(source.getSourceId());
if (p == null) {
p = (Permanent) game.getLastKnownInformation(source.getSourceId(), Zone.BATTLEFIELD);
if (p == null) {
return false;
}
}
int count = p.getCounters(game).getCount(CounterType.CHARGE);
for (Permanent perm : game.getBattlefield().getActivePermanents(StaticFilters.FILTER_PERMANENT_NON_LAND, source.getControllerId(), source, game)) {
if (perm.getManaValue() == count) {
perm.destroy(source, game, false);
}
}
return true;
}
@Override
public RatchetBombEffect copy() {
return new RatchetBombEffect(this);
}
}

View file

@ -17,15 +17,10 @@ import mage.counters.CounterType;
import mage.filter.FilterPermanent;
import mage.filter.StaticFilters;
import mage.filter.common.FilterNonlandPermanent;
import mage.filter.predicate.ObjectSourcePlayer;
import mage.filter.predicate.ObjectSourcePlayerPredicate;
import mage.game.Game;
import mage.game.permanent.Permanent;
import mage.filter.predicate.mageobject.ManaValueEqualToCountersSourceCountPredicate;
import mage.target.TargetPermanent;
import mage.target.common.TargetAnyTarget;
import java.util.Objects;
import java.util.Optional;
import java.util.UUID;
/**
@ -33,10 +28,12 @@ import java.util.UUID;
*/
public final class TheFiligreeSylex extends CardImpl {
private static final FilterPermanent filter = new FilterNonlandPermanent();
private static final FilterPermanent filter = new FilterNonlandPermanent(
"each nonland permanent with mana value equal to the number of oil counters on {this}"
);
static {
filter.add(TheFiligreeSylexPredicate.instance);
filter.add(new ManaValueEqualToCountersSourceCountPredicate(CounterType.OIL));
}
public TheFiligreeSylex(UUID ownerId, CardSetInfo setInfo) {
@ -50,12 +47,7 @@ public final class TheFiligreeSylex extends CardImpl {
));
// {T}, Sacrifice The Filigree Sylex: Destroy each nonland permanent with mana value equal to the number of oil counters on The Filigree Sylex.
Ability ability = new SimpleActivatedAbility(
new DestroyAllEffect(filter)
.setText("destroy each nonland permanent with mana value " +
"equal to the number of oil counters on {this}"),
new TapSourceCost()
);
Ability ability = new SimpleActivatedAbility(new DestroyAllEffect(filter), new TapSourceCost());
ability.addCost(new SacrificeSourceCost());
this.addAbility(ability);
@ -81,18 +73,3 @@ public final class TheFiligreeSylex extends CardImpl {
return new TheFiligreeSylex(this);
}
}
enum TheFiligreeSylexPredicate implements ObjectSourcePlayerPredicate<Permanent> {
instance;
@Override
public boolean apply(ObjectSourcePlayer<Permanent> input, Game game) {
return Optional
.ofNullable(input.getSource().getSourcePermanentOrLKI(game))
.filter(Objects::nonNull)
.map(permanent -> permanent.getCounters(game))
.map(counters -> counters.getCount(CounterType.OIL))
.orElse(-1)
.equals(input.getObject().getManaValue());
}
}

View file

@ -1,24 +1,18 @@
package mage.cards.w;
import java.util.UUID;
import mage.abilities.Ability;
import mage.abilities.triggers.BeginningOfDrawTriggeredAbility;
import mage.abilities.costs.mana.ManaCostsImpl;
import mage.abilities.effects.OneShotEffect;
import mage.abilities.effects.common.DestroyAllEffect;
import mage.abilities.keyword.CumulativeUpkeepAbility;
import mage.abilities.triggers.BeginningOfDrawTriggeredAbility;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
import mage.constants.ComparisonType;
import mage.constants.Outcome;
import mage.constants.TargetController;
import mage.counters.CounterType;
import mage.filter.FilterPermanent;
import mage.filter.common.FilterCreaturePermanent;
import mage.filter.predicate.mageobject.ManaValuePredicate;
import mage.game.Game;
import mage.game.permanent.Permanent;
import mage.filter.predicate.mageobject.ManaValueEqualToCountersSourceCountPredicate;
import java.util.UUID;
/**
*
@ -26,6 +20,13 @@ import mage.game.permanent.Permanent;
*/
public final class WaveOfTerror extends CardImpl {
private static final FilterPermanent filter = new FilterCreaturePermanent(
"each creature with mana value equal to the number of age counters on {this}"
);
static {
filter.add(new ManaValueEqualToCountersSourceCountPredicate(CounterType.AGE));
}
public WaveOfTerror(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{2}{B}");
@ -33,7 +34,7 @@ public final class WaveOfTerror extends CardImpl {
this.addAbility(new CumulativeUpkeepAbility(new ManaCostsImpl<>("{1}")));
// At the beginning of your draw step, destroy each creature with converted mana cost equal to the number of age counters on Wave of Terror. They can't be regenerated.
this.addAbility(new BeginningOfDrawTriggeredAbility(new WaveOfTerrorEffect(), false));
this.addAbility(new BeginningOfDrawTriggeredAbility(new DestroyAllEffect(filter, true), false));
}
private WaveOfTerror(final WaveOfTerror card) {
@ -45,34 +46,3 @@ public final class WaveOfTerror extends CardImpl {
return new WaveOfTerror(this);
}
}
class WaveOfTerrorEffect extends OneShotEffect {
WaveOfTerrorEffect() {
super(Outcome.DestroyPermanent);
this.staticText = "destroy each creature with mana value equal to the number of age counters on {this}. They can't be regenerated.";
}
private WaveOfTerrorEffect(final WaveOfTerrorEffect effect) {
super(effect);
}
@Override
public WaveOfTerrorEffect copy() {
return new WaveOfTerrorEffect(this);
}
@Override
public boolean apply(Game game, Ability source) {
Permanent permanent = game.getPermanentOrLKIBattlefield(source.getSourceId());
if (permanent == null) {
return false;
}
FilterCreaturePermanent filter = new FilterCreaturePermanent();
filter.add(new ManaValuePredicate(
ComparisonType.EQUAL_TO,
permanent.getCounters(game).getCount(CounterType.AGE)
));
return new DestroyAllEffect(filter, true).apply(game, source);
}
}

View file

@ -23,7 +23,11 @@ public class DestroyAllEffect extends OneShotEffect {
super(Outcome.DestroyPermanent);
this.filter = filter;
this.noRegen = noRegen;
this.staticText = "destroy all " + filter.getMessage() + (noRegen ? ". They can't be regenerated" : "");
String filterMessage = filter.getMessage();
if (!filterMessage.startsWith("each") && !filterMessage.startsWith("all")) {
filterMessage = "all " + filterMessage;
}
this.staticText = "destroy " + filterMessage + (noRegen ? ". They can't be regenerated" : "");
}
protected DestroyAllEffect(final DestroyAllEffect effect) {

View file

@ -0,0 +1,36 @@
package mage.filter.predicate.mageobject;
import mage.MageObject;
import mage.counters.CounterType;
import mage.filter.predicate.ObjectSourcePlayer;
import mage.filter.predicate.ObjectSourcePlayerPredicate;
import mage.game.Game;
import java.util.Optional;
/**
* @author xenohedron
*/
public class ManaValueEqualToCountersSourceCountPredicate implements ObjectSourcePlayerPredicate<MageObject> {
private final CounterType counterType;
public ManaValueEqualToCountersSourceCountPredicate(CounterType counterType) {
this.counterType = counterType;
}
@Override
public boolean apply(ObjectSourcePlayer<MageObject> input, Game game) {
return Optional
.ofNullable(input.getSource().getSourcePermanentOrLKI(game))
.map(permanent -> permanent.getCounters(game))
.map(counters -> counters.getCount(counterType))
.orElse(-1) // always false
.equals(input.getObject().getManaValue());
}
@Override
public String toString() {
return "mana value equal to the number of " + counterType.getName() + " counters on {this}";
}
}