mirror of
https://github.com/magefree/mage.git
synced 2026-01-10 12:52:06 -08:00
[OTC] Implement Smirking Spelljacker
This commit is contained in:
parent
788fbd26e1
commit
a86b629abe
4 changed files with 188 additions and 0 deletions
129
Mage.Sets/src/mage/cards/s/SmirkingSpelljacker.java
Normal file
129
Mage.Sets/src/mage/cards/s/SmirkingSpelljacker.java
Normal file
|
|
@ -0,0 +1,129 @@
|
|||
package mage.cards.s;
|
||||
|
||||
import mage.MageInt;
|
||||
import mage.MageObject;
|
||||
import mage.abilities.Ability;
|
||||
import mage.abilities.common.AttacksTriggeredAbility;
|
||||
import mage.abilities.common.EntersBattlefieldTriggeredAbility;
|
||||
import mage.abilities.condition.Condition;
|
||||
import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility;
|
||||
import mage.abilities.effects.OneShotEffect;
|
||||
import mage.abilities.effects.common.ExileTargetEffect;
|
||||
import mage.abilities.effects.common.MayCastTargetCardEffect;
|
||||
import mage.abilities.keyword.FlashAbility;
|
||||
import mage.abilities.keyword.FlyingAbility;
|
||||
import mage.cards.CardImpl;
|
||||
import mage.cards.CardSetInfo;
|
||||
import mage.constants.*;
|
||||
import mage.filter.FilterCard;
|
||||
import mage.filter.FilterSpell;
|
||||
import mage.game.ExileZone;
|
||||
import mage.game.Game;
|
||||
import mage.players.Player;
|
||||
import mage.target.TargetCard;
|
||||
import mage.target.TargetSpell;
|
||||
import mage.target.common.TargetCardInExile;
|
||||
import mage.target.targetpointer.FixedTarget;
|
||||
import mage.util.CardUtil;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
/**
|
||||
* @author Susucr
|
||||
*/
|
||||
public final class SmirkingSpelljacker extends CardImpl {
|
||||
|
||||
private static final FilterSpell filter = new FilterSpell("spell an opponent controls");
|
||||
|
||||
static {
|
||||
filter.add(TargetController.OPPONENT.getControllerPredicate());
|
||||
}
|
||||
|
||||
public SmirkingSpelljacker(UUID ownerId, CardSetInfo setInfo) {
|
||||
super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{4}{U}");
|
||||
|
||||
this.subtype.add(SubType.DJINN);
|
||||
this.subtype.add(SubType.WIZARD);
|
||||
this.subtype.add(SubType.ROGUE);
|
||||
this.power = new MageInt(3);
|
||||
this.toughness = new MageInt(3);
|
||||
|
||||
// Flash
|
||||
this.addAbility(FlashAbility.getInstance());
|
||||
|
||||
// Flying
|
||||
this.addAbility(FlyingAbility.getInstance());
|
||||
|
||||
// When Smirking Spelljacker enters the battlefield, exile target spell an opponent controls.
|
||||
Ability ability = new EntersBattlefieldTriggeredAbility(new ExileTargetEffect().setToSourceExileZone(true));
|
||||
ability.addTarget(new TargetSpell(filter));
|
||||
this.addAbility(ability);
|
||||
|
||||
// Whenever Smirking Spelljacker attacks, if a card is exiled with it, you may cast the exiled card without paying its mana cost.
|
||||
this.addAbility(new ConditionalInterveningIfTriggeredAbility(
|
||||
new AttacksTriggeredAbility(new SmirkingSpelljackerEffect()),
|
||||
SmirkingSpelljackerCondition.instance,
|
||||
"Whenever Smirking Spelljacker attacks, if a card is exiled with it, "
|
||||
+ "you may cast the exiled card without paying its mana cost."
|
||||
));
|
||||
}
|
||||
|
||||
private SmirkingSpelljacker(final SmirkingSpelljacker card) {
|
||||
super(card);
|
||||
}
|
||||
|
||||
@Override
|
||||
public SmirkingSpelljacker copy() {
|
||||
return new SmirkingSpelljacker(this);
|
||||
}
|
||||
}
|
||||
|
||||
enum SmirkingSpelljackerCondition implements Condition {
|
||||
instance;
|
||||
|
||||
@Override
|
||||
public boolean apply(Game game, Ability source) {
|
||||
MageObject sourceObject = source.getSourceObject(game);
|
||||
ExileZone exile = game.getExile().getExileZone(CardUtil.getExileZoneId(game, sourceObject.getId(), sourceObject.getZoneChangeCounter(game)));
|
||||
return exile != null && !exile.isEmpty();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "if a card is exiled with it";
|
||||
}
|
||||
}
|
||||
|
||||
class SmirkingSpelljackerEffect extends OneShotEffect {
|
||||
|
||||
SmirkingSpelljackerEffect() {
|
||||
super(Outcome.PlayForFree);
|
||||
staticText = "you may cast the exiled card without paying its mana cost";
|
||||
}
|
||||
|
||||
private SmirkingSpelljackerEffect(final SmirkingSpelljackerEffect effect) {
|
||||
super(effect);
|
||||
}
|
||||
|
||||
@Override
|
||||
public SmirkingSpelljackerEffect copy() {
|
||||
return new SmirkingSpelljackerEffect(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean apply(Game game, Ability source) {
|
||||
Player controller = game.getPlayer(source.getControllerId());
|
||||
if (controller == null) {
|
||||
return false;
|
||||
}
|
||||
FilterCard filter = new FilterCard("card exiled with " + CardUtil.getSourceLogName(game, source));
|
||||
TargetCard target = new TargetCardInExile(1, 1, filter, CardUtil.getExileZoneId(game, source));
|
||||
target.withNotTarget(true);
|
||||
controller.choose(Outcome.PlayForFree, target, source, game);
|
||||
new MayCastTargetCardEffect(CastManaAdjustment.WITHOUT_PAYING_MANA_COST)
|
||||
.setTargetPointer(new FixedTarget(target.getFirstTarget()))
|
||||
.apply(game, source);
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -237,6 +237,7 @@ public final class OutlawsOfThunderJunctionCommander extends ExpansionSet {
|
|||
cards.add(new SetCardInfo("Siphon Insight", 242, Rarity.RARE, mage.cards.s.SiphonInsight.class));
|
||||
cards.add(new SetCardInfo("Skullwinder", 207, Rarity.UNCOMMON, mage.cards.s.Skullwinder.class));
|
||||
cards.add(new SetCardInfo("Slither Blade", 114, Rarity.COMMON, mage.cards.s.SlitherBlade.class));
|
||||
cards.add(new SetCardInfo("Smirking Spelljacker", 16, Rarity.RARE, mage.cards.s.SmirkingSpelljacker.class));
|
||||
cards.add(new SetCardInfo("Smoldering Marsh", 321, Rarity.RARE, mage.cards.s.SmolderingMarsh.class));
|
||||
cards.add(new SetCardInfo("Sol Ring", 267, Rarity.UNCOMMON, mage.cards.s.SolRing.class));
|
||||
cards.add(new SetCardInfo("Springbloom Druid", 208, Rarity.COMMON, mage.cards.s.SpringbloomDruid.class));
|
||||
|
|
|
|||
|
|
@ -0,0 +1,51 @@
|
|||
package org.mage.test.cards.single.otc;
|
||||
|
||||
import mage.constants.PhaseStep;
|
||||
import mage.constants.Zone;
|
||||
import org.junit.Test;
|
||||
import org.mage.test.serverside.base.CardTestPlayerBase;
|
||||
|
||||
/**
|
||||
* @author Susucr
|
||||
*/
|
||||
public class SmirkingSpelljackerTest extends CardTestPlayerBase {
|
||||
|
||||
/**
|
||||
* {@link mage.cards.s.SmirkingSpelljacker Smirking Spelljacker} {4}{U}
|
||||
* Creature — Djinn Wizard Rogue
|
||||
* Flash
|
||||
* Flying
|
||||
* When Smirking Spelljacker enters the battlefield, exile target spell an opponent controls.
|
||||
* Whenever Smirking Spelljacker attacks, if a card is exiled with it, you may cast the exiled card without paying its mana cost.
|
||||
* 3/3
|
||||
*/
|
||||
private static final String spelljacker = "Smirking Spelljacker";
|
||||
|
||||
@Test
|
||||
public void test_Simple() {
|
||||
setStrictChooseMode(true);
|
||||
|
||||
addCard(Zone.HAND, playerB, spelljacker);
|
||||
addCard(Zone.HAND, playerA, "Lightning Bolt", 1);
|
||||
addCard(Zone.BATTLEFIELD, playerB, "Island", 5);
|
||||
addCard(Zone.BATTLEFIELD, playerA, "Mountain");
|
||||
|
||||
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Lightning Bolt", playerB);
|
||||
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerB, spelljacker);
|
||||
addTarget(playerB, "Lightning Bolt");
|
||||
|
||||
checkExileCount("Bolt in exile", 1, PhaseStep.POSTCOMBAT_MAIN, playerB, "Lightning Bolt", 1);
|
||||
|
||||
attack(2, playerB, spelljacker, playerA);
|
||||
setChoice(playerB, "Lightning Bolt"); // choosing bolt
|
||||
setChoice(playerB, true); // yes to cast bolt
|
||||
addTarget(playerB, playerA); // target for bolt
|
||||
|
||||
setStopAt(2, PhaseStep.END_COMBAT);
|
||||
execute();
|
||||
|
||||
assertLife(playerA, 20 - 3 - 3); // 3 from bolt, 3 from spelljacker
|
||||
assertPermanentCount(playerB, spelljacker, 1);
|
||||
assertGraveyardCount(playerA, "Lightning Bolt", 1);
|
||||
}
|
||||
}
|
||||
|
|
@ -34,6 +34,13 @@ public class MayCastTargetCardEffect extends OneShotEffect {
|
|||
this(CastManaAdjustment.NONE, thenExile);
|
||||
}
|
||||
|
||||
/**
|
||||
* Allows to cast the target card immediately, either for its cost or with a modifier (like for free, or mana as any type).
|
||||
*/
|
||||
public MayCastTargetCardEffect(CastManaAdjustment manaAdjustment) {
|
||||
this(manaAdjustment, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Allows to cast the target card immediately, either for its cost or with a modifier (like for free, or mana as any type).
|
||||
*/
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue