Implemented Rielle, the Everwise

This commit is contained in:
Evan Kranzler 2020-04-21 20:12:41 -04:00
parent 186239ffa0
commit 618af9b365
5 changed files with 178 additions and 31 deletions

View file

@ -0,0 +1,124 @@
package mage.cards.r;
import mage.MageInt;
import mage.abilities.TriggeredAbilityImpl;
import mage.abilities.common.SimpleStaticAbility;
import mage.abilities.dynamicvalue.DynamicValue;
import mage.abilities.dynamicvalue.common.CardsInControllerGraveyardCount;
import mage.abilities.dynamicvalue.common.StaticValue;
import mage.abilities.effects.common.DrawCardSourceControllerEffect;
import mage.abilities.effects.common.continuous.BoostSourceEffect;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.*;
import mage.filter.StaticFilters;
import mage.game.Game;
import mage.game.events.GameEvent;
import mage.watchers.Watcher;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
/**
* @author TheElk801
*/
public final class RielleTheEverwise extends CardImpl {
private static final DynamicValue xValue
= new CardsInControllerGraveyardCount(StaticFilters.FILTER_CARD_INSTANT_AND_SORCERY);
public RielleTheEverwise(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{U}{R}");
this.addSuperType(SuperType.LEGENDARY);
this.subtype.add(SubType.HUMAN);
this.subtype.add(SubType.WIZARD);
this.power = new MageInt(0);
this.toughness = new MageInt(3);
// Rielle, the Everwise gets +1/+0 for each instant and sorcery card in your graveyard.
this.addAbility(new SimpleStaticAbility(new BoostSourceEffect(
xValue, StaticValue.get(0), Duration.WhileOnBattlefield
).setText("{this} gets +1/+0 for each instant and sorcery card in your graveyard")));
// Whenever you discard one or more cards for the first time each turn, draw that many cards.
this.addAbility(new RielleTheEverwiseTriggeredAbility());
}
private RielleTheEverwise(final RielleTheEverwise card) {
super(card);
}
@Override
public RielleTheEverwise copy() {
return new RielleTheEverwise(this);
}
}
class RielleTheEverwiseTriggeredAbility extends TriggeredAbilityImpl {
RielleTheEverwiseTriggeredAbility() {
super(Zone.BATTLEFIELD, null);
this.addWatcher(new RielleTheEverwiseWatcher());
}
private RielleTheEverwiseTriggeredAbility(final RielleTheEverwiseTriggeredAbility ability) {
super(ability);
}
@Override
public boolean checkEventType(GameEvent event, Game game) {
return event.getType() == GameEvent.EventType.DISCARDED_CARDS;
}
@Override
public boolean checkTrigger(GameEvent event, Game game) {
RielleTheEverwiseWatcher watcher = game.getState().getWatcher(RielleTheEverwiseWatcher.class);
if (watcher == null
|| !watcher.checkDiscarded(event.getPlayerId())
|| !event.getPlayerId().equals(getControllerId())
|| event.getAmount() == 0) {
return false;
}
this.getEffects().clear();
this.addEffect(new DrawCardSourceControllerEffect(event.getAmount()));
return true;
}
@Override
public RielleTheEverwiseTriggeredAbility copy() {
return new RielleTheEverwiseTriggeredAbility(this);
}
@Override
public String getRule() {
return "Whenever you discard one or more cards for the first time each turn, draw that many cards.";
}
}
class RielleTheEverwiseWatcher extends Watcher {
private final Map<UUID, Integer> discardedThisTurn = new HashMap();
RielleTheEverwiseWatcher() {
super(WatcherScope.GAME);
}
@Override
public void watch(GameEvent event, Game game) {
if (event.getAmount() > 0) {
discardedThisTurn.compute(event.getPlayerId(), (u, i) -> i == null ? 1 : i + 1);
}
}
@Override
public void reset() {
super.reset();
this.discardedThisTurn.clear();
}
boolean checkDiscarded(UUID playerId) {
return discardedThisTurn.getOrDefault(playerId, 0) < 2;
}
}

View file

@ -270,6 +270,7 @@ public final class IkoriaLairOfBehemoths extends ExpansionSet {
cards.add(new SetCardInfo("Reconnaissance Mission", 65, Rarity.UNCOMMON, mage.cards.r.ReconnaissanceMission.class));
cards.add(new SetCardInfo("Regal Leosaur", 202, Rarity.UNCOMMON, mage.cards.r.RegalLeosaur.class));
cards.add(new SetCardInfo("Reptilian Reflection", 132, Rarity.UNCOMMON, mage.cards.r.ReptilianReflection.class));
cards.add(new SetCardInfo("Rielle, the Everwise", 203, Rarity.MYTHIC, mage.cards.r.RielleTheEverwise.class));
cards.add(new SetCardInfo("Rooting Moloch", 133, Rarity.UNCOMMON, mage.cards.r.RootingMoloch.class));
cards.add(new SetCardInfo("Rugged Highlands", 252, Rarity.COMMON, mage.cards.r.RuggedHighlands.class));
cards.add(new SetCardInfo("Ruinous Ultimatum", 204, Rarity.RARE, mage.cards.r.RuinousUltimatum.class));

View file

@ -33,12 +33,10 @@ public class DiscardHandControllerEffect extends OneShotEffect {
@Override
public boolean apply(Game game, Ability source) {
Player player = game.getPlayer(source.getControllerId());
if (player != null) {
for (Card card : player.getHand().getCards(game)) {
player.discard(card, source, game);
}
return true;
if (player == null) {
return false;
}
return false;
player.discard(player.getHand().size(),false,source,game);
return true;
}
}

View file

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

View file

@ -743,6 +743,18 @@ public abstract class PlayerImpl implements Player, Serializable {
@Override
public Cards discard(int amount, boolean random, Ability source, Game game) {
Cards discardedCards = doDiscard(amount, random, source, game);
if (!discardedCards.isEmpty()) {
UUID sourceId = source == null ? null : source.getSourceId();
game.fireEvent(GameEvent.getEvent(
GameEvent.EventType.DISCARDED_CARDS, sourceId,
sourceId, playerId, discardedCards.size()
));
}
return discardedCards;
}
private Cards doDiscard(int amount, boolean random, Ability source, Game game) {
Cards discardedCards = new CardsImpl();
if (amount <= 0) {
return discardedCards;
@ -752,7 +764,7 @@ public abstract class PlayerImpl implements Player, Serializable {
if (this.getHand().size() == 1 || this.getHand().size() == amount) {
List<UUID> cardsToDiscard = new ArrayList<>(this.getHand());
for (UUID id : cardsToDiscard) {
if (discard(this.getHand().get(id, game), source, game)) {
if (doDiscard(this.getHand().get(id, game), source, game, false)) {
discardedCards.add(id);
}
}
@ -762,7 +774,7 @@ public abstract class PlayerImpl implements Player, Serializable {
if (random) {
for (int i = 0; i < amount; i++) {
Card card = this.getHand().getRandom(game);
if (discard(card, source, game)) {
if (doDiscard(card, source, game, false)) {
discardedCards.add(card);
}
}
@ -773,7 +785,7 @@ public abstract class PlayerImpl implements Player, Serializable {
+ " card" + (possibleAmount > 1 ? "s" : "")), playerId);
choose(Outcome.Discard, target, source == null ? null : source.getSourceId(), game);
for (UUID cardId : target.getTargets()) {
if (discard(this.getHand().get(cardId, game), source, game)) {
if (doDiscard(this.getHand().get(cardId, game), source, game, false)) {
discardedCards.add(cardId);
}
}
@ -783,6 +795,10 @@ public abstract class PlayerImpl implements Player, Serializable {
@Override
public boolean discard(Card card, Ability source, Game game) {
return doDiscard(card, source, game, true);
}
private boolean doDiscard(Card card, Ability source, Game game, boolean fireEvent) {
//20100716 - 701.7
/* 701.7. Discard #
701.7a To discard a card, move it from its owner’s hand to that player’s graveyard.
@ -797,29 +813,36 @@ public abstract class PlayerImpl implements Player, Serializable {
about the discarded card, that cost payment is illegal; the game returns to
the moment before the cost was paid (see rule 717, "Handling Illegal Actions").
*/
if (card != null) {
GameEvent gameEvent = GameEvent.getEvent(GameEvent.EventType.DISCARD_CARD,
card.getId(), source == null
? null : source.getSourceId(), playerId);
gameEvent.setFlag(source != null); // event from effect or from cost (source == null)
if (!game.replaceEvent(gameEvent, source)) {
// write info to game log first so game log infos from triggered or replacement effects follow in the game log
if (!game.isSimulation()) {
game.informPlayers(getLogName() + " discards " + card.getLogName());
}
/* If a card is discarded while Rest in Peace is on the battlefield, abilities that function
* when a card is discarded (such as madness) still work, even though that card never reaches
* a graveyard. In addition, spells or abilities that check the characteristics of a discarded
* card (such as Chandra Ablaze's first ability) can find that card in exile. */
card.moveToZone(Zone.GRAVEYARD, source == null ? null : source.getSourceId(), game, false);
// So discard is also successful if card is moved to another zone by replacement effect!
game.fireEvent(GameEvent.getEvent(GameEvent.EventType.DISCARDED_CARD,
card.getId(), source == null
? null : source.getSourceId(), playerId));
return true;
}
if (card == null) {
return false;
}
return false;
GameEvent gameEvent = GameEvent.getEvent(GameEvent.EventType.DISCARD_CARD,
card.getId(), source == null
? null : source.getSourceId(), playerId);
gameEvent.setFlag(source != null); // event from effect or from cost (source == null)
if (game.replaceEvent(gameEvent, source)) {
return false;
}
// write info to game log first so game log infos from triggered or replacement effects follow in the game log
if (!game.isSimulation()) {
game.informPlayers(getLogName() + " discards " + card.getLogName());
}
/* If a card is discarded while Rest in Peace is on the battlefield, abilities that function
* when a card is discarded (such as madness) still work, even though that card never reaches
* a graveyard. In addition, spells or abilities that check the characteristics of a discarded
* card (such as Chandra Ablaze's first ability) can find that card in exile. */
card.moveToZone(Zone.GRAVEYARD, source == null ? null : source.getSourceId(), game, false);
// So discard is also successful if card is moved to another zone by replacement effect!
UUID sourceId = source == null ? null : source.getSourceId();
game.fireEvent(GameEvent.getEvent(GameEvent.EventType.DISCARDED_CARD,
card.getId(), sourceId, playerId));
if (fireEvent) {
game.fireEvent(GameEvent.getEvent(
GameEvent.EventType.DISCARDED_CARDS, sourceId,
sourceId, playerId, 1
));
}
return true;
}
@Override