Reworked AsThoughEffect. Added SPEND_ANY_MANA AsThoughType. Added some framework effects.

This commit is contained in:
LevelX2 2013-09-16 17:04:42 +02:00
parent 297ed13d86
commit 7c34668f0d
9 changed files with 328 additions and 90 deletions

View file

@ -28,18 +28,17 @@
package mage.abilities;
import mage.constants.AbilityType;
import mage.constants.AsThoughEffectType;
import mage.constants.CardType;
import mage.constants.Zone;
import java.util.UUID;
import mage.MageObject;
import mage.abilities.costs.mana.ManaCost;
import mage.abilities.keyword.FlashAbility;
import mage.game.Game;
import java.util.UUID;
import mage.constants.SpellAbilityType;
import mage.cards.SplitCard;
import mage.constants.AbilityType;
import mage.constants.AsThoughEffectType;
import mage.constants.CardType;
import mage.constants.SpellAbilityType;
import mage.constants.Zone;
import mage.game.Game;
/**
*
@ -71,24 +70,25 @@ public class SpellAbility extends ActivatedAbilityImpl<SpellAbility> {
}
// public SpellAbility(Cost cost, String cardName, Effect effect, Zone zone) {
// super(zone, effect, cost);
// this.spellAbilityType = SpellAbilityType.BASE;
// this.name = "Cast " + cardName;
// }
public SpellAbility(SpellAbility ability) {
super(ability);
this.spellAbilityType = ability.spellAbilityType;
}
@Override
public boolean canActivate(UUID playerId, Game game) {
public boolean spellCanBeActivatedRegularlyNow(UUID playerId, Game game) {
MageObject object = game.getObject(sourceId);
if ((object.getCardType().contains(CardType.INSTANT) ||
object.getAbilities().containsKey(FlashAbility.getInstance().getId()) ||
game.getContinuousEffects().asThough(sourceId, AsThoughEffectType.CAST, game) ||
game.canPlaySorcery(playerId))) {
return true;
}
return false;
}
@Override
public boolean canActivate(UUID playerId, Game game) {
if (this.spellCanBeActivatedRegularlyNow(playerId, game) ||
game.getContinuousEffects().asThough(sourceId, AsThoughEffectType.CAST, game)) {
if (spellAbilityType.equals(SpellAbilityType.SPLIT)) {
return false;
}

View file

@ -92,6 +92,17 @@ public abstract class ManaCostImpl<T extends ManaCostImpl<T>> extends CostImpl<T
return this.sourceFilter;
}
/*
* Restrict the allowed mana sources to pay the cost
*
* e.g. Spend only mana produced by basic lands to cast Imperiosaur.
* uses:
* private static final FilterLandPermanent filter = new FilterLandPermanent();
* static { filter.add(new SupertypePredicate("Basic")); }
*
* It will be cecked in ManaPool.pay method
*
*/
@Override
public void setSourceFilter(Filter filter) {
this.sourceFilter = filter;

View file

@ -29,11 +29,18 @@
package mage.abilities.effects;
import java.io.Serializable;
import java.util.*;
import mage.constants.AsThoughEffectType;
import mage.constants.Duration;
import mage.constants.Layer;
import mage.constants.SubLayer;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.Date;
import java.util.EnumMap;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.UUID;
import mage.MageObject;
import mage.abilities.Ability;
import mage.abilities.MageSingleton;
@ -42,8 +49,12 @@ import mage.abilities.StaticAbility;
import mage.abilities.keyword.SpliceOntoArcaneAbility;
import mage.cards.Cards;
import mage.cards.CardsImpl;
import mage.constants.AsThoughEffectType;
import mage.constants.Duration;
import mage.constants.Layer;
import mage.constants.Outcome;
import mage.constants.SpellAbilityType;
import mage.constants.SubLayer;
import mage.filter.FilterCard;
import mage.filter.predicate.Predicate;
import mage.filter.predicate.Predicates;
@ -69,7 +80,7 @@ public class ContinuousEffects implements Serializable {
private ContinuousEffectsList<RequirementEffect> requirementEffects = new ContinuousEffectsList<RequirementEffect>();
private ContinuousEffectsList<RestrictionEffect> restrictionEffects = new ContinuousEffectsList<RestrictionEffect>();
private ContinuousEffectsList<RestrictionUntapNotMoreThanEffect> restrictionUntapNotMoreThanEffects = new ContinuousEffectsList<RestrictionUntapNotMoreThanEffect>();
private ContinuousEffectsList<AsThoughEffect> asThoughEffects = new ContinuousEffectsList<AsThoughEffect>();
private Map<AsThoughEffectType, ContinuousEffectsList<AsThoughEffect>> asThoughEffectsMap = new EnumMap<AsThoughEffectType, ContinuousEffectsList<AsThoughEffect>>(AsThoughEffectType.class);
private ContinuousEffectsList<CostModificationEffect> costModificationEffects = new ContinuousEffectsList<CostModificationEffect>();
private ContinuousEffectsList<SpliceCardEffect> spliceCardEffects = new ContinuousEffectsList<SpliceCardEffect>();
@ -101,7 +112,10 @@ public class ContinuousEffects implements Serializable {
requirementEffects = effect.requirementEffects.copy();
restrictionEffects = effect.restrictionEffects.copy();
restrictionUntapNotMoreThanEffects = effect.restrictionUntapNotMoreThanEffects.copy();
asThoughEffects = effect.asThoughEffects.copy();
for (Map.Entry<AsThoughEffectType, ContinuousEffectsList<AsThoughEffect>> entry : effect.asThoughEffectsMap.entrySet()) {
asThoughEffectsMap.put(entry.getKey(), entry.getValue());
}
costModificationEffects = effect.costModificationEffects.copy();
spliceCardEffects = effect.spliceCardEffects.copy();
for (Map.Entry<UUID, UUID> entry : effect.sources.entrySet()) {
@ -118,7 +132,9 @@ public class ContinuousEffects implements Serializable {
allEffectsLists.add(requirementEffects);
allEffectsLists.add(restrictionEffects);
allEffectsLists.add(restrictionUntapNotMoreThanEffects);
allEffectsLists.add(asThoughEffects);
for(ContinuousEffectsList asThoughtlist :asThoughEffectsMap.values()) {
allEffectsLists.add(asThoughtlist);
}
allEffectsLists.add(costModificationEffects);
allEffectsLists.add(spliceCardEffects);
}
@ -141,7 +157,9 @@ public class ContinuousEffects implements Serializable {
preventionEffects.removeEndOfCombatEffects();
requirementEffects.removeEndOfCombatEffects();
restrictionEffects.removeEndOfCombatEffects();
asThoughEffects.removeEndOfCombatEffects();
for(ContinuousEffectsList asThoughtlist :asThoughEffectsMap.values()) {
asThoughtlist.removeEndOfCombatEffects();
}
costModificationEffects.removeEndOfCombatEffects();
spliceCardEffects.removeEndOfCombatEffects();
}
@ -152,7 +170,9 @@ public class ContinuousEffects implements Serializable {
preventionEffects.removeEndOfTurnEffects();
requirementEffects.removeEndOfTurnEffects();
restrictionEffects.removeEndOfTurnEffects();
asThoughEffects.removeEndOfTurnEffects();
for(ContinuousEffectsList asThoughtlist :asThoughEffectsMap.values()) {
asThoughtlist.removeEndOfTurnEffects();
}
costModificationEffects.removeEndOfTurnEffects();
spliceCardEffects.removeEndOfTurnEffects();
}
@ -164,7 +184,9 @@ public class ContinuousEffects implements Serializable {
requirementEffects.removeInactiveEffects(game);
restrictionEffects.removeInactiveEffects(game);
restrictionUntapNotMoreThanEffects.removeInactiveEffects(game);
asThoughEffects.removeInactiveEffects(game);
for(ContinuousEffectsList asThoughtlist :asThoughEffectsMap.values()) {
asThoughtlist.removeInactiveEffects(game);
}
costModificationEffects.removeInactiveEffects(game);
spliceCardEffects.removeInactiveEffects(game);
}
@ -394,15 +416,12 @@ public class ContinuousEffects implements Serializable {
}
public boolean asThough(UUID objectId, AsThoughEffectType type, Game game) {
List<AsThoughEffect> asThoughEffectsList = getApplicableAsThoughEffects(game);
List<AsThoughEffect> asThoughEffectsList = getApplicableAsThoughEffects(type, game);
for (AsThoughEffect effect: asThoughEffectsList) {
if (effect.getAsThoughEffectType() == type) {
HashSet<Ability> abilities = asThoughEffects.getAbility(effect.getId());
for (Ability ability : abilities) {
if (effect.applies(objectId, ability, game)) {
return true;
}
HashSet<Ability> abilities = asThoughEffectsMap.get(type).getAbility(effect.getId());
for (Ability ability : abilities) {
if (effect.applies(objectId, ability, game)) {
return true;
}
}
}
@ -412,24 +431,25 @@ public class ContinuousEffects implements Serializable {
/**
* Filters out asThough effects that are not active.
*
* @param AsThoughEffectType type
* @param game
* @return
*/
private List<AsThoughEffect> getApplicableAsThoughEffects(Game game) {
private List<AsThoughEffect> getApplicableAsThoughEffects(AsThoughEffectType type, Game game) {
List<AsThoughEffect> asThoughEffectsList = new ArrayList<AsThoughEffect>();
for (AsThoughEffect effect: asThoughEffects) {
HashSet<Ability> abilities = asThoughEffects.getAbility(effect.getId());
for (Ability ability : abilities) {
if (!(ability instanceof StaticAbility) || ability.isInUseableZone(game, null, false)) {
if (effect.getDuration() != Duration.OneUse || !effect.isUsed()) {
asThoughEffectsList.add(effect);
break;
if (asThoughEffectsMap.containsKey(type)) {
for (AsThoughEffect effect: asThoughEffectsMap.get(type)) {
HashSet<Ability> abilities = asThoughEffectsMap.get(type).getAbility(effect.getId());
for (Ability ability : abilities) {
if (!(ability instanceof StaticAbility) || ability.isInUseableZone(game, null, false)) {
if (effect.getDuration() != Duration.OneUse || !effect.isUsed()) {
asThoughEffectsList.add(effect);
break;
}
}
}
}
}
return asThoughEffectsList;
}
@ -743,7 +763,11 @@ public class ContinuousEffects implements Serializable {
break;
case ASTHOUGH:
AsThoughEffect newAsThoughEffect = (AsThoughEffect)effect;
asThoughEffects.addEffect(newAsThoughEffect, source);
if (!asThoughEffectsMap.containsKey(newAsThoughEffect.getAsThoughEffectType())) {
ContinuousEffectsList list = new ContinuousEffectsList();
asThoughEffectsMap.put(newAsThoughEffect.getAsThoughEffectType(), list);
}
asThoughEffectsMap.get(newAsThoughEffect.getAsThoughEffectType()).addEffect(newAsThoughEffect, source);
break;
case COSTMODIFICATION:
CostModificationEffect newCostModificationEffect = (CostModificationEffect)effect;

View file

@ -0,0 +1,70 @@
/*
* Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are
* permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this list of
* conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice, this list
* of conditions and the following disclaimer in the documentation and/or other materials
* provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* The views and conclusions contained in the software and documentation are those of the
* authors and should not be interpreted as representing official policies, either expressed
* or implied, of BetaSteward_at_googlemail.com.
*/
package mage.abilities.effects.common;
import mage.abilities.Ability;
import mage.abilities.effects.OneShotEffect;
import mage.cards.Card;
import mage.constants.Outcome;
import mage.constants.Zone;
import mage.game.Game;
/**
*
* @author LevelX2
*/
public class ReturnToBattlefieldUnderOwnerControlTargetEffect extends OneShotEffect<ReturnToBattlefieldUnderOwnerControlTargetEffect> {
public ReturnToBattlefieldUnderOwnerControlTargetEffect() {
super(Outcome.Benefit);
staticText = "return that card to the battlefield under its owner's control";
}
public ReturnToBattlefieldUnderOwnerControlTargetEffect(final ReturnToBattlefieldUnderOwnerControlTargetEffect effect) {
super(effect);
}
@Override
public ReturnToBattlefieldUnderOwnerControlTargetEffect copy() {
return new ReturnToBattlefieldUnderOwnerControlTargetEffect(this);
}
@Override
public boolean apply(Game game, Ability source) {
Card card = game.getCard(targetPointer.getFirst(game, source));
if (card != null) {
Zone currentZone = game.getState().getZone(card.getId());
if (card.putOntoBattlefield(game, currentZone, source.getId(), card.getOwnerId())) {
return true;
}
}
return false;
}
}

View file

@ -0,0 +1,77 @@
/*
* Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are
* permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this list of
* conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice, this list
* of conditions and the following disclaimer in the documentation and/or other materials
* provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* The views and conclusions contained in the software and documentation are those of the
* authors and should not be interpreted as representing official policies, either expressed
* or implied, of BetaSteward_at_googlemail.com.
*/
package mage.abilities.effects.common.continious;
import mage.abilities.Ability;
import mage.abilities.effects.RestrictionEffect;
import mage.constants.Duration;
import mage.filter.common.FilterCreaturePermanent;
import mage.game.Game;
import mage.game.permanent.Permanent;
/**
*
* @author LevelX2
*/
public class CantBeBlockedByCreaturesSourceEffect extends RestrictionEffect<CantBeBlockedByCreaturesSourceEffect> {
private FilterCreaturePermanent filter;
public CantBeBlockedByCreaturesSourceEffect(FilterCreaturePermanent filter, Duration duration) {
super(Duration.WhileOnBattlefield);
this.filter = filter;
staticText = new StringBuilder("{this} can't be blocked by ").append(filter.getMessage()).toString();
}
public CantBeBlockedByCreaturesSourceEffect(final CantBeBlockedByCreaturesSourceEffect effect) {
super(effect);
this.filter = effect.filter;
}
@Override
public boolean applies(Permanent permanent, Ability source, Game game) {
if (permanent.getId().equals(source.getSourceId())) {
return true;
}
return false;
}
@Override
public boolean canBeBlocked(Permanent attacker, Permanent blocker, Ability source, Game game) {
if (filter.match(blocker, source.getSourceId(), source.getControllerId(), game)) {
return false;
}
return true;
}
@Override
public CantBeBlockedByCreaturesSourceEffect copy() {
return new CantBeBlockedByCreaturesSourceEffect(this);
}
}

View file

@ -5,13 +5,14 @@ package mage.constants;
* @author North
*/
public enum AsThoughEffectType {
BLOCK_TAPPED,
BE_BLOCKED,
ATTACK,
BLOCK_TAPPED,
BE_BLOCKED,
CAST,
TARGET,
PAY,
DAMAGE,
HEXPROOF,
REVEAL_FACE_DOWN
SPEND_ANY_MANA,
PAY,
REVEAL_FACE_DOWN,
TARGET
}

View file

@ -28,19 +28,19 @@
package mage.players;
import mage.ConditionalMana;
import mage.constants.ManaType;
import mage.Mana;
import mage.abilities.Ability;
import mage.filter.Filter;
import mage.filter.FilterMana;
import mage.game.Game;
import mage.game.events.GameEvent;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import mage.ConditionalMana;
import mage.Mana;
import mage.abilities.Ability;
import mage.constants.AsThoughEffectType;
import mage.constants.ManaType;
import mage.filter.Filter;
import mage.filter.FilterMana;
import mage.game.Game;
import mage.game.events.GameEvent;
/**
*
@ -85,9 +85,14 @@ public class ManaPool implements Serializable {
}
for (ManaPoolItem mana : manaItems) {
if (filter == null || filter.match(game.getObject(mana.getSourceId()), game)) {
if (mana.get(manaType) > 0) {
boolean spendAnyMana = spendAnyMana(ability, game);
if (mana.get(manaType) > 0 || (spendAnyMana && mana.count() > 0)) {
game.fireEvent(new GameEvent(GameEvent.EventType.MANA_PAYED, ability.getId(), mana.getSourceId(), ability.getControllerId()));
mana.remove(manaType);
if (spendAnyMana) {
mana.removeAny();
} else {
mana.remove(manaType);
}
return true;
}
}
@ -95,6 +100,11 @@ public class ManaPool implements Serializable {
return false;
}
// check if any mana can be spend to cast the mana cost of an ability
private boolean spendAnyMana(Ability ability, Game game) {
return game.getContinuousEffects().asThough(ability.getSourceId(), AsThoughEffectType.SPEND_ANY_MANA, game);
}
public int get(ManaType manaType) {
return getMana().get(manaType);
}
@ -105,8 +115,9 @@ public class ManaPool implements Serializable {
}
for (ManaPoolItem mana : manaItems) {
if (mana.isConditional() && mana.getConditionalMana().get(manaType) > 0 && mana.getConditionalMana().apply(ability, game, mana.getSourceId())) {
if (filter == null || filter.match(game.getObject(mana.getSourceId()), game))
if (filter == null || filter.match(game.getObject(mana.getSourceId()), game)) {
return mana.getConditionalMana().get(manaType);
}
}
}
return 0;
@ -195,8 +206,9 @@ public class ManaPool implements Serializable {
if (count > 0) {
total += count;
c.removeAll(filter);
if (c.count() == 0)
if (c.count() == 0) {
it.remove();
}
}
}
}
@ -225,8 +237,9 @@ public class ManaPool implements Serializable {
total += item.getColorless();
item.removeColorless();
}
if (item.count() == 0)
if (item.count() == 0) {
it.remove();
}
}
}
return total;
@ -246,12 +259,24 @@ public class ManaPool implements Serializable {
}
Mana test = getMana();
Mana m = new Mana();
if (filter.isBlack()) m.setBlack(test.getBlack());
if (filter.isBlue()) m.setBlue(test.getBlue());
if (filter.isColorless()) m.setColorless(test.getColorless());
if (filter.isGreen()) m.setGreen(test.getGreen());
if (filter.isRed()) m.setRed(test.getRed());
if (filter.isWhite()) m.setWhite(test.getWhite());
if (filter.isBlack()) {
m.setBlack(test.getBlack());
}
if (filter.isBlue()) {
m.setBlue(test.getBlue());
}
if (filter.isColorless()) {
m.setColorless(test.getColorless());
}
if (filter.isGreen()) {
m.setGreen(test.getGreen());
}
if (filter.isRed()) {
m.setRed(test.getRed());
}
if (filter.isWhite()) {
m.setWhite(test.getWhite());
}
return m;
}

View file

@ -27,12 +27,11 @@
*/
package mage.players;
import mage.ConditionalMana;
import mage.constants.ManaType;
import mage.Mana;
import java.io.Serializable;
import java.util.UUID;
import mage.ConditionalMana;
import mage.Mana;
import mage.constants.ManaType;
/**
*
@ -74,8 +73,9 @@ public class ManaPoolItem implements Serializable {
this.white = item.white;
this.black = item.black;
this.colorless = item.colorless;
if (item.conditionalMana != null)
if (item.conditionalMana != null) {
this.conditionalMana = item.conditionalMana.copy();
}
this.sourceId = item.sourceId;
}
@ -92,8 +92,9 @@ public class ManaPoolItem implements Serializable {
}
public void removeRed() {
if (red > 0)
if (red > 0) {
red--;
}
}
public int getGreen() {
@ -101,8 +102,9 @@ public class ManaPoolItem implements Serializable {
}
public void removeGreen() {
if (green > 0)
if (green > 0) {
green--;
}
}
public int getBlue() {
@ -110,8 +112,9 @@ public class ManaPoolItem implements Serializable {
}
public void removeBlue() {
if (blue > 0)
if (blue > 0) {
blue--;
}
}
public int getBlack() {
@ -119,8 +122,9 @@ public class ManaPoolItem implements Serializable {
}
public void removeBlack() {
if (black > 0)
if (black > 0) {
black--;
}
}
public int getWhite() {
@ -128,8 +132,9 @@ public class ManaPoolItem implements Serializable {
}
public void removeWhite() {
if (white > 0)
if (white > 0) {
white--;
}
}
public int getColorless() {
@ -137,8 +142,9 @@ public class ManaPoolItem implements Serializable {
}
public void removeColorless() {
if (colorless > 0)
if (colorless > 0) {
colorless--;
}
}
public boolean isConditional() {
@ -154,8 +160,9 @@ public class ManaPoolItem implements Serializable {
}
public int count() {
if (conditionalMana == null)
if (conditionalMana == null) {
return red + green + blue + white + black + colorless;
}
return conditionalMana.count();
}
@ -177,31 +184,53 @@ public class ManaPoolItem implements Serializable {
return 0;
}
public void removeAny() {
if (black > 0) {
black--;
} else if (blue > 0) {
blue--;
} else if (green > 0) {
green--;
} else if (red > 0) {
red--;
} else if (white > 0) {
white--;
} else if (colorless > 0) {
colorless--;
}
}
public void remove(ManaType manaType) {
switch(manaType) {
case BLACK:
if (black > 0)
if (black > 0) {
black--;
}
break;
case BLUE:
if (blue > 0)
if (blue > 0) {
blue--;
}
break;
case GREEN:
if (green > 0)
if (green > 0) {
green--;
}
break;
case RED:
if (red > 0)
if (red > 0) {
red--;
}
break;
case WHITE:
if (white > 0)
if (white > 0) {
white--;
}
break;
case COLORLESS:
if (colorless > 0)
if (colorless > 0) {
colorless--;
}
break;
}
}

View file

@ -914,6 +914,7 @@ public abstract class PlayerImpl<T extends PlayerImpl<T>> implements Player, Ser
if (zone != Zone.HAND) {
if (zone != Zone.BATTLEFIELD && game.getContinuousEffects().asThough(object.getId(), AsThoughEffectType.CAST, game)) {
for (ActivatedAbility ability: object.getAbilities().getActivatedAbilities(Zone.HAND)) {
ability.setControllerId(this.getId());
useable.put(ability.getId(), ability);
}
}