Implemented Unpredictable Cyclone

This commit is contained in:
Evan Kranzler 2020-04-13 22:15:18 -04:00
parent a5fb946fb3
commit a689646735
4 changed files with 151 additions and 6 deletions

View file

@ -0,0 +1,108 @@
package mage.cards.u;
import mage.MageObjectReference;
import mage.abilities.Ability;
import mage.abilities.common.SimpleStaticAbility;
import mage.abilities.costs.mana.ManaCostsImpl;
import mage.abilities.effects.ReplacementEffectImpl;
import mage.abilities.keyword.CyclingAbility;
import mage.cards.*;
import mage.constants.CardType;
import mage.constants.Duration;
import mage.constants.Outcome;
import mage.constants.Zone;
import mage.game.Game;
import mage.game.events.GameEvent;
import mage.players.Player;
import java.util.UUID;
/**
* @author TheElk801
*/
public final class UnpredictableCyclone extends CardImpl {
public UnpredictableCyclone(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{3}{R}{R}");
// If a cycling ability of another nonland card would cause you to draw a card, instead exile cards from the top of your library until you exile a card that shares a card type with the cycled card. You may cast that card without paying its mana cost. Then put the exiled cards that weren't cast this way on the bottom of your library in a random order.
this.addAbility(new SimpleStaticAbility(new ArchmageAscensionReplacementEffect()));
// Cycling {2}
this.addAbility(new CyclingAbility(new ManaCostsImpl("{2}")));
}
private UnpredictableCyclone(final UnpredictableCyclone card) {
super(card);
}
@Override
public UnpredictableCyclone copy() {
return new UnpredictableCyclone(this);
}
}
class ArchmageAscensionReplacementEffect extends ReplacementEffectImpl {
ArchmageAscensionReplacementEffect() {
super(Duration.WhileOnBattlefield, Outcome.Benefit);
staticText = "If a cycling ability of another nonland card would cause you to draw a card, " +
"instead exile cards from the top of your library until you exile a card " +
"that shares a card type with the cycled card. You may cast that card without paying its mana cost. " +
"Then put the exiled cards that weren't cast this way on the bottom of your library in a random order.";
}
private ArchmageAscensionReplacementEffect(final ArchmageAscensionReplacementEffect effect) {
super(effect);
}
@Override
public ArchmageAscensionReplacementEffect copy() {
return new ArchmageAscensionReplacementEffect(this);
}
@Override
public boolean apply(Game game, Ability source) {
return true;
}
@Override
public boolean replaceEvent(GameEvent event, Ability source, Game game) {
Player player = game.getPlayer(event.getPlayerId());
Card sourceCard = game.getCard(event.getSourceId());
if (player == null || sourceCard == null || sourceCard.isLand()) {
return false;
}
Cards cards = new CardsImpl();
Card toCast = null;
for (Card card : player.getLibrary().getCards(game)) {
cards.add(card);
if (card.getCardType().stream().anyMatch(sourceCard.getCardType()::contains)) {
toCast = card;
break;
}
}
player.moveCards(cards, Zone.EXILED, source, game);
if (toCast != null && player.chooseUse(outcome, "Cast the exiled card?", source, game)) {
game.getState().setValue("PlayFromNotOwnHandZone" + toCast.getId(), Boolean.TRUE);
Boolean cardWasCast = player.cast(player.chooseAbilityForCast(toCast, game, true),
game, true, new MageObjectReference(source.getSourceObject(game), game));
game.getState().setValue("PlayFromNotOwnHandZone" + toCast.getId(), null);
if (cardWasCast) {
cards.remove(toCast);
}
}
player.putCardsOnBottomOfLibrary(cards, game, source, false);
return true;
}
@Override
public boolean checksEventType(GameEvent event, Game game) {
return event.getType() == GameEvent.EventType.CYCLE_DRAW;
}
@Override
public boolean applies(GameEvent event, Ability source, Game game) {
return event.getPlayerId().equals(source.getControllerId());
}
}

View file

@ -307,6 +307,7 @@ public final class IkoriaLairOfBehemoths extends ExpansionSet {
cards.add(new SetCardInfo("Unbreakable Bond", 101, Rarity.UNCOMMON, mage.cards.u.UnbreakableBond.class)); cards.add(new SetCardInfo("Unbreakable Bond", 101, Rarity.UNCOMMON, mage.cards.u.UnbreakableBond.class));
cards.add(new SetCardInfo("Unexpected Fangs", 102, Rarity.COMMON, mage.cards.u.UnexpectedFangs.class)); cards.add(new SetCardInfo("Unexpected Fangs", 102, Rarity.COMMON, mage.cards.u.UnexpectedFangs.class));
cards.add(new SetCardInfo("Unlikely Aid", 103, Rarity.COMMON, mage.cards.u.UnlikelyAid.class)); cards.add(new SetCardInfo("Unlikely Aid", 103, Rarity.COMMON, mage.cards.u.UnlikelyAid.class));
cards.add(new SetCardInfo("Unpredictable Cyclone", 139, Rarity.RARE, mage.cards.u.UnpredictableCyclone.class));
cards.add(new SetCardInfo("Vadrok, Apex of Thunder", 214, Rarity.MYTHIC, mage.cards.v.VadrokApexOfThunder.class)); cards.add(new SetCardInfo("Vadrok, Apex of Thunder", 214, Rarity.MYTHIC, mage.cards.v.VadrokApexOfThunder.class));
cards.add(new SetCardInfo("Vivien, Monsters' Advocate", 175, Rarity.MYTHIC, mage.cards.v.VivienMonstersAdvocate.class)); cards.add(new SetCardInfo("Vivien, Monsters' Advocate", 175, Rarity.MYTHIC, mage.cards.v.VivienMonstersAdvocate.class));
cards.add(new SetCardInfo("Void Beckoner", 104, Rarity.UNCOMMON, mage.cards.v.VoidBeckoner.class)); cards.add(new SetCardInfo("Void Beckoner", 104, Rarity.UNCOMMON, mage.cards.v.VoidBeckoner.class));

View file

@ -1,18 +1,21 @@
package mage.abilities.keyword; package mage.abilities.keyword;
import mage.abilities.Ability;
import mage.abilities.ActivatedAbilityImpl; import mage.abilities.ActivatedAbilityImpl;
import mage.abilities.costs.Cost; import mage.abilities.costs.Cost;
import mage.abilities.costs.common.CyclingDiscardCost; import mage.abilities.costs.common.CyclingDiscardCost;
import mage.abilities.costs.mana.ManaCost; import mage.abilities.costs.mana.ManaCost;
import mage.abilities.effects.common.DrawCardSourceControllerEffect; import mage.abilities.effects.OneShotEffect;
import mage.abilities.effects.common.search.SearchLibraryPutInHandEffect; import mage.abilities.effects.common.search.SearchLibraryPutInHandEffect;
import mage.constants.Outcome;
import mage.constants.Zone; import mage.constants.Zone;
import mage.filter.FilterCard; import mage.filter.FilterCard;
import mage.game.Game;
import mage.game.events.GameEvent;
import mage.players.Player;
import mage.target.common.TargetCardInLibrary; import mage.target.common.TargetCardInLibrary;
/** /**
*
* @author BetaSteward_at_googlemail.com * @author BetaSteward_at_googlemail.com
*/ */
public class CyclingAbility extends ActivatedAbilityImpl { public class CyclingAbility extends ActivatedAbilityImpl {
@ -21,7 +24,7 @@ public class CyclingAbility extends ActivatedAbilityImpl {
private final String text; private final String text;
public CyclingAbility(Cost cost) { public CyclingAbility(Cost cost) {
super(Zone.HAND, new DrawCardSourceControllerEffect(1), cost); super(Zone.HAND, new CyclingDrawEffect(), cost);
this.addCost(new CyclingDiscardCost()); this.addCost(new CyclingDiscardCost());
this.cost = cost; this.cost = cost;
this.text = "Cycling"; this.text = "Cycling";
@ -56,5 +59,38 @@ public class CyclingAbility extends ActivatedAbilityImpl {
rule.append(cost.getText()).append(" <i>(").append(super.getRule(true)).append(")</i>"); rule.append(cost.getText()).append(" <i>(").append(super.getRule(true)).append(")</i>");
return rule.toString(); return rule.toString();
} }
}
class CyclingDrawEffect extends OneShotEffect {
CyclingDrawEffect() {
super(Outcome.Benefit);
staticText = "draw a card";
}
private CyclingDrawEffect(final CyclingDrawEffect effect) {
super(effect);
}
@Override
public CyclingDrawEffect copy() {
return new CyclingDrawEffect(this);
}
@Override
public boolean apply(Game game, Ability source) {
Player player = game.getPlayer(source.getSourceId());
if (player == null) {
return false;
}
GameEvent event = GameEvent.getEvent(
GameEvent.EventType.CYCLE_DRAW, source.getSourceId(),
source.getSourceId(), source.getControllerId()
);
if (game.replaceEvent(event)) {
return true;
}
player.drawCards(1, game);
return true;
}
} }

View file

@ -85,7 +85,7 @@ public class GameEvent implements Serializable {
CONVOKED, CONVOKED,
DISCARD_CARD, DISCARD_CARD,
DISCARDED_CARD, DISCARDED_CARD,
CYCLE_CARD, CYCLED_CARD, CYCLE_CARD, CYCLED_CARD, CYCLE_DRAW,
CLASH, CLASHED, CLASH, CLASHED,
DAMAGE_PLAYER, DAMAGE_PLAYER,
/* DAMAGED_PLAYER /* DAMAGED_PLAYER