mirror of
https://github.com/magefree/mage.git
synced 2025-12-21 02:52:02 -08:00
* Fixed provisional game freezing bugs of the show playable cards feature #457 (caused by DelverAbility, OfferingAbility, Rooftop Storm, Omniscience, Aluren).
This commit is contained in:
parent
ad9b73c34c
commit
142e95fe42
20 changed files with 106 additions and 34 deletions
|
|
@ -114,7 +114,7 @@ class CantBeBlockedUnlessAllEffect extends RestrictionEffect {
|
||||||
// check if all creatures of defender are able to block this permanent
|
// check if all creatures of defender are able to block this permanent
|
||||||
// permanent.canBlock() can't be used because causing recursive call
|
// permanent.canBlock() can't be used because causing recursive call
|
||||||
for (Permanent permanent: game.getBattlefield().getAllActivePermanents(filter, blocker.getControllerId(), game)) {
|
for (Permanent permanent: game.getBattlefield().getAllActivePermanents(filter, blocker.getControllerId(), game)) {
|
||||||
if (permanent.isTapped() && !game.getState().getContinuousEffects().asThough(this.getId(), AsThoughEffectType.BLOCK_TAPPED, blocker.getControllerId(), game)) {
|
if (permanent.isTapped() && !game.getState().getContinuousEffects().asThough(this.getId(), AsThoughEffectType.BLOCK_TAPPED, source, blocker.getControllerId(), game)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
// check blocker restrictions
|
// check blocker restrictions
|
||||||
|
|
|
||||||
|
|
@ -42,6 +42,7 @@ import mage.players.Player;
|
||||||
import mage.util.CardUtil;
|
import mage.util.CardUtil;
|
||||||
|
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
|
import mage.abilities.ActivatedAbility;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
|
|
@ -100,9 +101,10 @@ class RooftopStormCostReductionEffect extends CostModificationEffectImpl {
|
||||||
Card sourceCard = game.getCard(spell.getSourceId());
|
Card sourceCard = game.getCard(spell.getSourceId());
|
||||||
if (sourceCard != null && sourceCard.hasSubtype("Zombie")) {
|
if (sourceCard != null && sourceCard.hasSubtype("Zombie")) {
|
||||||
Player player = game.getPlayer(spell.getControllerId());
|
Player player = game.getPlayer(spell.getControllerId());
|
||||||
if (player != null && player.chooseUse(Outcome.Benefit, "Pay {0} rather than pay the mana cost for Zombie creature", game)) {
|
if (player != null &&
|
||||||
|
(CardUtil.isCheckPlayableMode(spell) || player.chooseUse(Outcome.Benefit, "Pay {0} rather than pay the mana cost for Zombie creature", game))) {
|
||||||
spell.getManaCostsToPay().clear();
|
spell.getManaCostsToPay().clear();
|
||||||
spell.getManaCostsToPay().addAll(new ManaCostsImpl("{0}"));
|
spell.getManaCostsToPay().addAll(new ManaCostsImpl<>("{0}"));
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -42,6 +42,7 @@ import mage.game.stack.StackObject;
|
||||||
import mage.players.Player;
|
import mage.players.Player;
|
||||||
|
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
|
import mage.util.CardUtil;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
|
|
@ -99,7 +100,8 @@ class OmniscienceEffect extends CostModificationEffectImpl {
|
||||||
&& !sourceCard.getCardType().contains(CardType.LAND)) {
|
&& !sourceCard.getCardType().contains(CardType.LAND)) {
|
||||||
Player player = game.getPlayer(source.getControllerId());
|
Player player = game.getPlayer(source.getControllerId());
|
||||||
String message = "Cast " + sourceCard.getName() + " without paying its mana costs?";
|
String message = "Cast " + sourceCard.getName() + " without paying its mana costs?";
|
||||||
if (player != null && player.chooseUse(outcome, message, game)) {
|
if (player != null &&
|
||||||
|
(CardUtil.isCheckPlayableMode(abilityToModify) || player.chooseUse(outcome, message, game))) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -49,6 +49,7 @@ import mage.game.Game;
|
||||||
import mage.game.stack.Spell;
|
import mage.game.stack.Spell;
|
||||||
import mage.game.stack.StackObject;
|
import mage.game.stack.StackObject;
|
||||||
import mage.players.Player;
|
import mage.players.Player;
|
||||||
|
import mage.util.CardUtil;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
|
|
@ -113,7 +114,8 @@ class AlurenEffect extends CostModificationEffectImpl {
|
||||||
if (sourceCard != null && sourceCard.getCardType().contains(CardType.CREATURE) && sourceCard.getManaCost().convertedManaCost() <= 3) {
|
if (sourceCard != null && sourceCard.getCardType().contains(CardType.CREATURE) && sourceCard.getManaCost().convertedManaCost() <= 3) {
|
||||||
Player player = game.getPlayer(stackObject.getControllerId());
|
Player player = game.getPlayer(stackObject.getControllerId());
|
||||||
String message = "Cast " + sourceCard.getName() + " without paying its mana costs?";
|
String message = "Cast " + sourceCard.getName() + " without paying its mana costs?";
|
||||||
if (player != null && player.chooseUse(outcome, message, game)) {
|
if (player != null &&
|
||||||
|
(CardUtil.isCheckPlayableMode(abilityToModify) || player.chooseUse(outcome, message, game))) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -38,4 +38,20 @@ import mage.game.Game;
|
||||||
public interface ActivatedAbility extends Ability {
|
public interface ActivatedAbility extends Ability {
|
||||||
|
|
||||||
boolean canActivate(UUID playerId, Game game);
|
boolean canActivate(UUID playerId, Game game);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a fresh copy of this activated ability.
|
||||||
|
*
|
||||||
|
* @return A new copy of this ability.
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
ActivatedAbility copy();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set a flag to know, that the ability is only created adn used to check
|
||||||
|
* what's playbable for the player.
|
||||||
|
*/
|
||||||
|
void setCheckPlayableMode();
|
||||||
|
|
||||||
|
boolean isCheckPlayableMode();
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -53,9 +53,11 @@ public abstract class ActivatedAbilityImpl extends AbilityImpl implements Activa
|
||||||
protected TimingRule timing = TimingRule.INSTANT;
|
protected TimingRule timing = TimingRule.INSTANT;
|
||||||
protected TargetController mayActivate = TargetController.YOU;
|
protected TargetController mayActivate = TargetController.YOU;
|
||||||
protected UUID activatorId;
|
protected UUID activatorId;
|
||||||
|
protected boolean checkPlayableMode;
|
||||||
|
|
||||||
protected ActivatedAbilityImpl(AbilityType abilityType, Zone zone) {
|
protected ActivatedAbilityImpl(AbilityType abilityType, Zone zone) {
|
||||||
super(abilityType, zone);
|
super(abilityType, zone);
|
||||||
|
this.checkPlayableMode = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public ActivatedAbilityImpl(ActivatedAbilityImpl ability) {
|
public ActivatedAbilityImpl(ActivatedAbilityImpl ability) {
|
||||||
|
|
@ -63,6 +65,7 @@ public abstract class ActivatedAbilityImpl extends AbilityImpl implements Activa
|
||||||
timing = ability.timing;
|
timing = ability.timing;
|
||||||
mayActivate = ability.mayActivate;
|
mayActivate = ability.mayActivate;
|
||||||
activatorId = ability.activatorId;
|
activatorId = ability.activatorId;
|
||||||
|
checkPlayableMode = ability.checkPlayableMode;
|
||||||
}
|
}
|
||||||
|
|
||||||
public ActivatedAbilityImpl(Zone zone) {
|
public ActivatedAbilityImpl(Zone zone) {
|
||||||
|
|
@ -217,4 +220,14 @@ public abstract class ActivatedAbilityImpl extends AbilityImpl implements Activa
|
||||||
this.timing = timing;
|
this.timing = timing;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setCheckPlayableMode() {
|
||||||
|
checkPlayableMode = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isCheckPlayableMode() {
|
||||||
|
return checkPlayableMode;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -84,8 +84,8 @@ public class SpellAbility extends ActivatedAbilityImpl {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean canActivate(UUID playerId, Game game) {
|
public boolean canActivate(UUID playerId, Game game) {
|
||||||
if (this.spellCanBeActivatedRegularlyNow(playerId, game) ||
|
if (game.getContinuousEffects().asThough(sourceId, AsThoughEffectType.CAST, this, playerId, game) // check this first to allow Offering in main phase
|
||||||
game.getContinuousEffects().asThough(sourceId, AsThoughEffectType.CAST, playerId, game)) {
|
|| this.spellCanBeActivatedRegularlyNow(playerId, game)) {
|
||||||
if (spellAbilityType.equals(SpellAbilityType.SPLIT)) {
|
if (spellAbilityType.equals(SpellAbilityType.SPLIT)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -57,7 +57,7 @@ public class AlternativeCost2Impl <T extends AlternativeCost2Impl<T>> extends Co
|
||||||
if (reminderText != null) {
|
if (reminderText != null) {
|
||||||
this.reminderText = new StringBuilder("<i>").append(reminderText).append("</i>").toString();
|
this.reminderText = new StringBuilder("<i>").append(reminderText).append("</i>").toString();
|
||||||
}
|
}
|
||||||
this.add((Cost) cost);
|
this.add(cost);
|
||||||
}
|
}
|
||||||
|
|
||||||
public AlternativeCost2Impl(final AlternativeCost2Impl cost) {
|
public AlternativeCost2Impl(final AlternativeCost2Impl cost) {
|
||||||
|
|
|
||||||
|
|
@ -28,8 +28,6 @@
|
||||||
package mage.abilities.costs;
|
package mage.abilities.costs;
|
||||||
|
|
||||||
import java.util.Iterator;
|
import java.util.Iterator;
|
||||||
import java.util.LinkedList;
|
|
||||||
import java.util.List;
|
|
||||||
import mage.abilities.Ability;
|
import mage.abilities.Ability;
|
||||||
import mage.abilities.SpellAbility;
|
import mage.abilities.SpellAbility;
|
||||||
import mage.abilities.StaticAbility;
|
import mage.abilities.StaticAbility;
|
||||||
|
|
|
||||||
|
|
@ -39,6 +39,7 @@ import mage.game.Game;
|
||||||
*/
|
*/
|
||||||
public interface AsThoughEffect extends ContinuousEffect {
|
public interface AsThoughEffect extends ContinuousEffect {
|
||||||
|
|
||||||
|
boolean applies(UUID sourceId, Ability affectedAbility, Ability source, Game game);
|
||||||
boolean applies(UUID sourceId, Ability source, Game game);
|
boolean applies(UUID sourceId, Ability source, Game game);
|
||||||
AsThoughEffectType getAsThoughEffectType();
|
AsThoughEffectType getAsThoughEffectType();
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -28,10 +28,13 @@
|
||||||
|
|
||||||
package mage.abilities.effects;
|
package mage.abilities.effects;
|
||||||
|
|
||||||
|
import java.util.UUID;
|
||||||
|
import mage.abilities.Ability;
|
||||||
import mage.constants.AsThoughEffectType;
|
import mage.constants.AsThoughEffectType;
|
||||||
import mage.constants.Duration;
|
import mage.constants.Duration;
|
||||||
import mage.constants.EffectType;
|
import mage.constants.EffectType;
|
||||||
import mage.constants.Outcome;
|
import mage.constants.Outcome;
|
||||||
|
import mage.game.Game;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
|
|
@ -52,6 +55,11 @@ public abstract class AsThoughEffectImpl extends ContinuousEffectImpl implements
|
||||||
this.type = effect.type;
|
this.type = effect.type;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean applies(UUID sourceId, Ability affectedAbility, Ability source, Game game) {
|
||||||
|
return applies(sourceId, source, game);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public AsThoughEffectType getAsThoughEffectType() {
|
public AsThoughEffectType getAsThoughEffectType() {
|
||||||
return type;
|
return type;
|
||||||
|
|
|
||||||
|
|
@ -420,20 +420,32 @@ public class ContinuousEffects implements Serializable {
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean asThough(UUID objectId, AsThoughEffectType type, UUID controllerId, Game game) {
|
public boolean asThough(UUID objectId, AsThoughEffectType type, UUID controllerId, Game game) {
|
||||||
|
return asThough(objectId, type, null, controllerId, game);
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean asThough(UUID objectId, AsThoughEffectType type, Ability affectedAbility, UUID controllerId, Game game) {
|
||||||
List<AsThoughEffect> asThoughEffectsList = getApplicableAsThoughEffects(type, game);
|
List<AsThoughEffect> asThoughEffectsList = getApplicableAsThoughEffects(type, game);
|
||||||
for (AsThoughEffect effect: asThoughEffectsList) {
|
for (AsThoughEffect effect: asThoughEffectsList) {
|
||||||
HashSet<Ability> abilities = asThoughEffectsMap.get(type).getAbility(effect.getId());
|
HashSet<Ability> abilities = asThoughEffectsMap.get(type).getAbility(effect.getId());
|
||||||
for (Ability ability : abilities) {
|
for (Ability ability : abilities) {
|
||||||
if (controllerId.equals(ability.getControllerId())) {
|
if (controllerId.equals(ability.getControllerId())) {
|
||||||
if (effect.applies(objectId, ability, game)) {
|
if (affectedAbility == null) {
|
||||||
return true;
|
if (effect.applies(objectId, ability, game)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (effect.applies(objectId, affectedAbility, ability, game)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Filters out asThough effects that are not active.
|
* Filters out asThough effects that are not active.
|
||||||
*
|
*
|
||||||
|
|
|
||||||
|
|
@ -32,13 +32,10 @@ import mage.constants.Duration;
|
||||||
import mage.constants.EffectType;
|
import mage.constants.EffectType;
|
||||||
import mage.constants.Outcome;
|
import mage.constants.Outcome;
|
||||||
import mage.abilities.Ability;
|
import mage.abilities.Ability;
|
||||||
import mage.abilities.SpellAbility;
|
|
||||||
import mage.abilities.effects.ContinuousEffectImpl;
|
import mage.abilities.effects.ContinuousEffectImpl;
|
||||||
import mage.abilities.effects.CostModificationEffect;
|
import mage.abilities.effects.CostModificationEffect;
|
||||||
import mage.cards.Card;
|
|
||||||
import mage.constants.CostModificationType;
|
import mage.constants.CostModificationType;
|
||||||
import mage.game.Game;
|
import mage.game.Game;
|
||||||
import mage.game.stack.Spell;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Simple implementation of a {@link CostModificationEffect} offering simplified
|
* Simple implementation of a {@link CostModificationEffect} offering simplified
|
||||||
|
|
|
||||||
|
|
@ -85,7 +85,7 @@ import mage.util.CardUtil;
|
||||||
if (!target.canChoose(sourceId, controllerId, game)) {
|
if (!target.canChoose(sourceId, controllerId, game)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (player.chooseUse(Outcome.Detriment, "Delve cards from your graveyard?", game)) {
|
if (!CardUtil.isCheckPlayableMode(ability) && player.chooseUse(Outcome.Detriment, "Delve cards from your graveyard?", game)) {
|
||||||
player.chooseTarget(Outcome.Detriment, target, ability, game);
|
player.chooseTarget(Outcome.Detriment, target, ability, game);
|
||||||
if (target.getTargets().size() > 0) {
|
if (target.getTargets().size() > 0) {
|
||||||
int adjCost = 0;
|
int adjCost = 0;
|
||||||
|
|
@ -94,11 +94,11 @@ import mage.util.CardUtil;
|
||||||
if (card == null) {
|
if (card == null) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
card.moveToExile(null, null, this.getSourceId(), game);
|
player.moveCardToExileWithInfo(card, null, "", getSourceId(), game, Zone.GRAVEYARD);
|
||||||
++adjCost;
|
++adjCost;
|
||||||
}
|
}
|
||||||
game.informPlayers(new StringBuilder(player.getName()).append(" delved ")
|
game.informPlayers(new StringBuilder("Delve: ").append(player.getName()).append(" exiled ")
|
||||||
.append(adjCost).append(" creature").append(adjCost != 1?"s":"").append(" from his or her graveyard").toString());
|
.append(adjCost).append(" card").append(adjCost != 1?"s":"").append(" from his or her graveyard").toString());
|
||||||
CardUtil.adjustCost((SpellAbility)ability, adjCost);
|
CardUtil.adjustCost((SpellAbility)ability, adjCost);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -128,6 +128,11 @@ class OfferingAsThoughEffect extends AsThoughEffectImpl {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean applies(UUID sourceId, Ability source, Game game) {
|
public boolean applies(UUID sourceId, Ability source, Game game) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean applies(UUID sourceId, Ability affectedAbility, Ability source, Game game) {
|
||||||
if (sourceId.equals(source.getSourceId())) {
|
if (sourceId.equals(source.getSourceId())) {
|
||||||
Card card = game.getCard(sourceId);
|
Card card = game.getCard(sourceId);
|
||||||
if (!card.getOwnerId().equals(source.getControllerId())) {
|
if (!card.getOwnerId().equals(source.getControllerId())) {
|
||||||
|
|
@ -139,10 +144,7 @@ class OfferingAsThoughEffect extends AsThoughEffectImpl {
|
||||||
Object alreadyConfirmed = game.getState().getValue("offering_ok_" + card.getId());
|
Object alreadyConfirmed = game.getState().getValue("offering_ok_" + card.getId());
|
||||||
game.getState().setValue("offering_" + card.getId(), null);
|
game.getState().setValue("offering_" + card.getId(), null);
|
||||||
game.getState().setValue("offering_ok_" + card.getId(), null);
|
game.getState().setValue("offering_ok_" + card.getId(), null);
|
||||||
if (alreadyConfirmed != null) {
|
return alreadyConfirmed != null;
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
} else {
|
} else {
|
||||||
// first call -> remove previous Ids
|
// first call -> remove previous Ids
|
||||||
game.getState().setValue("offering_Id_" + card.getId(), null);
|
game.getState().setValue("offering_Id_" + card.getId(), null);
|
||||||
|
|
@ -153,7 +155,8 @@ class OfferingAsThoughEffect extends AsThoughEffectImpl {
|
||||||
FilterControlledCreaturePermanent filter = ((OfferingAbility) source).getFilter();
|
FilterControlledCreaturePermanent filter = ((OfferingAbility) source).getFilter();
|
||||||
Card spellToCast = game.getCard(source.getSourceId());
|
Card spellToCast = game.getCard(source.getSourceId());
|
||||||
Player player = game.getPlayer(source.getControllerId());
|
Player player = game.getPlayer(source.getControllerId());
|
||||||
if (player != null && player.chooseUse(Outcome.Benefit, "Offer a " + filter.getMessage() + " to cast " + spellToCast.getName() + "?", game)) {
|
if (player != null && !CardUtil.isCheckPlayableMode(affectedAbility) &&
|
||||||
|
player.chooseUse(Outcome.Benefit, "Offer a " + filter.getMessage() + " to cast " + spellToCast.getName() + "?", game)) {
|
||||||
Target target = new TargetControlledCreaturePermanent(1,1,filter,true);
|
Target target = new TargetControlledCreaturePermanent(1,1,filter,true);
|
||||||
player.chooseTarget(Outcome.Sacrifice, target, source, game);
|
player.chooseTarget(Outcome.Sacrifice, target, source, game);
|
||||||
if (!target.isChosen()) {
|
if (!target.isChosen()) {
|
||||||
|
|
@ -185,9 +188,9 @@ class OfferingAsThoughEffect extends AsThoughEffectImpl {
|
||||||
|
|
||||||
class OfferingCostReductionEffect extends CostModificationEffectImpl {
|
class OfferingCostReductionEffect extends CostModificationEffectImpl {
|
||||||
|
|
||||||
private UUID spellAbilityId;
|
private final UUID spellAbilityId;
|
||||||
private UUID activationId;
|
private final UUID activationId;
|
||||||
private ManaCosts<ManaCost> manaCostsToReduce;
|
private final ManaCosts<ManaCost> manaCostsToReduce;
|
||||||
|
|
||||||
OfferingCostReductionEffect (UUID spellAbilityId, ManaCosts<ManaCost> manaCostsToReduce, UUID activationId) {
|
OfferingCostReductionEffect (UUID spellAbilityId, ManaCosts<ManaCost> manaCostsToReduce, UUID activationId) {
|
||||||
super(Duration.OneUse, Outcome.Benefit, CostModificationType.REDUCE_COST);
|
super(Duration.OneUse, Outcome.Benefit, CostModificationType.REDUCE_COST);
|
||||||
|
|
|
||||||
|
|
@ -62,7 +62,7 @@ class ShadowEffect extends RestrictionEffect implements MageSingleton {
|
||||||
@Override
|
@Override
|
||||||
public boolean canBeBlocked(Permanent attacker, Permanent blocker, Ability source, Game game) {
|
public boolean canBeBlocked(Permanent attacker, Permanent blocker, Ability source, Game game) {
|
||||||
if (blocker.getAbilities().containsKey(ShadowAbility.getInstance().getId())
|
if (blocker.getAbilities().containsKey(ShadowAbility.getInstance().getId())
|
||||||
|| game.getContinuousEffects().asThough(blocker.getId(), AsThoughEffectType.BLOCK_SHADOW, blocker.getControllerId(), game)) {
|
|| game.getContinuousEffects().asThough(blocker.getId(), AsThoughEffectType.BLOCK_SHADOW, source, blocker.getControllerId(), game)) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
|
|
|
||||||
|
|
@ -193,7 +193,7 @@ public class SuspendAbility extends ActivatedAbilityImpl {
|
||||||
MageObject object = game.getObject(sourceId);
|
MageObject object = game.getObject(sourceId);
|
||||||
return (object.getCardType().contains(CardType.INSTANT) ||
|
return (object.getCardType().contains(CardType.INSTANT) ||
|
||||||
object.hasAbility(FlashAbility.getInstance().getId(), game) ||
|
object.hasAbility(FlashAbility.getInstance().getId(), game) ||
|
||||||
game.getContinuousEffects().asThough(sourceId, AsThoughEffectType.CAST, playerId, game) ||
|
game.getContinuousEffects().asThough(sourceId, AsThoughEffectType.CAST, this, playerId, game) ||
|
||||||
game.canPlaySorcery(playerId));
|
game.canPlaySorcery(playerId));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -118,7 +118,7 @@ public class ManaPool implements Serializable {
|
||||||
|
|
||||||
// check if any mana can be spend to cast the mana cost of an ability
|
// check if any mana can be spend to cast the mana cost of an ability
|
||||||
private boolean spendAnyMana(Ability ability, Game game) {
|
private boolean spendAnyMana(Ability ability, Game game) {
|
||||||
return game.getContinuousEffects().asThough(ability.getSourceId(), AsThoughEffectType.SPEND_ANY_MANA, ability.getControllerId(), game);
|
return game.getContinuousEffects().asThough(ability.getSourceId(), AsThoughEffectType.SPEND_ANY_MANA, ability, ability.getControllerId(), game);
|
||||||
}
|
}
|
||||||
|
|
||||||
public int get(ManaType manaType) {
|
public int get(ManaType manaType) {
|
||||||
|
|
|
||||||
|
|
@ -1834,8 +1834,12 @@ public abstract class PlayerImpl implements Player, Serializable {
|
||||||
}
|
}
|
||||||
|
|
||||||
protected boolean canPlay(ActivatedAbility ability, ManaOptions available, Game game) {
|
protected boolean canPlay(ActivatedAbility ability, ManaOptions available, Game game) {
|
||||||
if (!(ability instanceof ManaAbility) && ability.canActivate(playerId, game)) {
|
if (!(ability instanceof ManaAbility)) {
|
||||||
Ability copy = ability.copy();
|
ActivatedAbility copy = ability.copy();
|
||||||
|
copy.setCheckPlayableMode(); // prevents from endless loops for asking player to use effects by checking this mode
|
||||||
|
if (!copy.canActivate(playerId, game)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
game.getContinuousEffects().costModification(copy, game);
|
game.getContinuousEffects().costModification(copy, game);
|
||||||
|
|
||||||
Card card = game.getCard(ability.getSourceId());
|
Card card = game.getCard(ability.getSourceId());
|
||||||
|
|
|
||||||
|
|
@ -33,6 +33,7 @@ import java.util.UUID;
|
||||||
|
|
||||||
import mage.Mana;
|
import mage.Mana;
|
||||||
import mage.abilities.Ability;
|
import mage.abilities.Ability;
|
||||||
|
import mage.abilities.ActivatedAbility;
|
||||||
import mage.abilities.SpellAbility;
|
import mage.abilities.SpellAbility;
|
||||||
import mage.abilities.costs.AlternativeCost;
|
import mage.abilities.costs.AlternativeCost;
|
||||||
import mage.abilities.costs.AlternativeCostImpl;
|
import mage.abilities.costs.AlternativeCostImpl;
|
||||||
|
|
@ -490,4 +491,17 @@ public class CardUtil {
|
||||||
}
|
}
|
||||||
return uniqueString.toString();
|
return uniqueString.toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns if the ability is used to check which cards
|
||||||
|
* are playable on hand. (Issue #457)
|
||||||
|
* @param ability - ability to check
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public static boolean isCheckPlayableMode(Ability ability) {
|
||||||
|
if (ability instanceof ActivatedAbility) {
|
||||||
|
return ((ActivatedAbility) ability).isCheckPlayableMode();
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue