diff --git a/Mage.Sets/src/mage/cards/c/CurseOfHospitality.java b/Mage.Sets/src/mage/cards/c/CurseOfHospitality.java new file mode 100644 index 0000000000..791c905b46 --- /dev/null +++ b/Mage.Sets/src/mage/cards/c/CurseOfHospitality.java @@ -0,0 +1,166 @@ +package mage.cards.c; + +import mage.abilities.Ability; +import mage.abilities.TriggeredAbilityImpl; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.AttachEffect; +import mage.abilities.effects.common.continuous.GainAbilityAllEffect; +import mage.abilities.keyword.EnchantAbility; +import mage.abilities.keyword.TrampleAbility; +import mage.cards.Card; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.*; +import mage.filter.FilterPermanent; +import mage.filter.common.FilterCreaturePermanent; +import mage.filter.predicate.ObjectSourcePlayer; +import mage.filter.predicate.ObjectSourcePlayerPredicate; +import mage.game.Game; +import mage.game.events.DamagedEvent; +import mage.game.events.GameEvent; +import mage.game.permanent.Permanent; +import mage.players.Player; +import mage.target.TargetPlayer; +import mage.target.targetpointer.FixedTarget; +import mage.util.CardUtil; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class CurseOfHospitality extends CardImpl { + + private static final FilterPermanent filter + = new FilterCreaturePermanent("creatures attacking enchanted player"); + + static { + filter.add(CurseOfHospitalityPredicate.instance); + } + + public CurseOfHospitality(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{2}{R}"); + + this.subtype.add(SubType.AURA); + this.subtype.add(SubType.CURSE); + + // Enchant player + TargetPlayer auraTarget = new TargetPlayer(); + this.getSpellAbility().addTarget(auraTarget); + this.getSpellAbility().addEffect(new AttachEffect(Outcome.BoostCreature)); + this.addAbility(new EnchantAbility(auraTarget.getTargetName())); + + // Creatures attacking enchanted player have trample. + this.addAbility(new SimpleStaticAbility(new GainAbilityAllEffect( + TrampleAbility.getInstance(), Duration.WhileOnBattlefield, filter + ))); + + // Whenever a creature deals combat damage to enchanted player, that player exiles the top card of their library. Until end of turn, that creature's controller may play that card and they may spend mana as though it were mana of any color to cast that spell. + this.addAbility(new CurseOfHospitalityTriggeredAbility()); + } + + private CurseOfHospitality(final CurseOfHospitality card) { + super(card); + } + + @Override + public CurseOfHospitality copy() { + return new CurseOfHospitality(this); + } +} + +enum CurseOfHospitalityPredicate implements ObjectSourcePlayerPredicate { + instance; + + @Override + public boolean apply(ObjectSourcePlayer input, Game game) { + Permanent permanent = game.getPermanent(input.getSourceId()); + UUID defenderId = game.getCombat().getDefenderId(input.getObject().getId()); + return permanent != null && defenderId != null && defenderId.equals(permanent.getAttachedTo()); + } +} + +class CurseOfHospitalityTriggeredAbility extends TriggeredAbilityImpl { + + CurseOfHospitalityTriggeredAbility() { + super(Zone.BATTLEFIELD, new CurseOfHospitalityEffect()); + } + + private CurseOfHospitalityTriggeredAbility(final CurseOfHospitalityTriggeredAbility ability) { + super(ability); + } + + @Override + public CurseOfHospitalityTriggeredAbility copy() { + return new CurseOfHospitalityTriggeredAbility(this); + } + + @Override + public boolean checkEventType(GameEvent event, Game game) { + return event.getType() == GameEvent.EventType.DAMAGED_PLAYER; + } + + @Override + public boolean checkTrigger(GameEvent event, Game game) { + DamagedEvent dEvent = (DamagedEvent) event; + Permanent permanent = getSourcePermanentIfItStillExists(game); + if (!dEvent.isCombatDamage() || permanent == null + || !dEvent.getPlayerId().equals(permanent.getAttachedTo())) { + return false; + } + this.getEffects().setTargetPointer(new FixedTarget(game.getControllerId(dEvent.getSourceId()))); + return true; + } + + @Override + public String getRule() { + return "Whenever a creature deals combat damage to enchanted player, " + + "that player exiles the top card of their library. " + + "Until end of turn, that creature's controller may play that card " + + "and they may spend mana as though it were mana of any color to cast that spell."; + } +} + +class CurseOfHospitalityEffect extends OneShotEffect { + + CurseOfHospitalityEffect() { + super(Outcome.Benefit); + } + + private CurseOfHospitalityEffect(final CurseOfHospitalityEffect effect) { + super(effect); + } + + @Override + public CurseOfHospitalityEffect copy() { + return new CurseOfHospitalityEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Permanent permanent = source.getSourcePermanentOrLKI(game); + if (permanent == null) { + return false; + } + Player enchanted = game.getPlayer(permanent.getAttachedTo()); + if (enchanted == null) { + return false; + } + Card card = enchanted.getLibrary().getFromTop(game); + if (card == null) { + return false; + } + enchanted.moveCardsToExile( + card, source, game, true, + CardUtil.getExileZoneId(game, source), + CardUtil.getSourceLogName(game, source) + ); + Player player = game.getPlayer(getTargetPointer().getFirst(game, source)); + if (player == null) { + return true; + } + CardUtil.makeCardPlayable(game, source, card, Duration.EndOfTurn, true, player.getId(), null); + return true; + } +} diff --git a/Mage.Sets/src/mage/cards/r/RobberOfTheRich.java b/Mage.Sets/src/mage/cards/r/RobberOfTheRich.java index 08592b2ce2..e2ec8557fa 100644 --- a/Mage.Sets/src/mage/cards/r/RobberOfTheRich.java +++ b/Mage.Sets/src/mage/cards/r/RobberOfTheRich.java @@ -131,7 +131,7 @@ class RobberOfTheRichEffect extends OneShotEffect { if (card.getSpellAbility() != null) { // allow to cast the card // and you may spend mana as though it were mana of any color to cast it - CardUtil.makeCardPlayable(game, source, card, Duration.Custom, true, RobberOfTheRichAnyTurnAttackedCondition.instance); + CardUtil.makeCardPlayable(game, source, card, Duration.Custom, true, null, RobberOfTheRichAnyTurnAttackedCondition.instance); } return true; } diff --git a/Mage.Sets/src/mage/sets/InnistradCrimsonVow.java b/Mage.Sets/src/mage/sets/InnistradCrimsonVow.java index 17067aeb82..61f1f8ebc6 100644 --- a/Mage.Sets/src/mage/sets/InnistradCrimsonVow.java +++ b/Mage.Sets/src/mage/sets/InnistradCrimsonVow.java @@ -104,6 +104,7 @@ public final class InnistradCrimsonVow extends ExpansionSet { cards.add(new SetCardInfo("Cruel Witness", 55, Rarity.COMMON, mage.cards.c.CruelWitness.class)); cards.add(new SetCardInfo("Crushing Canopy", 194, Rarity.COMMON, mage.cards.c.CrushingCanopy.class)); cards.add(new SetCardInfo("Cultivator Colossus", 195, Rarity.MYTHIC, mage.cards.c.CultivatorColossus.class)); + cards.add(new SetCardInfo("Curse of Hospitality", 152, Rarity.RARE, mage.cards.c.CurseOfHospitality.class)); cards.add(new SetCardInfo("Dawnhart Disciple", 196, Rarity.COMMON, mage.cards.d.DawnhartDisciple.class)); cards.add(new SetCardInfo("Dawnhart Geist", 8, Rarity.UNCOMMON, mage.cards.d.DawnhartGeist.class)); cards.add(new SetCardInfo("Daybreak Combatants", 153, Rarity.COMMON, mage.cards.d.DaybreakCombatants.class)); diff --git a/Mage/src/main/java/mage/abilities/effects/common/asthought/CanPlayCardControllerEffect.java b/Mage/src/main/java/mage/abilities/effects/common/asthought/CanPlayCardControllerEffect.java index 77c269c29a..2e21df0178 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/asthought/CanPlayCardControllerEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/asthought/CanPlayCardControllerEffect.java @@ -24,22 +24,25 @@ import java.util.UUID; public class CanPlayCardControllerEffect extends AsThoughEffectImpl { private final MageObjectReference mor; + private final UUID playerId; private final Condition condition; public CanPlayCardControllerEffect(Game game, UUID cardId, int cardZCC, Duration duration) { - this(game, cardId, cardZCC, duration, null); + this(game, cardId, cardZCC, duration, null, null); } - public CanPlayCardControllerEffect(Game game, UUID cardId, int cardZCC, Duration duration, Condition condition) { + public CanPlayCardControllerEffect(Game game, UUID cardId, int cardZCC, Duration duration, UUID playerId, Condition condition) { super(AsThoughEffectType.PLAY_FROM_NOT_OWN_HAND_ZONE, duration, Outcome.Benefit); this.staticText = "You may play those card"; this.mor = new MageObjectReference(cardId, cardZCC, game); + this.playerId = playerId; this.condition = condition; } public CanPlayCardControllerEffect(final CanPlayCardControllerEffect effect) { super(effect); this.mor = effect.mor; + this.playerId = effect.playerId; this.condition = effect.condition; } @@ -65,6 +68,7 @@ public class CanPlayCardControllerEffect extends AsThoughEffectImpl { } UUID objectIdToCast = CardUtil.getMainCardId(game, sourceId); // affected to all card's parts - return mor.refersTo(objectIdToCast, game) && source.isControlledBy(affectedControllerId); + return mor.refersTo(objectIdToCast, game) + && (playerId == null ? source.isControlledBy(affectedControllerId) : playerId.equals(affectedControllerId)); } } diff --git a/Mage/src/main/java/mage/abilities/effects/common/asthought/YouMaySpendManaAsAnyColorToCastTargetEffect.java b/Mage/src/main/java/mage/abilities/effects/common/asthought/YouMaySpendManaAsAnyColorToCastTargetEffect.java index 69aef22e59..f4b06f3a36 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/asthought/YouMaySpendManaAsAnyColorToCastTargetEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/asthought/YouMaySpendManaAsAnyColorToCastTargetEffect.java @@ -15,27 +15,29 @@ import java.util.UUID; /** * Spend mana as any color to cast targeted card. Will not affected after any card movements or blinks. - * * Affects to all card's parts * * @author JayDi85 */ public class YouMaySpendManaAsAnyColorToCastTargetEffect extends AsThoughEffectImpl implements AsThoughManaEffect { + private final UUID playerId; private final Condition condition; public YouMaySpendManaAsAnyColorToCastTargetEffect(Duration duration) { - this(duration, null); + this(duration, null, null); } - public YouMaySpendManaAsAnyColorToCastTargetEffect(Duration duration, Condition condition) { + public YouMaySpendManaAsAnyColorToCastTargetEffect(Duration duration, UUID playerId, Condition condition) { super(AsThoughEffectType.SPEND_OTHER_MANA, duration, Outcome.Benefit); this.staticText = "You may spend mana as though it were mana of any color to cast it"; + this.playerId = playerId; this.condition = condition; } public YouMaySpendManaAsAnyColorToCastTargetEffect(final YouMaySpendManaAsAnyColorToCastTargetEffect effect) { super(effect); + this.playerId = effect.playerId; this.condition = effect.condition; } @@ -58,7 +60,7 @@ public class YouMaySpendManaAsAnyColorToCastTargetEffect extends AsThoughEffectI objectId = CardUtil.getMainCardId(game, objectId); // for split cards FixedTarget fixedTarget = ((FixedTarget) getTargetPointer()); UUID targetId = CardUtil.getMainCardId(game, fixedTarget.getTarget()); // Affects to all card's parts (example: Hostage Taker exile mdf card) - return source.isControlledBy(affectedControllerId) + return (playerId == null ? source.isControlledBy(affectedControllerId) : playerId.equals(affectedControllerId)) && Objects.equals(objectId, targetId) && game.getState().getZoneChangeCounter(objectId) <= fixedTarget.getZoneChangeCounter() + 1 && (game.getState().getZone(objectId) == Zone.STACK || game.getState().getZone(objectId) == Zone.EXILED); diff --git a/Mage/src/main/java/mage/util/CardUtil.java b/Mage/src/main/java/mage/util/CardUtil.java index 983b461a30..ea1bdf5591 100644 --- a/Mage/src/main/java/mage/util/CardUtil.java +++ b/Mage/src/main/java/mage/util/CardUtil.java @@ -1157,7 +1157,7 @@ public final class CardUtil { } public static void makeCardPlayable(Game game, Ability source, Card card, Duration duration, boolean anyColor) { - makeCardPlayable(game, source, card, duration, anyColor, null); + makeCardPlayable(game, source, card, duration, anyColor, null, null); } /** @@ -1172,16 +1172,16 @@ public final class CardUtil { * @param anyColor * @param condition can be null */ - public static void makeCardPlayable(Game game, Ability source, Card card, Duration duration, boolean anyColor, Condition condition) { + public static void makeCardPlayable(Game game, Ability source, Card card, Duration duration, boolean anyColor, UUID playerId, Condition condition) { // Effect can be used for cards in zones and permanents on battlefield // PermanentCard's ZCC is static, but we need updated ZCC from the card (after moved to another zone) // So there is a workaround to get actual card's ZCC // Example: Hostage Taker UUID objectId = card.getMainCard().getId(); int zcc = game.getState().getZoneChangeCounter(objectId); - game.addEffect(new CanPlayCardControllerEffect(game, objectId, zcc, duration, condition), source); + game.addEffect(new CanPlayCardControllerEffect(game, objectId, zcc, duration, playerId, condition), source); if (anyColor) { - game.addEffect(new YouMaySpendManaAsAnyColorToCastTargetEffect(duration, condition).setTargetPointer(new FixedTarget(objectId, zcc)), source); + game.addEffect(new YouMaySpendManaAsAnyColorToCastTargetEffect(duration, playerId, condition).setTargetPointer(new FixedTarget(objectId, zcc)), source); } }