-
Notifications
You must be signed in to change notification settings - Fork 784
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[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
- Loading branch information
1 parent
8772190
commit 30dac5c
Showing
3 changed files
with
235 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
106 changes: 106 additions & 0 deletions
106
Mage.Tests/src/test/java/org/mage/test/cards/enchantments/NowhereToRunTest.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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"); | ||
} | ||
|
||
} |