diff --git a/Mage.Sets/src/mage/cards/h/HellishRebuke.java b/Mage.Sets/src/mage/cards/h/HellishRebuke.java new file mode 100644 index 00000000000..8d3674604b0 --- /dev/null +++ b/Mage.Sets/src/mage/cards/h/HellishRebuke.java @@ -0,0 +1,123 @@ +package mage.cards.h; + +import mage.MageObject; +import mage.abilities.Ability; +import mage.abilities.TriggeredAbilityImpl; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.LoseLifeSourceControllerEffect; +import mage.abilities.effects.common.SacrificeSourceEffect; +import mage.abilities.effects.common.continuous.GainAbilityAllEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.Outcome; +import mage.constants.Zone; +import mage.filter.StaticFilters; +import mage.game.Game; +import mage.game.events.GameEvent; +import mage.watchers.common.SpellsCastWatcher; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class HellishRebuke extends CardImpl { + + public HellishRebuke(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{2}{B}"); + + // Until end of turn, permanents your opponents control gain "When this permanent deals damage to the player who cast Hellish Rebuke, sacrifice this permanent. You lose 2 life." + this.getSpellAbility().addEffect(new HellishRebukeEffect()); + this.getSpellAbility().addWatcher(new SpellsCastWatcher()); + } + + private HellishRebuke(final HellishRebuke card) { + super(card); + } + + @Override + public HellishRebuke copy() { + return new HellishRebuke(this); + } +} + +class HellishRebukeEffect extends OneShotEffect { + + HellishRebukeEffect() { + super(Outcome.Benefit); + staticText = "until end of turn, permanents your opponents control gain " + + "\"When this permanent deals damage to the player who cast {this}, " + + "sacrifice this permanent. You lose 2 life.\""; + } + + private HellishRebukeEffect(final HellishRebukeEffect effect) { + super(effect); + } + + @Override + public HellishRebukeEffect copy() { + return new HellishRebukeEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + MageObject mageObject = source.getSourceObject(game); + game.addEffect(new GainAbilityAllEffect( + new HellishRebukeTriggeredAbility(source, game), + Duration.EndOfTurn, StaticFilters.FILTER_OPPONENTS_PERMANENT + ), source); + return true; + } +} + +class HellishRebukeTriggeredAbility extends TriggeredAbilityImpl { + + private final String sourceName; + private final UUID casterId; + + HellishRebukeTriggeredAbility(Ability source, Game game) { + super(Zone.BATTLEFIELD, new SacrificeSourceEffect()); + this.addEffect(new LoseLifeSourceControllerEffect(2)); + this.sourceName = getSourceName(source, game); + this.casterId = getCasterId(source, game); + } + + private HellishRebukeTriggeredAbility(final HellishRebukeTriggeredAbility ability) { + super(ability); + this.sourceName = ability.sourceName; + this.casterId = ability.casterId; + } + + @Override + public boolean checkEventType(GameEvent event, Game game) { + return event.getType() == GameEvent.EventType.DAMAGED_PLAYER; + } + + @Override + public boolean checkTrigger(GameEvent event, Game game) { + return event.getSourceId().equals(getSourceId()) && event.getPlayerId().equals(casterId); + } + + @Override + public HellishRebukeTriggeredAbility copy() { + return new HellishRebukeTriggeredAbility(this); + } + + @Override + public String getRule() { + return "When this permanent deals damage to the player who cast " + + sourceName + ", sacrifice this permanent. You lose 2 life."; + } + + private static final String getSourceName(Ability source, Game game) { + MageObject object = source.getSourceObject(game); + return object != null ? object.getName() : "Hellish Rebuke"; + } + + private static final UUID getCasterId(Ability source, Game game) { + SpellsCastWatcher watcher = game.getState().getWatcher(SpellsCastWatcher.class); + return watcher.getCasterId(source, game); + } +} diff --git a/Mage.Sets/src/mage/sets/ForgottenRealmsCommander.java b/Mage.Sets/src/mage/sets/ForgottenRealmsCommander.java index c662f18d6cd..23ff352e9c0 100644 --- a/Mage.Sets/src/mage/sets/ForgottenRealmsCommander.java +++ b/Mage.Sets/src/mage/sets/ForgottenRealmsCommander.java @@ -125,6 +125,7 @@ public final class ForgottenRealmsCommander extends ExpansionSet { cards.add(new SetCardInfo("Halimar Depths", 244, Rarity.COMMON, mage.cards.h.HalimarDepths.class)); cards.add(new SetCardInfo("Haven of the Spirit Dragon", 245, Rarity.RARE, mage.cards.h.HavenOfTheSpiritDragon.class)); cards.add(new SetCardInfo("Heirloom Blade", 208, Rarity.UNCOMMON, mage.cards.h.HeirloomBlade.class)); + cards.add(new SetCardInfo("Hellish Rebuke", 26, Rarity.RARE, mage.cards.h.HellishRebuke.class)); cards.add(new SetCardInfo("Heroic Intervention", 161, Rarity.RARE, mage.cards.h.HeroicIntervention.class)); cards.add(new SetCardInfo("Hex", 101, Rarity.RARE, mage.cards.h.Hex.class)); cards.add(new SetCardInfo("High Market", 246, Rarity.RARE, mage.cards.h.HighMarket.class)); diff --git a/Mage/src/main/java/mage/watchers/common/SpellsCastWatcher.java b/Mage/src/main/java/mage/watchers/common/SpellsCastWatcher.java index c4235d5b9b5..94f222340a4 100644 --- a/Mage/src/main/java/mage/watchers/common/SpellsCastWatcher.java +++ b/Mage/src/main/java/mage/watchers/common/SpellsCastWatcher.java @@ -1,6 +1,8 @@ package mage.watchers.common; import mage.MageObject; +import mage.abilities.Ability; +import mage.cards.Card; import mage.constants.WatcherScope; import mage.constants.Zone; import mage.filter.StaticFilters; @@ -68,4 +70,18 @@ public class SpellsCastWatcher extends Watcher { public int getNumberOfNonCreatureSpells() { return nonCreatureSpells; } + + public UUID getCasterId(Ability source, Game game) { + for (Map.Entry> entry : spellsCast.entrySet()) { + if (entry.getValue() + .stream() + .map(Spell::getCard) + .map(Card::getMainCard) + .anyMatch(card -> card.getId().equals(source.getSourceId()) + && card.getZoneChangeCounter(game) == source.getSourceObjectZoneChangeCounter())) { + return entry.getKey(); + } + } + return null; + } }