mirror of
https://github.com/correl/mage.git
synced 2024-11-25 03:00:11 +00:00
[CLB] Implemented Gale, Waterdeep Prodigy (#9423)
This commit is contained in:
parent
6464b84c3f
commit
3c3ba6f5a9
3 changed files with 252 additions and 0 deletions
190
Mage.Sets/src/mage/cards/g/GaleWaterdeepProdigy.java
Normal file
190
Mage.Sets/src/mage/cards/g/GaleWaterdeepProdigy.java
Normal file
|
@ -0,0 +1,190 @@
|
||||||
|
package mage.cards.g;
|
||||||
|
|
||||||
|
import mage.ApprovingObject;
|
||||||
|
import mage.MageInt;
|
||||||
|
import mage.abilities.Ability;
|
||||||
|
import mage.abilities.common.ChooseABackgroundAbility;
|
||||||
|
import mage.abilities.common.SpellCastControllerTriggeredAbility;
|
||||||
|
import mage.abilities.effects.ContinuousEffect;
|
||||||
|
import mage.abilities.effects.OneShotEffect;
|
||||||
|
import mage.abilities.effects.ReplacementEffectImpl;
|
||||||
|
import mage.cards.Card;
|
||||||
|
import mage.cards.CardImpl;
|
||||||
|
import mage.cards.CardSetInfo;
|
||||||
|
import mage.constants.*;
|
||||||
|
import mage.filter.FilterCard;
|
||||||
|
import mage.filter.common.FilterInstantOrSorcerySpell;
|
||||||
|
import mage.game.Game;
|
||||||
|
import mage.game.events.GameEvent;
|
||||||
|
import mage.game.events.ZoneChangeEvent;
|
||||||
|
import mage.game.stack.Spell;
|
||||||
|
import mage.players.Player;
|
||||||
|
import mage.target.common.TargetCardInYourGraveyard;
|
||||||
|
import mage.target.targetpointer.FixedTarget;
|
||||||
|
import mage.watchers.common.CastFromHandWatcher;
|
||||||
|
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Rjayz
|
||||||
|
*/
|
||||||
|
public final class GaleWaterdeepProdigy extends CardImpl {
|
||||||
|
|
||||||
|
public GaleWaterdeepProdigy(UUID ownerId, CardSetInfo setInfo) {
|
||||||
|
super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{U}");
|
||||||
|
|
||||||
|
this.addSuperType(SuperType.LEGENDARY);
|
||||||
|
this.subtype.add(SubType.HUMAN);
|
||||||
|
this.subtype.add(SubType.WIZARD);
|
||||||
|
this.power = new MageInt(1);
|
||||||
|
this.toughness = new MageInt(3);
|
||||||
|
|
||||||
|
// Whenever you cast an instant or sorcery spell from your hand,
|
||||||
|
// you may cast up to one of the other type from your graveyard.
|
||||||
|
// If a spell cast from your graveyard this way would be put into your graveyard, exile it instead.
|
||||||
|
this.addAbility(new GaleWaterdeepProdigyTriggeredAbility());
|
||||||
|
|
||||||
|
// Choose a Background
|
||||||
|
this.addAbility(ChooseABackgroundAbility.getInstance());
|
||||||
|
}
|
||||||
|
|
||||||
|
private GaleWaterdeepProdigy(final GaleWaterdeepProdigy card) {
|
||||||
|
super(card);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public GaleWaterdeepProdigy copy() {
|
||||||
|
return new GaleWaterdeepProdigy(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class GaleWaterdeepProdigyTriggeredAbility extends SpellCastControllerTriggeredAbility {
|
||||||
|
|
||||||
|
private static final FilterCard SORCERY_FILTER = new FilterCard("a sorcery card in your graveyard");
|
||||||
|
private static final FilterCard INSTANT_FILTER = new FilterCard("an instant card in your graveyard");
|
||||||
|
|
||||||
|
static {
|
||||||
|
SORCERY_FILTER.add(CardType.SORCERY.getPredicate());
|
||||||
|
INSTANT_FILTER.add(CardType.INSTANT.getPredicate());
|
||||||
|
}
|
||||||
|
|
||||||
|
public GaleWaterdeepProdigyTriggeredAbility() {
|
||||||
|
super(new GaleWaterdeepProdigyEffect(),
|
||||||
|
new FilterInstantOrSorcerySpell("an instant or sorcery spell from your hand"),
|
||||||
|
false);
|
||||||
|
addWatcher(new CastFromHandWatcher());
|
||||||
|
}
|
||||||
|
|
||||||
|
public GaleWaterdeepProdigyTriggeredAbility(GaleWaterdeepProdigyTriggeredAbility ability) {
|
||||||
|
super(ability);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean checkTrigger(GameEvent event, Game game) {
|
||||||
|
if (!super.checkTrigger(event, game)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
CastFromHandWatcher watcher = game.getState().getWatcher(CastFromHandWatcher.class);
|
||||||
|
if (watcher == null || !watcher.spellWasCastFromHand(event.getSourceId())) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
Spell spell = game.getState().getStack().getSpell(event.getSourceId());
|
||||||
|
if (spell == null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
FilterCard filterCard;
|
||||||
|
if (spell.isSorcery()) {
|
||||||
|
filterCard = INSTANT_FILTER;
|
||||||
|
} else {
|
||||||
|
filterCard = SORCERY_FILTER;
|
||||||
|
}
|
||||||
|
this.getTargets().clear();
|
||||||
|
this.getTargets().add(new TargetCardInYourGraveyard(filterCard));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public GaleWaterdeepProdigyTriggeredAbility copy() {
|
||||||
|
return new GaleWaterdeepProdigyTriggeredAbility(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class GaleWaterdeepProdigyEffect extends OneShotEffect {
|
||||||
|
|
||||||
|
GaleWaterdeepProdigyEffect() {
|
||||||
|
super(Outcome.PutCardInPlay);
|
||||||
|
this.staticText = "you may cast up to one of the other type from your graveyard. " +
|
||||||
|
"If a spell cast from your graveyard this way would be put into your graveyard, exile it instead.";
|
||||||
|
}
|
||||||
|
|
||||||
|
private GaleWaterdeepProdigyEffect(final GaleWaterdeepProdigyEffect effect) {
|
||||||
|
super(effect);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public GaleWaterdeepProdigyEffect copy() {
|
||||||
|
return new GaleWaterdeepProdigyEffect(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean apply(Game game, Ability source) {
|
||||||
|
Player controller = game.getPlayer(source.getControllerId());
|
||||||
|
if (controller == null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
Card card = game.getCard(this.getTargetPointer().getFirst(game, source));
|
||||||
|
if (card != null
|
||||||
|
&& controller.chooseUse(Outcome.Neutral, "Cast " + card.getLogName() + '?', source, game)) {
|
||||||
|
game.getState().setValue("PlayFromNotOwnHandZone" + card.getId(), Boolean.TRUE);
|
||||||
|
controller.cast(controller.chooseAbilityForCast(card, game, false),
|
||||||
|
game, false, new ApprovingObject(source, game));
|
||||||
|
game.getState().setValue("PlayFromNotOwnHandZone" + card.getId(), null);
|
||||||
|
ContinuousEffect effect = new GaleWaterdeepProdigyReplacementEffect(card.getId());
|
||||||
|
effect.setTargetPointer(new FixedTarget(card.getId(), game.getState().getZoneChangeCounter(card.getId())));
|
||||||
|
game.addEffect(effect, source);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class GaleWaterdeepProdigyReplacementEffect extends ReplacementEffectImpl {
|
||||||
|
|
||||||
|
private final UUID cardId;
|
||||||
|
|
||||||
|
GaleWaterdeepProdigyReplacementEffect(UUID cardId) {
|
||||||
|
super(Duration.EndOfTurn, Outcome.Exile);
|
||||||
|
this.cardId = cardId;
|
||||||
|
staticText = "If a spell cast from your graveyard this way would be put into your graveyard, exile it instead.";
|
||||||
|
}
|
||||||
|
|
||||||
|
private GaleWaterdeepProdigyReplacementEffect(final GaleWaterdeepProdigyReplacementEffect effect) {
|
||||||
|
super(effect);
|
||||||
|
this.cardId = effect.cardId;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public GaleWaterdeepProdigyReplacementEffect copy() {
|
||||||
|
return new GaleWaterdeepProdigyReplacementEffect(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean replaceEvent(GameEvent event, Ability source, Game game) {
|
||||||
|
((ZoneChangeEvent) event).setToZone(Zone.EXILED);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean checksEventType(GameEvent event, Game game) {
|
||||||
|
return event.getType() == GameEvent.EventType.ZONE_CHANGE;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean applies(GameEvent event, Ability source, Game game) {
|
||||||
|
ZoneChangeEvent zEvent = (ZoneChangeEvent) event;
|
||||||
|
return zEvent.getToZone() == Zone.GRAVEYARD
|
||||||
|
&& zEvent.getTargetId().equals(this.cardId);
|
||||||
|
}
|
||||||
|
}
|
|
@ -250,6 +250,7 @@ public final class CommanderLegendsBattleForBaldursGate extends ExpansionSet {
|
||||||
cards.add(new SetCardInfo("Fraying Line", 314, Rarity.RARE, mage.cards.f.FrayingLine.class));
|
cards.add(new SetCardInfo("Fraying Line", 314, Rarity.RARE, mage.cards.f.FrayingLine.class));
|
||||||
cards.add(new SetCardInfo("From the Catacombs", 671, Rarity.RARE, mage.cards.f.FromTheCatacombs.class));
|
cards.add(new SetCardInfo("From the Catacombs", 671, Rarity.RARE, mage.cards.f.FromTheCatacombs.class));
|
||||||
cards.add(new SetCardInfo("Frontline Medic", 693, Rarity.RARE, mage.cards.f.FrontlineMedic.class));
|
cards.add(new SetCardInfo("Frontline Medic", 693, Rarity.RARE, mage.cards.f.FrontlineMedic.class));
|
||||||
|
cards.add(new SetCardInfo("Gale, Waterdeep Prodigy", 72, Rarity.RARE, mage.cards.g.GaleWaterdeepProdigy.class));
|
||||||
cards.add(new SetCardInfo("Gale's Redirection", 73, Rarity.RARE, mage.cards.g.GalesRedirection.class));
|
cards.add(new SetCardInfo("Gale's Redirection", 73, Rarity.RARE, mage.cards.g.GalesRedirection.class));
|
||||||
cards.add(new SetCardInfo("Galepowder Mage", 694, Rarity.RARE, mage.cards.g.GalepowderMage.class));
|
cards.add(new SetCardInfo("Galepowder Mage", 694, Rarity.RARE, mage.cards.g.GalepowderMage.class));
|
||||||
cards.add(new SetCardInfo("Game Trail", 894, Rarity.RARE, mage.cards.g.GameTrail.class));
|
cards.add(new SetCardInfo("Game Trail", 894, Rarity.RARE, mage.cards.g.GameTrail.class));
|
||||||
|
|
|
@ -0,0 +1,61 @@
|
||||||
|
package org.mage.test.cards.single.clb;
|
||||||
|
|
||||||
|
import mage.constants.PhaseStep;
|
||||||
|
import mage.constants.Zone;
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.mage.test.serverside.base.CardTestPlayerBase;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Rjayz
|
||||||
|
*/
|
||||||
|
public class GaleWaterdeepProdigyTest extends CardTestPlayerBase {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void TestGaleWaterDeepProdigy() {
|
||||||
|
addCard(Zone.BATTLEFIELD, playerA, "Island", 10);
|
||||||
|
addCard(Zone.BATTLEFIELD, playerA, "Mountain", 10);
|
||||||
|
|
||||||
|
// Whenever you cast an instant or sorcery spell from your hand, you may cast up to one of the other type from your graveyard.
|
||||||
|
// If a spell cast from your graveyard this way would be put into your graveyard, exile it instead.
|
||||||
|
addCard(Zone.BATTLEFIELD, playerA, "Gale, Waterdeep Prodigy", 1);
|
||||||
|
|
||||||
|
// Draw two cards, sorcery
|
||||||
|
addCard(Zone.HAND, playerA, "Divination");
|
||||||
|
// Deal three damage to any target, instant
|
||||||
|
addCard(Zone.GRAVEYARD, playerA, "Lightning Bolt");
|
||||||
|
|
||||||
|
playerA.getLibrary().clear();
|
||||||
|
addCard(Zone.LIBRARY, playerA, "Island");
|
||||||
|
addCard(Zone.LIBRARY, playerA, "Island");
|
||||||
|
skipInitShuffling();
|
||||||
|
|
||||||
|
setStrictChooseMode(true);
|
||||||
|
|
||||||
|
// Cast Divination from hand,
|
||||||
|
// this will trigger Gale's ability and let playerA cast an instant from their graveyard
|
||||||
|
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Divination", true);
|
||||||
|
// Target Lightning Bolt in graveyard with Gale's ability
|
||||||
|
addTarget(playerA, "Lightning Bolt");
|
||||||
|
// Choose to cast Lightning Bolt when prompted
|
||||||
|
setChoice(playerA, true);
|
||||||
|
// Target opponent with Lightning bolt
|
||||||
|
addTarget(playerA, playerB);
|
||||||
|
|
||||||
|
execute();
|
||||||
|
|
||||||
|
// Assert Divination was cast from hand
|
||||||
|
assertHandCount(playerA, 2);
|
||||||
|
assertHandCount(playerA, "Island", 2);
|
||||||
|
assertLibraryCount(playerA, 0);
|
||||||
|
assertGraveyardCount(playerA, 1);
|
||||||
|
assertGraveyardCount(playerA, "Divination", 1);
|
||||||
|
|
||||||
|
// Assert Lightning Bolt was cast from graveyard,
|
||||||
|
// and afterwards exiled instead of being put back into the graveyard
|
||||||
|
assertExileCount(playerA, 1);
|
||||||
|
assertExileCount(playerA, "Lightning Bolt", 1);
|
||||||
|
|
||||||
|
// Assert opponent was targeted by Lightning Bolt
|
||||||
|
assertLife(playerB, 17);
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in a new issue