[SPM] implement Rhino's Rampage

This commit is contained in:
jmlundeen 2025-09-04 10:59:03 -05:00
parent 43d315861d
commit 8b6b90c8d8
3 changed files with 188 additions and 0 deletions

View file

@ -0,0 +1,95 @@
package mage.cards.r;
import mage.abilities.Ability;
import mage.abilities.common.delayed.ReflexiveTriggeredAbility;
import mage.abilities.effects.OneShotEffect;
import mage.abilities.effects.common.DestroyTargetEffect;
import mage.abilities.effects.common.FightTargetsEffect;
import mage.abilities.effects.common.continuous.BoostTargetEffect;
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.filter.FilterPermanent;
import mage.filter.common.FilterArtifactPermanent;
import mage.filter.common.FilterCreaturePermanent;
import mage.filter.predicate.Predicates;
import mage.filter.predicate.mageobject.ManaValuePredicate;
import mage.game.Game;
import mage.game.permanent.Permanent;
import mage.target.TargetPermanent;
import mage.target.common.TargetControlledCreaturePermanent;
import java.util.UUID;
/**
*
* @author Jmlundeen
*/
public final class RhinosRampage extends CardImpl {
private static final FilterPermanent filter = new FilterCreaturePermanent("creature an opponent controls");
static {
filter.add(TargetController.OPPONENT.getControllerPredicate());
}
public RhinosRampage(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{R/G}");
// Target creature you control gets +1/+0 until end of turn. It fights target creature an opponent controls. When excess damage is dealt to the creature an opponent controls this way, destroy up to one target noncreature artifact with mana value 3 or less.
this.getSpellAbility().addEffect(new BoostTargetEffect(1, 0));
this.getSpellAbility().addEffect(new FightTargetsEffect()
.setText("It fights target creature an opponent controls"));
this.getSpellAbility().addEffect(new RhinosRampageEffect());
this.getSpellAbility().addTarget(new TargetControlledCreaturePermanent());
this.getSpellAbility().addTarget(new TargetPermanent(filter));
}
private RhinosRampage(final RhinosRampage card) {
super(card);
}
@Override
public RhinosRampage copy() {
return new RhinosRampage(this);
}
}
class RhinosRampageEffect extends OneShotEffect {
public RhinosRampageEffect() {
super(Outcome.BoostCreature);
staticText = "When excess damage is dealt to the creature an opponent controls this way, destroy up to one target noncreature " +
"artifact with mana value 3 or less";
}
protected RhinosRampageEffect(final RhinosRampageEffect effect) {
super(effect);
}
@Override
public RhinosRampageEffect copy() {
return new RhinosRampageEffect(this);
}
@Override
public boolean apply(Game game, Ability source) {
Permanent permanent = game.getPermanentOrLKIBattlefield(source.getTargets().get(1).getFirstTarget());
if (permanent == null || permanent.getDamage() <= permanent.getToughness().getBaseValue()) {
return false;
}
FilterPermanent filter = new FilterArtifactPermanent("noncreature artifact with mana value 3 or less");
filter.add(Predicates.not(CardType.CREATURE.getPredicate()));
filter.add(new ManaValuePredicate(ComparisonType.OR_LESS, 3));
ReflexiveTriggeredAbility ability = new ReflexiveTriggeredAbility(new DestroyTargetEffect(), false);
ability.addTarget(new TargetPermanent(0, 1, filter));
game.fireReflexiveTriggeredAbility(ability, source);
return true;
}
}

View file

@ -159,6 +159,7 @@ public final class MarvelsSpiderMan extends ExpansionSet {
cards.add(new SetCardInfo("Raging Goblinoids", 85, Rarity.UNCOMMON, mage.cards.r.RagingGoblinoids.class)); cards.add(new SetCardInfo("Raging Goblinoids", 85, Rarity.UNCOMMON, mage.cards.r.RagingGoblinoids.class));
cards.add(new SetCardInfo("Rent Is Due", 11, Rarity.RARE, mage.cards.r.RentIsDue.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Rent Is Due", 11, Rarity.RARE, mage.cards.r.RentIsDue.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Rent Is Due", 247, Rarity.RARE, mage.cards.r.RentIsDue.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Rent Is Due", 247, Rarity.RARE, mage.cards.r.RentIsDue.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Rhino's Rampage", 141, Rarity.UNCOMMON, mage.cards.r.RhinosRampage.class));
cards.add(new SetCardInfo("Rhino, Barreling Brute", 140, Rarity.UNCOMMON, mage.cards.r.RhinoBarrelingBrute.class)); cards.add(new SetCardInfo("Rhino, Barreling Brute", 140, Rarity.UNCOMMON, mage.cards.r.RhinoBarrelingBrute.class));
cards.add(new SetCardInfo("Risky Research", 62, Rarity.COMMON, mage.cards.r.RiskyResearch.class)); cards.add(new SetCardInfo("Risky Research", 62, Rarity.COMMON, mage.cards.r.RiskyResearch.class));
cards.add(new SetCardInfo("Robotics Mastery", 41, Rarity.UNCOMMON, mage.cards.r.RoboticsMastery.class)); cards.add(new SetCardInfo("Robotics Mastery", 41, Rarity.UNCOMMON, mage.cards.r.RoboticsMastery.class));

View file

@ -0,0 +1,92 @@
package org.mage.test.cards.single.spm;
import mage.constants.PhaseStep;
import mage.constants.Zone;
import org.junit.Test;
import org.mage.test.serverside.base.CardTestPlayerBase;
/**
*
* @author Jmlundeen
*/
public class RhinosRampageTest extends CardTestPlayerBase {
/*
Rhino's Rampage
{R/G}
Sorcery
Target creature you control gets +1/+0 until end of turn. It fights target creature an opponent controls.
When excess damage is dealt to the creature an opponent controls this way, destroy up to one target noncreature artifact with mana value 3 or less.
*/
private static final String rhinosRampage = "Rhino's Rampage";
/*
Bear Cub
{1}{G}
Creature - Bear
2/2
*/
private static final String bearCub = "Bear Cub";
/*
Fugitive Wizard
{U}
Creature - Human Wizard
1/1
*/
private static final String fugitiveWizard = "Fugitive Wizard";
/*
Tormod's Crypt
{0}
Artifact
{T}, Sacrifice Tormod's Crypt: Exile all cards from target player's graveyard.
*/
private static final String tormodsCrypt = "Tormod's Crypt";
@Test
public void testRhinosRampageExcess() {
setStrictChooseMode(true);
addCard(Zone.HAND, playerA, rhinosRampage);
addCard(Zone.BATTLEFIELD, playerA, "Forest");
addCard(Zone.BATTLEFIELD, playerA, bearCub);
addCard(Zone.BATTLEFIELD, playerB, fugitiveWizard);
addCard(Zone.BATTLEFIELD, playerB, tormodsCrypt);
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, rhinosRampage);
addTarget(playerA, bearCub);
addTarget(playerA, fugitiveWizard);
addTarget(playerA, tormodsCrypt);
setStopAt(1, PhaseStep.END_TURN);
execute();
assertGraveyardCount(playerB, fugitiveWizard, 1);
assertGraveyardCount(playerB, tormodsCrypt, 1);
}
@Test
public void testRhinosRampageNoExcess() {
setStrictChooseMode(true);
addCard(Zone.HAND, playerA, rhinosRampage);
addCard(Zone.BATTLEFIELD, playerA, "Forest");
addCard(Zone.BATTLEFIELD, playerA, fugitiveWizard);
addCard(Zone.BATTLEFIELD, playerB, bearCub);
addCard(Zone.BATTLEFIELD, playerB, tormodsCrypt);
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, rhinosRampage);
addTarget(playerA, fugitiveWizard);
addTarget(playerA, bearCub);
setStopAt(1, PhaseStep.END_TURN);
execute();
assertGraveyardCount(playerA, fugitiveWizard, 1);
assertGraveyardCount(playerB, bearCub, 1);
assertPermanentCount(playerB, tormodsCrypt, 1);
}
}