[VOW] Implemented Curse of Hospitality

This commit is contained in:
Evan Kranzler 2021-11-12 08:52:57 -05:00
parent 38f0e83274
commit 5260d6d363
6 changed files with 185 additions and 12 deletions

View file

@ -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<Permanent> {
instance;
@Override
public boolean apply(ObjectSourcePlayer<Permanent> 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;
}
}

View file

@ -131,7 +131,7 @@ class RobberOfTheRichEffect extends OneShotEffect {
if (card.getSpellAbility() != null) { if (card.getSpellAbility() != null) {
// allow to cast the card // allow to cast the card
// and you may spend mana as though it were mana of any color to cast it // 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; return true;
} }

View file

@ -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("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("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("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 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("Dawnhart Geist", 8, Rarity.UNCOMMON, mage.cards.d.DawnhartGeist.class));
cards.add(new SetCardInfo("Daybreak Combatants", 153, Rarity.COMMON, mage.cards.d.DaybreakCombatants.class)); cards.add(new SetCardInfo("Daybreak Combatants", 153, Rarity.COMMON, mage.cards.d.DaybreakCombatants.class));

View file

@ -24,22 +24,25 @@ import java.util.UUID;
public class CanPlayCardControllerEffect extends AsThoughEffectImpl { public class CanPlayCardControllerEffect extends AsThoughEffectImpl {
private final MageObjectReference mor; private final MageObjectReference mor;
private final UUID playerId;
private final Condition condition; private final Condition condition;
public CanPlayCardControllerEffect(Game game, UUID cardId, int cardZCC, Duration duration) { 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); super(AsThoughEffectType.PLAY_FROM_NOT_OWN_HAND_ZONE, duration, Outcome.Benefit);
this.staticText = "You may play those card"; this.staticText = "You may play those card";
this.mor = new MageObjectReference(cardId, cardZCC, game); this.mor = new MageObjectReference(cardId, cardZCC, game);
this.playerId = playerId;
this.condition = condition; this.condition = condition;
} }
public CanPlayCardControllerEffect(final CanPlayCardControllerEffect effect) { public CanPlayCardControllerEffect(final CanPlayCardControllerEffect effect) {
super(effect); super(effect);
this.mor = effect.mor; this.mor = effect.mor;
this.playerId = effect.playerId;
this.condition = effect.condition; 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 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));
} }
} }

View file

@ -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. * Spend mana as any color to cast targeted card. Will not affected after any card movements or blinks.
*
* Affects to all card's parts * Affects to all card's parts
* *
* @author JayDi85 * @author JayDi85
*/ */
public class YouMaySpendManaAsAnyColorToCastTargetEffect extends AsThoughEffectImpl implements AsThoughManaEffect { public class YouMaySpendManaAsAnyColorToCastTargetEffect extends AsThoughEffectImpl implements AsThoughManaEffect {
private final UUID playerId;
private final Condition condition; private final Condition condition;
public YouMaySpendManaAsAnyColorToCastTargetEffect(Duration duration) { 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); 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.staticText = "You may spend mana as though it were mana of any color to cast it";
this.playerId = playerId;
this.condition = condition; this.condition = condition;
} }
public YouMaySpendManaAsAnyColorToCastTargetEffect(final YouMaySpendManaAsAnyColorToCastTargetEffect effect) { public YouMaySpendManaAsAnyColorToCastTargetEffect(final YouMaySpendManaAsAnyColorToCastTargetEffect effect) {
super(effect); super(effect);
this.playerId = effect.playerId;
this.condition = effect.condition; this.condition = effect.condition;
} }
@ -58,7 +60,7 @@ public class YouMaySpendManaAsAnyColorToCastTargetEffect extends AsThoughEffectI
objectId = CardUtil.getMainCardId(game, objectId); // for split cards objectId = CardUtil.getMainCardId(game, objectId); // for split cards
FixedTarget fixedTarget = ((FixedTarget) getTargetPointer()); FixedTarget fixedTarget = ((FixedTarget) getTargetPointer());
UUID targetId = CardUtil.getMainCardId(game, fixedTarget.getTarget()); // Affects to all card's parts (example: Hostage Taker exile mdf card) 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) && Objects.equals(objectId, targetId)
&& game.getState().getZoneChangeCounter(objectId) <= fixedTarget.getZoneChangeCounter() + 1 && game.getState().getZoneChangeCounter(objectId) <= fixedTarget.getZoneChangeCounter() + 1
&& (game.getState().getZone(objectId) == Zone.STACK || game.getState().getZone(objectId) == Zone.EXILED); && (game.getState().getZone(objectId) == Zone.STACK || game.getState().getZone(objectId) == Zone.EXILED);

View file

@ -1157,7 +1157,7 @@ public final class CardUtil {
} }
public static void makeCardPlayable(Game game, Ability source, Card card, Duration duration, boolean anyColor) { 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 anyColor
* @param condition can be null * @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 // 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) // 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 // So there is a workaround to get actual card's ZCC
// Example: Hostage Taker // Example: Hostage Taker
UUID objectId = card.getMainCard().getId(); UUID objectId = card.getMainCard().getId();
int zcc = game.getState().getZoneChangeCounter(objectId); 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) { 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);
} }
} }