[DMU] Implemented Sphinx of Clear Skies (#9474)

* create common class for effects similar to Fact or Fiction

* [DMU] Implemented Sphinx of Clear Skies

* change text generation to staticText
This commit is contained in:
Evan Kranzler 2022-09-05 16:14:16 -04:00 committed by GitHub
parent e92b8ce99a
commit 02968c9cc1
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
9 changed files with 281 additions and 663 deletions

View file

@ -1,23 +1,16 @@
package mage.cards.e; package mage.cards.e;
import mage.MageObject; import mage.abilities.dynamicvalue.AdditiveDynamicValue;
import mage.abilities.Ability; import mage.abilities.dynamicvalue.DynamicValue;
import mage.abilities.effects.OneShotEffect; import mage.abilities.dynamicvalue.common.ManacostVariableValue;
import mage.cards.*; import mage.abilities.dynamicvalue.common.StaticValue;
import mage.abilities.effects.common.RevealAndSeparatePilesEffect;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType; import mage.constants.CardType;
import mage.constants.Outcome; import mage.constants.TargetController;
import mage.constants.Zone; import mage.constants.Zone;
import mage.filter.FilterCard;
import mage.game.Game;
import mage.players.Player;
import mage.target.Target;
import mage.target.TargetCard;
import mage.target.common.TargetOpponent;
import mage.util.GameLog;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import java.util.UUID; import java.util.UUID;
/** /**
@ -25,11 +18,16 @@ import java.util.UUID;
*/ */
public final class EpiphanyAtTheDrownyard extends CardImpl { public final class EpiphanyAtTheDrownyard extends CardImpl {
private static final DynamicValue xValue = new AdditiveDynamicValue(ManacostVariableValue.REGULAR, StaticValue.get(1));
public EpiphanyAtTheDrownyard(UUID ownerId, CardSetInfo setInfo) { public EpiphanyAtTheDrownyard(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{X}{U}"); super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{X}{U}");
// Reveal the top X plus one cards of your library and separate them into two piles. An opponent chooses one of those piles. Put that pile into your hand and the other into your graveyard. // Reveal the top X plus one cards of your library and separate them into two piles. An opponent chooses one of those piles. Put that pile into your hand and the other into your graveyard.
this.getSpellAbility().addEffect(new EpiphanyAtTheDrownyardEffect()); this.getSpellAbility().addEffect(new RevealAndSeparatePilesEffect(
xValue, TargetController.YOU, TargetController.OPPONENT, Zone.GRAVEYARD
).setText("reveal the top X plus one cards of your library and separate them into two piles. " +
"An opponent chooses one of those piles. Put that pile into your hand and the other into your graveyard"));
} }
private EpiphanyAtTheDrownyard(final EpiphanyAtTheDrownyard card) { private EpiphanyAtTheDrownyard(final EpiphanyAtTheDrownyard card) {
@ -41,108 +39,3 @@ public final class EpiphanyAtTheDrownyard extends CardImpl {
return new EpiphanyAtTheDrownyard(this); return new EpiphanyAtTheDrownyard(this);
} }
} }
class EpiphanyAtTheDrownyardEffect extends OneShotEffect {
EpiphanyAtTheDrownyardEffect() {
super(Outcome.DrawCard);
this.staticText = "Reveal the top X plus one cards of your library and separate them into two piles. An opponent chooses one of those piles. Put that pile into your hand and the other into your graveyard";
}
private EpiphanyAtTheDrownyardEffect(final EpiphanyAtTheDrownyardEffect effect) {
super(effect);
}
@Override
public EpiphanyAtTheDrownyardEffect copy() {
return new EpiphanyAtTheDrownyardEffect(this);
}
@Override
public boolean apply(Game game, Ability source) {
Player controller = game.getPlayer(source.getControllerId());
MageObject sourceObject = game.getObject(source);
if (controller == null || sourceObject == null) {
return false;
}
Cards cards = new CardsImpl(controller.getLibrary().getTopCards(game, source.getManaCostsToPay().getX() + 1));
controller.revealCards(sourceObject.getIdName(), cards, game);
Player opponent;
Set<UUID> opponents = game.getOpponents(controller.getId());
if (opponents.size() == 1) {
opponent = game.getPlayer(opponents.iterator().next());
} else {
Target target = new TargetOpponent(true);
controller.chooseTarget(Outcome.Detriment, target, source, game);
opponent = game.getPlayer(target.getFirstTarget());
}
if (opponent != null) {
TargetCard target = new TargetCard(0, cards.size(), Zone.LIBRARY, new FilterCard("cards to put in the first pile"));
List<Card> pile1 = new ArrayList<>();
Cards pile1CardsIds = new CardsImpl();
target.setRequired(false);
if (controller.choose(Outcome.Neutral, cards, target, game)) {
List<UUID> targets = target.getTargets();
for (UUID targetId : targets) {
Card card = game.getCard(targetId);
if (card != null) {
pile1.add(card);
pile1CardsIds.add(card.getId());
}
}
}
List<Card> pile2 = new ArrayList<>();
Cards pile2CardsIds = new CardsImpl();
for (UUID cardId : cards) {
Card card = game.getCard(cardId);
if (card != null && !pile1.contains(card)) {
pile2.add(card);
pile2CardsIds.add(card.getId());
}
}
boolean choice = opponent.choosePile(Outcome.Detriment, "Choose a pile to put into " + controller.getName() + "'s hand.", pile1, pile2, game);
Zone pile1Zone = Zone.GRAVEYARD;
Zone pile2Zone = Zone.HAND;
if (choice) {
pile1Zone = Zone.HAND;
pile2Zone = Zone.GRAVEYARD;
}
StringBuilder sb = new StringBuilder(sourceObject.getLogName() + ": Pile 1, going to ").append(pile1Zone == Zone.HAND ? "Hand" : "Graveyard").append(": ");
int i = 0;
for (UUID cardUuid : pile1CardsIds) {
i++;
Card card = game.getCard(cardUuid);
if (card != null) {
sb.append(GameLog.getColoredObjectName(card));
if (i < pile1CardsIds.size()) {
sb.append(", ");
}
}
}
controller.moveCards(new CardsImpl(pile1CardsIds), pile1Zone, source, game);
game.informPlayers(sb.toString());
sb = new StringBuilder(sourceObject.getLogName() + ": Pile 2, going to ").append(pile2Zone == Zone.HAND ? "Hand" : "Graveyard").append(':');
i = 0;
for (UUID cardUuid : pile2CardsIds) {
Card card = game.getCard(cardUuid);
if (card != null) {
i++;
sb.append(' ').append(GameLog.getColoredObjectName(card));
if (i < pile2CardsIds.size()) {
sb.append(", ");
}
}
}
controller.moveCards(new CardsImpl(pile2CardsIds), pile2Zone, source, game);
game.informPlayers(sb.toString());
}
return true;
}
}

View file

@ -1,22 +1,12 @@
package mage.cards.f; package mage.cards.f;
import mage.MageObject; import mage.abilities.effects.common.RevealAndSeparatePilesEffect;
import mage.abilities.Ability; import mage.cards.CardImpl;
import mage.abilities.effects.OneShotEffect; import mage.cards.CardSetInfo;
import mage.cards.*;
import mage.constants.CardType; import mage.constants.CardType;
import mage.constants.Outcome; import mage.constants.TargetController;
import mage.constants.Zone; import mage.constants.Zone;
import mage.filter.FilterCard;
import mage.game.Game;
import mage.players.Player;
import mage.target.Target;
import mage.target.TargetCard;
import mage.target.common.TargetOpponent;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import java.util.UUID; import java.util.UUID;
/** /**
@ -28,7 +18,9 @@ public final class FactOrFiction extends CardImpl {
super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{3}{U}"); super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{3}{U}");
// Reveal the top five cards of your library. An opponent separates those cards into two piles. Put one pile into your hand and the other into your graveyard. // Reveal the top five cards of your library. An opponent separates those cards into two piles. Put one pile into your hand and the other into your graveyard.
this.getSpellAbility().addEffect(new FactOrFictionEffect()); this.getSpellAbility().addEffect(new RevealAndSeparatePilesEffect(
5, TargetController.OPPONENT, TargetController.YOU, Zone.GRAVEYARD
));
} }
private FactOrFiction(final FactOrFiction card) { private FactOrFiction(final FactOrFiction card) {
@ -40,97 +32,3 @@ public final class FactOrFiction extends CardImpl {
return new FactOrFiction(this); return new FactOrFiction(this);
} }
} }
class FactOrFictionEffect extends OneShotEffect {
FactOrFictionEffect() {
super(Outcome.DrawCard);
this.staticText = "Reveal the top five cards of your library. An opponent separates those cards into two piles. Put one pile into your hand and the other into your graveyard";
}
private FactOrFictionEffect(final FactOrFictionEffect effect) {
super(effect);
}
@Override
public FactOrFictionEffect copy() {
return new FactOrFictionEffect(this);
}
@Override
public boolean apply(Game game, Ability source) {
Player controller = game.getPlayer(source.getControllerId());
MageObject sourceObject = source.getSourceObject(game);
if (controller == null || sourceObject == null) {
return false;
}
Cards cards = new CardsImpl(controller.getLibrary().getTopCards(game, 5));
controller.revealCards(sourceObject.getName(), cards, game);
Set<UUID> opponents = game.getOpponents(source.getControllerId());
if (!opponents.isEmpty()) {
Player opponent = game.getPlayer(opponents.iterator().next());
if (opponents.size() > 1) {
Target targetOpponent = new TargetOpponent(true);
if (controller.chooseTarget(Outcome.Neutral, targetOpponent, source, game)) {
opponent = game.getPlayer(targetOpponent.getFirstTarget());
game.informPlayers(controller.getLogName() + " chose " + opponent.getLogName() + " to separate the revealed cards");
}
}
TargetCard target = new TargetCard(0, cards.size(), Zone.LIBRARY, new FilterCard("cards to put in the first pile"));
List<Card> pile1 = new ArrayList<>();
if (opponent.choose(Outcome.Neutral, cards, target, game)) {
List<UUID> targets = target.getTargets();
for (UUID targetId : targets) {
Card card = cards.get(targetId, game);
if (card != null) {
pile1.add(card);
cards.remove(card);
}
}
}
List<Card> pile2 = new ArrayList<>();
pile2.addAll(cards.getCards(game));
boolean choice = controller.choosePile(outcome, "Choose a pile to put into your hand.", pile1, pile2, game);
Zone pile1Zone = Zone.GRAVEYARD;
Zone pile2Zone = Zone.HAND;
if (choice) {
pile1Zone = Zone.HAND;
pile2Zone = Zone.GRAVEYARD;
}
StringBuilder sb = new StringBuilder("Pile 1, going to ").append(pile1Zone == Zone.HAND ? "Hand" : "Graveyard").append(": ");
int i = 0;
for (Card card : pile1) {
i++;
sb.append(card.getName());
if (i < pile1.size()) {
sb.append(", ");
}
}
cards.clear();
cards.addAll(pile1);
controller.moveCards(cards, pile1Zone, source, game);
game.informPlayers(sb.toString());
sb = new StringBuilder("Pile 2, going to ").append(pile2Zone == Zone.HAND ? "Hand" : "Graveyard").append(':');
i = 0;
for (Card card : pile2) {
i++;
sb.append(' ').append(card.getName());
if (i < pile2.size()) {
sb.append(", ");
}
}
cards.clear();
cards.addAll(pile2);
controller.moveCards(cards, pile2Zone, source, game);
game.informPlayers(sb.toString());
}
return true;
}
}

View file

@ -4,22 +4,18 @@ import mage.abilities.Ability;
import mage.abilities.DelayedTriggeredAbility; import mage.abilities.DelayedTriggeredAbility;
import mage.abilities.LoyaltyAbility; import mage.abilities.LoyaltyAbility;
import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.OneShotEffect;
import mage.abilities.effects.common.RevealAndSeparatePilesEffect;
import mage.abilities.effects.common.continuous.BoostTargetEffect; import mage.abilities.effects.common.continuous.BoostTargetEffect;
import mage.cards.*; import mage.cards.*;
import mage.constants.*; import mage.constants.*;
import mage.filter.FilterCard;
import mage.filter.StaticFilters; import mage.filter.StaticFilters;
import mage.game.Game; import mage.game.Game;
import mage.game.events.GameEvent; import mage.game.events.GameEvent;
import mage.players.Player; import mage.players.Player;
import mage.target.TargetCard;
import mage.target.common.TargetCardInLibrary; import mage.target.common.TargetCardInLibrary;
import mage.target.common.TargetOpponent;
import mage.target.targetpointer.FixedTarget; import mage.target.targetpointer.FixedTarget;
import mage.util.CardUtil; import mage.util.CardUtil;
import java.util.ArrayList;
import java.util.Set;
import java.util.UUID; import java.util.UUID;
/** /**
@ -39,7 +35,9 @@ public final class JaceArchitectOfThought extends CardImpl {
// -2: Reveal the top three cards of your library. An opponent separates those cards into two piles. // -2: Reveal the top three cards of your library. An opponent separates those cards into two piles.
// Put one pile into your hand and the other on the bottom of your library in any order. // Put one pile into your hand and the other on the bottom of your library in any order.
this.addAbility(new LoyaltyAbility(new JaceArchitectOfThoughtEffect2(), -2)); this.addAbility(new LoyaltyAbility(new RevealAndSeparatePilesEffect(
3, TargetController.OPPONENT, TargetController.YOU, Zone.LIBRARY
), -2));
// -8: For each player, search that player's library for a nonland card and exile it, // -8: For each player, search that player's library for a nonland card and exile it,
// then that player shuffles their library. You may cast those cards without paying their mana costs. // then that player shuffles their library. You may cast those cards without paying their mana costs.
@ -128,79 +126,6 @@ class JaceArchitectOfThoughtDelayedTriggeredAbility extends DelayedTriggeredAbil
} }
} }
class JaceArchitectOfThoughtEffect2 extends OneShotEffect {
public JaceArchitectOfThoughtEffect2() {
super(Outcome.DrawCard);
this.staticText = "Reveal the top three cards of your library. An opponent separates those cards "
+ "into two piles. Put one pile into your hand and the other on the bottom of your library in any order";
}
public JaceArchitectOfThoughtEffect2(final JaceArchitectOfThoughtEffect2 effect) {
super(effect);
}
@Override
public JaceArchitectOfThoughtEffect2 copy() {
return new JaceArchitectOfThoughtEffect2(this);
}
@Override
public boolean apply(Game game, Ability source) {
Player player = game.getPlayer(source.getControllerId());
if (player == null) {
return false;
}
Cards allCards = new CardsImpl(player.getLibrary().getTopCards(game, 3));
player.revealCards(source, allCards, game);
Set<UUID> opponents = game.getOpponents(source.getControllerId());
if (!opponents.isEmpty()) {
Player opponent = null;
if (opponents.size() > 1) {
TargetOpponent targetOpponent = new TargetOpponent();
if (player.chooseTarget(Outcome.Neutral, targetOpponent, source, game)) {
opponent = game.getPlayer(targetOpponent.getFirstTarget());
}
}
if (opponent == null) {
opponent = game.getPlayer(opponents.iterator().next());
}
TargetCard target = new TargetCard(0, allCards.size(), Zone.LIBRARY, new FilterCard("cards to put in the first pile"));
target.setNotTarget(true);
opponent.choose(Outcome.Neutral, allCards, target, game);
Cards pile1 = new CardsImpl(target.getTargets());
Cards pile2 = new CardsImpl(allCards);
pile2.removeAll(pile1);
player.revealCards(source, "Pile 1", pile1, game);
player.revealCards(source, "Pile 2", pile2, game);
postPileToLog("Pile 1", pile1.getCards(game), game);
postPileToLog("Pile 2", pile2.getCards(game), game);
boolean pileChoice = player.choosePile(Outcome.Neutral, "Choose a pile to to put into your hand.",
new ArrayList<>(pile1.getCards(game)),
new ArrayList<>(pile2.getCards(game)), game);
game.informPlayers(player.getLogName() + " chose pile" + (pileChoice ? "1" : "2"));
player.moveCards(pileChoice ? pile1 : pile2, Zone.HAND, source, game);
player.putCardsOnBottomOfLibrary(pileChoice ? pile2 : pile1, game, source, true);
return true;
}
return false;
}
private void postPileToLog(String pileName, Set<Card> cards, Game game) {
StringBuilder message = new StringBuilder(pileName).append(": ");
cards.forEach((card) -> {
message.append(card.getName()).append(' ');
});
if (cards.isEmpty()) {
message.append(" (empty)");
}
game.informPlayers(message.toString());
}
}
class JaceArchitectOfThoughtEffect3 extends OneShotEffect { class JaceArchitectOfThoughtEffect3 extends OneShotEffect {
public JaceArchitectOfThoughtEffect3() { public JaceArchitectOfThoughtEffect3() {

View file

@ -0,0 +1,52 @@
package mage.cards.s;
import mage.MageInt;
import mage.abilities.common.DealsCombatDamageToAPlayerTriggeredAbility;
import mage.abilities.costs.mana.ManaCostsImpl;
import mage.abilities.dynamicvalue.common.DomainValue;
import mage.abilities.effects.common.RevealAndSeparatePilesEffect;
import mage.abilities.hint.common.DomainHint;
import mage.abilities.keyword.FlyingAbility;
import mage.abilities.keyword.WardAbility;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.*;
import java.util.UUID;
/**
* @author TheElk801
*/
public final class SphinxOfClearSkies extends CardImpl {
public SphinxOfClearSkies(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{U}{U}");
this.subtype.add(SubType.SPHINX);
this.power = new MageInt(5);
this.toughness = new MageInt(5);
// Flying
this.addAbility(FlyingAbility.getInstance());
// Ward {2}
this.addAbility(new WardAbility(new ManaCostsImpl<>("{2}"), false));
// Domain -- Whenever Sphinx of Clear Skies deals combat damage to a player, reveal the top X cards of your library, where X is the number of basic land types among lands you control. An opponent separates those cards into two piles. Put one pile into your hand and the other into your graveyard.
this.addAbility(new DealsCombatDamageToAPlayerTriggeredAbility(new RevealAndSeparatePilesEffect(
DomainValue.REGULAR, TargetController.OPPONENT, TargetController.YOU, Zone.GRAVEYARD
).setText("reveal the top X cards of your library, where X is the number of basic land types " +
"among lands you control. An opponent separates those cards into two piles. " +
"Put one pile into your hand and the other into your graveyard"), false
).setAbilityWord(AbilityWord.DOMAIN).addHint(DomainHint.instance));
}
private SphinxOfClearSkies(final SphinxOfClearSkies card) {
super(card);
}
@Override
public SphinxOfClearSkies copy() {
return new SphinxOfClearSkies(this);
}
}

View file

@ -1,34 +1,19 @@
package mage.cards.s; package mage.cards.s;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import java.util.UUID;
import mage.MageInt; import mage.MageInt;
import mage.MageObject;
import mage.abilities.Ability;
import mage.abilities.common.EntersBattlefieldTriggeredAbility; import mage.abilities.common.EntersBattlefieldTriggeredAbility;
import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.RevealAndSeparatePilesEffect;
import mage.abilities.keyword.FlyingAbility; import mage.abilities.keyword.FlyingAbility;
import mage.cards.Card;
import mage.cards.CardImpl; import mage.cards.CardImpl;
import mage.cards.CardSetInfo; import mage.cards.CardSetInfo;
import mage.cards.Cards;
import mage.cards.CardsImpl;
import mage.constants.CardType; import mage.constants.CardType;
import mage.constants.Outcome;
import mage.constants.SubType; import mage.constants.SubType;
import mage.constants.TargetController;
import mage.constants.Zone; import mage.constants.Zone;
import mage.filter.FilterCard;
import mage.game.Game; import java.util.UUID;
import mage.players.Player;
import mage.target.Target;
import mage.target.TargetCard;
import mage.target.common.TargetOpponent;
/** /**
*
* @author North * @author North
*/ */
public final class SphinxOfUthuun extends CardImpl { public final class SphinxOfUthuun extends CardImpl {
@ -41,7 +26,9 @@ public final class SphinxOfUthuun extends CardImpl {
this.toughness = new MageInt(6); this.toughness = new MageInt(6);
this.addAbility(FlyingAbility.getInstance()); this.addAbility(FlyingAbility.getInstance());
this.addAbility(new EntersBattlefieldTriggeredAbility(new SphinxOfUthuunEffect())); this.addAbility(new EntersBattlefieldTriggeredAbility(new RevealAndSeparatePilesEffect(
5, TargetController.OPPONENT, TargetController.YOU, Zone.GRAVEYARD
)));
} }
private SphinxOfUthuun(final SphinxOfUthuun card) { private SphinxOfUthuun(final SphinxOfUthuun card) {
@ -53,97 +40,3 @@ public final class SphinxOfUthuun extends CardImpl {
return new SphinxOfUthuun(this); return new SphinxOfUthuun(this);
} }
} }
class SphinxOfUthuunEffect extends OneShotEffect {
public SphinxOfUthuunEffect() {
super(Outcome.DrawCard);
this.staticText = "reveal the top five cards of your library. An opponent separates those cards into two piles. Put one pile into your hand and the other into your graveyard";
}
public SphinxOfUthuunEffect(final SphinxOfUthuunEffect effect) {
super(effect);
}
@Override
public SphinxOfUthuunEffect copy() {
return new SphinxOfUthuunEffect(this);
}
@Override
public boolean apply(Game game, Ability source) {
Player controller = game.getPlayer(source.getControllerId());
MageObject sourceObject = source.getSourceObject(game);
if (controller == null || sourceObject == null) {
return false;
}
Cards cards = new CardsImpl(controller.getLibrary().getTopCards(game, 5));
controller.revealCards(source, cards, game);
Set<UUID> opponents = game.getOpponents(source.getControllerId());
if (!opponents.isEmpty()) {
Player opponent = game.getPlayer(opponents.iterator().next());
if (opponents.size() > 1) {
Target targetOpponent = new TargetOpponent(true);
if (controller.chooseTarget(Outcome.Neutral, targetOpponent, source, game)) {
opponent = game.getPlayer(targetOpponent.getFirstTarget());
game.informPlayers(controller.getLogName() + " chose " + opponent.getLogName() + " to separate the revealed cards");
}
}
TargetCard target = new TargetCard(0, cards.size(), Zone.LIBRARY, new FilterCard("cards to put in the first pile"));
target.setRequired(false);
List<Card> pile1 = new ArrayList<>();
Cards pile1CardsIds = new CardsImpl();
if (opponent.choose(Outcome.Neutral, cards, target, game)) {
pile1CardsIds.addAll(target.getTargets());
pile1.addAll(pile1CardsIds.getCards(game));
}
List<Card> pile2 = new ArrayList<>();
Cards pile2CardsIds = new CardsImpl(cards);
pile2CardsIds.removeAll(pile1CardsIds);
pile2.addAll(pile2CardsIds.getCards(game));
boolean choice = controller.choosePile(Outcome.DestroyPermanent, "Choose a pile to put into hand.", pile1, pile2, game);
Zone pile1Zone = Zone.GRAVEYARD;
Zone pile2Zone = Zone.HAND;
if (choice) {
pile1Zone = Zone.HAND;
pile2Zone = Zone.GRAVEYARD;
}
StringBuilder sb = new StringBuilder(sourceObject.getLogName()).append(": Pile 1, going to ").append(pile1Zone == Zone.HAND ? "Hand" : "Graveyard").append(": ");
int i = 0;
for (UUID cardUuid : pile1CardsIds) {
i++;
Card card = game.getCard(cardUuid);
if (card != null) {
sb.append(card.getName());
if (i < pile1CardsIds.size()) {
sb.append(", ");
}
}
}
controller.moveCards(pile1CardsIds, pile1Zone, source, game);
game.informPlayers(sb.toString());
sb = new StringBuilder(sourceObject.getLogName()).append(": Pile 2, going to ").append(pile2Zone == Zone.HAND ? "Hand" : "Graveyard").append(':');
i = 0;
for (UUID cardUuid : pile2CardsIds) {
Card card = game.getCard(cardUuid);
if (card != null) {
i++;
sb.append(' ').append(card.getName());
if (i < pile2CardsIds.size()) {
sb.append(", ");
}
}
}
controller.moveCards(pile2CardsIds, pile2Zone, source, game);
game.informPlayers(sb.toString());
}
return true;
}
}

View file

@ -1,31 +1,15 @@
package mage.cards.s; package mage.cards.s;
import java.util.ArrayList; import mage.abilities.effects.common.RevealAndSeparatePilesEffect;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Set;
import java.util.UUID;
import mage.MageObject;
import mage.abilities.Ability;
import mage.abilities.effects.OneShotEffect;
import mage.cards.Card;
import mage.cards.CardImpl; import mage.cards.CardImpl;
import mage.cards.CardSetInfo; import mage.cards.CardSetInfo;
import mage.cards.Cards;
import mage.cards.CardsImpl;
import mage.constants.CardType; import mage.constants.CardType;
import mage.constants.Outcome; import mage.constants.TargetController;
import mage.constants.Zone; import mage.constants.Zone;
import mage.filter.FilterCard;
import mage.game.Game; import java.util.UUID;
import mage.players.Player;
import mage.target.Target;
import mage.target.TargetCard;
import mage.target.common.TargetOpponent;
import mage.util.GameLog;
/** /**
*
* @author LevelX2 * @author LevelX2
*/ */
public final class SteamAugury extends CardImpl { public final class SteamAugury extends CardImpl {
@ -34,7 +18,9 @@ public final class SteamAugury extends CardImpl {
super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{2}{U}{R}"); super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{2}{U}{R}");
// Reveal the top five cards of your library and separate them into two piles. An opponent chooses one of those piles. Put that pile into your hand and the other into your graveyard. // Reveal the top five cards of your library and separate them into two piles. An opponent chooses one of those piles. Put that pile into your hand and the other into your graveyard.
this.getSpellAbility().addEffect(new SteamAuguryEffect()); this.getSpellAbility().addEffect(new RevealAndSeparatePilesEffect(
5, TargetController.YOU, TargetController.OPPONENT, Zone.GRAVEYARD
));
} }
private SteamAugury(final SteamAugury card) { private SteamAugury(final SteamAugury card) {
@ -46,112 +32,3 @@ public final class SteamAugury extends CardImpl {
return new SteamAugury(this); return new SteamAugury(this);
} }
} }
class SteamAuguryEffect extends OneShotEffect {
public SteamAuguryEffect() {
super(Outcome.DrawCard);
this.staticText = "Reveal the top five cards of your library and separate them into two piles. An opponent chooses one of those piles. Put that pile into your hand and the other into your graveyard";
}
public SteamAuguryEffect(final SteamAuguryEffect effect) {
super(effect);
}
@Override
public SteamAuguryEffect copy() {
return new SteamAuguryEffect(this);
}
@Override
public boolean apply(Game game, Ability source) {
Player controller = game.getPlayer(source.getControllerId());
MageObject sourceObject = game.getObject(source);
Set<Card> cardsToGraveyard = new LinkedHashSet<>();
Set<Card> cardsToHand = new LinkedHashSet<>();
if (controller == null || sourceObject == null) {
return false;
}
Cards cards = new CardsImpl(controller.getLibrary().getTopCards(game, 5));
controller.revealCards(sourceObject.getIdName(), cards, game);
Player opponent;
Set<UUID> opponents = game.getOpponents(controller.getId());
if (opponents.size() == 1) {
opponent = game.getPlayer(opponents.iterator().next());
} else {
Target target = new TargetOpponent(true);
controller.chooseTarget(Outcome.Detriment, target, source, game);
opponent = game.getPlayer(target.getFirstTarget());
}
if (opponent != null) {
TargetCard target = new TargetCard(0, cards.size(), Zone.LIBRARY, new FilterCard("cards to put in the first pile"));
List<Card> pile1 = new ArrayList<>();
Cards pile1CardsIds = new CardsImpl();
target.setRequired(false);
if (controller.choose(Outcome.Neutral, cards, target, game)) {
List<UUID> targets = target.getTargets();
for (UUID targetId : targets) {
Card card = game.getCard(targetId);
if (card != null) {
pile1.add(card);
pile1CardsIds.add(card.getId());
}
}
}
List<Card> pile2 = new ArrayList<>();
Cards pile2CardsIds = new CardsImpl();
for (UUID cardId : cards) {
Card card = game.getCard(cardId);
if (card != null && !pile1.contains(card)) {
pile2.add(card);
pile2CardsIds.add(card.getId());
}
}
boolean choice = opponent.choosePile(Outcome.Detriment, "Choose a pile to put into " + controller.getName() + "'s hand.", pile1, pile2, game);
Zone pile1Zone = Zone.GRAVEYARD;
Zone pile2Zone = Zone.HAND;
if (choice) {
pile1Zone = Zone.HAND;
pile2Zone = Zone.GRAVEYARD;
}
StringBuilder sb = new StringBuilder(sourceObject.getLogName() + ": Pile 1, going to ").append(pile1Zone == Zone.HAND ? "Hand" : "Graveyard").append(": ");
int i = 0;
for (UUID cardUuid : pile1CardsIds) {
i++;
Card card = game.getCard(cardUuid);
if (card != null) {
sb.append(GameLog.getColoredObjectName(card));
if (i < pile1CardsIds.size()) {
sb.append(", ");
}
cardsToGraveyard.add(card);
}
}
controller.moveCards(cardsToGraveyard, pile1Zone, source, game);
game.informPlayers(sb.toString());
sb = new StringBuilder(sourceObject.getLogName() + ": Pile 2, going to ").append(pile2Zone == Zone.HAND ? "Hand" : "Graveyard").append(':');
i = 0;
for (UUID cardUuid : pile2CardsIds) {
Card card = game.getCard(cardUuid);
if (card != null) {
i++;
sb.append(' ').append(GameLog.getColoredObjectName(card));
if (i < pile2CardsIds.size()) {
sb.append(", ");
}
cardsToHand.add(card);
}
}
controller.moveCards(cardsToHand, pile2Zone, source, game);
game.informPlayers(sb.toString());
}
return true;
}
}

View file

@ -1,27 +1,17 @@
package mage.cards.u; package mage.cards.u;
import mage.MageInt; import mage.MageInt;
import mage.MageObject;
import mage.abilities.Ability;
import mage.abilities.common.EntersBattlefieldThisOrAnotherTriggeredAbility; import mage.abilities.common.EntersBattlefieldThisOrAnotherTriggeredAbility;
import mage.abilities.common.SimpleStaticAbility; import mage.abilities.common.SimpleStaticAbility;
import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.RevealAndSeparatePilesEffect;
import mage.abilities.effects.common.cost.SpellsCostReductionControllerEffect; import mage.abilities.effects.common.cost.SpellsCostReductionControllerEffect;
import mage.abilities.keyword.FlyingAbility; import mage.abilities.keyword.FlyingAbility;
import mage.cards.*; import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.*; import mage.constants.*;
import mage.filter.FilterCard; import mage.filter.FilterCard;
import mage.filter.FilterPermanent; import mage.filter.FilterPermanent;
import mage.game.Game;
import mage.players.Player;
import mage.target.Target;
import mage.target.TargetCard;
import mage.target.common.TargetOpponent;
import java.util.ArrayList;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Set;
import java.util.UUID; import java.util.UUID;
/** /**
@ -51,9 +41,9 @@ public final class UneshCriosphinxSovereign extends CardImpl {
this.addAbility(new SimpleStaticAbility(new SpellsCostReductionControllerEffect(filter, 2))); this.addAbility(new SimpleStaticAbility(new SpellsCostReductionControllerEffect(filter, 2)));
// Whenever Unesh, Criosphinx Sovereign or another Sphinx enters the battlefield under your control, reveal the top four cards of your library. An opponent seperates those cards into two piles. Put one pile into your hand and the other into your graveyard. // Whenever Unesh, Criosphinx Sovereign or another Sphinx enters the battlefield under your control, reveal the top four cards of your library. An opponent seperates those cards into two piles. Put one pile into your hand and the other into your graveyard.
this.addAbility(new EntersBattlefieldThisOrAnotherTriggeredAbility( this.addAbility(new EntersBattlefieldThisOrAnotherTriggeredAbility(new RevealAndSeparatePilesEffect(
new UneshCriosphinxSovereignEffect(), filter2, false, true 4, TargetController.OPPONENT, TargetController.YOU, Zone.GRAVEYARD
)); ), filter2, false, true));
} }
private UneshCriosphinxSovereign(final UneshCriosphinxSovereign card) { private UneshCriosphinxSovereign(final UneshCriosphinxSovereign card) {
@ -65,97 +55,3 @@ public final class UneshCriosphinxSovereign extends CardImpl {
return new UneshCriosphinxSovereign(this); return new UneshCriosphinxSovereign(this);
} }
} }
class UneshCriosphinxSovereignEffect extends OneShotEffect {
UneshCriosphinxSovereignEffect() {
super(Outcome.DrawCard);
this.staticText = "reveal the top four cards of your library. An opponent separates those cards into two piles. Put one pile into your hand and the other into your graveyard";
}
private UneshCriosphinxSovereignEffect(final UneshCriosphinxSovereignEffect effect) {
super(effect);
}
@Override
public UneshCriosphinxSovereignEffect copy() {
return new UneshCriosphinxSovereignEffect(this);
}
@Override
public boolean apply(Game game, Ability source) {
Player controller = game.getPlayer(source.getControllerId());
Set<Card> cardsToGraveyard = new LinkedHashSet<>();
Set<Card> cardsToHand = new LinkedHashSet<>();
MageObject sourceObject = source.getSourceObject(game);
if (controller == null || sourceObject == null) {
return false;
}
Cards cards = new CardsImpl(controller.getLibrary().getTopCards(game, 4));
controller.revealCards(sourceObject.getName(), cards, game);
Set<UUID> opponents = game.getOpponents(source.getControllerId());
if (!opponents.isEmpty()) {
Player opponent = game.getPlayer(opponents.iterator().next());
if (opponents.size() > 1) {
Target targetOpponent = new TargetOpponent(true);
if (controller.chooseTarget(Outcome.Neutral, targetOpponent, source, game)) {
opponent = game.getPlayer(targetOpponent.getFirstTarget());
game.informPlayers(controller.getLogName() + " chose " + opponent.getLogName() + " to separate the revealed cards");
}
}
TargetCard target = new TargetCard(0, cards.size(), Zone.LIBRARY, new FilterCard("cards to put in the first pile"));
List<Card> pile1 = new ArrayList<>();
if (opponent.choose(Outcome.Neutral, cards, target, game)) {
List<UUID> targets = target.getTargets();
for (UUID targetId : targets) {
Card card = cards.get(targetId, game);
if (card != null) {
pile1.add(card);
cards.remove(card);
}
}
}
List<Card> pile2 = new ArrayList<>();
pile2.addAll(cards.getCards(game));
boolean choice = controller.choosePile(outcome, "Choose a pile to put into your hand.", pile1, pile2, game);
Zone pile1Zone = Zone.GRAVEYARD;
Zone pile2Zone = Zone.HAND;
if (choice) {
pile1Zone = Zone.HAND;
pile2Zone = Zone.GRAVEYARD;
}
StringBuilder sb = new StringBuilder("Pile 1, going to ").append(pile1Zone == Zone.HAND ? "Hand" : "Graveyard").append(": ");
int i = 0;
for (Card card : pile1) {
i++;
sb.append(card.getName());
if (i < pile1.size()) {
sb.append(", ");
}
cardsToGraveyard.add(card);
}
controller.moveCards(cardsToGraveyard, pile1Zone, source, game);
game.informPlayers(sb.toString());
sb = new StringBuilder("Pile 2, going to ").append(pile2Zone == Zone.HAND ? "Hand" : "Graveyard").append(':');
i = 0;
for (Card card : pile2) {
i++;
sb.append(' ').append(card.getName());
if (i < pile2.size()) {
sb.append(", ");
}
cardsToHand.add(card);
}
controller.moveCards(cardsToHand, pile2Zone, source, game);
game.informPlayers(sb.toString());
}
return true;
}
}

View file

@ -212,6 +212,7 @@ public final class DominariaUnited extends ExpansionSet {
cards.add(new SetCardInfo("Snarespinner", 179, Rarity.COMMON, mage.cards.s.Snarespinner.class)); cards.add(new SetCardInfo("Snarespinner", 179, Rarity.COMMON, mage.cards.s.Snarespinner.class));
cards.add(new SetCardInfo("Soaring Drake", 66, Rarity.COMMON, mage.cards.s.SoaringDrake.class)); cards.add(new SetCardInfo("Soaring Drake", 66, Rarity.COMMON, mage.cards.s.SoaringDrake.class));
cards.add(new SetCardInfo("Soul of Windgrace", 220, Rarity.MYTHIC, mage.cards.s.SoulOfWindgrace.class)); cards.add(new SetCardInfo("Soul of Windgrace", 220, Rarity.MYTHIC, mage.cards.s.SoulOfWindgrace.class));
cards.add(new SetCardInfo("Sphinx of Clear Skies", 67, Rarity.MYTHIC, mage.cards.s.SphinxOfClearSkies.class));
cards.add(new SetCardInfo("Splatter Goblin", 109, Rarity.COMMON, mage.cards.s.SplatterGoblin.class)); cards.add(new SetCardInfo("Splatter Goblin", 109, Rarity.COMMON, mage.cards.s.SplatterGoblin.class));
cards.add(new SetCardInfo("Sprouting Goblin", 145, Rarity.UNCOMMON, mage.cards.s.SproutingGoblin.class)); cards.add(new SetCardInfo("Sprouting Goblin", 145, Rarity.UNCOMMON, mage.cards.s.SproutingGoblin.class));
cards.add(new SetCardInfo("Stall for Time", 34, Rarity.COMMON, mage.cards.s.StallForTime.class)); cards.add(new SetCardInfo("Stall for Time", 34, Rarity.COMMON, mage.cards.s.StallForTime.class));

View file

@ -0,0 +1,183 @@
package mage.abilities.effects.common;
import mage.MageObject;
import mage.abilities.Ability;
import mage.abilities.dynamicvalue.DynamicValue;
import mage.abilities.dynamicvalue.common.StaticValue;
import mage.abilities.effects.OneShotEffect;
import mage.cards.Card;
import mage.cards.Cards;
import mage.cards.CardsImpl;
import mage.constants.Outcome;
import mage.constants.TargetController;
import mage.constants.Zone;
import mage.filter.FilterCard;
import mage.game.Game;
import mage.players.Player;
import mage.target.Target;
import mage.target.TargetCard;
import mage.target.common.TargetOpponent;
import mage.util.CardUtil;
import java.util.*;
import java.util.stream.Collectors;
/**
* @author TheElk801
*/
public class RevealAndSeparatePilesEffect extends OneShotEffect {
private static final FilterCard filter = new FilterCard("cards to put in the first pile");
private final DynamicValue amount;
private final TargetController playerWhoSeparates;
private final TargetController playerWhoChooses;
private final Zone targetZone;
private final boolean anyOrder;
public RevealAndSeparatePilesEffect(int amount, TargetController playerWhoSeparates, TargetController playerWhoChooses, Zone targetZone) {
this(StaticValue.get(amount), playerWhoSeparates, playerWhoChooses, targetZone);
}
public RevealAndSeparatePilesEffect(DynamicValue amount, TargetController playerWhoSeparates, TargetController playerWhoChooses, Zone targetZone) {
this(amount, playerWhoSeparates, playerWhoChooses, targetZone, true);
}
public RevealAndSeparatePilesEffect(DynamicValue amount, TargetController playerWhoSeparates, TargetController playerWhoChooses, Zone targetZone, boolean anyOrder) {
super(Outcome.DrawCard);
this.amount = amount;
this.playerWhoSeparates = playerWhoSeparates;
this.playerWhoChooses = playerWhoChooses;
this.targetZone = targetZone;
this.anyOrder = anyOrder;
this.staticText = this.generateText();
}
private RevealAndSeparatePilesEffect(final RevealAndSeparatePilesEffect effect) {
super(effect);
this.amount = effect.amount;
this.playerWhoSeparates = effect.playerWhoSeparates;
this.playerWhoChooses = effect.playerWhoChooses;
this.targetZone = effect.targetZone;
this.anyOrder = effect.anyOrder;
}
@Override
public RevealAndSeparatePilesEffect copy() {
return new RevealAndSeparatePilesEffect(this);
}
@Override
public boolean apply(Game game, Ability source) {
Player controller = game.getPlayer(source.getControllerId());
int toReveal = amount.calculate(game, source, this);
if (controller == null || toReveal < 1) {
return false;
}
return doPiles(controller, source, game, toReveal);
}
private static Player getExecutingPlayer(Player controller, Game game, Ability source, TargetController targetController, String message) {
switch (targetController) {
case YOU:
return controller;
case OPPONENT:
Player opponent;
Set<UUID> opponents = game.getOpponents(source.getControllerId());
if (opponents.isEmpty()) {
return null;
}
if (opponents.size() == 1) {
opponent = game.getPlayer(opponents.iterator().next());
} else {
Target targetOpponent = new TargetOpponent(true);
controller.chooseTarget(Outcome.Neutral, targetOpponent, source, game);
opponent = game.getPlayer(targetOpponent.getFirstTarget());
game.informPlayers(controller.getLogName() + " chose " + opponent.getLogName() + " to " + message);
}
return opponent;
}
return null;
}
private boolean doPiles(Player controller, Ability source, Game game, int toReveal) {
Cards cards = new CardsImpl(controller.getLibrary().getTopCards(game, toReveal));
controller.revealCards(source, cards, game);
Player separatingPlayer = this.getExecutingPlayer(controller, game, source, playerWhoSeparates, "separate the revealed cards");
TargetCard target = new TargetCard(0, cards.size(), Zone.LIBRARY, filter);
List<Card> pile1 = new ArrayList<>();
separatingPlayer.choose(Outcome.Neutral, cards, target, game);
target.getTargets()
.stream()
.map(game::getCard)
.filter(Objects::nonNull)
.forEach(pile1::add);
cards.removeIf(target.getTargets()::contains);
List<Card> pile2 = new ArrayList<>();
pile2.addAll(cards.getCards(game));
Player choosingPlayer = this.getExecutingPlayer(controller, game, source, playerWhoChooses, "choose the piles");
boolean choice = choosingPlayer.choosePile(outcome, "Choose a pile to put into " + targetZone + ".", pile1, pile2, game);
Zone pile1Zone = choice ? targetZone : Zone.HAND;
Zone pile2Zone = choice ? Zone.HAND : targetZone;
game.informPlayers("Pile 1, going to " + pile1Zone + ": " + (pile1.isEmpty() ? " (none)" : pile1.stream().map(MageObject::getName).collect(Collectors.joining(", "))));
cards.clear();
cards.addAll(pile1);
if (pile1Zone == Zone.LIBRARY) {
controller.putCardsOnBottomOfLibrary(cards, game, source, anyOrder);
} else {
controller.moveCards(cards, pile1Zone, source, game);
}
game.informPlayers("Pile 2, going to " + pile2Zone + ": " + (pile2.isEmpty() ? " (none)" : pile2.stream().map(MageObject::getName).collect(Collectors.joining(", "))));
cards.clear();
cards.addAll(pile2);
if (pile2Zone == Zone.LIBRARY) {
controller.putCardsOnBottomOfLibrary(cards, game, source, anyOrder);
} else {
controller.moveCards(cards, pile2Zone, source, game);
}
return true;
}
private String generateText() {
StringBuilder sb = new StringBuilder("reveal the top ");
if (amount instanceof StaticValue) {
sb.append(CardUtil.numberToText(((StaticValue) amount).getValue()));
sb.append(" cards of your library");
} else {
sb.append("X cards of your library, where X is the number of ");
sb.append(amount.getMessage());
}
switch (playerWhoSeparates) {
case YOU:
sb.append(" and separate them");
break;
case OPPONENT:
sb.append(". An opponent separates those cards");
break;
}
sb.append(" into two piles. ");
switch (playerWhoChooses) {
case YOU:
sb.append("Put one pile into your hand and the other ");
break;
case OPPONENT:
sb.append("An opponent chooses one of those piles. Put that pile into your hand and the other ");
break;
}
switch (targetZone) {
case GRAVEYARD:
sb.append("into your graveyard");
break;
case LIBRARY:
sb.append("on the bottom of your library in a");
sb.append(anyOrder ? "ny" : " random");
sb.append(" order");
break;
}
return sb.toString();
}
}