[TDM] Implement Mistrise Village

This commit is contained in:
jmlundeen 2025-04-11 08:33:49 -05:00
parent efa1cd0a07
commit 089d8c1be0
3 changed files with 155 additions and 0 deletions

View file

@ -0,0 +1,112 @@
package mage.cards.m;
import java.util.UUID;
import mage.MageObject;
import mage.abilities.Ability;
import mage.abilities.common.CantBeCounteredSourceAbility;
import mage.abilities.common.EntersBattlefieldTappedUnlessAbility;
import mage.abilities.common.SimpleActivatedAbility;
import mage.abilities.condition.common.YouControlPermanentCondition;
import mage.abilities.costs.common.TapSourceCost;
import mage.abilities.costs.mana.ManaCostsImpl;
import mage.abilities.effects.ContinuousRuleModifyingEffectImpl;
import mage.abilities.effects.Effect;
import mage.abilities.effects.common.AddContinuousEffectToGame;
import mage.abilities.effects.common.continuous.NextSpellCastHasAbilityEffect;
import mage.abilities.mana.BlueManaAbility;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
import mage.constants.Duration;
import mage.constants.Outcome;
import mage.constants.SubType;
import mage.filter.common.FilterLandPermanent;
import mage.filter.predicate.Predicates;
import mage.game.Game;
import mage.game.events.GameEvent;
import mage.game.stack.Spell;
import mage.game.stack.StackObject;
/**
*
* @author Jmlundeen
*/
public final class MistriseVillage extends CardImpl {
private static final FilterLandPermanent filter = new FilterLandPermanent("Mountain or a Forest");
static {
filter.add(Predicates.or(SubType.MOUNTAIN.getPredicate(), SubType.FOREST.getPredicate()));
}
private static final YouControlPermanentCondition condition = new YouControlPermanentCondition(filter);
public MistriseVillage(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.LAND}, "");
// This land enters tapped unless you control a Mountain or a Forest.
this.addAbility(new EntersBattlefieldTappedUnlessAbility(condition).addHint(condition.getHint()));
// {T}: Add {U}.
this.addAbility(new BlueManaAbility());
// {U}, {T}: The next spell you cast this turn can't be countered.
Effect effect = new AddContinuousEffectToGame(new MistriseCantBeCounteredEffect());
Ability ability = new SimpleActivatedAbility(effect, new ManaCostsImpl<>("{U}"));
ability.addCost(new TapSourceCost());
this.addAbility(ability);
}
private MistriseVillage(final MistriseVillage card) {
super(card);
}
@Override
public MistriseVillage copy() {
return new MistriseVillage(this);
}
}
class MistriseCantBeCounteredEffect extends ContinuousRuleModifyingEffectImpl {
public MistriseCantBeCounteredEffect() {
super(Duration.OneUse, Outcome.Benefit, false, true);
staticText = "the next spell you cast this turn can't be countered";
}
protected MistriseCantBeCounteredEffect(final MistriseCantBeCounteredEffect effect) {
super(effect);
}
@Override
public MistriseCantBeCounteredEffect copy() {
return new MistriseCantBeCounteredEffect(this);
}
@Override
public boolean checksEventType(GameEvent event, Game game) {
return event.getType() == GameEvent.EventType.COUNTER;
}
@Override
public String getInfoMessage(Ability source, GameEvent event, Game game) {
StackObject sourceObject = game.getStack().getStackObject(event.getSourceId());
StackObject targetObject = game.getStack().getStackObject(event.getTargetId());
if (sourceObject != null && targetObject != null) {
return targetObject.getName() + " cannot be countered by " + sourceObject.getName();
}
return staticText;
}
@Override
public boolean applies(GameEvent event, Ability source, Game game) {
Spell spell = game.getStack().getSpell(event.getTargetId());
boolean res = spell != null && spell.isControlledBy(source.getControllerId());
if (res) {
discard();
}
return res;
}
}

View file

@ -167,6 +167,7 @@ public final class TarkirDragonstorm extends ExpansionSet {
cards.add(new SetCardInfo("Mardu Siegebreaker", 206, Rarity.RARE, mage.cards.m.MarduSiegebreaker.class));
cards.add(new SetCardInfo("Marshal of the Lost", 207, Rarity.UNCOMMON, mage.cards.m.MarshalOfTheLost.class));
cards.add(new SetCardInfo("Meticulous Artisan", 112, Rarity.COMMON, mage.cards.m.MeticulousArtisan.class));
cards.add(new SetCardInfo("Mistrise Village", 261, Rarity.RARE, mage.cards.m.MistriseVillage.class));
cards.add(new SetCardInfo("Molten Exhale", 113, Rarity.COMMON, mage.cards.m.MoltenExhale.class));
cards.add(new SetCardInfo("Monastery Messenger", 208, Rarity.COMMON, mage.cards.m.MonasteryMessenger.class));
cards.add(new SetCardInfo("Mountain", 283, Rarity.LAND, mage.cards.basiclands.Mountain.class, NON_FULL_USE_VARIOUS));

View file

@ -0,0 +1,42 @@
package org.mage.test.cards.single.tdm;
import mage.constants.PhaseStep;
import mage.constants.Zone;
import org.junit.Test;
import org.mage.test.serverside.base.CardTestPlayerBase;
public class MistriseVillageTest extends CardTestPlayerBase {
private static final String MISTRISE = "Mistrise Village";
private static final String COUNTER = "Counterspell";
private static final String CUB = "Bear Cub";
private static final String BEARS = "Balduvian Bears";
@Test
public void testCounter() {
setStrictChooseMode(true);
addCard(Zone.BATTLEFIELD, playerA, MISTRISE);
addCard(Zone.BATTLEFIELD, playerA, "Island");
addCard(Zone.BATTLEFIELD, playerA, "Forest", 4);
addCard(Zone.BATTLEFIELD, playerB, "Island", 4);
addCard(Zone.HAND, playerB, COUNTER, 2);
addCard(Zone.HAND, playerA, CUB);
addCard(Zone.HAND, playerA, BEARS);
activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "{U}, {T}");
waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN, playerA);
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, CUB, true);
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerB, COUNTER, CUB, CUB);
castSpell(1, PhaseStep.POSTCOMBAT_MAIN, playerA, BEARS, true);
castSpell(1, PhaseStep.POSTCOMBAT_MAIN, playerB, COUNTER, BEARS, BEARS);
setStopAt(1, PhaseStep.END_TURN);
execute();
assertPermanentCount(playerA, CUB, 1);
assertGraveyardCount(playerA, BEARS, 1);
assertGraveyardCount(playerB, COUNTER, 2);
}
}