diff --git a/Mage.Sets/src/mage/cards/r/RixMaadiReveler.java b/Mage.Sets/src/mage/cards/r/RixMaadiReveler.java new file mode 100644 index 0000000000..82136a1ee7 --- /dev/null +++ b/Mage.Sets/src/mage/cards/r/RixMaadiReveler.java @@ -0,0 +1,83 @@ +package mage.cards.r; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.condition.common.SpectacleCondition; +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.keyword.SpectacleAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Outcome; +import mage.constants.SubType; +import mage.game.Game; +import mage.players.Player; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class RixMaadiReveler extends CardImpl { + + public RixMaadiReveler(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{R}"); + + this.subtype.add(SubType.HUMAN); + this.subtype.add(SubType.SHAMAN); + this.power = new MageInt(2); + this.toughness = new MageInt(2); + + // Spectacle {2}{B}{R} + this.addAbility(new SpectacleAbility(this, new ManaCostsImpl("{2}{B}{R}"))); + + // When Rix Maadi Reveler enters the battlefield, discard a card, then draw a card. If Rix Maadi Reveler's spectacle cost was paid, instead discard your hand, then draw three cards. + this.addAbility(new EntersBattlefieldTriggeredAbility(new RixMaadiRevelerEffect(), false)); + } + + public RixMaadiReveler(final RixMaadiReveler card) { + super(card); + } + + @Override + public RixMaadiReveler copy() { + return new RixMaadiReveler(this); + } +} + +class RixMaadiRevelerEffect extends OneShotEffect { + + RixMaadiRevelerEffect() { + super(Outcome.Benefit); + staticText = "discard a card, then draw a card. " + + "If {this}'s spectacle cost was paid, " + + "instead discard your hand, then draw three cards."; + } + + private RixMaadiRevelerEffect(final RixMaadiRevelerEffect effect) { + super(effect); + } + + @Override + public RixMaadiRevelerEffect copy() { + return new RixMaadiRevelerEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player player = game.getPlayer(source.getControllerId()); + if (player == null) { + return false; + } + if (SpectacleCondition.instance.apply(game, source)) { + player.discard(player.getHand().size(), false, source, game); + player.drawCards(3, game); + } else { + player.discard(1, false, source, game); + player.drawCards(1, game); + } + return true; + } +} diff --git a/Mage.Sets/src/mage/sets/RavnicaAllegiance.java b/Mage.Sets/src/mage/sets/RavnicaAllegiance.java index 9c183b651a..7638afdcb6 100644 --- a/Mage.Sets/src/mage/sets/RavnicaAllegiance.java +++ b/Mage.Sets/src/mage/sets/RavnicaAllegiance.java @@ -34,6 +34,7 @@ public final class RavnicaAllegiance extends ExpansionSet { cards.add(new SetCardInfo("Growth Spiral", 178, Rarity.COMMON, mage.cards.g.GrowthSpiral.class)); cards.add(new SetCardInfo("Mortify", 192, Rarity.UNCOMMON, mage.cards.m.Mortify.class)); + cards.add(new SetCardInfo("Rix Maadi Reveler", 109, Rarity.RARE, mage.cards.r.RixMaadiReveler.class)); cards.add(new SetCardInfo("The Haunt of Hightower", 273, Rarity.MYTHIC, mage.cards.t.TheHauntOfHightower.class)); } diff --git a/Mage/src/main/java/mage/abilities/condition/common/SpectacleCondition.java b/Mage/src/main/java/mage/abilities/condition/common/SpectacleCondition.java new file mode 100644 index 0000000000..8082411944 --- /dev/null +++ b/Mage/src/main/java/mage/abilities/condition/common/SpectacleCondition.java @@ -0,0 +1,33 @@ + +package mage.abilities.condition.common; + +import mage.abilities.Ability; +import mage.abilities.condition.Condition; +import mage.abilities.keyword.SpectacleAbility; +import mage.constants.AbilityType; +import mage.game.Game; + +import java.util.ArrayList; +import java.util.List; + +/** + * @author TheElk801 + */ +public enum SpectacleCondition implements Condition { + + instance; + + @Override + public boolean apply(Game game, Ability source) { + if (source.getAbilityType() == AbilityType.TRIGGERED) { + @SuppressWarnings("unchecked") + List spectacleActivations = (ArrayList) game.getState().getValue(SpectacleAbility.SPECTACLE_ACTIVATION_VALUE_KEY + source.getSourceId()); + if (spectacleActivations != null) { + return spectacleActivations.contains(game.getState().getZoneChangeCounter(source.getSourceId()) - 1); + } + return false; + } else { + return source instanceof SpectacleAbility; + } + } +} diff --git a/Mage/src/main/java/mage/abilities/keyword/SpectacleAbility.java b/Mage/src/main/java/mage/abilities/keyword/SpectacleAbility.java new file mode 100644 index 0000000000..e646742d6a --- /dev/null +++ b/Mage/src/main/java/mage/abilities/keyword/SpectacleAbility.java @@ -0,0 +1,80 @@ + +package mage.abilities.keyword; + +import mage.abilities.SpellAbility; +import mage.abilities.costs.mana.ManaCost; +import mage.cards.Card; +import mage.constants.SpellAbilityType; +import mage.constants.Zone; +import mage.game.Game; +import mage.watchers.common.PlayerLostLifeWatcher; + +import java.util.ArrayList; +import java.util.UUID; + +/** + * @author TheElk801 + */ +public class SpectacleAbility extends SpellAbility { + + public static final String SPECTACLE_ACTIVATION_VALUE_KEY = "spectacleActivation"; + + private String rule; + + public SpectacleAbility(Card card, ManaCost spectacleCosts) { + super(spectacleCosts, card.getName() + " with spectacle", Zone.HAND, SpellAbilityType.BASE_ALTERNATE); + this.getCosts().addAll(card.getSpellAbility().getCosts().copy()); + this.getEffects().addAll(card.getSpellAbility().getEffects().copy()); + this.getTargets().addAll(card.getSpellAbility().getTargets().copy()); + this.spellAbilityType = SpellAbilityType.BASE_ALTERNATE; + this.timing = card.getSpellAbility().getTiming(); + this.setRuleAtTheTop(true); + this.rule = "Spectacle " + spectacleCosts.getText() + + " (You may cast this spell for its spectacle cost rather than its mana cost if an opponent lost life this turn.)"; + } + + public SpectacleAbility(final SpectacleAbility ability) { + super(ability); + this.rule = ability.rule; + } + + @Override + public ActivationStatus canActivate(UUID playerId, Game game) { + PlayerLostLifeWatcher watcher = (PlayerLostLifeWatcher) game.getState().getWatchers().get(PlayerLostLifeWatcher.class.getSimpleName()); + if (watcher != null && watcher.getAllOppLifeLost(playerId, game) > 0) { + return super.canActivate(playerId, game); + } + return ActivationStatus.getFalse(); + } + + @Override + @SuppressWarnings("unchecked") + public boolean activate(Game game, boolean noMana) { + if (super.activate(game, noMana)) { + ArrayList spectacleActivations = (ArrayList) game.getState().getValue(SPECTACLE_ACTIVATION_VALUE_KEY + getSourceId()); + if (spectacleActivations == null) { + spectacleActivations = new ArrayList<>(); // zoneChangeCounter + game.getState().setValue(SPECTACLE_ACTIVATION_VALUE_KEY + getSourceId(), spectacleActivations); + } + spectacleActivations.add(game.getState().getZoneChangeCounter(getSourceId())); + return true; + } + return false; + } + + @Override + public SpectacleAbility copy() { + return new SpectacleAbility(this); + } + + @Override + public String getRule(boolean all) { + return getRule(); + } + + @Override + public String getRule() { + return rule; + } + +} diff --git a/Utils/keywords.txt b/Utils/keywords.txt index c108ac7d90..bef1ffec8a 100644 --- a/Utils/keywords.txt +++ b/Utils/keywords.txt @@ -82,6 +82,7 @@ Shroud|instance| Soulbond|instance| Soulshift|number| Skulk|new| +Spectacle|card, cost| Storm|new| Sunburst|new| Swampcycling|cost|