mirror of
https://github.com/magefree/mage.git
synced 2025-12-20 02:30:08 -08:00
[REX] Implement Grim Giganotosaurus (#12103)
* Implement Grim Giganotosaurus * Refactor MonstrosityAbility to take cost adjuster * Update Nemesis of Mortals' monstrous ability and add test for cost reduction
This commit is contained in:
parent
9d7bf27d38
commit
b0d7daa85e
5 changed files with 147 additions and 13 deletions
83
Mage.Sets/src/mage/cards/g/GrimGiganotosaurus.java
Normal file
83
Mage.Sets/src/mage/cards/g/GrimGiganotosaurus.java
Normal file
|
|
@ -0,0 +1,83 @@
|
|||
package mage.cards.g;
|
||||
|
||||
import java.util.UUID;
|
||||
import mage.MageInt;
|
||||
import mage.abilities.Ability;
|
||||
import mage.abilities.common.BecomesMonstrousSourceTriggeredAbility;
|
||||
import mage.abilities.costs.CostAdjuster;
|
||||
import mage.abilities.dynamicvalue.DynamicValue;
|
||||
import mage.abilities.dynamicvalue.common.PermanentsOnBattlefieldCount;
|
||||
import mage.abilities.effects.common.DestroyAllEffect;
|
||||
import mage.abilities.keyword.MonstrosityAbility;
|
||||
import mage.constants.ComparisonType;
|
||||
import mage.constants.SubType;
|
||||
import mage.cards.CardImpl;
|
||||
import mage.cards.CardSetInfo;
|
||||
import mage.constants.CardType;
|
||||
import mage.filter.FilterPermanent;
|
||||
import mage.filter.common.FilterCreaturePermanent;
|
||||
import mage.filter.common.FilterOpponentsCreaturePermanent;
|
||||
import mage.filter.predicate.Predicates;
|
||||
import mage.filter.predicate.mageobject.AnotherPredicate;
|
||||
import mage.filter.predicate.mageobject.PowerPredicate;
|
||||
import mage.game.Game;
|
||||
import mage.players.Player;
|
||||
import mage.util.CardUtil;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author jimga150
|
||||
*/
|
||||
public final class GrimGiganotosaurus extends CardImpl {
|
||||
|
||||
private static final FilterPermanent filter = new FilterPermanent("artifacts and creatures other than {this}");
|
||||
static {
|
||||
filter.add(AnotherPredicate.instance);
|
||||
filter.add(Predicates.or(CardType.ARTIFACT.getPredicate(), CardType.CREATURE.getPredicate()));
|
||||
}
|
||||
|
||||
public GrimGiganotosaurus(UUID ownerId, CardSetInfo setInfo) {
|
||||
super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{5}{B}{G}");
|
||||
|
||||
this.subtype.add(SubType.DINOSAUR);
|
||||
this.power = new MageInt(10);
|
||||
this.toughness = new MageInt(10);
|
||||
|
||||
// {10}{B}{G}: Monstrosity 10. This ability costs {1} less to activate for each creature with power 4 or greater your opponents control.
|
||||
this.addAbility(new MonstrosityAbility("{10}{B}{G}", 10,
|
||||
GrimGiganotosaurusAdjuster.instance,
|
||||
"This ability costs {1} less to activate for each creature with power 4 or greater your opponents control. "));
|
||||
|
||||
// When Grim Giganotosaurus becomes monstrous, destroy all artifacts and creatures other than Grim Giganotosaurus.
|
||||
this.addAbility(new BecomesMonstrousSourceTriggeredAbility(new DestroyAllEffect(filter)));
|
||||
}
|
||||
|
||||
private GrimGiganotosaurus(final GrimGiganotosaurus card) {
|
||||
super(card);
|
||||
}
|
||||
|
||||
@Override
|
||||
public GrimGiganotosaurus copy() {
|
||||
return new GrimGiganotosaurus(this);
|
||||
}
|
||||
}
|
||||
|
||||
enum GrimGiganotosaurusAdjuster implements CostAdjuster {
|
||||
instance;
|
||||
|
||||
private static final FilterCreaturePermanent filter = new FilterOpponentsCreaturePermanent("creature with power 4 or greater your opponents control");
|
||||
|
||||
static {
|
||||
filter.add(new PowerPredicate(ComparisonType.MORE_THAN, 3));
|
||||
}
|
||||
|
||||
private static final DynamicValue xValue = new PermanentsOnBattlefieldCount(filter);
|
||||
|
||||
@Override
|
||||
public void adjustCosts(Ability ability, Game game) {
|
||||
Player controller = game.getPlayer(ability.getControllerId());
|
||||
if (controller != null) {
|
||||
CardUtil.reduceCost(ability, xValue.calculate(game, ability, null));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -6,7 +6,6 @@ import mage.abilities.common.SimpleStaticAbility;
|
|||
import mage.abilities.costs.CostAdjuster;
|
||||
import mage.abilities.dynamicvalue.DynamicValue;
|
||||
import mage.abilities.dynamicvalue.common.CardsInControllerGraveyardCount;
|
||||
import mage.abilities.effects.Effect;
|
||||
import mage.abilities.effects.common.cost.SpellCostReductionForEachSourceEffect;
|
||||
import mage.abilities.hint.Hint;
|
||||
import mage.abilities.hint.ValueHint;
|
||||
|
|
@ -45,12 +44,9 @@ public final class NemesisOfMortals extends CardImpl {
|
|||
this.addAbility(ability);
|
||||
|
||||
// {7}{G}{G}: Monstrosity 5. This ability costs {1} less to activate for each creature card in your graveyard.
|
||||
ability = new MonstrosityAbility("{7}{G}{G}", 5);
|
||||
for (Effect effect : ability.getEffects()) {
|
||||
effect.setText("Monstrosity 5. This ability costs {1} less to activate for each creature card in your graveyard");
|
||||
}
|
||||
ability.setCostAdjuster(NemesisOfMortalsAdjuster.instance);
|
||||
this.addAbility(ability);
|
||||
this.addAbility(new MonstrosityAbility("{7}{G}{G}", 5,
|
||||
NemesisOfMortalsAdjuster.instance,
|
||||
"This ability costs {1} less to activate for each creature card in your graveyard"));
|
||||
}
|
||||
|
||||
private NemesisOfMortals(final NemesisOfMortals card) {
|
||||
|
|
|
|||
|
|
@ -30,6 +30,7 @@ public final class JurassicWorldCollection extends ExpansionSet {
|
|||
cards.add(new SetCardInfo("Ellie and Alan, Paleontologists", 10, Rarity.RARE, mage.cards.e.EllieAndAlanPaleontologists.class));
|
||||
cards.add(new SetCardInfo("Forest", 25, Rarity.LAND, mage.cards.basiclands.Forest.class, FULL_ART_BFZ_VARIOUS));
|
||||
cards.add(new SetCardInfo("Forest", "25b", Rarity.LAND, mage.cards.basiclands.Forest.class, FULL_ART_BFZ_VARIOUS));
|
||||
cards.add(new SetCardInfo("Grim Giganotosaurus", 11, Rarity.RARE, mage.cards.g.GrimGiganotosaurus.class));
|
||||
cards.add(new SetCardInfo("Henry Wu, InGen Geneticist", 12, Rarity.RARE, mage.cards.h.HenryWuInGenGeneticist.class));
|
||||
cards.add(new SetCardInfo("Hunting Velociraptor", 4, Rarity.RARE, mage.cards.h.HuntingVelociraptor.class));
|
||||
cards.add(new SetCardInfo("Island", 22, Rarity.LAND, mage.cards.basiclands.Island.class, FULL_ART_BFZ_VARIOUS));
|
||||
|
|
|
|||
|
|
@ -0,0 +1,42 @@
|
|||
package org.mage.test.cards.abilities.activated;
|
||||
|
||||
import mage.constants.PhaseStep;
|
||||
import mage.constants.Zone;
|
||||
import org.junit.Test;
|
||||
import org.mage.test.serverside.base.CardTestPlayerBase;
|
||||
|
||||
public class NemesisOfMortalsTests extends CardTestPlayerBase {
|
||||
|
||||
@Test
|
||||
public void testNoCostReduction() {
|
||||
|
||||
addCard(Zone.BATTLEFIELD, playerA, "Nemesis of Mortals");
|
||||
addCard(Zone.BATTLEFIELD, playerA, "Forest", 9);
|
||||
|
||||
activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "{7}{G}{G}");
|
||||
|
||||
setStrictChooseMode(true);
|
||||
setStopAt(1, PhaseStep.END_TURN);
|
||||
execute();
|
||||
|
||||
assertTappedCount("Forest", true, 9);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testWithCostReduction() {
|
||||
|
||||
addCard(Zone.BATTLEFIELD, playerA, "Nemesis of Mortals");
|
||||
addCard(Zone.BATTLEFIELD, playerA, "Forest", 9);
|
||||
|
||||
addCard(Zone.GRAVEYARD, playerA, "Memnite", 4);
|
||||
addCard(Zone.GRAVEYARD, playerA, "Forest", 2);
|
||||
|
||||
activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "{7}{G}{G}");
|
||||
|
||||
setStrictChooseMode(true);
|
||||
setStopAt(1, PhaseStep.END_TURN);
|
||||
execute();
|
||||
|
||||
assertTappedCount("Forest", true, 5);
|
||||
}
|
||||
}
|
||||
|
|
@ -2,7 +2,9 @@ package mage.abilities.keyword;
|
|||
|
||||
import mage.abilities.Ability;
|
||||
import mage.abilities.ActivatedAbilityImpl;
|
||||
import mage.abilities.costs.CostAdjuster;
|
||||
import mage.abilities.costs.mana.ManaCostsImpl;
|
||||
import mage.abilities.effects.Effect;
|
||||
import mage.abilities.effects.OneShotEffect;
|
||||
import mage.abilities.hint.common.MonstrousHint;
|
||||
import mage.constants.Outcome;
|
||||
|
|
@ -44,15 +46,21 @@ public class MonstrosityAbility extends ActivatedAbilityImpl {
|
|||
|
||||
private final int monstrosityValue;
|
||||
|
||||
public MonstrosityAbility(String manaString, int monstrosityValue) {
|
||||
this(manaString, monstrosityValue, null, "");
|
||||
}
|
||||
|
||||
/**
|
||||
* @param manaString
|
||||
* @param monstrosityValue use Integer.MAX_VALUE for monstrosity X.
|
||||
* @param costAdjuster
|
||||
* @param costAdjusterText Clarifies the cost adjusting condition(s).
|
||||
*/
|
||||
public MonstrosityAbility(String manaString, int monstrosityValue) {
|
||||
super(Zone.BATTLEFIELD, new BecomeMonstrousSourceEffect(monstrosityValue), new ManaCostsImpl<>(manaString));
|
||||
public MonstrosityAbility(String manaString, int monstrosityValue, CostAdjuster costAdjuster, String costAdjusterText) {
|
||||
super(Zone.BATTLEFIELD, new BecomeMonstrousSourceEffect(monstrosityValue, costAdjusterText), new ManaCostsImpl<>(manaString));
|
||||
this.monstrosityValue = monstrosityValue;
|
||||
|
||||
this.addHint(MonstrousHint.instance);
|
||||
setCostAdjuster(costAdjuster);
|
||||
}
|
||||
|
||||
protected MonstrosityAbility(final MonstrosityAbility ability) {
|
||||
|
|
@ -74,8 +82,12 @@ public class MonstrosityAbility extends ActivatedAbilityImpl {
|
|||
class BecomeMonstrousSourceEffect extends OneShotEffect {
|
||||
|
||||
public BecomeMonstrousSourceEffect(int monstrosityValue) {
|
||||
this(monstrosityValue, "");
|
||||
}
|
||||
|
||||
public BecomeMonstrousSourceEffect(int monstrosityValue, String costAdjusterText) {
|
||||
super(Outcome.BoostCreature);
|
||||
this.staticText = setText(monstrosityValue);
|
||||
this.staticText = setText(monstrosityValue, costAdjusterText);
|
||||
}
|
||||
|
||||
protected BecomeMonstrousSourceEffect(final BecomeMonstrousSourceEffect effect) {
|
||||
|
|
@ -110,9 +122,9 @@ class BecomeMonstrousSourceEffect extends OneShotEffect {
|
|||
return true;
|
||||
}
|
||||
|
||||
private String setText(int monstrosityValue) {
|
||||
private String setText(int monstrosityValue, String costAdjusterText) {
|
||||
return "Monstrosity " + (monstrosityValue == Integer.MAX_VALUE ? "X" : monstrosityValue) +
|
||||
". <i>(If this creature isn't monstrous, put " +
|
||||
". " + costAdjusterText + "<i>(If this creature isn't monstrous, put " +
|
||||
(monstrosityValue == Integer.MAX_VALUE ? "X" : CardUtil.numberToText(monstrosityValue)) +
|
||||
" +1/+1 counters on it and it becomes monstrous.)</i>";
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue