Divided thoughtAs.Cast into two different states CAST_FROM_NON_HAND_ZONE and CAST_AS_INSTANT. Some checks and tests still needed.

This commit is contained in:
LevelX2 2014-08-08 17:27:10 +02:00
parent 708f54b66c
commit 4f0f42133d
27 changed files with 88 additions and 119 deletions

View file

@ -77,7 +77,7 @@ public class MisthollowGriffin extends CardImpl {
class MisthollowGriffinPlayEffect extends AsThoughEffectImpl {
public MisthollowGriffinPlayEffect() {
super(AsThoughEffectType.CAST, Duration.EndOfGame, Outcome.Benefit);
super(AsThoughEffectType.CAST_FROM_NON_HAND_ZONE, Duration.EndOfGame, Outcome.Benefit);
staticText = "You may cast {this} from exile";
}

View file

@ -112,7 +112,7 @@ class StolenGoodsCastFromExileEffect extends AsThoughEffectImpl {
private final UUID cardId;
public StolenGoodsCastFromExileEffect(UUID cardId) {
super(AsThoughEffectType.CAST, Duration.EndOfTurn, Outcome.Benefit);
super(AsThoughEffectType.CAST_FROM_NON_HAND_ZONE, Duration.EndOfTurn, Outcome.Benefit);
staticText = "You may cast card from exile";
this.cardId = cardId;
}

View file

@ -113,7 +113,7 @@ class OrnateKanzashiCastFromExileEffect extends AsThoughEffectImpl {
private UUID cardId;
public OrnateKanzashiCastFromExileEffect(UUID cardId) {
super(AsThoughEffectType.CAST, Duration.EndOfTurn, Outcome.Benefit);
super(AsThoughEffectType.CAST_FROM_NON_HAND_ZONE, Duration.EndOfTurn, Outcome.Benefit);
staticText = "You may play card from exile";
this.cardId = cardId;
}

View file

@ -94,10 +94,10 @@ public class FiendOfTheShadows extends CardImpl {
class FiendOfTheShadowsEffect extends AsThoughEffectImpl {
private UUID exileId;
private final UUID exileId;
public FiendOfTheShadowsEffect(UUID exileId) {
super(AsThoughEffectType.CAST, Duration.EndOfGame, Outcome.Benefit);
super(AsThoughEffectType.CAST_FROM_NON_HAND_ZONE, Duration.EndOfGame, Outcome.Benefit);
this.exileId = exileId;
staticText = "You may play that card for as long as it remains exiled";
}

View file

@ -88,7 +88,7 @@ class GravecrawlerPlayEffect extends AsThoughEffectImpl {
}
public GravecrawlerPlayEffect() {
super(AsThoughEffectType.CAST, Duration.EndOfGame, Outcome.Benefit);
super(AsThoughEffectType.CAST_FROM_NON_HAND_ZONE, Duration.EndOfGame, Outcome.Benefit);
staticText = "You may cast Gravecrawler from your graveyard as long as you control a Zombie";
}
@ -111,8 +111,9 @@ class GravecrawlerPlayEffect extends AsThoughEffectImpl {
if (sourceId.equals(source.getSourceId())) {
Card card = game.getCard(source.getSourceId());
if (card != null && game.getState().getZone(source.getSourceId()) == Zone.GRAVEYARD && game.canPlaySorcery(source.getControllerId())) {
if (game.getBattlefield().countAll(filter, source.getControllerId(), game) > 0)
if (game.getBattlefield().countAll(filter, source.getControllerId(), game) > 0) {
return true;
}
}
}
return false;

View file

@ -95,7 +95,7 @@ public class HavengulLich extends CardImpl {
class HavengulLichPlayEffect extends AsThoughEffectImpl {
public HavengulLichPlayEffect() {
super(AsThoughEffectType.CAST, Duration.EndOfTurn, Outcome.Benefit);
super(AsThoughEffectType.CAST_FROM_NON_HAND_ZONE, Duration.EndOfTurn, Outcome.Benefit);
staticText = "You may cast target creature card in a graveyard this turn";
}

View file

@ -78,7 +78,7 @@ public class NightveilSpecter extends CardImpl {
// Flying
this.addAbility(FlyingAbility.getInstance());
// Whenever Nightveil Specter deals combat damage to a player, that player exiles the top card of his or her library.
// Whenever Nightveil Specter deals combat damage to a player, that player exiles the top card of his or her library.
this.addAbility(new DealsDamageToAPlayerTriggeredAbility(new NightveilSpecterExileEffect(),false, true));
// You may play cards exiled with Nightveil Specter.
@ -129,7 +129,7 @@ class NightveilSpecterExileEffect extends OneShotEffect {
class NightveilSpecterEffect extends AsThoughEffectImpl {
public NightveilSpecterEffect() {
super(AsThoughEffectType.CAST, Duration.EndOfGame, Outcome.Benefit);
super(AsThoughEffectType.CAST_FROM_NON_HAND_ZONE, Duration.EndOfGame, Outcome.Benefit);
staticText = "You may play cards exiled with {this}";
}
@ -154,18 +154,7 @@ class NightveilSpecterEffect extends AsThoughEffectImpl {
Player controller = game.getPlayer(source.getControllerId());
if (controller != null && card != null && game.getState().getZone(card.getId()) == Zone.EXILED) {
ExileZone zone = game.getExile().getExileZone(CardUtil.getCardExileZoneId(game, source));
if (zone != null && zone.contains(card.getId())) {
if (card.getCardType().contains(CardType.LAND)) {
// If the revealed card is a land, you can play it only if it's your turn and you haven't yet played a land this turn.
if (game.getActivePlayerId().equals(source.getControllerId()) && controller.canPlayLand()) {
return true;
}
} else {
if (card.getSpellAbility().spellCanBeActivatedRegularlyNow(source.getControllerId(), game)) {
return true;
}
}
}
return zone != null && zone.contains(card.getId());
}
return false;
}

View file

@ -82,7 +82,7 @@ class QuickenAsThoughEffect extends AsThoughEffectImpl {
private int zoneChangeCounter;
public QuickenAsThoughEffect() {
super(AsThoughEffectType.CAST, Duration.EndOfTurn, Outcome.Benefit);
super(AsThoughEffectType.CAST_AS_INSTANT, Duration.EndOfTurn, Outcome.Benefit);
staticText = "The next sorcery card you cast this turn can be cast as though it had flash";
}
@ -128,7 +128,7 @@ class QuickenAsThoughEffect extends AsThoughEffectImpl {
class QuickenWatcher extends Watcher {
public List<String> activeQuickenSpells = new ArrayList<String>();
public List<String> activeQuickenSpells = new ArrayList<>();
public QuickenWatcher() {
super("consumeQuickenWatcher", WatcherScope.PLAYER);

View file

@ -123,7 +123,7 @@ class PropheticFlamespeakerCastFromExileEffect extends AsThoughEffectImpl {
private final UUID cardId;
public PropheticFlamespeakerCastFromExileEffect(UUID cardId) {
super(AsThoughEffectType.CAST, Duration.EndOfTurn, Outcome.Benefit);
super(AsThoughEffectType.CAST_FROM_NON_HAND_ZONE, Duration.EndOfTurn, Outcome.Benefit);
staticText = "You may play card from exile";
this.cardId = cardId;
}

View file

@ -229,7 +229,7 @@ class ChandraPyromasterEffect2 extends OneShotEffect {
class ChandraPyromasterCastFromExileEffect extends AsThoughEffectImpl {
public ChandraPyromasterCastFromExileEffect() {
super(AsThoughEffectType.CAST, Duration.EndOfTurn, Outcome.Benefit);
super(AsThoughEffectType.CAST_FROM_NON_HAND_ZONE, Duration.EndOfTurn, Outcome.Benefit);
staticText = "You may play the card from exile this turn";
}

View file

@ -95,7 +95,7 @@ class SavageSummoningAsThoughEffect extends AsThoughEffectImpl {
private int zoneChangeCounter;
public SavageSummoningAsThoughEffect() {
super(AsThoughEffectType.CAST, Duration.EndOfTurn, Outcome.Benefit);
super(AsThoughEffectType.CAST_AS_INSTANT, Duration.EndOfTurn, Outcome.Benefit);
staticText = "The next creature card you cast this turn can be cast as though it had flash";
}

View file

@ -120,7 +120,7 @@ class ActOnImpulseMayPlayExiledEffect extends AsThoughEffectImpl {
public List<UUID> cards = new ArrayList<>();
public ActOnImpulseMayPlayExiledEffect(List<UUID> cards) {
super(AsThoughEffectType.CAST, Duration.EndOfTurn, Outcome.Benefit);
super(AsThoughEffectType.CAST_FROM_NON_HAND_ZONE, Duration.EndOfTurn, Outcome.Benefit);
this.cards.addAll(cards);
}
@ -145,16 +145,7 @@ class ActOnImpulseMayPlayExiledEffect extends AsThoughEffectImpl {
Player controller = game.getPlayer(source.getControllerId());
if (controller != null && card != null && game.getState().getZone(sourceId) == Zone.EXILED) {
if (cards.contains(sourceId)) {
if (card.getCardType().contains(CardType.LAND)) {
// If the revealed card is a land, you can play it only if it's your turn and you haven't yet played a land this turn.
if (game.getActivePlayerId().equals(source.getControllerId()) && controller.canPlayLand()) {
return true;
}
} else {
if (card.getSpellAbility().spellCanBeActivatedRegularlyNow(source.getControllerId(), game)) {
return true;
}
}
return true;
}
}
return false;

View file

@ -117,7 +117,7 @@ class PraetorsGraspPlayEffect extends AsThoughEffectImpl {
private UUID cardId;
public PraetorsGraspPlayEffect(UUID cardId) {
super(AsThoughEffectType.CAST, Duration.EndOfGame, Outcome.Benefit);
super(AsThoughEffectType.CAST_FROM_NON_HAND_ZONE, Duration.EndOfGame, Outcome.Benefit);
this.cardId = cardId;
staticText = "You may look at and play that card for as long as it remains exiled";
}
@ -143,9 +143,7 @@ class PraetorsGraspPlayEffect extends AsThoughEffectImpl {
Card card = game.getCard(cardId);
Player controller = game.getPlayer(source.getControllerId());
if (controller != null && card != null && game.getState().getZone(cardId) == Zone.EXILED) {
if (card.getCardType().contains(CardType.INSTANT) || game.canPlaySorcery(source.getControllerId())) {
return true;
}
return true;
}
}
return false;
@ -155,7 +153,7 @@ class PraetorsGraspPlayEffect extends AsThoughEffectImpl {
class PraetorsGraspRevealEffect extends AsThoughEffectImpl {
private UUID cardId;
private final UUID cardId;
public PraetorsGraspRevealEffect(UUID cardId) {
super(AsThoughEffectType.REVEAL_FACE_DOWN, Duration.EndOfGame, Outcome.Benefit);

View file

@ -38,7 +38,7 @@ import mage.constants.CardType;
import mage.constants.Duration;
import mage.constants.Rarity;
import mage.constants.Zone;
import mage.filter.common.FilterCreatureCard;
import mage.filter.FilterCard;
import mage.filter.predicate.mageobject.CardTypePredicate;
/**
@ -46,7 +46,8 @@ import mage.filter.predicate.mageobject.CardTypePredicate;
*/
public class HypersonicDragon extends CardImpl {
private static final FilterCreatureCard filter = new FilterCreatureCard("sorcery spells");
private static final FilterCard filter = new FilterCard("sorcery spells");
static {
filter.add(new CardTypePredicate(CardType.SORCERY));
}

View file

@ -125,11 +125,11 @@ class KnacksawCliqueEffect extends OneShotEffect {
class KnacksawCliqueCastFromExileEffect extends AsThoughEffectImpl {
private UUID cardId;
private UUID exileId;
private final UUID cardId;
private final UUID exileId;
public KnacksawCliqueCastFromExileEffect(UUID cardId, UUID exileId) {
super(AsThoughEffectType.CAST, Duration.EndOfTurn, Outcome.Benefit);
super(AsThoughEffectType.CAST_FROM_NON_HAND_ZONE, Duration.EndOfTurn, Outcome.Benefit);
staticText = "Until end of turn, you may play that card";
this.cardId = cardId;
this.exileId = exileId;
@ -155,12 +155,8 @@ class KnacksawCliqueCastFromExileEffect extends AsThoughEffectImpl {
public boolean applies(UUID sourceId, Ability source, Game game) {
if (sourceId.equals(this.cardId)) {
Card card = game.getCard(this.cardId);
if (card != null
&& game.getState().getExile().getExileZone(exileId).contains(cardId)) {
if (card.getSpellAbility() != null
&& card.getSpellAbility().spellCanBeActivatedRegularlyNow(source.getControllerId(), game)) {
return true;
}
if (card != null && game.getState().getExile().getExileZone(exileId).contains(cardId)) {
return true;
}
}
return false;

View file

@ -145,7 +145,7 @@ class DaxosOfMeletisCastFromExileEffect extends AsThoughEffectImpl {
private UUID exileId;
public DaxosOfMeletisCastFromExileEffect(UUID cardId, UUID exileId) {
super(AsThoughEffectType.CAST, Duration.EndOfTurn, Outcome.Benefit);
super(AsThoughEffectType.CAST_FROM_NON_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;

View file

@ -159,7 +159,7 @@ class PsychicIntrusionCastFromExileEffect extends AsThoughEffectImpl {
private UUID exileId;
public PsychicIntrusionCastFromExileEffect(UUID cardId, UUID exileId) {
super(AsThoughEffectType.CAST, Duration.EndOfGame, Outcome.Benefit);
super(AsThoughEffectType.CAST_FROM_NON_HAND_ZONE, Duration.EndOfGame, Outcome.Benefit);
staticText = "You may cast that card for as long as it remains exiled, and you may spend mana as though it were mana of any color to cast that spell";
this.cardId = cardId;
this.exileId = exileId;

View file

@ -37,6 +37,7 @@ import mage.abilities.costs.common.SacrificeSourceCost;
import mage.abilities.costs.common.TapSourceCost;
import mage.abilities.costs.mana.ManaCostsImpl;
import mage.abilities.effects.AsThoughEffectImpl;
import mage.abilities.effects.ContinuousEffect;
import mage.abilities.effects.OneShotEffect;
import mage.abilities.effects.common.CreateDelayedTriggeredAbilityEffect;
import mage.cards.Card;
@ -54,6 +55,7 @@ import mage.game.events.GameEvent;
import mage.players.Player;
import mage.target.common.TargetCardInLibrary;
import mage.target.common.TargetOpponent;
import mage.target.targetpointer.FixedTarget;
import mage.util.CardUtil;
/**
@ -67,12 +69,12 @@ public class GrinningTotem extends CardImpl {
this.expansionSetCode = "TSB";
// {2}, {tap}, Sacrifice Grinning Totem: Search target opponent's library for a card and exile it. Then that player shuffles his or her library.
// Until the beginning of your next upkeep, you may play that card.
Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new GrinningTotemSearchAndExileEffect(), new ManaCostsImpl("{2}"));
ability.addCost(new TapSourceCost());
ability.addCost(new SacrificeSourceCost());
ability.addTarget(new TargetOpponent());
// Until the beginning of your next upkeep, you may play that card.
ability.addEffect(new GrinningTotemMayPlayEffect());
// ability.addEffect(new GrinningTotemMayPlayEffect());
// At the beginning of your next upkeep, if you haven't played it, put it into its owner's graveyard.
ability.addEffect(new CreateDelayedTriggeredAbilityEffect(new GrinningTotemDelayedTriggeredAbility()));
@ -93,7 +95,7 @@ class GrinningTotemSearchAndExileEffect extends OneShotEffect {
public GrinningTotemSearchAndExileEffect() {
super(Outcome.Benefit);
this.staticText = "Search target opponent's library for a card and exile it. Then that player shuffles his or her library.";
this.staticText = "Search target opponent's library for a card and exile it. Then that player shuffles his or her library. Until the beginning of your next upkeep, you may play that card";
}
public GrinningTotemSearchAndExileEffect(final GrinningTotemSearchAndExileEffect effect) {
@ -117,7 +119,10 @@ class GrinningTotemSearchAndExileEffect extends OneShotEffect {
Card card = targetOpponent.getLibrary().remove(targetCard.getFirstTarget(), game);
if (card != null) {
you.moveCardToExileWithInfo(card, CardUtil.getCardExileZoneId(game, source), sourcObject != null ? sourcObject.getName() : "", source.getSourceId(), game, Zone.LIBRARY);
}
ContinuousEffect effect = new GrinningTotemMayPlayEffect();
effect.setTargetPointer(new FixedTarget(card.getId()));
game.addEffect(effect, source);
}
}
}
targetOpponent.shuffleLibrary(game);
@ -131,7 +136,7 @@ class GrinningTotemSearchAndExileEffect extends OneShotEffect {
class GrinningTotemMayPlayEffect extends AsThoughEffectImpl {
public GrinningTotemMayPlayEffect() {
super(AsThoughEffectType.CAST, Duration.Custom, Outcome.Benefit);
super(AsThoughEffectType.CAST_FROM_NON_HAND_ZONE, Duration.Custom, Outcome.Benefit);
this.staticText = "Until the beginning of your next upkeep, you may play that card.";
}
@ -161,25 +166,10 @@ class GrinningTotemMayPlayEffect extends AsThoughEffectImpl {
@Override
public boolean applies(UUID sourceId, Ability source, Game game) {
// implementation from NightveilSpecterEffect
Card card = game.getCard(sourceId);
Player controller = game.getPlayer(source.getControllerId());
if (controller != null && card != null && game.getState().getZone(card.getId()) == Zone.EXILED) {
ExileZone zone = game.getExile().getExileZone(CardUtil.getCardExileZoneId(game, source));
if (zone != null && zone.contains(card.getId())) {
if (card.getCardType().contains(CardType.LAND)) {
// If the revealed card is a land, you can play it only if it's your turn and you haven't yet played a land this turn.
if (game.getActivePlayerId().equals(source.getControllerId()) && controller.canPlayLand()) {
return true;
}
} else {
if (card.getSpellAbility().spellCanBeActivatedRegularlyNow(source.getControllerId(), game)) {
return true;
}
}
}
if (targetPointer.getTargets(game, source).contains(sourceId)) {
return game.getState().getZone(sourceId).equals(Zone.EXILED);
}
return false;
return false;
}
}
@ -196,8 +186,8 @@ class GrinningTotemDelayedTriggeredAbility extends DelayedTriggeredAbility {
@Override
public boolean checkInterveningIfClause(Game game) {
ExileZone zone = game.getExile().getExileZone(CardUtil.getCardExileZoneId(game, this.getSourceId()));
return zone.getCards(game).size() > 0;
ExileZone exileZone = game.getExile().getExileZone(CardUtil.getCardExileZoneId(game, this.getSourceId()));
return exileZone != null && exileZone.getCards(game).size() > 0;
}
@Override
@ -207,10 +197,7 @@ class GrinningTotemDelayedTriggeredAbility extends DelayedTriggeredAbility {
@Override
public boolean checkTrigger(GameEvent event, Game game) {
if (event.getType() == GameEvent.EventType.UPKEEP_STEP_PRE && game.getActivePlayerId().equals(this.getControllerId())) {
return true;
}
return false;
return event.getType() == GameEvent.EventType.UPKEEP_STEP_PRE && game.getActivePlayerId().equals(this.getControllerId());
}
@Override

View file

@ -119,10 +119,10 @@ class ThadaAdelAcquisitorEffect extends OneShotEffect {
class ThadaAdelPlayFromExileEffect extends AsThoughEffectImpl {
private UUID cardId;
private final UUID cardId;
public ThadaAdelPlayFromExileEffect(UUID cardId) {
super(AsThoughEffectType.CAST, Duration.EndOfTurn, Outcome.Benefit);
super(AsThoughEffectType.CAST_FROM_NON_HAND_ZONE, Duration.EndOfTurn, Outcome.Benefit);
staticText = "You may play this card from exile";
this.cardId = cardId;
}
@ -147,15 +147,7 @@ class ThadaAdelPlayFromExileEffect extends AsThoughEffectImpl {
if (sourceId.equals(this.cardId)) {
Card card = game.getCard(this.cardId);
if (card != null && game.getState().getZone(this.cardId) == Zone.EXILED) {
Player you = game.getPlayer(source.getControllerId());
if (you != null && you.chooseUse(Outcome.Benefit, "Play the card?", game)) {
if (card.getCardType().contains(CardType.LAND)) {
you.playLand(card, game);
} else {
you.cast(card.getSpellAbility(), game, false);
}
}
return false;
return true;
}
}
return false;

View file

@ -85,7 +85,7 @@ public class SpellAbility extends ActivatedAbilityImpl {
@Override
public boolean canActivate(UUID playerId, Game game) {
if (game.getContinuousEffects().asThough(sourceId, AsThoughEffectType.CAST, this, playerId, game) // check this first to allow Offering in main phase
if (game.getContinuousEffects().asThough(sourceId, AsThoughEffectType.CAST_AS_INSTANT, this, playerId, game) // check this first to allow Offering in main phase
|| this.spellCanBeActivatedRegularlyNow(playerId, game)) {
if (spellAbilityType.equals(SpellAbilityType.SPLIT)) {
return false;

View file

@ -54,7 +54,7 @@ public class CastAsThoughItHadFlashEffect extends AsThoughEffectImpl {
}
public CastAsThoughItHadFlashEffect(Duration duration, FilterCard filter, boolean anyPlayer) {
super(AsThoughEffectType.CAST, duration, Outcome.Benefit);
super(AsThoughEffectType.CAST_AS_INSTANT, duration, Outcome.Benefit);
this.filter = filter;
this.anyPlayer = anyPlayer;
staticText = setText();

View file

@ -52,7 +52,7 @@ public class PlayTheTopCardEffect extends AsThoughEffectImpl {
}
public PlayTheTopCardEffect(FilterCard filter) {
super(AsThoughEffectType.CAST, Duration.WhileOnBattlefield, Outcome.Benefit);
super(AsThoughEffectType.CAST_FROM_NON_HAND_ZONE, Duration.WhileOnBattlefield, Outcome.Benefit);
this.filter = filter;
staticText = "You may play the top card of your library if it's a " + filter.getMessage();
}

View file

@ -71,7 +71,7 @@ public class MadnessAbility extends StaticAbility {
* It checks:
* 1. That card is in Exile zone
* 2. It is being cast by owner
* 3. It been discarded so it contains 'madness' mark stored in game state
* 3. It has been discarded so it contains 'madness' mark stored in game state
*
*/
class MadnessPlayEffect extends AsThoughEffectImpl {
@ -79,7 +79,7 @@ class MadnessPlayEffect extends AsThoughEffectImpl {
private Cost cost;
public MadnessPlayEffect(Cost cost) {
super(AsThoughEffectType.CAST, Duration.EndOfGame, Outcome.Benefit);
super(AsThoughEffectType.CAST_AS_INSTANT, Duration.EndOfGame, Outcome.Benefit);
staticText = null;
this.cost = cost;
}

View file

@ -70,14 +70,17 @@ import mage.util.CardUtil;
* match colored mana in the colored mana cost of the card with offering, or is in excess
* of the card's colored mana cost, reduces that much generic mana in the total cost. #
*
* @param subtype name of the subtype that can be offered
*
* @author LevelX2
*/
public class OfferingAbility extends StaticAbility {
private FilterControlledCreaturePermanent filter = new FilterControlledCreaturePermanent();
/**
*
* @param subtype name of the subtype that can be offered
*/
public OfferingAbility(String subtype) {
super(Zone.ALL, null);
filter.add(new SubtypePredicate(subtype));
@ -109,7 +112,7 @@ public class OfferingAbility extends StaticAbility {
class OfferingAsThoughEffect extends AsThoughEffectImpl {
public OfferingAsThoughEffect() {
super(AsThoughEffectType.CAST, Duration.EndOfGame, Outcome.Benefit);
super(AsThoughEffectType.CAST_AS_INSTANT, Duration.EndOfGame, Outcome.Benefit);
}
public OfferingAsThoughEffect(final OfferingAsThoughEffect effect) {

View file

@ -193,7 +193,7 @@ public class SuspendAbility extends ActivatedAbilityImpl {
MageObject object = game.getObject(sourceId);
return (object.getCardType().contains(CardType.INSTANT) ||
object.hasAbility(FlashAbility.getInstance().getId(), game) ||
game.getContinuousEffects().asThough(sourceId, AsThoughEffectType.CAST, this, playerId, game) ||
game.getContinuousEffects().asThough(sourceId, AsThoughEffectType.CAST_AS_INSTANT, this, playerId, game) ||
game.canPlaySorcery(playerId));
}

View file

@ -10,7 +10,8 @@ public enum AsThoughEffectType {
BLOCK_TAPPED,
BLOCK_SHADOW,
BE_BLOCKED,
CAST,
CAST_FROM_NON_HAND_ZONE,
CAST_AS_INSTANT,
DAMAGE,
HEXPROOF,
PAY,

View file

@ -967,10 +967,11 @@ public abstract class PlayerImpl implements Player, Serializable {
}
}
}
if (zone != Zone.BATTLEFIELD && game.getContinuousEffects().asThough(object.getId(), AsThoughEffectType.CAST, this.getId(), game)) {
if (zone != Zone.BATTLEFIELD && game.getContinuousEffects().asThough(object.getId(), AsThoughEffectType.CAST_FROM_NON_HAND_ZONE, this.getId(), game)) {
for (Ability ability: object.getAbilities()) {
ability.setControllerId(this.getId());
if (ability instanceof ActivatedAbility && ability.getZone().match(Zone.HAND)) {
if (ability instanceof ActivatedAbility && ability.getZone().match(Zone.HAND)
&& ((ActivatedAbility) ability).canActivate(playerId, game)) {
useable.put(ability.getId(), (ActivatedAbility) ability);
}
}
@ -1923,7 +1924,7 @@ public abstract class PlayerImpl implements Player, Serializable {
playable.add(ability);
}
}
if (game.getContinuousEffects().asThough(card.getId(), AsThoughEffectType.CAST, this.getId(), game)) {
if (game.getContinuousEffects().asThough(card.getId(), AsThoughEffectType.CAST_FROM_NON_HAND_ZONE, this.getId(), game)) {
for (ActivatedAbility ability : card.getAbilities().getActivatedAbilities(Zone.HAND)) {
if (ability instanceof SpellAbility || ability instanceof PlayLandAbility) {
playable.add(ability);
@ -1933,11 +1934,15 @@ public abstract class PlayerImpl implements Player, Serializable {
}
for (ExileZone exile : game.getExile().getExileZones()) {
for (Card card : exile.getCards(game)) {
if (game.getContinuousEffects().asThough(card.getId(), AsThoughEffectType.CAST, this.getId(), game)) {
for (Ability ability : card.getAbilities()) {
ability.setControllerId(this.getId()); // controller must be set for case owner != caster
if (ability.getZone().match(Zone.HAND) && (ability instanceof SpellAbility || ability instanceof PlayLandAbility)) {
playable.add(ability);
if (game.getContinuousEffects().asThough(card.getId(), AsThoughEffectType.CAST_FROM_NON_HAND_ZONE, this.getId(), game)) {
for (Ability ability : card.getAbilities()) {
if (ability.getZone().match(Zone.HAND)) {
ability.setControllerId(this.getId()); // controller must be set for case owner != caster
if (ability instanceof ActivatedAbility) {
if (((ActivatedAbility) ability).canActivate(playerId, game)) {
playable.add(ability);
}
}
}
}
}
@ -1945,7 +1950,7 @@ public abstract class PlayerImpl implements Player, Serializable {
}
for (Cards cards : game.getState().getRevealed().values()) {
for (Card card : cards.getCards(game)) {
if (game.getContinuousEffects().asThough(card.getId(), AsThoughEffectType.CAST, this.getId(), game)) {
if (game.getContinuousEffects().asThough(card.getId(), AsThoughEffectType.CAST_FROM_NON_HAND_ZONE, this.getId(), game)) {
for (ActivatedAbility ability : card.getAbilities().getActivatedAbilities(Zone.HAND)) {
if (ability instanceof SpellAbility || ability instanceof PlayLandAbility) {
playable.add(ability);
@ -2346,14 +2351,19 @@ public abstract class PlayerImpl implements Player, Serializable {
public boolean moveCardToGraveyardWithInfo(Card card, UUID sourceId, Game game, Zone fromZone) {
boolean result = false;
if (card.moveToZone(Zone.GRAVEYARD, sourceId, game, fromZone != null ? fromZone.equals(Zone.BATTLEFIELD) : false)) {
game.informPlayers(new StringBuilder(this.getName())
StringBuilder sb = new StringBuilder(this.getName())
.append(" puts ").append(card.getLogName()).append(" ")
.append(fromZone != null ? new StringBuilder("from ").append(fromZone.toString().toLowerCase(Locale.ENGLISH)).append(" "):"")
.append("into his or her graveyard").toString());
.append(fromZone != null ? new StringBuilder("from ").append(fromZone.toString().toLowerCase(Locale.ENGLISH)).append(" "):"");
if (card.getOwnerId().equals(getId())) {
sb.append("into his or her graveyard");
} else {
sb.append("it into its owner's graveyard");
}
game.informPlayers(sb.toString());
result = true;
}
return result;
}
}
@Override
public boolean moveCardToLibraryWithInfo(Card card, UUID sourceId, Game game, Zone fromZone, boolean toTop, boolean withName) {