[DSK] Implement Nowhere to Run (#13208)

* [DSK] implemented Nowhere to Run

* [DSK] implemented Nowhere to Run

* NowhereToRun - fixed typo in static test

* NowhereToRun - fixed hexproof effect
This commit is contained in:
Marco Romano 2025-01-09 21:07:13 +01:00 committed by GitHub
parent 8772190c7b
commit 30dac5cc9f
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 235 additions and 0 deletions

View file

@ -0,0 +1,128 @@
package mage.cards.n;
import mage.abilities.Ability;
import mage.abilities.common.EntersBattlefieldTriggeredAbility;
import mage.abilities.common.SimpleStaticAbility;
import mage.abilities.effects.AsThoughEffect;
import mage.abilities.effects.AsThoughEffectImpl;
import mage.abilities.effects.ContinuousEffect;
import mage.abilities.effects.ContinuousRuleModifyingEffectImpl;
import mage.abilities.effects.common.continuous.BoostTargetEffect;
import mage.abilities.keyword.FlashAbility;
import mage.abilities.keyword.WardAbility;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.AsThoughEffectType;
import mage.constants.CardType;
import mage.constants.Duration;
import mage.constants.Outcome;
import mage.game.Game;
import mage.game.events.GameEvent;
import mage.game.permanent.Permanent;
import mage.target.common.TargetOpponentsCreaturePermanent;
import java.util.UUID;
/**
* @author markort147
*/
public final class NowhereToRun extends CardImpl {
public NowhereToRun(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{1}{B}");
// Flash
this.addAbility(FlashAbility.getInstance());
// When Nowhere to Run enters, target creature an opponent controls gets -3/-3 until end of turn.
Ability etbAbility = new EntersBattlefieldTriggeredAbility(new BoostTargetEffect(-3, -3, Duration.EndOfTurn));
etbAbility.addTarget(new TargetOpponentsCreaturePermanent());
this.addAbility(etbAbility);
// Creatures your opponents control can be the targets of spells and abilities as though they didn't have hexproof. Ward abilities of those creatures don't trigger.
Ability staticAbility = new SimpleStaticAbility(new NowhereToRunHexproofEffect());
staticAbility.addEffect(new NowhereToRunWardEffect());
this.addAbility(staticAbility);
}
private NowhereToRun(final NowhereToRun card) {
super(card);
}
@Override
public NowhereToRun copy() {
return new NowhereToRun(this);
}
}
class NowhereToRunHexproofEffect extends AsThoughEffectImpl {
NowhereToRunHexproofEffect() {
super(AsThoughEffectType.HEXPROOF, Duration.WhileOnBattlefield, Outcome.Benefit);
staticText = "Creatures your opponents control "
+ "can be the targets of spells and "
+ "abilities as though they didn't "
+ "have hexproof.";
}
private NowhereToRunHexproofEffect(final NowhereToRunHexproofEffect effect) {
super(effect);
}
@Override
public boolean applies(UUID sourceId, Ability source, UUID affectedControllerId, Game game) {
if (affectedControllerId.equals(source.getControllerId())) {
Permanent creature = game.getPermanent(sourceId);
return creature != null
&& creature.isCreature(game)
&& game.getOpponents(source.getControllerId()).contains(creature.getControllerId());
}
return false;
}
@Override
public boolean apply(Game game, Ability source) {
return true;
}
@Override
public AsThoughEffect copy() {
return new NowhereToRunHexproofEffect(this);
}
}
class NowhereToRunWardEffect extends ContinuousRuleModifyingEffectImpl {
NowhereToRunWardEffect() {
super(Duration.WhileOnBattlefield, Outcome.Benefit);
staticText = "Ward abilities of those creatures don't trigger.";
}
private NowhereToRunWardEffect(final NowhereToRunWardEffect effect) {
super(effect);
}
@Override
public boolean checksEventType(GameEvent event, Game game) {
return event.getType().equals(GameEvent.EventType.NUMBER_OF_TRIGGERS);
}
@Override
public boolean applies(GameEvent event, Ability source, Game game) {
Permanent permanent = game.getPermanent(event.getSourceId());
if (permanent == null || !permanent.isCreature(game)) {
return false;
}
if (!game.getOpponents(source.getControllerId()).contains(permanent.getControllerId())) {
return false;
}
return getValue("targetAbility") instanceof WardAbility;
}
@Override
public ContinuousEffect copy() {
return new NowhereToRunWardEffect(this);
}
}

View file

@ -166,6 +166,7 @@ public final class DuskmournHouseOfHorror extends ExpansionSet {
cards.add(new SetCardInfo("Neglected Manor", 264, Rarity.COMMON, mage.cards.n.NeglectedManor.class));
cards.add(new SetCardInfo("Niko, Light of Hope", 224, Rarity.MYTHIC, mage.cards.n.NikoLightOfHope.class));
cards.add(new SetCardInfo("Norin, Swift Survivalist", 145, Rarity.UNCOMMON, mage.cards.n.NorinSwiftSurvivalist.class));
cards.add(new SetCardInfo("Nowhere to Run", 111, Rarity.UNCOMMON, mage.cards.n.NowhereToRun.class));
cards.add(new SetCardInfo("Oblivious Bookworm", 225, Rarity.UNCOMMON, mage.cards.o.ObliviousBookworm.class));
cards.add(new SetCardInfo("Omnivorous Flytrap", 192, Rarity.RARE, mage.cards.o.OmnivorousFlytrap.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Omnivorous Flytrap", 322, Rarity.RARE, mage.cards.o.OmnivorousFlytrap.class, NON_FULL_USE_VARIOUS));

View file

@ -0,0 +1,106 @@
package org.mage.test.cards.enchantments;
import mage.constants.PhaseStep;
import mage.constants.Zone;
import org.junit.Assert;
import org.junit.Test;
import org.mage.test.serverside.base.CardTestPlayerBase;
/**
* @author markort147
*/
public class NowhereToRunTest extends CardTestPlayerBase {
// Prevent ward from triggering on opponent's creatures
@Test
public void testWardPreventingOnOpponentsCreatures() {
addCard(Zone.BATTLEFIELD, playerB, "Waterfall Aerialist", 1);
addCard(Zone.BATTLEFIELD, playerA, "Plains", 1);
addCard(Zone.BATTLEFIELD, playerA, "Swamp", 1);
addCard(Zone.HAND, playerA, "Nowhere to Run", 1);
setStrictChooseMode(true);
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Nowhere to Run");
addTarget(playerA, "Waterfall Aerialist");
setStopAt(1, PhaseStep.BEGIN_COMBAT);
execute();
assertPermanentCount(playerA, "Waterfall Aerialist", 0);
}
// Does not prevent ward from triggering on own creatures
@Test
public void testWardOnOwnCreatures() {
addCard(Zone.BATTLEFIELD, playerA, "Waterfall Aerialist", 1);
addCard(Zone.BATTLEFIELD, playerA, "Nowhere to Run", 1);
addCard(Zone.HAND, playerB, "Swords to Plowshares", 1);
addCard(Zone.BATTLEFIELD, playerB, "Plains", 1);
setStrictChooseMode(true);
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerB, "Swords to Plowshares");
addTarget(playerB, "Waterfall Aerialist");
setChoice(playerB, false);
setStopAt(1, PhaseStep.BEGIN_COMBAT);
execute();
assertPermanentCount(playerA, "Waterfall Aerialist", 1);
assertGraveyardCount(playerB, "Swords to Plowshares", 1);
}
// Prevent hexproof on opponent's creatures
@Test
public void testHexproofOnCreatures() {
addCard(Zone.BATTLEFIELD, playerB, "Gladecover Scout", 1);
addCard(Zone.BATTLEFIELD, playerA, "Plains", 1);
addCard(Zone.BATTLEFIELD, playerA, "Swamp", 1);
addCard(Zone.BATTLEFIELD, playerA, "Nowhere to Run", 1);
addCard(Zone.HAND, playerA, "Go for the Throat", 1);
setStrictChooseMode(true);
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Go for the Throat");
addTarget(playerA, "Gladecover Scout");
setStopAt(1, PhaseStep.BEGIN_COMBAT);
execute();
assertPermanentCount(playerB, "Gladecover Scout", 0);
}
// Does not prevent hexproof on non-creature permanents
@Test
public void testHexproofOnOtherPermanents() {
addCard(Zone.BATTLEFIELD, playerB, "Valgavoth's Lair", 1);
setChoice(playerB, "Red");
addCard(Zone.BATTLEFIELD, playerA, "Nowhere to Run", 1);
addCard(Zone.BATTLEFIELD, playerA, "Mountain", 3);
addCard(Zone.HAND, playerA, "Stone Rain", 1);
setStrictChooseMode(true);
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Stone Rain");
addTarget(playerA, "Valgavoth's Lair");
setStopAt(1, PhaseStep.BEGIN_COMBAT);
try {
execute();
} catch (Throwable e) {
if (!e.getMessage().contains("Targets list was setup by addTarget with [Valgavoth's Lair], but not used")) {
Assert.fail("must throw error about bad targets, but got:\n" + e.getMessage());
}
return;
}
Assert.fail("must throw exception on execute");
}
}