mirror of
https://github.com/correl/mage.git
synced 2024-12-24 11:50:45 +00:00
* Double faces and adventure cards: improved support with some "exile and cast" effects like Hostage Taker (#7446);
This commit is contained in:
parent
43014f7f5e
commit
e3db50f111
12 changed files with 201 additions and 190 deletions
|
@ -188,11 +188,7 @@ class GontiLordOfLuxurySpendAnyManaEffect extends AsThoughEffectImpl implements
|
|||
if (theCard == null) {
|
||||
return false;
|
||||
}
|
||||
Card mainCard = theCard.getMainCard();
|
||||
if (mainCard == null) {
|
||||
return false;
|
||||
}
|
||||
objectId = mainCard.getId(); // for split cards
|
||||
objectId = theCard.getMainCard().getId(); // for split cards
|
||||
if (objectId.equals(((FixedTarget) getTargetPointer()).getTarget())
|
||||
&& game.getState().getZoneChangeCounter(objectId) <= ((FixedTarget) getTargetPointer()).getZoneChangeCounter() + 1) {
|
||||
// if the card moved from exile to spell the zone change counter is increased by 1 (effect must applies before and on stack, use isCheckPlayableMode?)
|
||||
|
@ -237,11 +233,7 @@ class GontiLordOfLuxuryLookEffect extends AsThoughEffectImpl {
|
|||
if (theCard == null) {
|
||||
return false;
|
||||
}
|
||||
Card mainCard = theCard.getMainCard();
|
||||
if (mainCard == null) {
|
||||
return false;
|
||||
}
|
||||
objectId = mainCard.getId(); // for split cards
|
||||
objectId = theCard.getMainCard().getId(); // for split cards
|
||||
if (affectedControllerId.equals(source.getControllerId())
|
||||
&& game.getState().getZone(objectId) == Zone.EXILED) {
|
||||
Player controller = game.getPlayer(source.getControllerId());
|
||||
|
|
|
@ -113,7 +113,7 @@ class IdentityThiefEffect extends OneShotEffect {
|
|||
if (controller != null
|
||||
&& targetPermanent != null
|
||||
&& sourcePermanent != null) {
|
||||
ContinuousEffect copyEffect = new CopyEffect(Duration.EndOfTurn, targetPermanent.getMainCard(), source.getSourceId());
|
||||
ContinuousEffect copyEffect = new CopyEffect(Duration.EndOfTurn, targetPermanent, source.getSourceId());
|
||||
copyEffect.setTargetPointer(new FixedTarget(sourcePermanent.getId()));
|
||||
game.addEffect(copyEffect, source);
|
||||
UUID exileZoneId = CardUtil.getExileZoneId(game, source.getSourceId(), source.getSourceObjectZoneChangeCounter());
|
||||
|
|
|
@ -8,8 +8,8 @@ import mage.abilities.condition.Condition;
|
|||
import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility;
|
||||
import mage.abilities.effects.AsThoughEffectImpl;
|
||||
import mage.abilities.effects.AsThoughManaEffect;
|
||||
import mage.abilities.effects.ContinuousEffect;
|
||||
import mage.abilities.effects.OneShotEffect;
|
||||
import mage.abilities.hint.ConditionHint;
|
||||
import mage.abilities.keyword.HasteAbility;
|
||||
import mage.abilities.keyword.ReachAbility;
|
||||
import mage.cards.Card;
|
||||
|
@ -25,6 +25,7 @@ import mage.players.Player;
|
|||
import mage.target.targetpointer.FixedTarget;
|
||||
import mage.util.CardUtil;
|
||||
import mage.watchers.Watcher;
|
||||
import mage.watchers.common.AttackedThisTurnWatcher;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.Objects;
|
||||
|
@ -52,14 +53,17 @@ public final class RobberOfTheRich extends CardImpl {
|
|||
this.addAbility(HasteAbility.getInstance());
|
||||
|
||||
// Whenever Robber of the Rich attacks, if defending player has more cards in hand than you, exile the top card of their library. During any turn you attacked with a Rogue, you may cast that card and you may spend mana as though it were mana of any color to cast that spell.
|
||||
this.addAbility(new ConditionalInterveningIfTriggeredAbility(
|
||||
Ability ability = new ConditionalInterveningIfTriggeredAbility(
|
||||
new AttacksTriggeredAbility(
|
||||
new RobberOfTheRichEffect(), false, "", SetTargetPointer.PLAYER
|
||||
), RobberOfTheRichCondition.instance, "Whenever {this} attacks, " +
|
||||
), RobberOfTheRichAttacksCondition.instance, "Whenever {this} attacks, " +
|
||||
"if defending player has more cards in hand than you, exile the top card of their library. " +
|
||||
"During any turn you attacked with a Rogue, you may cast that card and " +
|
||||
"you may spend mana as though it were mana of any color to cast that spell."
|
||||
), new RobberOfTheRichWatcher());
|
||||
"you may spend mana as though it were mana of any color to cast that spell.");
|
||||
ability.addWatcher(new AttackedThisTurnWatcher());
|
||||
ability.addHint(new ConditionHint(RobberOfTheRichAnyTurnAttackedCondition.instance));
|
||||
|
||||
this.addAbility(ability);
|
||||
}
|
||||
|
||||
private RobberOfTheRich(final RobberOfTheRich card) {
|
||||
|
@ -72,7 +76,7 @@ public final class RobberOfTheRich extends CardImpl {
|
|||
}
|
||||
}
|
||||
|
||||
enum RobberOfTheRichCondition implements Condition {
|
||||
enum RobberOfTheRichAttacksCondition implements Condition {
|
||||
instance;
|
||||
|
||||
@Override
|
||||
|
@ -83,6 +87,30 @@ enum RobberOfTheRichCondition implements Condition {
|
|||
}
|
||||
}
|
||||
|
||||
enum RobberOfTheRichAnyTurnAttackedCondition implements Condition {
|
||||
instance;
|
||||
|
||||
@Override
|
||||
public boolean apply(Game game, Ability source) {
|
||||
// your turn
|
||||
if (!source.isControlledBy(game.getActivePlayerId())) {
|
||||
return false;
|
||||
}
|
||||
// attacked with Rogue
|
||||
AttackedThisTurnWatcher watcher = game.getState().getWatcher(AttackedThisTurnWatcher.class);
|
||||
return watcher != null && watcher.getAttackedThisTurnCreatures()
|
||||
.stream()
|
||||
.map(mor -> mor.getPermanentOrLKIBattlefield(game))
|
||||
.filter(Objects::nonNull)
|
||||
.anyMatch(permanent -> permanent.hasSubtype(SubType.ROGUE, game));
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "During that turn you attacked with a Rogue";
|
||||
}
|
||||
}
|
||||
|
||||
class RobberOfTheRichEffect extends OneShotEffect {
|
||||
|
||||
RobberOfTheRichEffect() {
|
||||
|
@ -114,129 +142,12 @@ class RobberOfTheRichEffect extends OneShotEffect {
|
|||
// move card to exile
|
||||
controller.moveCardToExileWithInfo(card, exileId, sourceObject.getIdName(), source, game, Zone.LIBRARY, true);
|
||||
// Add effects only if the card has a spellAbility (e.g. not for lands).
|
||||
if (card.getSpellAbility() == null) {
|
||||
return true;
|
||||
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.makeCardPlayableAndSpendManaAsAnyColor(game, source, card, Duration.Custom, RobberOfTheRichAnyTurnAttackedCondition.instance);
|
||||
}
|
||||
// allow to cast the card
|
||||
game.addEffect(new RobberOfTheRichCastFromExileEffect(card.getId(), exileId), source);
|
||||
// and you may spend mana as though it were mana of any color to cast it
|
||||
ContinuousEffect effect = new RobberOfTheRichSpendAnyManaEffect();
|
||||
effect.setTargetPointer(new FixedTarget(card.getId()));
|
||||
game.addEffect(effect, source);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
class RobberOfTheRichCastFromExileEffect extends AsThoughEffectImpl {
|
||||
|
||||
private UUID cardId;
|
||||
private UUID exileId;
|
||||
|
||||
RobberOfTheRichCastFromExileEffect(UUID cardId, UUID exileId) {
|
||||
super(AsThoughEffectType.PLAY_FROM_NOT_OWN_HAND_ZONE, Duration.Custom, Outcome.Benefit);
|
||||
this.cardId = cardId;
|
||||
this.exileId = exileId;
|
||||
}
|
||||
|
||||
private RobberOfTheRichCastFromExileEffect(final RobberOfTheRichCastFromExileEffect effect) {
|
||||
super(effect);
|
||||
this.cardId = effect.cardId;
|
||||
this.exileId = effect.exileId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean apply(Game game, Ability source) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public RobberOfTheRichCastFromExileEffect copy() {
|
||||
return new RobberOfTheRichCastFromExileEffect(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean applies(UUID sourceId, Ability source, UUID affectedControllerId, Game game) {
|
||||
RobberOfTheRichWatcher watcher = game.getState().getWatcher(RobberOfTheRichWatcher.class);
|
||||
if (watcher == null || !watcher.getAttackedWithRogue(source.getControllerId())) {
|
||||
return false;
|
||||
}
|
||||
if (!sourceId.equals(cardId) || !source.isControlledBy(affectedControllerId)) {
|
||||
return false;
|
||||
}
|
||||
ExileZone exileZone = game.getState().getExile().getExileZone(exileId);
|
||||
if (exileZone != null && exileZone.contains(cardId)) {
|
||||
return true;
|
||||
}
|
||||
discard();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
class RobberOfTheRichSpendAnyManaEffect extends AsThoughEffectImpl implements AsThoughManaEffect {
|
||||
|
||||
RobberOfTheRichSpendAnyManaEffect() {
|
||||
super(AsThoughEffectType.SPEND_OTHER_MANA, Duration.Custom, Outcome.Benefit);
|
||||
}
|
||||
|
||||
private RobberOfTheRichSpendAnyManaEffect(final RobberOfTheRichSpendAnyManaEffect effect) {
|
||||
super(effect);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean apply(Game game, Ability source) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public RobberOfTheRichSpendAnyManaEffect copy() {
|
||||
return new RobberOfTheRichSpendAnyManaEffect(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean applies(UUID objectId, Ability source, UUID affectedControllerId, Game game) {
|
||||
objectId = CardUtil.getMainCardId(game, objectId); // for split cards
|
||||
FixedTarget fixedTarget = ((FixedTarget) getTargetPointer());
|
||||
return source.isControlledBy(affectedControllerId)
|
||||
&& Objects.equals(objectId, fixedTarget.getTarget())
|
||||
&& game.getState().getZoneChangeCounter(objectId) <= fixedTarget.getZoneChangeCounter() + 1
|
||||
&& (game.getState().getZone(objectId) == Zone.STACK || game.getState().getZone(objectId) == Zone.EXILED);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ManaType getAsThoughManaType(ManaType manaType, ManaPoolItem mana, UUID affectedControllerId, Ability source, Game game) {
|
||||
return mana.getFirstAvailable();
|
||||
}
|
||||
}
|
||||
|
||||
class RobberOfTheRichWatcher extends Watcher {
|
||||
|
||||
private Set<UUID> rogueAttackers = new HashSet();
|
||||
|
||||
RobberOfTheRichWatcher() {
|
||||
super(WatcherScope.GAME);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void watch(GameEvent event, Game game) {
|
||||
if (event.getType() != GameEvent.EventType.ATTACKER_DECLARED) {
|
||||
return;
|
||||
}
|
||||
Permanent permanent = game.getPermanent(event.getSourceId());
|
||||
if (permanent == null || !permanent.hasSubtype(SubType.ROGUE, game)) {
|
||||
return;
|
||||
}
|
||||
rogueAttackers.add(event.getPlayerId());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void reset() {
|
||||
super.reset();
|
||||
rogueAttackers.clear();
|
||||
}
|
||||
|
||||
boolean getAttackedWithRogue(UUID playerId) {
|
||||
return rogueAttackers.contains(playerId);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -87,41 +87,3 @@ class StolenStrategyEffect extends OneShotEffect {
|
|||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
class StolenStrategyCastFromExileEffect extends AsThoughEffectImpl {
|
||||
|
||||
private final UUID cardId;
|
||||
private final UUID exileId;
|
||||
|
||||
public StolenStrategyCastFromExileEffect(UUID cardId, UUID exileId) {
|
||||
super(AsThoughEffectType.PLAY_FROM_NOT_OWN_HAND_ZONE, Duration.EndOfTurn, Outcome.Benefit);
|
||||
staticText = "Until end of turn, you may cast that card and you may spend mana as though it were mana of any color to cast it";
|
||||
this.cardId = cardId;
|
||||
this.exileId = exileId;
|
||||
}
|
||||
|
||||
public StolenStrategyCastFromExileEffect(final StolenStrategyCastFromExileEffect effect) {
|
||||
super(effect);
|
||||
this.cardId = effect.cardId;
|
||||
this.exileId = effect.exileId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean apply(Game game, Ability source) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public StolenStrategyCastFromExileEffect copy() {
|
||||
return new StolenStrategyCastFromExileEffect(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean applies(UUID sourceId, Ability source, UUID affectedControllerId, Game game) {
|
||||
if (sourceId.equals(cardId) && source.isControlledBy(affectedControllerId)) {
|
||||
ExileZone exileZone = game.getState().getExile().getExileZone(exileId);
|
||||
return exileZone != null && exileZone.contains(cardId);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -242,9 +242,9 @@ class ValkiGodOfLiesCopyExiledEffect extends OneShotEffect {
|
|||
Cards cards = game.getExile().getExileZone(exileId);
|
||||
if (!cards.isEmpty()
|
||||
&& controller.choose(Outcome.Benefit, cards, target, game)) {
|
||||
Card chosenExiledCreature = game.getCard(target.getFirstTarget());
|
||||
if (chosenExiledCreature != null) {
|
||||
ContinuousEffect copyEffect = new CopyEffect(Duration.WhileOnBattlefield, chosenExiledCreature.getMainCard(), source.getSourceId());
|
||||
Card chosenExiledCard = game.getCard(target.getFirstTarget());
|
||||
if (chosenExiledCard != null) {
|
||||
ContinuousEffect copyEffect = new CopyEffect(Duration.WhileOnBattlefield, chosenExiledCard.getMainCard(), source.getSourceId());
|
||||
copyEffect.setTargetPointer(new FixedTarget(Valki.getId()));
|
||||
game.addEffect(copyEffect, source);
|
||||
return true;
|
||||
|
|
|
@ -689,4 +689,58 @@ public class AdventureCardsTest extends CardTestPlayerBase {
|
|||
execute();
|
||||
assertAllCommandsUsed();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test_HostageTaker_CastFromExileAllParts() {
|
||||
// bug: mdf must be playable as both sides
|
||||
// https://github.com/magefree/mage/pull/7446
|
||||
|
||||
// Curious Pair {1}{G}, creature
|
||||
// Treats to Share {G}, sorcery
|
||||
// Create a Food token.
|
||||
addCard(Zone.HAND, playerA, "Curious Pair");
|
||||
addCard(Zone.BATTLEFIELD, playerA, "Forest", 2); // for prepare
|
||||
addCard(Zone.BATTLEFIELD, playerA, "Swamp", 2); // cast from hostage taker for any color
|
||||
//
|
||||
// When Hostage Taker enters the battlefield, exile another target artifact or creature until Hostage Taker
|
||||
// leaves the battlefield. You may cast that card as long as it remains exiled, and you may spend mana
|
||||
// as though it were mana of any type to cast that spell.
|
||||
addCard(Zone.HAND, playerA, "Hostage Taker", 2); // {2}{U}{B}
|
||||
addCard(Zone.BATTLEFIELD, playerA, "Island", 3);
|
||||
addCard(Zone.BATTLEFIELD, playerA, "Swamp", 1);
|
||||
|
||||
// prepare adventure card on battlefield
|
||||
activateManaAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "{T}: Add {G}", 2);
|
||||
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Curious Pair");
|
||||
waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN);
|
||||
checkPermanentCount("prepare", 1, PhaseStep.PRECOMBAT_MAIN, playerA, "Curious Pair", 1);
|
||||
|
||||
// turn 1 - exile by hostage
|
||||
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Hostage Taker");
|
||||
addTarget(playerA, "Curious Pair");
|
||||
waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN);
|
||||
checkExileCount("after exile 1", 1, PhaseStep.PRECOMBAT_MAIN, playerA, "Curious Pair", 1);
|
||||
// play as creature for any color
|
||||
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Curious Pair");
|
||||
waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN);
|
||||
checkPermanentCount("after play 1", 1, PhaseStep.PRECOMBAT_MAIN, playerA, "Curious Pair", 1);
|
||||
|
||||
// eat green mana (test what hostage's any color effect work)
|
||||
activateManaAbility(3, PhaseStep.PRECOMBAT_MAIN, playerA, "{T}: Add {G}", 2);
|
||||
|
||||
// turn 3 - exile by hostage
|
||||
castSpell(3, PhaseStep.POSTCOMBAT_MAIN, playerA, "Hostage Taker");
|
||||
addTarget(playerA, "Curious Pair");
|
||||
waitStackResolved(3, PhaseStep.POSTCOMBAT_MAIN);
|
||||
checkExileCount("after exile 3", 3, PhaseStep.POSTCOMBAT_MAIN, playerA, "Curious Pair", 1);
|
||||
// play as adventure spell
|
||||
castSpell(3, PhaseStep.POSTCOMBAT_MAIN, playerA, "Treats to Share");
|
||||
waitStackResolved(3, PhaseStep.POSTCOMBAT_MAIN);
|
||||
checkPermanentCount("after play 3", 3, PhaseStep.POSTCOMBAT_MAIN, playerA, "Food", 1);
|
||||
|
||||
setStrictChooseMode(true);
|
||||
setStopAt(3, PhaseStep.END_TURN);
|
||||
execute();
|
||||
assertAllCommandsUsed();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -696,6 +696,46 @@ public class ModalDoubleFacesCardsTest extends CardTestPlayerBase {
|
|||
assertPermanentCount(playerA, "Balduvian Bears", 2);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test_Single_HostageTaker_CastFromExile() {
|
||||
// bug: mdf must be playable as both sides
|
||||
// https://github.com/magefree/mage/pull/7446
|
||||
|
||||
// Akoum Warrior {5}{R} - creature
|
||||
// Akoum Teeth - land
|
||||
addCard(Zone.HAND, playerA, "Akoum Warrior");
|
||||
addCard(Zone.BATTLEFIELD, playerA, "Mountain", 6);
|
||||
addCard(Zone.BATTLEFIELD, playerA, "Swamp", 6); // cast from hostage taker for any color
|
||||
//
|
||||
// When Hostage Taker enters the battlefield, exile another target artifact or creature until Hostage Taker
|
||||
// leaves the battlefield. You may cast that card as long as it remains exiled, and you may spend mana
|
||||
// as though it were mana of any type to cast that spell.
|
||||
addCard(Zone.HAND, playerA, "Hostage Taker", 1); // {2}{U}{B}
|
||||
addCard(Zone.BATTLEFIELD, playerA, "Island", 3);
|
||||
addCard(Zone.BATTLEFIELD, playerA, "Swamp", 1);
|
||||
|
||||
// prepare mdf on battlefield
|
||||
activateManaAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "{T}: Add {R}", 6);
|
||||
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Akoum Warrior");
|
||||
waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN);
|
||||
checkPermanentCount("prepare", 1, PhaseStep.PRECOMBAT_MAIN, playerA, "Akoum Warrior", 1);
|
||||
|
||||
// exile by hostage
|
||||
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Hostage Taker");
|
||||
addTarget(playerA, "Akoum Warrior");
|
||||
waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN);
|
||||
checkExileCount("after exile", 1, PhaseStep.PRECOMBAT_MAIN, playerA, "Akoum Warrior", 1);
|
||||
// play as creature for any color
|
||||
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Akoum Warrior");
|
||||
|
||||
setStrictChooseMode(true);
|
||||
setStopAt(1, PhaseStep.END_TURN);
|
||||
execute();
|
||||
assertAllCommandsUsed();
|
||||
|
||||
assertPermanentCount(playerA, "Akoum Warrior", 1);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test_ETB_OnlySideCardsCanAddAbilitiesToGame() {
|
||||
// possible bug: double triggers (loadCard adds abilities from main + side cards instead side card only)
|
||||
|
|
|
@ -2,11 +2,13 @@ package mage.abilities.effects.common.asthought;
|
|||
|
||||
import mage.MageObjectReference;
|
||||
import mage.abilities.Ability;
|
||||
import mage.abilities.condition.Condition;
|
||||
import mage.abilities.effects.AsThoughEffectImpl;
|
||||
import mage.constants.AsThoughEffectType;
|
||||
import mage.constants.Duration;
|
||||
import mage.constants.Outcome;
|
||||
import mage.game.Game;
|
||||
import mage.util.CardUtil;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
|
@ -14,22 +16,31 @@ import java.util.UUID;
|
|||
* Play card from current zone. Will be discarded on any card movements or blinks.
|
||||
* <p>
|
||||
* Recommends to use combo effects from CardUtil.makeCardPlayableAndSpendManaAsAnyColor instead signle effect
|
||||
* <p>
|
||||
* Affected to all card's parts
|
||||
*
|
||||
* @author JayDi85
|
||||
*/
|
||||
public class CanPlayCardControllerEffect extends AsThoughEffectImpl {
|
||||
|
||||
protected final MageObjectReference mor;
|
||||
private final MageObjectReference mor;
|
||||
private final Condition condition;
|
||||
|
||||
public CanPlayCardControllerEffect(Game game, UUID cardId, int cardZCC, Duration duration) {
|
||||
this(game, cardId, cardZCC, duration, null);
|
||||
}
|
||||
|
||||
public CanPlayCardControllerEffect(Game game, UUID cardId, int cardZCC, Duration duration, 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.condition = condition;
|
||||
}
|
||||
|
||||
public CanPlayCardControllerEffect(final CanPlayCardControllerEffect effect) {
|
||||
super(effect);
|
||||
this.mor = effect.mor;
|
||||
this.condition = effect.condition;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -48,6 +59,12 @@ public class CanPlayCardControllerEffect extends AsThoughEffectImpl {
|
|||
discard();
|
||||
return false;
|
||||
}
|
||||
return mor.refersTo(sourceId, game) && source.isControlledBy(affectedControllerId);
|
||||
|
||||
if (condition != null && !condition.apply(game, source)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
UUID objectIdToCast = CardUtil.getMainCardId(game, sourceId); // affected to all card's parts
|
||||
return mor.refersTo(objectIdToCast, game) && source.isControlledBy(affectedControllerId);
|
||||
}
|
||||
}
|
|
@ -1,6 +1,7 @@
|
|||
package mage.abilities.effects.common.asthought;
|
||||
|
||||
import mage.abilities.Ability;
|
||||
import mage.abilities.condition.Condition;
|
||||
import mage.abilities.effects.AsThoughEffectImpl;
|
||||
import mage.abilities.effects.AsThoughManaEffect;
|
||||
import mage.constants.*;
|
||||
|
@ -15,17 +16,27 @@ 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 Condition condition;
|
||||
|
||||
public YouMaySpendManaAsAnyColorToCastTargetEffect(Duration duration) {
|
||||
this(duration, null);
|
||||
}
|
||||
|
||||
public YouMaySpendManaAsAnyColorToCastTargetEffect(Duration duration, 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.condition = condition;
|
||||
}
|
||||
|
||||
public YouMaySpendManaAsAnyColorToCastTargetEffect(final YouMaySpendManaAsAnyColorToCastTargetEffect effect) {
|
||||
super(effect);
|
||||
this.condition = effect.condition;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -40,10 +51,15 @@ public class YouMaySpendManaAsAnyColorToCastTargetEffect extends AsThoughEffectI
|
|||
|
||||
@Override
|
||||
public boolean applies(UUID objectId, Ability source, UUID affectedControllerId, Game game) {
|
||||
if (condition != null && !condition.apply(game, source)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
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)
|
||||
&& Objects.equals(objectId, fixedTarget.getTarget())
|
||||
&& Objects.equals(objectId, targetId)
|
||||
&& game.getState().getZoneChangeCounter(objectId) <= fixedTarget.getZoneChangeCounter() + 1
|
||||
&& (game.getState().getZone(objectId) == Zone.STACK || game.getState().getZone(objectId) == Zone.EXILED);
|
||||
}
|
||||
|
|
|
@ -10,6 +10,7 @@ import mage.cards.Card;
|
|||
import mage.cards.LevelerCard;
|
||||
import mage.game.Game;
|
||||
import mage.game.events.ZoneChangeEvent;
|
||||
import mage.util.CardUtil;
|
||||
|
||||
import javax.annotation.processing.SupportedSourceVersion;
|
||||
import javax.lang.model.SourceVersion;
|
||||
|
@ -22,10 +23,8 @@ import java.util.UUID;
|
|||
public class PermanentCard extends PermanentImpl {
|
||||
|
||||
protected int maxLevelCounters;
|
||||
// A copy of the origin card that was cast (this is not the original card, so it's possible to chnage some attribute to this blueprint to change attributes to the permanent if it enters the battlefield with e.g. a subtype)
|
||||
// A copy of the origin card that was cast (this is not the original card, so it's possible to change some attribute to this blueprint to change attributes to the permanent if it enters the battlefield with e.g. a subtype)
|
||||
protected Card card;
|
||||
// A copy of original card that was used for copy and create current permanent (used in copy effects and special commands like adjustTargets)
|
||||
protected Card copiedFromCard;
|
||||
// the number this permanent instance had
|
||||
protected int zoneChangeCounter;
|
||||
|
||||
|
@ -220,4 +219,8 @@ public class PermanentCard extends PermanentImpl {
|
|||
card.setZoneChangeCounter(value, game);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Card getMainCard() {
|
||||
return card.getMainCard();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,6 +3,7 @@ package mage.game.permanent;
|
|||
import mage.MageObject;
|
||||
import mage.abilities.Ability;
|
||||
import mage.abilities.costs.mana.ManaCost;
|
||||
import mage.cards.Card;
|
||||
import mage.constants.EmptyNames;
|
||||
import mage.game.Game;
|
||||
import mage.game.permanent.token.Token;
|
||||
|
@ -118,4 +119,9 @@ public class PermanentToken extends PermanentImpl {
|
|||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Card getMainCard() {
|
||||
// token don't have game card, so return itself
|
||||
return this;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -13,6 +13,7 @@ import mage.abilities.Abilities;
|
|||
import mage.abilities.Ability;
|
||||
import mage.abilities.Mode;
|
||||
import mage.abilities.SpellAbility;
|
||||
import mage.abilities.condition.Condition;
|
||||
import mage.abilities.costs.VariableCost;
|
||||
import mage.abilities.costs.mana.*;
|
||||
import mage.abilities.effects.ContinuousEffect;
|
||||
|
@ -1024,21 +1025,30 @@ public final class CardUtil {
|
|||
}
|
||||
}
|
||||
|
||||
public static void makeCardPlayableAndSpendManaAsAnyColor(Game game, Ability source, Card card, Duration duration) {
|
||||
makeCardPlayableAndSpendManaAsAnyColor(game, source, card, duration, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add effects to game that allows to play/cast card from current zone and spend mana as any type for it.
|
||||
* Effects will be discarded/ignored on any card movements or blinks (after ZCC change)
|
||||
*
|
||||
* Affected to all card's parts
|
||||
*
|
||||
* @param game
|
||||
* @param card
|
||||
* @param duration
|
||||
* @param condition can be null
|
||||
*/
|
||||
public static void makeCardPlayableAndSpendManaAsAnyColor(Game game, Ability source, Card card, Duration duration) {
|
||||
public static void makeCardPlayableAndSpendManaAsAnyColor(Game game, Ability source, Card card, Duration duration, Condition condition) {
|
||||
// Effect can be used for cards in zones and permanents on battlefield
|
||||
// So there is a workaround to get real ZCC (PermanentCard's ZCC is static, but it must be from Card's ZCC)
|
||||
// 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
|
||||
int zcc = game.getState().getZoneChangeCounter(card.getId());
|
||||
game.addEffect(new CanPlayCardControllerEffect(game, card.getId(), zcc, duration), source);
|
||||
game.addEffect(new YouMaySpendManaAsAnyColorToCastTargetEffect(duration).setTargetPointer(new FixedTarget(card.getId(), zcc)), source);
|
||||
UUID objectId = card.getMainCard().getId();
|
||||
int zcc = game.getState().getZoneChangeCounter(objectId);
|
||||
game.addEffect(new CanPlayCardControllerEffect(game, objectId, zcc, duration, condition), source);
|
||||
game.addEffect(new YouMaySpendManaAsAnyColorToCastTargetEffect(duration, condition).setTargetPointer(new FixedTarget(objectId, zcc)), source);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
Loading…
Reference in a new issue