Skip to content

Commit 8e340f8

Browse files
markort1474825764518
authored andcommitted
[DSK] Implement Nowhere to Run (magefree#13208)
* [DSK] implemented Nowhere to Run * [DSK] implemented Nowhere to Run * NowhereToRun - fixed typo in static test * NowhereToRun - fixed hexproof effect
1 parent 31ae609 commit 8e340f8

File tree

3 files changed

+235
-0
lines changed

3 files changed

+235
-0
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,128 @@
1+
package mage.cards.n;
2+
3+
import mage.abilities.Ability;
4+
import mage.abilities.common.EntersBattlefieldTriggeredAbility;
5+
import mage.abilities.common.SimpleStaticAbility;
6+
import mage.abilities.effects.AsThoughEffect;
7+
import mage.abilities.effects.AsThoughEffectImpl;
8+
import mage.abilities.effects.ContinuousEffect;
9+
import mage.abilities.effects.ContinuousRuleModifyingEffectImpl;
10+
import mage.abilities.effects.common.continuous.BoostTargetEffect;
11+
import mage.abilities.keyword.FlashAbility;
12+
import mage.abilities.keyword.WardAbility;
13+
import mage.cards.CardImpl;
14+
import mage.cards.CardSetInfo;
15+
import mage.constants.AsThoughEffectType;
16+
import mage.constants.CardType;
17+
import mage.constants.Duration;
18+
import mage.constants.Outcome;
19+
import mage.game.Game;
20+
import mage.game.events.GameEvent;
21+
import mage.game.permanent.Permanent;
22+
import mage.target.common.TargetOpponentsCreaturePermanent;
23+
24+
import java.util.UUID;
25+
26+
/**
27+
* @author markort147
28+
*/
29+
public final class NowhereToRun extends CardImpl {
30+
31+
public NowhereToRun(UUID ownerId, CardSetInfo setInfo) {
32+
super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{1}{B}");
33+
34+
// Flash
35+
this.addAbility(FlashAbility.getInstance());
36+
37+
// When Nowhere to Run enters, target creature an opponent controls gets -3/-3 until end of turn.
38+
Ability etbAbility = new EntersBattlefieldTriggeredAbility(new BoostTargetEffect(-3, -3, Duration.EndOfTurn));
39+
etbAbility.addTarget(new TargetOpponentsCreaturePermanent());
40+
this.addAbility(etbAbility);
41+
42+
// 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.
43+
Ability staticAbility = new SimpleStaticAbility(new NowhereToRunHexproofEffect());
44+
staticAbility.addEffect(new NowhereToRunWardEffect());
45+
this.addAbility(staticAbility);
46+
}
47+
48+
private NowhereToRun(final NowhereToRun card) {
49+
super(card);
50+
}
51+
52+
@Override
53+
public NowhereToRun copy() {
54+
return new NowhereToRun(this);
55+
}
56+
}
57+
58+
class NowhereToRunHexproofEffect extends AsThoughEffectImpl {
59+
60+
NowhereToRunHexproofEffect() {
61+
super(AsThoughEffectType.HEXPROOF, Duration.WhileOnBattlefield, Outcome.Benefit);
62+
staticText = "Creatures your opponents control "
63+
+ "can be the targets of spells and "
64+
+ "abilities as though they didn't "
65+
+ "have hexproof.";
66+
}
67+
68+
private NowhereToRunHexproofEffect(final NowhereToRunHexproofEffect effect) {
69+
super(effect);
70+
}
71+
72+
@Override
73+
public boolean applies(UUID sourceId, Ability source, UUID affectedControllerId, Game game) {
74+
if (affectedControllerId.equals(source.getControllerId())) {
75+
Permanent creature = game.getPermanent(sourceId);
76+
return creature != null
77+
&& creature.isCreature(game)
78+
&& game.getOpponents(source.getControllerId()).contains(creature.getControllerId());
79+
}
80+
return false;
81+
}
82+
83+
@Override
84+
public boolean apply(Game game, Ability source) {
85+
return true;
86+
}
87+
88+
@Override
89+
public AsThoughEffect copy() {
90+
return new NowhereToRunHexproofEffect(this);
91+
}
92+
}
93+
94+
class NowhereToRunWardEffect extends ContinuousRuleModifyingEffectImpl {
95+
96+
97+
NowhereToRunWardEffect() {
98+
super(Duration.WhileOnBattlefield, Outcome.Benefit);
99+
staticText = "Ward abilities of those creatures don't trigger.";
100+
}
101+
102+
private NowhereToRunWardEffect(final NowhereToRunWardEffect effect) {
103+
super(effect);
104+
}
105+
106+
@Override
107+
public boolean checksEventType(GameEvent event, Game game) {
108+
return event.getType().equals(GameEvent.EventType.NUMBER_OF_TRIGGERS);
109+
}
110+
111+
@Override
112+
public boolean applies(GameEvent event, Ability source, Game game) {
113+
Permanent permanent = game.getPermanent(event.getSourceId());
114+
if (permanent == null || !permanent.isCreature(game)) {
115+
return false;
116+
}
117+
if (!game.getOpponents(source.getControllerId()).contains(permanent.getControllerId())) {
118+
return false;
119+
}
120+
121+
return getValue("targetAbility") instanceof WardAbility;
122+
}
123+
124+
@Override
125+
public ContinuousEffect copy() {
126+
return new NowhereToRunWardEffect(this);
127+
}
128+
}

Mage.Sets/src/mage/sets/DuskmournHouseOfHorror.java

+1
Original file line numberDiff line numberDiff line change
@@ -166,6 +166,7 @@ private DuskmournHouseOfHorror() {
166166
cards.add(new SetCardInfo("Neglected Manor", 264, Rarity.COMMON, mage.cards.n.NeglectedManor.class));
167167
cards.add(new SetCardInfo("Niko, Light of Hope", 224, Rarity.MYTHIC, mage.cards.n.NikoLightOfHope.class));
168168
cards.add(new SetCardInfo("Norin, Swift Survivalist", 145, Rarity.UNCOMMON, mage.cards.n.NorinSwiftSurvivalist.class));
169+
cards.add(new SetCardInfo("Nowhere to Run", 111, Rarity.UNCOMMON, mage.cards.n.NowhereToRun.class));
169170
cards.add(new SetCardInfo("Oblivious Bookworm", 225, Rarity.UNCOMMON, mage.cards.o.ObliviousBookworm.class));
170171
cards.add(new SetCardInfo("Omnivorous Flytrap", 192, Rarity.RARE, mage.cards.o.OmnivorousFlytrap.class, NON_FULL_USE_VARIOUS));
171172
cards.add(new SetCardInfo("Omnivorous Flytrap", 322, Rarity.RARE, mage.cards.o.OmnivorousFlytrap.class, NON_FULL_USE_VARIOUS));
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,106 @@
1+
package org.mage.test.cards.enchantments;
2+
3+
import mage.constants.PhaseStep;
4+
import mage.constants.Zone;
5+
import org.junit.Assert;
6+
import org.junit.Test;
7+
import org.mage.test.serverside.base.CardTestPlayerBase;
8+
9+
/**
10+
* @author markort147
11+
*/
12+
public class NowhereToRunTest extends CardTestPlayerBase {
13+
14+
// Prevent ward from triggering on opponent's creatures
15+
@Test
16+
public void testWardPreventingOnOpponentsCreatures() {
17+
18+
addCard(Zone.BATTLEFIELD, playerB, "Waterfall Aerialist", 1);
19+
addCard(Zone.BATTLEFIELD, playerA, "Plains", 1);
20+
addCard(Zone.BATTLEFIELD, playerA, "Swamp", 1);
21+
addCard(Zone.HAND, playerA, "Nowhere to Run", 1);
22+
23+
setStrictChooseMode(true);
24+
25+
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Nowhere to Run");
26+
addTarget(playerA, "Waterfall Aerialist");
27+
28+
setStopAt(1, PhaseStep.BEGIN_COMBAT);
29+
execute();
30+
31+
assertPermanentCount(playerA, "Waterfall Aerialist", 0);
32+
}
33+
34+
// Does not prevent ward from triggering on own creatures
35+
@Test
36+
public void testWardOnOwnCreatures() {
37+
38+
addCard(Zone.BATTLEFIELD, playerA, "Waterfall Aerialist", 1);
39+
addCard(Zone.BATTLEFIELD, playerA, "Nowhere to Run", 1);
40+
addCard(Zone.HAND, playerB, "Swords to Plowshares", 1);
41+
addCard(Zone.BATTLEFIELD, playerB, "Plains", 1);
42+
43+
setStrictChooseMode(true);
44+
45+
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerB, "Swords to Plowshares");
46+
addTarget(playerB, "Waterfall Aerialist");
47+
setChoice(playerB, false);
48+
49+
setStopAt(1, PhaseStep.BEGIN_COMBAT);
50+
execute();
51+
52+
assertPermanentCount(playerA, "Waterfall Aerialist", 1);
53+
assertGraveyardCount(playerB, "Swords to Plowshares", 1);
54+
}
55+
56+
// Prevent hexproof on opponent's creatures
57+
@Test
58+
public void testHexproofOnCreatures() {
59+
60+
addCard(Zone.BATTLEFIELD, playerB, "Gladecover Scout", 1);
61+
addCard(Zone.BATTLEFIELD, playerA, "Plains", 1);
62+
addCard(Zone.BATTLEFIELD, playerA, "Swamp", 1);
63+
addCard(Zone.BATTLEFIELD, playerA, "Nowhere to Run", 1);
64+
addCard(Zone.HAND, playerA, "Go for the Throat", 1);
65+
66+
setStrictChooseMode(true);
67+
68+
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Go for the Throat");
69+
addTarget(playerA, "Gladecover Scout");
70+
71+
setStopAt(1, PhaseStep.BEGIN_COMBAT);
72+
execute();
73+
74+
assertPermanentCount(playerB, "Gladecover Scout", 0);
75+
}
76+
77+
// Does not prevent hexproof on non-creature permanents
78+
@Test
79+
public void testHexproofOnOtherPermanents() {
80+
81+
addCard(Zone.BATTLEFIELD, playerB, "Valgavoth's Lair", 1);
82+
setChoice(playerB, "Red");
83+
84+
addCard(Zone.BATTLEFIELD, playerA, "Nowhere to Run", 1);
85+
addCard(Zone.BATTLEFIELD, playerA, "Mountain", 3);
86+
addCard(Zone.HAND, playerA, "Stone Rain", 1);
87+
88+
setStrictChooseMode(true);
89+
90+
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Stone Rain");
91+
addTarget(playerA, "Valgavoth's Lair");
92+
93+
setStopAt(1, PhaseStep.BEGIN_COMBAT);
94+
95+
try {
96+
execute();
97+
} catch (Throwable e) {
98+
if (!e.getMessage().contains("Targets list was setup by addTarget with [Valgavoth's Lair], but not used")) {
99+
Assert.fail("must throw error about bad targets, but got:\n" + e.getMessage());
100+
}
101+
return;
102+
}
103+
Assert.fail("must throw exception on execute");
104+
}
105+
106+
}

0 commit comments

Comments
 (0)