[CMM] Implement Nyxborn Behemoth (#10670)

* [CMM] Implement Nyxborn Behemoth

Regroup the different dynamic values for "total mana value of [FILTER]" under a shared class.

* refactor hints inside TotalPermanentsManaValue

* apply review on TotalPermanentsManaValue->copy
This commit is contained in:
Susucre 2023-07-27 18:50:47 +02:00 committed by GitHub
parent 9eb7e2870e
commit c4f13be87f
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
8 changed files with 197 additions and 152 deletions

View file

@ -1,24 +1,20 @@
package mage.cards.a;
import java.util.UUID;
import mage.MageInt;
import mage.abilities.Ability;
import mage.abilities.common.SimpleStaticAbility;
import mage.abilities.dynamicvalue.DynamicValue;
import mage.abilities.effects.Effect;
import mage.abilities.dynamicvalue.common.TotalPermanentsManaValue;
import mage.abilities.effects.common.continuous.SetBasePowerToughnessSourceEffect;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
import mage.constants.SubType;
import mage.constants.Zone;
import mage.filter.common.FilterControlledCreaturePermanent;
import mage.game.Game;
import mage.game.permanent.Permanent;
import mage.filter.StaticFilters;
import java.util.UUID;
/**
*
* @author Backfir3
* @author Susucr
*/
public final class AncientOoze extends CardImpl {
@ -30,9 +26,12 @@ public final class AncientOoze extends CardImpl {
this.power = new MageInt(0);
this.toughness = new MageInt(0);
// Ancient Ooze's power and toughness are each equal to the total converted mana cost of other creatures you control.
this.addAbility(new SimpleStaticAbility(Zone.ALL, new SetBasePowerToughnessSourceEffect(new AncientOozePowerToughnessValue())
.setText("{this}'s power and toughness are each equal to the total mana value of other creatures you control.")
// Ancient Ooze's power and toughness are each equal to the total mana value of other creatures you control.
this.addAbility(new SimpleStaticAbility(
Zone.ALL,
new SetBasePowerToughnessSourceEffect(
new TotalPermanentsManaValue(StaticFilters.FILTER_OTHER_CONTROLLED_CREATURES)
)
));
}
@ -44,33 +43,4 @@ public final class AncientOoze extends CardImpl {
public AncientOoze copy() {
return new AncientOoze(this);
}
}
class AncientOozePowerToughnessValue implements DynamicValue {
@Override
public int calculate(Game game, Ability sourceAbility, Effect effect) {
int value = 0;
for (Permanent creature : game.getBattlefield().getActivePermanents(new FilterControlledCreaturePermanent(), sourceAbility.getControllerId(), game)) {
if (creature != null && !sourceAbility.getSourceId().equals(creature.getId())) {
value += creature.getManaValue();
}
}
return value;
}
@Override
public AncientOozePowerToughnessValue copy() {
return new AncientOozePowerToughnessValue();
}
@Override
public String toString() {
return "X";
}
@Override
public String getMessage() {
return "total mana value of other creatures you control";
}
}
}

View file

@ -1,18 +1,14 @@
package mage.cards.e;
import mage.MageInt;
import mage.MageObject;
import mage.abilities.Ability;
import mage.abilities.common.SimpleActivatedAbility;
import mage.abilities.common.SimpleStaticAbility;
import mage.abilities.costs.common.SacrificeTargetCost;
import mage.abilities.costs.mana.ManaCostsImpl;
import mage.abilities.dynamicvalue.DynamicValue;
import mage.abilities.effects.Effect;
import mage.abilities.dynamicvalue.common.TotalPermanentsManaValue;
import mage.abilities.effects.common.ReturnSourceFromGraveyardToHandEffect;
import mage.abilities.effects.common.cost.SpellCostReductionSourceEffect;
import mage.abilities.hint.Hint;
import mage.abilities.hint.ValueHint;
import mage.abilities.keyword.FlyingAbility;
import mage.abilities.keyword.TrampleAbility;
import mage.cards.CardImpl;
@ -23,7 +19,6 @@ import mage.constants.Zone;
import mage.filter.FilterPermanent;
import mage.filter.StaticFilters;
import mage.filter.common.FilterControlledPermanent;
import mage.game.Game;
import java.util.UUID;
@ -32,9 +27,10 @@ import java.util.UUID;
*/
public final class EarthquakeDragon extends CardImpl {
private static final Hint hint = new ValueHint(
"Total mana value of Dragons you control", EarthquakeDragonValue.instance
);
private static final FilterPermanent filter = new FilterControlledPermanent(SubType.DRAGON);
private static final TotalPermanentsManaValue xValue = new TotalPermanentsManaValue(filter);
public EarthquakeDragon(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{14}{G}");
@ -46,8 +42,10 @@ public final class EarthquakeDragon extends CardImpl {
// This spell costs {X} less to cast, where X is the total mana value of Dragons you control.
this.addAbility(new SimpleStaticAbility(
Zone.ALL, new SpellCostReductionSourceEffect(EarthquakeDragonValue.instance)
).addHint(hint).setRuleAtTheTop(true));
Zone.ALL,
new SpellCostReductionSourceEffect(xValue)
).addHint(xValue.getHint()).setRuleAtTheTop(true)
);
// Flying
this.addAbility(FlyingAbility.getInstance());
@ -71,34 +69,4 @@ public final class EarthquakeDragon extends CardImpl {
public EarthquakeDragon copy() {
return new EarthquakeDragon(this);
}
}
enum EarthquakeDragonValue implements DynamicValue {
instance;
private static final FilterPermanent filter = new FilterControlledPermanent(SubType.DRAGON);
@Override
public int calculate(Game game, Ability sourceAbility, Effect effect) {
return game
.getBattlefield()
.getActivePermanents(filter, sourceAbility.getControllerId(), sourceAbility, game)
.stream()
.mapToInt(MageObject::getManaValue)
.sum();
}
@Override
public EarthquakeDragonValue copy() {
return this;
}
@Override
public String getMessage() {
return "the total mana value of Dragons you control";
}
@Override
public String toString() {
return "X";
}
}
}

View file

@ -1,42 +1,40 @@
package mage.cards.m;
import mage.MageInt;
import mage.abilities.Ability;
import mage.abilities.SpellAbility;
import mage.abilities.common.SimpleActivatedAbility;
import mage.abilities.common.SimpleStaticAbility;
import mage.abilities.costs.common.SacrificeTargetCost;
import mage.abilities.dynamicvalue.DynamicValue;
import mage.abilities.effects.Effect;
import mage.abilities.dynamicvalue.common.TotalPermanentsManaValue;
import mage.abilities.effects.common.ReturnSourceFromGraveyardToHandEffect;
import mage.abilities.effects.common.cost.CostModificationEffectImpl;
import mage.abilities.effects.common.cost.SpellCostReductionSourceEffect;
import mage.abilities.hint.ValueHint;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.*;
import mage.constants.CardType;
import mage.constants.SubType;
import mage.constants.Zone;
import mage.filter.FilterPermanent;
import mage.filter.common.FilterControlledArtifactPermanent;
import mage.filter.common.FilterControlledPermanent;
import mage.filter.predicate.Predicates;
import mage.game.Game;
import mage.game.permanent.Permanent;
import mage.target.common.TargetControlledPermanent;
import mage.util.CardUtil;
import org.checkerframework.checker.nullness.qual.NonNull;
import java.util.List;
import java.util.Objects;
import java.util.UUID;
/**
* @author emerald000
* @author emerald000, Susucr
*/
public final class MetalworkColossus extends CardImpl {
private static final String message = "Total mana value of noncreature artifacts you control";
private static final FilterControlledPermanent filter = new FilterControlledArtifactPermanent("artifacts");
private static final FilterPermanent filterCostReduction = new FilterControlledArtifactPermanent("noncreature artifacts you control");
static {
filterCostReduction.add(Predicates.not(CardType.CREATURE.getPredicate()));
}
private static final TotalPermanentsManaValue xValue = new TotalPermanentsManaValue(filterCostReduction);
public MetalworkColossus(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT, CardType.CREATURE}, "{11}");
this.subtype.add(SubType.CONSTRUCT);
@ -44,11 +42,10 @@ public final class MetalworkColossus extends CardImpl {
this.toughness = new MageInt(10);
// This spell costs {X} less to cast, where X is the total mana value of noncreature artifacts you control.
DynamicValue xValue = new totalNonCreatureArtifactManaValue();
this.addAbility(new SimpleStaticAbility(
Zone.ALL,
new SpellCostReductionSourceEffect(xValue)
).addHint(new ValueHint(message, xValue))
Zone.ALL,
new SpellCostReductionSourceEffect(xValue)
).addHint(xValue.getHint()).setRuleAtTheTop(true)
);
// Sacrifice two artifacts: Return Metalwork Colossus from your graveyard to your hand.
@ -63,51 +60,4 @@ public final class MetalworkColossus extends CardImpl {
public MetalworkColossus copy() {
return new MetalworkColossus(this);
}
}
class totalNonCreatureArtifactManaValue implements DynamicValue {
private static final String message = "the total mana value of noncreature artifacts you control";
private static final FilterPermanent filter = new FilterControlledArtifactPermanent("noncreature artifacts you control");
static {
filter.add(Predicates.not(CardType.CREATURE.getPredicate()));
}
totalNonCreatureArtifactManaValue() {
// Nothing to do.
}
private totalNonCreatureArtifactManaValue(final totalNonCreatureArtifactManaValue dynamicValue) {
super();
}
@Override
public DynamicValue copy() {
return new totalNonCreatureArtifactManaValue(this);
}
@Override
public int calculate(Game game, Ability sourceAbility, Effect effect) {
int totalCMC = 0;
List<Permanent> permanents = game.getBattlefield().getActivePermanents(
filter,
sourceAbility.getControllerId(),
sourceAbility,
game);
for (Permanent permanent : permanents) {
totalCMC += permanent.getManaValue();
}
return totalCMC;
}
@Override
public String getMessage() {
return message;
}
@Override
public String toString() {
return "X";
}
}
}

View file

@ -0,0 +1,76 @@
package mage.cards.n;
import mage.MageInt;
import mage.abilities.ActivatedAbility;
import mage.abilities.common.SimpleActivatedAbility;
import mage.abilities.common.SimpleStaticAbility;
import mage.abilities.costs.common.SacrificeTargetCost;
import mage.abilities.costs.mana.ManaCostsImpl;
import mage.abilities.dynamicvalue.common.TotalPermanentsManaValue;
import mage.abilities.effects.common.continuous.GainAbilitySourceEffect;
import mage.abilities.effects.common.cost.SpellCostReductionSourceEffect;
import mage.abilities.keyword.IndestructibleAbility;
import mage.abilities.keyword.TrampleAbility;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
import mage.constants.Duration;
import mage.constants.SubType;
import mage.constants.Zone;
import mage.filter.FilterPermanent;
import mage.filter.StaticFilters;
import mage.filter.common.FilterControlledEnchantmentPermanent;
import mage.filter.predicate.Predicates;
import java.util.UUID;
/**
* @author Susucr
*/
public final class NyxbornBehemoth extends CardImpl {
private static final FilterPermanent filter = new FilterControlledEnchantmentPermanent("noncreature enchantments you control");
static {
filter.add(Predicates.not(CardType.CREATURE.getPredicate()));
}
private static final TotalPermanentsManaValue xValue = new TotalPermanentsManaValue(filter);
public NyxbornBehemoth(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT, CardType.CREATURE}, "{10}{G}{G}");
this.subtype.add(SubType.BEAST);
this.power = new MageInt(10);
this.toughness = new MageInt(10);
// This spell costs {X} less to cast, where X is the total mana value of noncreature enchantments you control.
this.addAbility(new SimpleStaticAbility(
Zone.ALL,
new SpellCostReductionSourceEffect(xValue)
).addHint(xValue.getHint()).setRuleAtTheTop(true)
);
// Trample
this.addAbility(TrampleAbility.getInstance());
// {1}{G}, Sacrifice another enchantment: Nyxborn Behemoth gains indestructible until end of turn.
ActivatedAbility ability = new SimpleActivatedAbility(
Zone.BATTLEFIELD,
new GainAbilitySourceEffect(IndestructibleAbility.getInstance(), Duration.EndOfTurn),
new ManaCostsImpl<>("{1}{G}")
);
ability.addCost(new SacrificeTargetCost(StaticFilters.FILTER_CONTROLLED_ANOTHER_ENCHANTMENT_SHORT_TEXT));
this.addAbility(ability);
}
private NyxbornBehemoth(final NyxbornBehemoth card) {
super(card);
}
@Override
public NyxbornBehemoth copy() {
return new NyxbornBehemoth(this);
}
}

View file

@ -431,6 +431,7 @@ public final class CommanderMasters extends ExpansionSet {
cards.add(new SetCardInfo("Norn's Annex", 829, Rarity.RARE, mage.cards.n.NornsAnnex.class));
cards.add(new SetCardInfo("Not of This World", 807, Rarity.UNCOMMON, mage.cards.n.NotOfThisWorld.class));
cards.add(new SetCardInfo("Nyx Weaver", 933, Rarity.UNCOMMON, mage.cards.n.NyxWeaver.class));
cards.add(new SetCardInfo("Nyxborn Behemoth", 742, Rarity.RARE, mage.cards.n.NyxbornBehemoth.class));
cards.add(new SetCardInfo("Oath of Gideon", 830, Rarity.RARE, mage.cards.o.OathOfGideon.class));
cards.add(new SetCardInfo("Oath of Jace", 854, Rarity.RARE, mage.cards.o.OathOfJace.class));
cards.add(new SetCardInfo("Oath of Teferi", 934, Rarity.RARE, mage.cards.o.OathOfTeferi.class));

View file

@ -0,0 +1,64 @@
package mage.abilities.dynamicvalue.common;
import mage.abilities.Ability;
import mage.abilities.dynamicvalue.DynamicValue;
import mage.abilities.effects.Effect;
import mage.abilities.hint.Hint;
import mage.abilities.hint.ValueHint;
import mage.filter.FilterPermanent;
import mage.game.Game;
import mage.game.permanent.Permanent;
import java.util.List;
public class TotalPermanentsManaValue implements DynamicValue {
private final String message;
private final ValueHint hint;
private final FilterPermanent filter;
public TotalPermanentsManaValue(FilterPermanent filter) {
this.filter = filter.copy();
this.message = "the total mana value of " + filter.getMessage();
this.hint = new ValueHint("Total mana value of " + filter.getMessage(), this);
}
private TotalPermanentsManaValue(final TotalPermanentsManaValue value) {
this.filter = value.filter.copy();
this.message = value.message;
this.hint = value.hint.copy();
}
@Override
public TotalPermanentsManaValue copy() {
return new TotalPermanentsManaValue(this);
}
@Override
public int calculate(Game game, Ability sourceAbility, Effect effect) {
int totalCMC = 0;
List<Permanent> permanents = game.getBattlefield().getActivePermanents(
filter,
sourceAbility.getControllerId(),
sourceAbility,
game);
for (Permanent permanent : permanents) {
totalCMC += permanent.getManaValue();
}
return totalCMC;
}
@Override
public String getMessage() {
return message;
}
@Override
public String toString() {
return "X";
}
public Hint getHint() {
return hint;
}
}

View file

@ -28,7 +28,7 @@ public class ValueHint implements Hint {
}
@Override
public Hint copy() {
public ValueHint copy() {
return new ValueHint(this);
}
}

View file

@ -483,6 +483,14 @@ public final class StaticFilters {
FILTER_CONTROLLED_PERMANENT_ENCHANTMENT.setLockedFilter(true);
}
public static final FilterControlledPermanent FILTER_CONTROLLED_ANOTHER_ENCHANTMENT_SHORT_TEXT = new FilterControlledPermanent("another enchantment");
static {
FILTER_CONTROLLED_ANOTHER_ENCHANTMENT_SHORT_TEXT.add(AnotherPredicate.instance);
FILTER_CONTROLLED_ANOTHER_ENCHANTMENT_SHORT_TEXT.add(CardType.ENCHANTMENT.getPredicate());
FILTER_CONTROLLED_ANOTHER_ENCHANTMENT_SHORT_TEXT.setLockedFilter(true);
}
public static final FilterControlledPermanent FILTER_CONTROLLED_PERMANENT_LAND = new FilterControlledLandPermanent();
static {
@ -625,6 +633,14 @@ public final class StaticFilters {
FILTER_CONTROLLED_CREATURES.setLockedFilter(true);
}
public static final FilterControlledCreaturePermanent FILTER_OTHER_CONTROLLED_CREATURES = new FilterControlledCreaturePermanent("other creatures you control");
static {
FILTER_OTHER_CONTROLLED_CREATURES.add(AnotherPredicate.instance);
FILTER_OTHER_CONTROLLED_CREATURES.setLockedFilter(true);
}
public static final FilterControlledCreaturePermanent FILTER_CONTROLLED_A_CREATURE = new FilterControlledCreaturePermanent("a creature you control");
static {