mirror of
https://github.com/magefree/mage.git
synced 2025-12-25 04:52:07 -08:00
* Added logic to add permitting object to play/cast events.
This commit is contained in:
parent
b97a443a37
commit
27ced167fb
124 changed files with 1095 additions and 964 deletions
|
|
@ -157,7 +157,7 @@ public class AbilitiesImpl<T extends Ability> extends ArrayList<T> implements Ab
|
|||
return stream()
|
||||
.filter(ability -> ability instanceof ActivatedManaAbilityImpl)
|
||||
.filter(ability -> ability.getZone().match(zone))
|
||||
.filter(ability -> (((ActivatedManaAbilityImpl) ability).canActivate(ability.getControllerId(), game)))
|
||||
.filter(ability -> (((ActivatedManaAbilityImpl) ability).canActivate(ability.getControllerId(), game).canActivate()))
|
||||
.map(ability -> (ActivatedManaAbilityImpl) ability)
|
||||
.collect(Collectors.toCollection(AbilitiesImpl::new));
|
||||
|
||||
|
|
|
|||
|
|
@ -28,6 +28,7 @@
|
|||
package mage.abilities;
|
||||
|
||||
import java.util.UUID;
|
||||
import mage.MageObjectReference;
|
||||
import mage.abilities.mana.ManaOptions;
|
||||
import mage.constants.TargetController;
|
||||
import mage.game.Game;
|
||||
|
|
@ -38,9 +39,36 @@ import mage.game.Game;
|
|||
*/
|
||||
public interface ActivatedAbility extends Ability {
|
||||
|
||||
boolean canActivate(UUID playerId, Game game);
|
||||
final public class ActivationStatus {
|
||||
|
||||
public void setMayActivate(TargetController mayActivate);
|
||||
private final boolean canActivate;
|
||||
private final MageObjectReference permittingObject;
|
||||
|
||||
public ActivationStatus(boolean canActivate, MageObjectReference permittingObject) {
|
||||
this.canActivate = canActivate;
|
||||
this.permittingObject = permittingObject;
|
||||
}
|
||||
|
||||
public boolean canActivate() {
|
||||
return canActivate;
|
||||
}
|
||||
|
||||
public MageObjectReference getPermittingObject() {
|
||||
return permittingObject;
|
||||
}
|
||||
|
||||
public static ActivationStatus getFalse() {
|
||||
return new ActivationStatus(false, null);
|
||||
}
|
||||
|
||||
public static ActivationStatus getTrue() {
|
||||
return new ActivationStatus(true, null);
|
||||
}
|
||||
}
|
||||
|
||||
ActivationStatus canActivate(UUID playerId, Game game); // has to return a reference to the permitting ability/source
|
||||
|
||||
void setMayActivate(TargetController mayActivate);
|
||||
|
||||
/**
|
||||
* Returns the minimal possible cost for what the ability can be activated
|
||||
|
|
|
|||
|
|
@ -29,6 +29,7 @@ package mage.abilities;
|
|||
|
||||
import java.util.UUID;
|
||||
import mage.MageObject;
|
||||
import mage.MageObjectReference;
|
||||
import mage.abilities.condition.Condition;
|
||||
import mage.abilities.costs.Cost;
|
||||
import mage.abilities.costs.Costs;
|
||||
|
|
@ -177,38 +178,39 @@ public abstract class ActivatedAbilityImpl extends AbilityImpl implements Activa
|
|||
public abstract ActivatedAbilityImpl copy();
|
||||
|
||||
@Override
|
||||
public boolean canActivate(UUID playerId, Game game) {
|
||||
public ActivationStatus canActivate(UUID playerId, Game game) {
|
||||
//20091005 - 602.2
|
||||
if (!(hasMoreActivationsThisTurn(game) && (condition == null || condition.apply(game, this)))) {
|
||||
return false;
|
||||
return ActivationStatus.getFalse();
|
||||
}
|
||||
switch (mayActivate) {
|
||||
case ANY:
|
||||
break;
|
||||
|
||||
case NOT_YOU:
|
||||
if (controlsAbility(playerId, game)) {
|
||||
return false;
|
||||
return ActivationStatus.getFalse();
|
||||
}
|
||||
break;
|
||||
case TEAM:
|
||||
if (game.getPlayer(controllerId).hasOpponent(playerId, game)) {
|
||||
return false;
|
||||
return ActivationStatus.getFalse();
|
||||
}
|
||||
break;
|
||||
case OPPONENT:
|
||||
if (!game.getPlayer(controllerId).hasOpponent(playerId, game)) {
|
||||
return false;
|
||||
return ActivationStatus.getFalse();
|
||||
}
|
||||
break;
|
||||
case OWNER:
|
||||
Permanent permanent = game.getPermanent(getSourceId());
|
||||
if (!permanent.getOwnerId().equals(playerId)) {
|
||||
return false;
|
||||
return ActivationStatus.getFalse();
|
||||
}
|
||||
break;
|
||||
case YOU:
|
||||
if (!controlsAbility(playerId, game)) {
|
||||
return false;
|
||||
return ActivationStatus.getFalse();
|
||||
}
|
||||
break;
|
||||
case CONTROLLER_ATTACHED_TO:
|
||||
|
|
@ -219,17 +221,17 @@ public abstract class ActivatedAbilityImpl extends AbilityImpl implements Activa
|
|||
break;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
return ActivationStatus.getFalse();
|
||||
}
|
||||
//20091005 - 602.5d/602.5e
|
||||
if (timing == TimingRule.INSTANT || game.canPlaySorcery(playerId)
|
||||
|| null != game.getContinuousEffects().asThough(sourceId, AsThoughEffectType.ACTIVATE_AS_INSTANT, this, controllerId, game)) {
|
||||
MageObjectReference permittingObject = game.getContinuousEffects().asThough(sourceId, AsThoughEffectType.ACTIVATE_AS_INSTANT, this, controllerId, game);
|
||||
if (timing == TimingRule.INSTANT || game.canPlaySorcery(playerId) || null != permittingObject) {
|
||||
if (costs.canPay(this, sourceId, playerId, game) && canChooseTarget(game)) {
|
||||
this.activatorId = playerId;
|
||||
return true;
|
||||
return new ActivationStatus(true, permittingObject);
|
||||
}
|
||||
}
|
||||
return false;
|
||||
return ActivationStatus.getFalse();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
@ -310,10 +312,12 @@ public abstract class ActivatedAbilityImpl extends AbilityImpl implements Activa
|
|||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setMaxActivationsPerTurn(int maxActivationsPerTurn) {
|
||||
this.maxActivationsPerTurn = maxActivationsPerTurn;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getMaxActivationsPerTurn(Game game) {
|
||||
return maxActivationsPerTurn;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -28,6 +28,7 @@
|
|||
package mage.abilities;
|
||||
|
||||
import java.util.UUID;
|
||||
import mage.MageObjectReference;
|
||||
import mage.constants.AbilityType;
|
||||
import mage.constants.AsThoughEffectType;
|
||||
import mage.constants.Zone;
|
||||
|
|
@ -50,13 +51,13 @@ public class PlayLandAbility extends ActivatedAbilityImpl {
|
|||
}
|
||||
|
||||
@Override
|
||||
public boolean canActivate(UUID playerId, Game game) {
|
||||
if (!controlsAbility(playerId, game)
|
||||
&& null == game.getContinuousEffects().asThough(getSourceId(), AsThoughEffectType.PLAY_FROM_NOT_OWN_HAND_ZONE, playerId, game)) {
|
||||
return false;
|
||||
public ActivationStatus canActivate(UUID playerId, Game game) {
|
||||
MageObjectReference permittingObject = game.getContinuousEffects().asThough(getSourceId(), AsThoughEffectType.PLAY_FROM_NOT_OWN_HAND_ZONE, null, playerId, game);
|
||||
if (!controlsAbility(playerId, game) && null == permittingObject) {
|
||||
return ActivationStatus.getFalse();
|
||||
}
|
||||
//20091005 - 114.2a
|
||||
return game.getActivePlayerId().equals(playerId) && game.getPlayer(playerId).canPlayLand() && game.canPlaySorcery(playerId);
|
||||
return new ActivationStatus(game.getActivePlayerId().equals(playerId) && game.getPlayer(playerId).canPlayLand() && game.canPlaySorcery(playerId), permittingObject);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
|||
|
|
@ -29,6 +29,7 @@ package mage.abilities;
|
|||
|
||||
import java.util.UUID;
|
||||
import mage.MageObject;
|
||||
import mage.MageObjectReference;
|
||||
import mage.abilities.costs.Cost;
|
||||
import mage.abilities.costs.VariableCost;
|
||||
import mage.abilities.costs.mana.ManaCost;
|
||||
|
|
@ -91,48 +92,49 @@ public class SpellAbility extends ActivatedAbilityImpl {
|
|||
}
|
||||
|
||||
@Override
|
||||
public boolean canActivate(UUID playerId, Game game) {
|
||||
public ActivationStatus canActivate(UUID playerId, Game game) {
|
||||
if (null != 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 == SpellAbilityType.SPLIT || spellAbilityType == SpellAbilityType.SPLIT_AFTERMATH) {
|
||||
return false;
|
||||
return ActivationStatus.getFalse();
|
||||
}
|
||||
// fix for Gitaxian Probe and casting opponent's spells
|
||||
if (null == game.getContinuousEffects().asThough(getSourceId(), AsThoughEffectType.PLAY_FROM_NOT_OWN_HAND_ZONE, playerId, game)) {
|
||||
MageObjectReference permittingSource = game.getContinuousEffects().asThough(getSourceId(), AsThoughEffectType.PLAY_FROM_NOT_OWN_HAND_ZONE, null, playerId, game);
|
||||
if (permittingSource == null) {
|
||||
Card card = game.getCard(sourceId);
|
||||
if (!(card != null && card.getOwnerId().equals(playerId))) {
|
||||
return false;
|
||||
return ActivationStatus.getFalse();
|
||||
}
|
||||
}
|
||||
// Check if rule modifying events prevent to cast the spell in check playable mode
|
||||
if (this.isCheckPlayableMode()) {
|
||||
if (game.getContinuousEffects().preventedByRuleModification(
|
||||
GameEvent.getEvent(GameEvent.EventType.CAST_SPELL, this.getId(), this.getSourceId(), playerId), this, game, true)) {
|
||||
return false;
|
||||
return ActivationStatus.getFalse();
|
||||
}
|
||||
}
|
||||
// Alternate spell abilities (Flashback, Overload) can't be cast with no mana to pay option
|
||||
if (getSpellAbilityType() == SpellAbilityType.BASE_ALTERNATE) {
|
||||
Player player = game.getPlayer(playerId);
|
||||
if (player != null && getSourceId().equals(player.getCastSourceIdWithAlternateMana())) {
|
||||
return false;
|
||||
return ActivationStatus.getFalse();
|
||||
}
|
||||
}
|
||||
if (costs.canPay(this, sourceId, controllerId, game)) {
|
||||
if (getSpellAbilityType() == SpellAbilityType.SPLIT_FUSED) {
|
||||
SplitCard splitCard = (SplitCard) game.getCard(getSourceId());
|
||||
if (splitCard != null) {
|
||||
return (splitCard.getLeftHalfCard().getSpellAbility().canChooseTarget(game)
|
||||
&& splitCard.getRightHalfCard().getSpellAbility().canChooseTarget(game));
|
||||
return new ActivationStatus(splitCard.getLeftHalfCard().getSpellAbility().canChooseTarget(game)
|
||||
&& splitCard.getRightHalfCard().getSpellAbility().canChooseTarget(game), null);
|
||||
}
|
||||
return false;
|
||||
return ActivationStatus.getFalse();
|
||||
|
||||
} else {
|
||||
return canChooseTarget(game);
|
||||
return new ActivationStatus(canChooseTarget(game), permittingSource);
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
return ActivationStatus.getFalse();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
|||
|
|
@ -1,16 +1,16 @@
|
|||
/*
|
||||
* 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
|
||||
|
|
@ -20,18 +20,17 @@
|
|||
* 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.common;
|
||||
|
||||
import java.util.UUID;
|
||||
import mage.constants.Zone;
|
||||
import mage.abilities.ActivatedAbilityImpl;
|
||||
import mage.abilities.effects.common.PassEffect;
|
||||
import mage.constants.Zone;
|
||||
import mage.game.Game;
|
||||
|
||||
/**
|
||||
|
|
@ -55,8 +54,8 @@ public class PassAbility extends ActivatedAbilityImpl {
|
|||
}
|
||||
|
||||
@Override
|
||||
public boolean canActivate(UUID playerId, Game game) {
|
||||
return true;
|
||||
public ActivationStatus canActivate(UUID playerId, Game game) {
|
||||
return ActivationStatus.getTrue();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
|||
|
|
@ -63,7 +63,7 @@ public class TapSourceCost extends CostImpl {
|
|||
Permanent permanent = game.getPermanent(sourceId);
|
||||
if (permanent != null) {
|
||||
return !permanent.isTapped()
|
||||
&& (permanent.canTap() || null != game.getContinuousEffects().asThough(sourceId, AsThoughEffectType.ACTIVATE_HASTE, controllerId, game));
|
||||
&& (permanent.canTap() || null != game.getContinuousEffects().asThough(sourceId, AsThoughEffectType.ACTIVATE_HASTE, ability, controllerId, game));
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -62,7 +62,7 @@ public class UntapSourceCost extends CostImpl {
|
|||
public boolean canPay(Ability ability, UUID sourceId, UUID controllerId, Game game) {
|
||||
Permanent permanent = game.getPermanent(sourceId);
|
||||
if (permanent != null) {
|
||||
return permanent.isTapped() && (permanent.canTap() || null != game.getContinuousEffects().asThough(sourceId, AsThoughEffectType.ACTIVATE_HASTE, controllerId, game));
|
||||
return permanent.isTapped() && (permanent.canTap() || null != game.getContinuousEffects().asThough(sourceId, AsThoughEffectType.ACTIVATE_HASTE, ability, controllerId, game));
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -82,9 +82,9 @@ public class ConditionalGainActivatedAbility extends ActivatedAbilityImpl {
|
|||
}
|
||||
|
||||
@Override
|
||||
public boolean canActivate(UUID playerId, Game game) {
|
||||
public ActivationStatus canActivate(UUID playerId, Game game) {
|
||||
if (!condition.apply(game, this)) {
|
||||
return false;
|
||||
return ActivationStatus.getFalse();
|
||||
}
|
||||
return super.canActivate(playerId, game);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -32,6 +32,7 @@ import java.util.*;
|
|||
import java.util.Map.Entry;
|
||||
import java.util.stream.Collectors;
|
||||
import mage.MageObject;
|
||||
import mage.MageObjectReference;
|
||||
import mage.abilities.*;
|
||||
import mage.abilities.effects.common.continuous.BecomesFaceDownCreatureEffect;
|
||||
import mage.abilities.effects.common.continuous.CommanderReplacementEffect;
|
||||
|
|
@ -502,19 +503,6 @@ public class ContinuousEffects implements Serializable {
|
|||
return spliceEffects;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param objectId
|
||||
* @param type
|
||||
* @param controllerId
|
||||
* @param game
|
||||
* @return sourceId of the permitting effect if any exists otherwise returns
|
||||
* null
|
||||
*/
|
||||
public UUID asThough(UUID objectId, AsThoughEffectType type, UUID controllerId, Game game) {
|
||||
return asThough(objectId, type, null, controllerId, game);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param objectId
|
||||
|
|
@ -525,17 +513,17 @@ public class ContinuousEffects implements Serializable {
|
|||
* @return sourceId of the permitting effect if any exists otherwise returns
|
||||
* null
|
||||
*/
|
||||
public UUID asThough(UUID objectId, AsThoughEffectType type, Ability affectedAbility, UUID controllerId, Game game) {
|
||||
public MageObjectReference asThough(UUID objectId, AsThoughEffectType type, Ability affectedAbility, UUID controllerId, Game game) {
|
||||
List<AsThoughEffect> asThoughEffectsList = getApplicableAsThoughEffects(type, game);
|
||||
for (AsThoughEffect effect : asThoughEffectsList) {
|
||||
Set<Ability> abilities = asThoughEffectsMap.get(type).getAbility(effect.getId());
|
||||
for (Ability ability : abilities) {
|
||||
if (affectedAbility == null) {
|
||||
if (effect.applies(objectId, ability, controllerId, game)) {
|
||||
return ability.getSourceId();
|
||||
return new MageObjectReference(ability.getSourceObject(game), game);
|
||||
}
|
||||
} else if (effect.applies(objectId, affectedAbility, ability, game)) {
|
||||
return ability.getSourceId();
|
||||
return new MageObjectReference(ability.getSourceObject(game), game);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -28,6 +28,7 @@
|
|||
package mage.abilities.effects.common;
|
||||
|
||||
import java.util.Set;
|
||||
import mage.MageObjectReference;
|
||||
import mage.abilities.Ability;
|
||||
import mage.abilities.effects.OneShotEffect;
|
||||
import mage.cards.Card;
|
||||
|
|
@ -88,7 +89,7 @@ public class CastCardFromOutsideTheGameEffect extends OneShotEffect {
|
|||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
Cards filteredCards = new CardsImpl();
|
||||
for (Card card : filtered) {
|
||||
filteredCards.add(card.getId());
|
||||
|
|
@ -98,7 +99,7 @@ public class CastCardFromOutsideTheGameEffect extends OneShotEffect {
|
|||
if (player.choose(Outcome.Benefit, filteredCards, target, game)) {
|
||||
Card card = player.getSideboard().get(target.getFirstTarget(), game);
|
||||
if (card != null) {
|
||||
player.cast(card.getSpellAbility(), game, true);
|
||||
player.cast(card.getSpellAbility(), game, true, new MageObjectReference(source.getSourceObject(game), game));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -106,4 +107,4 @@ public class CastCardFromOutsideTheGameEffect extends OneShotEffect {
|
|||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -28,6 +28,7 @@
|
|||
package mage.abilities.effects.common;
|
||||
|
||||
import java.util.UUID;
|
||||
import mage.MageObjectReference;
|
||||
import mage.abilities.Ability;
|
||||
import mage.abilities.SpellAbility;
|
||||
import mage.abilities.common.DealsCombatDamageToAPlayerTriggeredAbility;
|
||||
|
|
@ -151,7 +152,7 @@ class CipherStoreEffect extends OneShotEffect {
|
|||
}
|
||||
ability.getEffects().remove(cipherEffect);
|
||||
if (ability instanceof SpellAbility) {
|
||||
controller.cast(ability, game, true);
|
||||
controller.cast(ability, game, true, new MageObjectReference(source.getSourceObject(game), game));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -27,6 +27,8 @@
|
|||
*/
|
||||
package mage.abilities.effects.common;
|
||||
|
||||
import java.util.UUID;
|
||||
import mage.MageObjectReference;
|
||||
import mage.abilities.Ability;
|
||||
import mage.abilities.effects.OneShotEffect;
|
||||
import mage.cards.Card;
|
||||
|
|
@ -36,8 +38,6 @@ import mage.game.Game;
|
|||
import mage.players.Player;
|
||||
import mage.util.CardUtil;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
/**
|
||||
* @author LevelX2
|
||||
*
|
||||
|
|
@ -82,7 +82,7 @@ public class HideawayPlayEffect extends OneShotEffect {
|
|||
}
|
||||
}
|
||||
|
||||
if (!controller.playCard(card, game, true, true)) {
|
||||
if (!controller.playCard(card, game, true, true, new MageObjectReference(source.getSourceObject(game), game))) {
|
||||
if (card.getZoneChangeCounter(game) == zcc) {
|
||||
card.setFaceDown(true, game);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -24,16 +24,16 @@
|
|||
* 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.constants.Outcome;
|
||||
import mage.constants.Zone;
|
||||
import mage.MageObjectReference;
|
||||
import mage.abilities.Ability;
|
||||
import mage.abilities.Mode;
|
||||
import mage.abilities.effects.OneShotEffect;
|
||||
import mage.cards.Card;
|
||||
import mage.constants.Outcome;
|
||||
import mage.constants.Zone;
|
||||
import mage.game.Game;
|
||||
import mage.players.Player;
|
||||
import mage.target.Target;
|
||||
|
|
@ -62,7 +62,7 @@ public class PlayTargetWithoutPayingManaEffect extends OneShotEffect {
|
|||
Player controller = game.getPlayer(source.getControllerId());
|
||||
Card target = (Card) game.getObject(source.getFirstTarget());
|
||||
if (controller != null && target != null) {
|
||||
return controller.cast(target.getSpellAbility(), game, true);
|
||||
return controller.cast(target.getSpellAbility(), game, true, new MageObjectReference(source.getSourceObject(game), game));
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
|
@ -74,8 +74,7 @@ public class PlayTargetWithoutPayingManaEffect extends OneShotEffect {
|
|||
Target target = mode.getTargets().get(0);
|
||||
if (mode.getTargets().get(0).getZone() == Zone.HAND) {
|
||||
sb.append("you may put ").append(target.getTargetName()).append(" from your hand onto the battlefield");
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
sb.append("you may cast target ").append(target.getTargetName()).append(" without paying its mana cost");
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -27,6 +27,7 @@
|
|||
*/
|
||||
package mage.abilities.effects.common.cost;
|
||||
|
||||
import mage.MageObjectReference;
|
||||
import mage.abilities.Ability;
|
||||
import mage.abilities.effects.OneShotEffect;
|
||||
import mage.cards.Card;
|
||||
|
|
@ -101,7 +102,7 @@ public class CastWithoutPayingManaCostEffect extends OneShotEffect {
|
|||
}
|
||||
}
|
||||
if (cardToCast != null) {
|
||||
controller.cast(cardToCast.getSpellAbility(), game, true);
|
||||
controller.cast(cardToCast.getSpellAbility(), game, true, new MageObjectReference(source.getSourceObject(game), game));
|
||||
}
|
||||
}
|
||||
return true;
|
||||
|
|
|
|||
|
|
@ -38,12 +38,15 @@ import mage.choices.ChoiceColor;
|
|||
import mage.game.Game;
|
||||
import mage.players.Player;
|
||||
import mage.util.CardUtil;
|
||||
import org.apache.log4j.Logger;
|
||||
|
||||
/**
|
||||
* @author noxx
|
||||
*/
|
||||
public class AddConditionalManaOfAnyColorEffect extends ManaEffect {
|
||||
|
||||
private static final Logger logger = Logger.getLogger(AddConditionalManaOfAnyColorEffect.class);
|
||||
|
||||
private final DynamicValue amount;
|
||||
private final ConditionalManaBuilder manaBuilder;
|
||||
private final boolean oneChoice;
|
||||
|
|
@ -87,8 +90,13 @@ public class AddConditionalManaOfAnyColorEffect extends ManaEffect {
|
|||
public boolean apply(Game game, Ability source) {
|
||||
Player controller = game.getPlayer(source.getControllerId());
|
||||
if (controller != null) {
|
||||
checkToFirePossibleEvents(getMana(game, source), game, source);
|
||||
controller.getManaPool().addMana(getMana(game, source), game, source);
|
||||
Mana mana = getMana(game, source);
|
||||
if (mana != null) {
|
||||
checkToFirePossibleEvents(mana, game, source);
|
||||
controller.getManaPool().addMana(mana, game, source);
|
||||
} else {
|
||||
logger.error("There was no mana created: " + source.getSourceObject(game).getName() + " - Ability: " + source.getRule());
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
|
|
|
|||
|
|
@ -1,158 +1,159 @@
|
|||
/*
|
||||
* 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.keyword;
|
||||
|
||||
import mage.Mana;
|
||||
import mage.abilities.Ability;
|
||||
import mage.abilities.SpecialAction;
|
||||
import mage.abilities.common.SimpleStaticAbility;
|
||||
import mage.abilities.costs.Cost;
|
||||
import mage.abilities.costs.mana.AlternateManaPaymentAbility;
|
||||
import mage.abilities.costs.mana.GenericManaCost;
|
||||
import mage.abilities.costs.mana.ManaCost;
|
||||
import mage.abilities.effects.OneShotEffect;
|
||||
import mage.constants.AbilityType;
|
||||
import mage.constants.ManaType;
|
||||
import mage.constants.Outcome;
|
||||
import mage.constants.TargetController;
|
||||
import mage.constants.Zone;
|
||||
import mage.filter.FilterPlayer;
|
||||
import mage.filter.predicate.other.PlayerPredicate;
|
||||
import mage.game.Game;
|
||||
import mage.players.ManaPool;
|
||||
import mage.players.Player;
|
||||
import mage.target.Target;
|
||||
import mage.target.TargetPlayer;
|
||||
|
||||
/*
|
||||
* @author emerald000
|
||||
*/
|
||||
public class AssistAbility extends SimpleStaticAbility implements AlternateManaPaymentAbility {
|
||||
|
||||
private static final FilterPlayer filter = new FilterPlayer("another player");
|
||||
static {
|
||||
filter.add(new PlayerPredicate(TargetController.NOT_YOU));
|
||||
}
|
||||
|
||||
public AssistAbility() {
|
||||
super(Zone.STACK, null);
|
||||
this.setRuleAtTheTop(true);
|
||||
}
|
||||
|
||||
public AssistAbility(final AssistAbility ability) {
|
||||
super(ability);
|
||||
}
|
||||
|
||||
@Override
|
||||
public AssistAbility copy() {
|
||||
return new AssistAbility(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addSpecialAction(Ability source, Game game, ManaCost unpaid) {
|
||||
Player controller = game.getPlayer(source.getControllerId());
|
||||
if (controller != null
|
||||
&& source.getAbilityType() == AbilityType.SPELL
|
||||
&& unpaid.getMana().getGeneric() >= 1
|
||||
&& game.getState().getValue(source.getSourceId().toString() + game.getState().getZoneChangeCounter(source.getSourceId())) == null) {
|
||||
SpecialAction specialAction = new AssistSpecialAction(unpaid);
|
||||
specialAction.setControllerId(source.getControllerId());
|
||||
specialAction.setSourceId(source.getSourceId());
|
||||
Target target = new TargetPlayer(1, 1, true, filter);
|
||||
specialAction.addTarget(target);
|
||||
if (specialAction.canActivate(source.getControllerId(), game)) {
|
||||
game.getState().getSpecialActions().add(specialAction);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getRule() {
|
||||
return "Assist <i>(Another player can help pay the generic mana of this spell's cost.)</i>";
|
||||
}
|
||||
}
|
||||
|
||||
class AssistSpecialAction extends SpecialAction {
|
||||
|
||||
AssistSpecialAction(ManaCost unpaid) {
|
||||
super(Zone.ALL, true);
|
||||
setRuleVisible(false);
|
||||
this.addEffect(new AssistEffect(unpaid));
|
||||
}
|
||||
|
||||
AssistSpecialAction(final AssistSpecialAction ability) {
|
||||
super(ability);
|
||||
}
|
||||
|
||||
@Override
|
||||
public AssistSpecialAction copy() {
|
||||
return new AssistSpecialAction(this);
|
||||
}
|
||||
}
|
||||
|
||||
class AssistEffect extends OneShotEffect {
|
||||
|
||||
private final ManaCost unpaid;
|
||||
|
||||
AssistEffect(ManaCost unpaid) {
|
||||
super(Outcome.Benefit);
|
||||
this.unpaid = unpaid;
|
||||
this.staticText = "Assist <i>(Another player can help pay the generic mana of this spell's cost.)</i>";
|
||||
}
|
||||
|
||||
AssistEffect(final AssistEffect effect) {
|
||||
super(effect);
|
||||
this.unpaid = effect.unpaid;
|
||||
}
|
||||
|
||||
@Override
|
||||
public AssistEffect copy() {
|
||||
return new AssistEffect(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean apply(Game game, Ability source) {
|
||||
Player controller = game.getPlayer(source.getControllerId());
|
||||
Player targetPlayer = game.getPlayer(this.getTargetPointer().getFirst(game, source));
|
||||
if (controller != null && targetPlayer != null) {
|
||||
int amountToPay = targetPlayer.announceXMana(0, unpaid.getMana().getGeneric(), "How much mana to pay?", game, source);
|
||||
if (amountToPay > 0) {
|
||||
Cost cost = new GenericManaCost(amountToPay);
|
||||
if (cost.pay(source, game, source.getSourceId(), targetPlayer.getId(), false)) {
|
||||
ManaPool manaPool = controller.getManaPool();
|
||||
manaPool.addMana(Mana.ColorlessMana(amountToPay), game, source);
|
||||
manaPool.unlockManaType(ManaType.COLORLESS);
|
||||
game.informPlayers(targetPlayer.getLogName() + " paid " + amountToPay + " mana.");
|
||||
game.getState().setValue(source.getSourceId().toString() + game.getState().getZoneChangeCounter(source.getSourceId()), true);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
/*
|
||||
* 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.keyword;
|
||||
|
||||
import mage.Mana;
|
||||
import mage.abilities.Ability;
|
||||
import mage.abilities.SpecialAction;
|
||||
import mage.abilities.common.SimpleStaticAbility;
|
||||
import mage.abilities.costs.Cost;
|
||||
import mage.abilities.costs.mana.AlternateManaPaymentAbility;
|
||||
import mage.abilities.costs.mana.GenericManaCost;
|
||||
import mage.abilities.costs.mana.ManaCost;
|
||||
import mage.abilities.effects.OneShotEffect;
|
||||
import mage.constants.AbilityType;
|
||||
import mage.constants.ManaType;
|
||||
import mage.constants.Outcome;
|
||||
import mage.constants.TargetController;
|
||||
import mage.constants.Zone;
|
||||
import mage.filter.FilterPlayer;
|
||||
import mage.filter.predicate.other.PlayerPredicate;
|
||||
import mage.game.Game;
|
||||
import mage.players.ManaPool;
|
||||
import mage.players.Player;
|
||||
import mage.target.Target;
|
||||
import mage.target.TargetPlayer;
|
||||
|
||||
/*
|
||||
* @author emerald000
|
||||
*/
|
||||
public class AssistAbility extends SimpleStaticAbility implements AlternateManaPaymentAbility {
|
||||
|
||||
private static final FilterPlayer filter = new FilterPlayer("another player");
|
||||
|
||||
static {
|
||||
filter.add(new PlayerPredicate(TargetController.NOT_YOU));
|
||||
}
|
||||
|
||||
public AssistAbility() {
|
||||
super(Zone.STACK, null);
|
||||
this.setRuleAtTheTop(true);
|
||||
}
|
||||
|
||||
public AssistAbility(final AssistAbility ability) {
|
||||
super(ability);
|
||||
}
|
||||
|
||||
@Override
|
||||
public AssistAbility copy() {
|
||||
return new AssistAbility(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addSpecialAction(Ability source, Game game, ManaCost unpaid) {
|
||||
Player controller = game.getPlayer(source.getControllerId());
|
||||
if (controller != null
|
||||
&& source.getAbilityType() == AbilityType.SPELL
|
||||
&& unpaid.getMana().getGeneric() >= 1
|
||||
&& game.getState().getValue(source.getSourceId().toString() + game.getState().getZoneChangeCounter(source.getSourceId())) == null) {
|
||||
SpecialAction specialAction = new AssistSpecialAction(unpaid);
|
||||
specialAction.setControllerId(source.getControllerId());
|
||||
specialAction.setSourceId(source.getSourceId());
|
||||
Target target = new TargetPlayer(1, 1, true, filter);
|
||||
specialAction.addTarget(target);
|
||||
if (specialAction.canActivate(source.getControllerId(), game).canActivate()) {
|
||||
game.getState().getSpecialActions().add(specialAction);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getRule() {
|
||||
return "Assist <i>(Another player can help pay the generic mana of this spell's cost.)</i>";
|
||||
}
|
||||
}
|
||||
|
||||
class AssistSpecialAction extends SpecialAction {
|
||||
|
||||
AssistSpecialAction(ManaCost unpaid) {
|
||||
super(Zone.ALL, true);
|
||||
setRuleVisible(false);
|
||||
this.addEffect(new AssistEffect(unpaid));
|
||||
}
|
||||
|
||||
AssistSpecialAction(final AssistSpecialAction ability) {
|
||||
super(ability);
|
||||
}
|
||||
|
||||
@Override
|
||||
public AssistSpecialAction copy() {
|
||||
return new AssistSpecialAction(this);
|
||||
}
|
||||
}
|
||||
|
||||
class AssistEffect extends OneShotEffect {
|
||||
|
||||
private final ManaCost unpaid;
|
||||
|
||||
AssistEffect(ManaCost unpaid) {
|
||||
super(Outcome.Benefit);
|
||||
this.unpaid = unpaid;
|
||||
this.staticText = "Assist <i>(Another player can help pay the generic mana of this spell's cost.)</i>";
|
||||
}
|
||||
|
||||
AssistEffect(final AssistEffect effect) {
|
||||
super(effect);
|
||||
this.unpaid = effect.unpaid;
|
||||
}
|
||||
|
||||
@Override
|
||||
public AssistEffect copy() {
|
||||
return new AssistEffect(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean apply(Game game, Ability source) {
|
||||
Player controller = game.getPlayer(source.getControllerId());
|
||||
Player targetPlayer = game.getPlayer(this.getTargetPointer().getFirst(game, source));
|
||||
if (controller != null && targetPlayer != null) {
|
||||
int amountToPay = targetPlayer.announceXMana(0, unpaid.getMana().getGeneric(), "How much mana to pay?", game, source);
|
||||
if (amountToPay > 0) {
|
||||
Cost cost = new GenericManaCost(amountToPay);
|
||||
if (cost.pay(source, game, source.getSourceId(), targetPlayer.getId(), false)) {
|
||||
ManaPool manaPool = controller.getManaPool();
|
||||
manaPool.addMana(Mana.ColorlessMana(amountToPay), game, source);
|
||||
manaPool.unlockManaType(ManaType.COLORLESS);
|
||||
game.informPlayers(targetPlayer.getLogName() + " paid " + amountToPay + " mana.");
|
||||
game.getState().setValue(source.getSourceId().toString() + game.getState().getZoneChangeCounter(source.getSourceId()), true);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -27,6 +27,7 @@
|
|||
*/
|
||||
package mage.abilities.keyword;
|
||||
|
||||
import mage.MageObjectReference;
|
||||
import mage.abilities.Ability;
|
||||
import mage.abilities.TriggeredAbilityImpl;
|
||||
import mage.abilities.effects.OneShotEffect;
|
||||
|
|
@ -124,7 +125,7 @@ class CascadeEffect extends OneShotEffect {
|
|||
|
||||
if (card != null) {
|
||||
if (controller.chooseUse(outcome, "Use cascade effect on " + card.getLogName() + '?', source, game)) {
|
||||
controller.cast(card.getSpellAbility(), game, true);
|
||||
controller.cast(card.getSpellAbility(), game, true, new MageObjectReference(source.getSourceObject(game), game));
|
||||
}
|
||||
}
|
||||
// Move the remaining cards to the buttom of the library in a random order
|
||||
|
|
|
|||
|
|
@ -145,7 +145,7 @@ public class ConvokeAbility extends SimpleStaticAbility implements AlternateMana
|
|||
Target target = new TargetControlledCreaturePermanent(1, 1, filter, true);
|
||||
target.setTargetName("creature to convoke");
|
||||
specialAction.addTarget(target);
|
||||
if (specialAction.canActivate(source.getControllerId(), game)) {
|
||||
if (specialAction.canActivate(source.getControllerId(), game).canActivate()) {
|
||||
game.getState().getSpecialActions().add(specialAction);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -110,7 +110,7 @@ public class DelveAbility extends SimpleStaticAbility implements AlternateManaPa
|
|||
}
|
||||
specialAction.addCost(new ExileFromGraveCost(new TargetCardInYourGraveyard(
|
||||
0, Math.min(controller.getGraveyard().size(), unpaidAmount), new FilterCard(), true)));
|
||||
if (specialAction.canActivate(source.getControllerId(), game)) {
|
||||
if (specialAction.canActivate(source.getControllerId(), game).canActivate()) {
|
||||
game.getState().getSpecialActions().add(specialAction);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,140 +1,140 @@
|
|||
/*
|
||||
* 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.keyword;
|
||||
|
||||
import java.util.UUID;
|
||||
import mage.Mana;
|
||||
import mage.abilities.SpellAbility;
|
||||
import mage.abilities.costs.common.SacrificeTargetCost;
|
||||
import mage.abilities.costs.mana.ManaCost;
|
||||
import mage.abilities.costs.mana.ManaCosts;
|
||||
import mage.abilities.mana.ManaOptions;
|
||||
import mage.cards.Card;
|
||||
import mage.constants.Outcome;
|
||||
import mage.constants.SpellAbilityType;
|
||||
import mage.constants.Zone;
|
||||
import mage.filter.common.FilterControlledCreaturePermanent;
|
||||
import mage.filter.predicate.mageobject.CardIdPredicate;
|
||||
import mage.game.Game;
|
||||
import mage.game.permanent.Permanent;
|
||||
import mage.players.Player;
|
||||
import mage.target.TargetPermanent;
|
||||
import mage.target.common.TargetControlledCreaturePermanent;
|
||||
import mage.util.CardUtil;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author emerald000
|
||||
*/
|
||||
public class EmergeAbility extends SpellAbility {
|
||||
|
||||
private final ManaCosts<ManaCost> emergeCost;
|
||||
|
||||
public EmergeAbility(Card card, ManaCosts<ManaCost> emergeCost) {
|
||||
super(emergeCost, card.getName() + " with emerge", Zone.HAND, SpellAbilityType.BASE_ALTERNATE);
|
||||
this.getCosts().addAll(card.getSpellAbility().getCosts().copy());
|
||||
this.getEffects().addAll(card.getSpellAbility().getEffects().copy());
|
||||
this.getTargets().addAll(card.getSpellAbility().getTargets().copy());
|
||||
this.timing = card.getSpellAbility().getTiming();
|
||||
this.setRuleAtTheTop(true);
|
||||
this.emergeCost = emergeCost.copy();
|
||||
}
|
||||
|
||||
public EmergeAbility(final EmergeAbility ability) {
|
||||
super(ability);
|
||||
this.emergeCost = ability.emergeCost.copy();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canActivate(UUID playerId, Game game) {
|
||||
if (super.canActivate(playerId, game)) {
|
||||
Player controller = game.getPlayer(this.getControllerId());
|
||||
if (controller != null) {
|
||||
for (Permanent creature : game.getBattlefield().getActivePermanents(new FilterControlledCreaturePermanent(), this.getControllerId(), this.getSourceId(), game)) {
|
||||
ManaCost costToPay = CardUtil.reduceCost(emergeCost.copy(), creature.getConvertedManaCost());
|
||||
if (costToPay.canPay(this, this.getSourceId(), this.getControllerId(), game)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ManaOptions getMinimumCostToActivate(UUID playerId, Game game) {
|
||||
int maxCMC = 0;
|
||||
for (Permanent creature : game.getBattlefield().getActivePermanents(new FilterControlledCreaturePermanent(), playerId, this.getSourceId(), game)) {
|
||||
int cmc = creature.getConvertedManaCost();
|
||||
if (cmc > maxCMC) {
|
||||
maxCMC = cmc;
|
||||
}
|
||||
}
|
||||
ManaOptions manaOptions = super.getMinimumCostToActivate(playerId, game);
|
||||
for (Mana mana : manaOptions) {
|
||||
if (mana.getGeneric() > maxCMC) {
|
||||
mana.setGeneric(mana.getGeneric() - maxCMC);
|
||||
} else {
|
||||
mana.setGeneric(0);
|
||||
}
|
||||
}
|
||||
return manaOptions;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean activate(Game game, boolean noMana) {
|
||||
Player controller = game.getPlayer(this.getControllerId());
|
||||
if (controller != null) {
|
||||
TargetPermanent target = new TargetControlledCreaturePermanent(new FilterControlledCreaturePermanent("creature to sacrifice for emerge"));
|
||||
if (controller.choose(Outcome.Sacrifice, target, this.getSourceId(), game)) {
|
||||
Permanent creature = game.getPermanent(target.getFirstTarget());
|
||||
CardUtil.reduceCost(this, creature.getConvertedManaCost());
|
||||
FilterControlledCreaturePermanent filter = new FilterControlledCreaturePermanent(creature.getLogName());
|
||||
filter.add(new CardIdPredicate(creature.getId()));
|
||||
this.addCost(new SacrificeTargetCost(new TargetControlledCreaturePermanent(filter)));
|
||||
return super.activate(game, false);
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public EmergeAbility copy() {
|
||||
return new EmergeAbility(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getRule(boolean all) {
|
||||
return getRule();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getRule() {
|
||||
return "Emerge " + emergeCost.getText() + " <i>(You may cast this spell by sacrificing a creature and paying the emerge cost reduced by that creature's converted mana cost.)</i>";
|
||||
}
|
||||
}
|
||||
/*
|
||||
* 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.keyword;
|
||||
|
||||
import java.util.UUID;
|
||||
import mage.Mana;
|
||||
import mage.abilities.SpellAbility;
|
||||
import mage.abilities.costs.common.SacrificeTargetCost;
|
||||
import mage.abilities.costs.mana.ManaCost;
|
||||
import mage.abilities.costs.mana.ManaCosts;
|
||||
import mage.abilities.mana.ManaOptions;
|
||||
import mage.cards.Card;
|
||||
import mage.constants.Outcome;
|
||||
import mage.constants.SpellAbilityType;
|
||||
import mage.constants.Zone;
|
||||
import mage.filter.common.FilterControlledCreaturePermanent;
|
||||
import mage.filter.predicate.mageobject.CardIdPredicate;
|
||||
import mage.game.Game;
|
||||
import mage.game.permanent.Permanent;
|
||||
import mage.players.Player;
|
||||
import mage.target.TargetPermanent;
|
||||
import mage.target.common.TargetControlledCreaturePermanent;
|
||||
import mage.util.CardUtil;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author emerald000
|
||||
*/
|
||||
public class EmergeAbility extends SpellAbility {
|
||||
|
||||
private final ManaCosts<ManaCost> emergeCost;
|
||||
|
||||
public EmergeAbility(Card card, ManaCosts<ManaCost> emergeCost) {
|
||||
super(emergeCost, card.getName() + " with emerge", Zone.HAND, SpellAbilityType.BASE_ALTERNATE);
|
||||
this.getCosts().addAll(card.getSpellAbility().getCosts().copy());
|
||||
this.getEffects().addAll(card.getSpellAbility().getEffects().copy());
|
||||
this.getTargets().addAll(card.getSpellAbility().getTargets().copy());
|
||||
this.timing = card.getSpellAbility().getTiming();
|
||||
this.setRuleAtTheTop(true);
|
||||
this.emergeCost = emergeCost.copy();
|
||||
}
|
||||
|
||||
public EmergeAbility(final EmergeAbility ability) {
|
||||
super(ability);
|
||||
this.emergeCost = ability.emergeCost.copy();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ActivationStatus canActivate(UUID playerId, Game game) {
|
||||
if (super.canActivate(playerId, game).canActivate()) {
|
||||
Player controller = game.getPlayer(this.getControllerId());
|
||||
if (controller != null) {
|
||||
for (Permanent creature : game.getBattlefield().getActivePermanents(new FilterControlledCreaturePermanent(), this.getControllerId(), this.getSourceId(), game)) {
|
||||
ManaCost costToPay = CardUtil.reduceCost(emergeCost.copy(), creature.getConvertedManaCost());
|
||||
if (costToPay.canPay(this, this.getSourceId(), this.getControllerId(), game)) {
|
||||
return ActivationStatus.getTrue();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return ActivationStatus.getFalse();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ManaOptions getMinimumCostToActivate(UUID playerId, Game game) {
|
||||
int maxCMC = 0;
|
||||
for (Permanent creature : game.getBattlefield().getActivePermanents(new FilterControlledCreaturePermanent(), playerId, this.getSourceId(), game)) {
|
||||
int cmc = creature.getConvertedManaCost();
|
||||
if (cmc > maxCMC) {
|
||||
maxCMC = cmc;
|
||||
}
|
||||
}
|
||||
ManaOptions manaOptions = super.getMinimumCostToActivate(playerId, game);
|
||||
for (Mana mana : manaOptions) {
|
||||
if (mana.getGeneric() > maxCMC) {
|
||||
mana.setGeneric(mana.getGeneric() - maxCMC);
|
||||
} else {
|
||||
mana.setGeneric(0);
|
||||
}
|
||||
}
|
||||
return manaOptions;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean activate(Game game, boolean noMana) {
|
||||
Player controller = game.getPlayer(this.getControllerId());
|
||||
if (controller != null) {
|
||||
TargetPermanent target = new TargetControlledCreaturePermanent(new FilterControlledCreaturePermanent("creature to sacrifice for emerge"));
|
||||
if (controller.choose(Outcome.Sacrifice, target, this.getSourceId(), game)) {
|
||||
Permanent creature = game.getPermanent(target.getFirstTarget());
|
||||
CardUtil.reduceCost(this, creature.getConvertedManaCost());
|
||||
FilterControlledCreaturePermanent filter = new FilterControlledCreaturePermanent(creature.getLogName());
|
||||
filter.add(new CardIdPredicate(creature.getId()));
|
||||
this.addCost(new SacrificeTargetCost(new TargetControlledCreaturePermanent(filter)));
|
||||
return super.activate(game, false);
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public EmergeAbility copy() {
|
||||
return new EmergeAbility(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getRule(boolean all) {
|
||||
return getRule();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getRule() {
|
||||
return "Emerge " + emergeCost.getText() + " <i>(You may cast this spell by sacrificing a creature and paying the emerge cost reduced by that creature's converted mana cost.)</i>";
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -27,6 +27,7 @@
|
|||
*/
|
||||
package mage.abilities.keyword;
|
||||
|
||||
import java.util.UUID;
|
||||
import mage.abilities.ActivatedAbilityImpl;
|
||||
import mage.abilities.costs.Cost;
|
||||
import mage.abilities.effects.common.AttachEffect;
|
||||
|
|
@ -39,8 +40,6 @@ import mage.game.permanent.Permanent;
|
|||
import mage.target.Target;
|
||||
import mage.target.common.TargetControlledCreaturePermanent;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
/**
|
||||
* @author BetaSteward_at_googlemail.com
|
||||
*/
|
||||
|
|
@ -57,14 +56,15 @@ public class EquipAbility extends ActivatedAbilityImpl {
|
|||
}
|
||||
|
||||
@Override
|
||||
public boolean canActivate(UUID playerId, Game game) {
|
||||
if (super.canActivate(playerId, game)) {
|
||||
public ActivationStatus canActivate(UUID playerId, Game game) {
|
||||
ActivationStatus activationStatus = super.canActivate(playerId, game);
|
||||
if (activationStatus.canActivate()) {
|
||||
Permanent permanent = game.getPermanent(sourceId);
|
||||
if (permanent != null && permanent.hasSubtype(SubType.EQUIPMENT, game)) {
|
||||
return true;
|
||||
return activationStatus;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
return activationStatus;
|
||||
}
|
||||
|
||||
public EquipAbility(final EquipAbility ability) {
|
||||
|
|
|
|||
|
|
@ -1,96 +1,95 @@
|
|||
/*
|
||||
* 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.keyword;
|
||||
|
||||
import mage.abilities.ActivatedAbilityImpl;
|
||||
import mage.abilities.costs.Cost;
|
||||
import mage.abilities.effects.common.AttachEffect;
|
||||
import mage.constants.Outcome;
|
||||
import mage.constants.SubType;
|
||||
import mage.constants.TimingRule;
|
||||
import mage.constants.Zone;
|
||||
import mage.game.Game;
|
||||
import mage.game.permanent.Permanent;
|
||||
import mage.target.Target;
|
||||
import mage.target.common.TargetControlledCreaturePermanent;
|
||||
|
||||
import java.util.UUID;
|
||||
import mage.constants.SuperType;
|
||||
import mage.filter.FilterPermanent;
|
||||
import mage.filter.common.FilterControlledCreaturePermanent;
|
||||
import mage.filter.predicate.mageobject.SupertypePredicate;
|
||||
|
||||
/**
|
||||
* @author Rystan
|
||||
*/
|
||||
public class EquipLegendaryAbility extends ActivatedAbilityImpl {
|
||||
|
||||
private static final FilterControlledCreaturePermanent filter = new FilterControlledCreaturePermanent("legendary creature you control");
|
||||
|
||||
static {
|
||||
filter.add(new SupertypePredicate(SuperType.LEGENDARY));
|
||||
}
|
||||
|
||||
public EquipLegendaryAbility(Outcome outcome, Cost cost) {
|
||||
this(outcome, cost, new TargetControlledCreaturePermanent(filter));
|
||||
}
|
||||
|
||||
public EquipLegendaryAbility(Outcome outcome, Cost cost, Target target) {
|
||||
super(Zone.BATTLEFIELD, new AttachEffect(outcome, "Equip"), cost);
|
||||
this.addTarget(target);
|
||||
this.timing = TimingRule.SORCERY;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canActivate(UUID playerId, Game game) {
|
||||
if (super.canActivate(playerId, game)) {
|
||||
Permanent permanent = game.getPermanent(sourceId);
|
||||
if (permanent != null && permanent.hasSubtype(SubType.EQUIPMENT, game)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public EquipLegendaryAbility(final EquipLegendaryAbility ability) {
|
||||
super(ability);
|
||||
}
|
||||
|
||||
@Override
|
||||
public EquipLegendaryAbility copy() {
|
||||
return new EquipLegendaryAbility(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getRule() {
|
||||
return "Equip legendary creature " + costs.getText() +
|
||||
manaCosts.getText() + " (" + manaCosts.getText() +
|
||||
": <i>Attach to target legendary creature you control. Equip only as a sorcery.)</i>";
|
||||
}
|
||||
|
||||
}
|
||||
/*
|
||||
* 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.keyword;
|
||||
|
||||
import java.util.UUID;
|
||||
import mage.abilities.ActivatedAbilityImpl;
|
||||
import mage.abilities.costs.Cost;
|
||||
import mage.abilities.effects.common.AttachEffect;
|
||||
import mage.constants.Outcome;
|
||||
import mage.constants.SubType;
|
||||
import mage.constants.SuperType;
|
||||
import mage.constants.TimingRule;
|
||||
import mage.constants.Zone;
|
||||
import mage.filter.common.FilterControlledCreaturePermanent;
|
||||
import mage.filter.predicate.mageobject.SupertypePredicate;
|
||||
import mage.game.Game;
|
||||
import mage.game.permanent.Permanent;
|
||||
import mage.target.Target;
|
||||
import mage.target.common.TargetControlledCreaturePermanent;
|
||||
|
||||
/**
|
||||
* @author Rystan
|
||||
*/
|
||||
public class EquipLegendaryAbility extends ActivatedAbilityImpl {
|
||||
|
||||
private static final FilterControlledCreaturePermanent filter = new FilterControlledCreaturePermanent("legendary creature you control");
|
||||
|
||||
static {
|
||||
filter.add(new SupertypePredicate(SuperType.LEGENDARY));
|
||||
}
|
||||
|
||||
public EquipLegendaryAbility(Outcome outcome, Cost cost) {
|
||||
this(outcome, cost, new TargetControlledCreaturePermanent(filter));
|
||||
}
|
||||
|
||||
public EquipLegendaryAbility(Outcome outcome, Cost cost, Target target) {
|
||||
super(Zone.BATTLEFIELD, new AttachEffect(outcome, "Equip"), cost);
|
||||
this.addTarget(target);
|
||||
this.timing = TimingRule.SORCERY;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ActivationStatus canActivate(UUID playerId, Game game) {
|
||||
ActivationStatus activationStatus = super.canActivate(playerId, game);
|
||||
if (activationStatus.canActivate()) {
|
||||
Permanent permanent = game.getPermanent(sourceId);
|
||||
if (permanent != null && permanent.hasSubtype(SubType.EQUIPMENT, game)) {
|
||||
return activationStatus;
|
||||
}
|
||||
}
|
||||
return activationStatus;
|
||||
}
|
||||
|
||||
public EquipLegendaryAbility(final EquipLegendaryAbility ability) {
|
||||
super(ability);
|
||||
}
|
||||
|
||||
@Override
|
||||
public EquipLegendaryAbility copy() {
|
||||
return new EquipLegendaryAbility(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getRule() {
|
||||
return "Equip legendary creature " + costs.getText()
|
||||
+ manaCosts.getText() + " (" + manaCosts.getText()
|
||||
+ ": <i>Attach to target legendary creature you control. Equip only as a sorcery.)</i>";
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -83,13 +83,14 @@ public class FlashbackAbility extends SpellAbility {
|
|||
}
|
||||
|
||||
@Override
|
||||
public boolean canActivate(UUID playerId, Game game) {
|
||||
if (super.canActivate(playerId, game)) {
|
||||
public ActivationStatus canActivate(UUID playerId, Game game) {
|
||||
ActivationStatus activationStatus = super.canActivate(playerId, game);
|
||||
if (activationStatus.canActivate()) {
|
||||
Card card = game.getCard(getSourceId());
|
||||
if (card != null) {
|
||||
// Cards with no Mana Costs cant't be flashbacked (e.g. Ancestral Vision)
|
||||
if (card.getManaCost().isEmpty()) {
|
||||
return false;
|
||||
return ActivationStatus.getFalse();
|
||||
}
|
||||
// Flashback can never cast a split card by Fuse, because Fuse only works from hand
|
||||
if (card.isSplitCard()) {
|
||||
|
|
@ -102,7 +103,7 @@ public class FlashbackAbility extends SpellAbility {
|
|||
return card.getSpellAbility().canActivate(playerId, game);
|
||||
}
|
||||
}
|
||||
return false;
|
||||
return activationStatus;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
|||
|
|
@ -43,10 +43,10 @@ import mage.game.Game;
|
|||
*
|
||||
* 702.56b A forecast ability may be activated only during the upkeep step of
|
||||
* the card's owner and only once each turn. The controller of the forecast
|
||||
* ability reveals the card with that ability from their hand as the
|
||||
* ability is activated. That player plays with that card revealed in their
|
||||
* hand until it leaves the player's hand or until a step or phase that isn't an
|
||||
* upkeep step begins, whichever comes first.
|
||||
* ability reveals the card with that ability from their hand as the ability is
|
||||
* activated. That player plays with that card revealed in their hand until it
|
||||
* leaves the player's hand or until a step or phase that isn't an upkeep step
|
||||
* begins, whichever comes first.
|
||||
*
|
||||
* @author LevelX2
|
||||
*
|
||||
|
|
@ -68,11 +68,11 @@ public class ForecastAbility extends LimitedTimesPerTurnActivatedAbility {
|
|||
}
|
||||
|
||||
@Override
|
||||
public boolean canActivate(UUID playerId, Game game) {
|
||||
public ActivationStatus canActivate(UUID playerId, Game game) {
|
||||
// May be activated only during the upkeep step of the card's owner
|
||||
// Because it can only be activated from a players hand it should be ok to check here with controllerId instead of card.getOwnerId().
|
||||
if (!game.getActivePlayerId().equals(controllerId) || PhaseStep.UPKEEP != game.getStep().getType()) {
|
||||
return false;
|
||||
return ActivationStatus.getFalse();
|
||||
}
|
||||
return super.canActivate(playerId, game);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,7 +6,6 @@
|
|||
package mage.abilities.keyword;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
import mage.Mana;
|
||||
import mage.abilities.Ability;
|
||||
import mage.abilities.SpecialAction;
|
||||
|
|
@ -69,7 +68,7 @@ public class ImproviseAbility extends SimpleStaticAbility implements AlternateMa
|
|||
Target target = new TargetControlledPermanent(1, unpaid.getMana().getGeneric(), filter, true);
|
||||
target.setTargetName("artifact to Improvise");
|
||||
specialAction.addTarget(target);
|
||||
if (specialAction.canActivate(source.getControllerId(), game)) {
|
||||
if (specialAction.canActivate(source.getControllerId(), game).canActivate()) {
|
||||
game.getState().getSpecialActions().add(specialAction);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@ package mage.abilities.keyword;
|
|||
|
||||
import java.util.UUID;
|
||||
import mage.MageObject;
|
||||
import mage.MageObjectReference;
|
||||
import mage.abilities.Ability;
|
||||
import mage.abilities.SpellAbility;
|
||||
import mage.abilities.StaticAbility;
|
||||
|
|
@ -33,10 +34,10 @@ import mage.players.Player;
|
|||
* first ability is applied.
|
||||
*
|
||||
* "Madness [cost]" means "If a player would discard this card, that player
|
||||
* discards it, but may exile it instead of putting it into their
|
||||
* graveyard" and "When this card is exiled this way, its owner may cast it by
|
||||
* paying [cost] rather than paying its mana cost. If that player doesn't, he or
|
||||
* she puts this card into their graveyard.
|
||||
* discards it, but may exile it instead of putting it into their graveyard" and
|
||||
* "When this card is exiled this way, its owner may cast it by paying [cost]
|
||||
* rather than paying its mana cost. If that player doesn't, he or she puts this
|
||||
* card into their graveyard.
|
||||
*
|
||||
* 702.33b. Casting a spell using its madness ability follows the rules for
|
||||
* paying alternative costs in rules 601.2b and 601.2e-g.
|
||||
|
|
@ -219,7 +220,7 @@ class MadnessCastEffect extends OneShotEffect {
|
|||
castByMadness.setSpellAbilityCastMode(SpellAbilityCastMode.MADNESS);
|
||||
costRef.clear();
|
||||
costRef.add(madnessCost);
|
||||
boolean result = owner.cast(castByMadness, game, false);
|
||||
boolean result = owner.cast(castByMadness, game, false, new MageObjectReference(source.getSourceObject(game), game));
|
||||
return result;
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -27,6 +27,7 @@
|
|||
*/
|
||||
package mage.abilities.keyword;
|
||||
|
||||
import mage.MageObjectReference;
|
||||
import mage.abilities.Ability;
|
||||
import mage.abilities.SpellAbility;
|
||||
import mage.abilities.TriggeredAbilityImpl;
|
||||
|
|
@ -52,8 +53,8 @@ import mage.watchers.common.MiracleWatcher;
|
|||
* cost."
|
||||
*
|
||||
* 702.92b If a player chooses to reveal a card using its miracle ability, he or
|
||||
* she plays with that card revealed until that card leaves their hand,
|
||||
* that ability resolves, or that ability otherwise leaves the stack.
|
||||
* she plays with that card revealed until that card leaves their hand, that
|
||||
* ability resolves, or that ability otherwise leaves the stack.
|
||||
*
|
||||
* You can cast a card for its miracle cost only as the miracle triggered
|
||||
* ability resolves. If you don't want to cast it at that time (or you can't
|
||||
|
|
@ -172,7 +173,7 @@ class MiracleEffect extends OneShotEffect {
|
|||
// replace with the new cost
|
||||
costRef.clear();
|
||||
costRef.add(miracleCosts);
|
||||
controller.cast(abilityToCast, game, false);
|
||||
controller.cast(abilityToCast, game, false, new MageObjectReference(source.getSourceObject(game), game));
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
|
|
|
|||
|
|
@ -28,6 +28,7 @@
|
|||
package mage.abilities.keyword;
|
||||
|
||||
import java.util.UUID;
|
||||
import mage.MageObjectReference;
|
||||
import mage.abilities.Ability;
|
||||
import mage.abilities.DelayedTriggeredAbility;
|
||||
import mage.abilities.SpellAbility;
|
||||
|
|
@ -206,7 +207,7 @@ class ReboundCastSpellFromExileEffect extends OneShotEffect {
|
|||
Player player = game.getPlayer(source.getControllerId());
|
||||
if (player != null && reboundCard != null) {
|
||||
SpellAbility ability = reboundCard.getSpellAbility();
|
||||
player.cast(ability, game, true);
|
||||
player.cast(ability, game, true, new MageObjectReference(source.getSourceObject(game), game));
|
||||
zone.remove(reboundCard.getId());
|
||||
return true;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
package mage.abilities.keyword;
|
||||
|
||||
import mage.MageObject;
|
||||
import mage.MageObjectReference;
|
||||
import mage.abilities.Ability;
|
||||
import mage.abilities.TriggeredAbilityImpl;
|
||||
import mage.abilities.effects.OneShotEffect;
|
||||
|
|
@ -103,7 +104,7 @@ class RippleEffect extends OneShotEffect {
|
|||
while (player.canRespond() && cards.count(sameNameFilter, game) > 0 && player.choose(Outcome.PlayForFree, cards, target1, game)) {
|
||||
Card card = cards.get(target1.getFirstTarget(), game);
|
||||
if (card != null) {
|
||||
player.cast(card.getSpellAbility(), game, true);
|
||||
player.cast(card.getSpellAbility(), game, true, new MageObjectReference(source.getSourceObject(game), game));
|
||||
cards.remove(card);
|
||||
}
|
||||
target1.clearChosen();
|
||||
|
|
|
|||
|
|
@ -27,6 +27,7 @@
|
|||
*/
|
||||
package mage.abilities.keyword;
|
||||
|
||||
import java.util.Iterator;
|
||||
import mage.MageObject;
|
||||
import mage.abilities.Ability;
|
||||
import mage.abilities.SpellAbility;
|
||||
|
|
@ -42,63 +43,66 @@ import mage.game.Game;
|
|||
import mage.game.stack.Spell;
|
||||
import mage.players.Player;
|
||||
|
||||
import java.util.Iterator;
|
||||
|
||||
|
||||
/**
|
||||
* 702.45. Splice
|
||||
*
|
||||
* 702.45a Splice is a static ability that functions while a card is in your hand.
|
||||
* "Splice onto [subtype] [cost]" means "You may reveal this card from your hand
|
||||
* as you cast a [subtype] spell. If you do, copy this card's text box onto that
|
||||
* spell and pay [cost] as an additional cost to cast that spell." Paying a card's
|
||||
* splice cost follows the rules for paying additional costs in rules 601.2b and
|
||||
* 601.2e-g.
|
||||
* 702.45a Splice is a static ability that functions while a card is in your
|
||||
* hand. "Splice onto [subtype] [cost]" means "You may reveal this card from
|
||||
* your hand as you cast a [subtype] spell. If you do, copy this card's text box
|
||||
* onto that spell and pay [cost] as an additional cost to cast that spell."
|
||||
* Paying a card's splice cost follows the rules for paying additional costs in
|
||||
* rules 601.2b and 601.2e-g.
|
||||
*
|
||||
* Example: Since the card with splice remains in the player's hand, it can later
|
||||
* be cast normally or spliced onto another spell. It can even be discarded to pay
|
||||
* a "discard a card" cost of the spell it's spliced onto.
|
||||
* Example: Since the card with splice remains in the player's hand, it can
|
||||
* later be cast normally or spliced onto another spell. It can even be
|
||||
* discarded to pay a "discard a card" cost of the spell it's spliced onto.
|
||||
*
|
||||
* 702.45b You can't choose to use a splice ability if you can't make the required
|
||||
* choices (targets, etc.) for that card's instructions. You can't splice any one
|
||||
* card onto the same spell more than once. If you're splicing more than one card
|
||||
* onto a spell, reveal them all at once and choose the order in which their
|
||||
* instructions will be followed. The instructions on the main spell have to be
|
||||
* followed first.
|
||||
* 702.45b You can't choose to use a splice ability if you can't make the
|
||||
* required choices (targets, etc.) for that card's instructions. You can't
|
||||
* splice any one card onto the same spell more than once. If you're splicing
|
||||
* more than one card onto a spell, reveal them all at once and choose the order
|
||||
* in which their instructions will be followed. The instructions on the main
|
||||
* spell have to be followed first.
|
||||
*
|
||||
* 702.45c The spell has the characteristics of the main spell, plus the text boxes
|
||||
* of each of the spliced cards. The spell doesn't gain any other characteristics
|
||||
* (name, mana cost, color, supertypes, card types, subtypes, etc.) of the spliced
|
||||
* cards. Text copied onto the spell that refers to a card by name refers to the spell
|
||||
* on the stack, not the card from which the text was copied.
|
||||
* 702.45c The spell has the characteristics of the main spell, plus the text
|
||||
* boxes of each of the spliced cards. The spell doesn't gain any other
|
||||
* characteristics (name, mana cost, color, supertypes, card types, subtypes,
|
||||
* etc.) of the spliced cards. Text copied onto the spell that refers to a card
|
||||
* by name refers to the spell on the stack, not the card from which the text
|
||||
* was copied.
|
||||
*
|
||||
* Example: Glacial Ray is a red card with splice onto Arcane that reads, "Glacial
|
||||
* Ray deals 2 damage to any target." Suppose Glacial Ray is spliced
|
||||
* onto Reach Through Mists, a blue spell. The spell is still blue, and Reach Through
|
||||
* Mists deals the damage. This means that the ability can target a creature with
|
||||
* protection from red and deal 2 damage to that creature.
|
||||
* Example: Glacial Ray is a red card with splice onto Arcane that reads,
|
||||
* "Glacial Ray deals 2 damage to any target." Suppose Glacial Ray is spliced
|
||||
* onto Reach Through Mists, a blue spell. The spell is still blue, and Reach
|
||||
* Through Mists deals the damage. This means that the ability can target a
|
||||
* creature with protection from red and deal 2 damage to that creature.
|
||||
*
|
||||
* 702.45d Choose targets for the added text normally (see rule 601.2c). Note that a
|
||||
* spell with one or more targets will be countered if all of its targets are illegal
|
||||
* on resolution.
|
||||
* 702.45d Choose targets for the added text normally (see rule 601.2c). Note
|
||||
* that a spell with one or more targets will be countered if all of its targets
|
||||
* are illegal on resolution.
|
||||
*
|
||||
* 702.45e The spell loses any splice changes once it leaves the stack (for example,
|
||||
* when it's countered, it's exiled, or it resolves).
|
||||
* 702.45e The spell loses any splice changes once it leaves the stack (for
|
||||
* example, when it's countered, it's exiled, or it resolves).
|
||||
*
|
||||
* Rulings
|
||||
* Rulings
|
||||
*
|
||||
* You must reveal all of the cards you intend to splice at the same time. Each individual card can only be spliced once onto a spell.
|
||||
* If you have more than one card with the same name in your hand, you may splice both of them onto the spell.
|
||||
* A card with a splice ability can't be spliced onto itself because the spell is on the stack (and not in your hand) when you reveal the cards you want to splice onto it.
|
||||
* The target for a card that's spliced onto a spell may be the same as the target chosen for the original spell or for another spliced-on card. (A recent change to the targeting rules allows this, but most other cards are unaffected by the change.)
|
||||
* If you splice a targeted card onto an untargeted spell, the entire spell will be countered if the target isn't legal when the spell resolves.
|
||||
* If you splice an untargeted card onto a targeted spell, the entire spell will be countered if the target isn't legal when the spell resolves.
|
||||
* A spell is countered on resolution only if *all* of its targets are illegal (or the spell is countered by an effect).
|
||||
* You must reveal all of the cards you intend to splice at the same time. Each
|
||||
* individual card can only be spliced once onto a spell. If you have more than
|
||||
* one card with the same name in your hand, you may splice both of them onto
|
||||
* the spell. A card with a splice ability can't be spliced onto itself because
|
||||
* the spell is on the stack (and not in your hand) when you reveal the cards
|
||||
* you want to splice onto it. The target for a card that's spliced onto a spell
|
||||
* may be the same as the target chosen for the original spell or for another
|
||||
* spliced-on card. (A recent change to the targeting rules allows this, but
|
||||
* most other cards are unaffected by the change.) If you splice a targeted card
|
||||
* onto an untargeted spell, the entire spell will be countered if the target
|
||||
* isn't legal when the spell resolves. If you splice an untargeted card onto a
|
||||
* targeted spell, the entire spell will be countered if the target isn't legal
|
||||
* when the spell resolves. A spell is countered on resolution only if *all* of
|
||||
* its targets are illegal (or the spell is countered by an effect).
|
||||
*
|
||||
* @author LevelX2
|
||||
*/
|
||||
|
||||
|
||||
public class SpliceOntoArcaneAbility extends SimpleStaticAbility {
|
||||
|
||||
private static final String KEYWORD_TEXT = "Splice onto Arcane";
|
||||
|
|
@ -134,8 +138,8 @@ public class SpliceOntoArcaneAbility extends SimpleStaticAbility {
|
|||
@Override
|
||||
public String getRule() {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append(KEYWORD_TEXT).append(nonManaCosts?"-":" ");
|
||||
sb.append(spliceCosts.getText()).append(nonManaCosts?". ":" ");
|
||||
sb.append(KEYWORD_TEXT).append(nonManaCosts ? "-" : " ");
|
||||
sb.append(spliceCosts.getText()).append(nonManaCosts ? ". " : " ");
|
||||
sb.append("<i>(As you cast an Arcane spell, you may reveal this card from your hand and pay its splice cost. If you do, add this card's effects to that spell.)</i>");
|
||||
return sb.toString();
|
||||
}
|
||||
|
|
@ -193,7 +197,7 @@ class SpliceOntoArcaneEffect extends SpliceCardEffectImpl {
|
|||
if (card.getManaCost().isEmpty()) { // e.g. Evermind
|
||||
return card.getSpellAbility().spellCanBeActivatedRegularlyNow(source.getControllerId(), game);
|
||||
} else {
|
||||
return card.getSpellAbility().canActivate(source.getControllerId(), game);
|
||||
return card.getSpellAbility().canActivate(source.getControllerId(), game).canActivate();
|
||||
}
|
||||
}
|
||||
return false;
|
||||
|
|
|
|||
|
|
@ -66,7 +66,7 @@ public class SurgeAbility extends SpellAbility {
|
|||
}
|
||||
|
||||
@Override
|
||||
public boolean canActivate(UUID playerId, Game game) {
|
||||
public ActivationStatus canActivate(UUID playerId, Game game) {
|
||||
// check if controller or teammate has already cast a spell this turn
|
||||
CastSpellLastTurnWatcher watcher = (CastSpellLastTurnWatcher) game.getState().getWatchers().get(CastSpellLastTurnWatcher.class.getSimpleName());
|
||||
if (watcher != null) {
|
||||
|
|
@ -81,7 +81,7 @@ public class SurgeAbility extends SpellAbility {
|
|||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
return ActivationStatus.getFalse();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
|||
|
|
@ -31,6 +31,7 @@ import java.util.ArrayList;
|
|||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
import mage.MageObject;
|
||||
import mage.MageObjectReference;
|
||||
import mage.abilities.Ability;
|
||||
import mage.abilities.SpecialAction;
|
||||
import mage.abilities.TriggeredAbilityImpl;
|
||||
|
|
@ -228,16 +229,16 @@ public class SuspendAbility extends SpecialAction {
|
|||
}
|
||||
|
||||
@Override
|
||||
public boolean canActivate(UUID playerId, Game game) {
|
||||
public ActivationStatus canActivate(UUID playerId, Game game) {
|
||||
if (game.getState().getZone(getSourceId()) != Zone.HAND) {
|
||||
// Supend can only be activated from hand
|
||||
return false;
|
||||
return ActivationStatus.getFalse();
|
||||
}
|
||||
MageObject object = game.getObject(sourceId);
|
||||
return (object.isInstant()
|
||||
return new ActivationStatus(object.isInstant()
|
||||
|| object.hasAbility(FlashAbility.getInstance().getId(), game)
|
||||
|| null != game.getContinuousEffects().asThough(sourceId, AsThoughEffectType.CAST_AS_INSTANT, this, playerId, game)
|
||||
|| game.canPlaySorcery(playerId));
|
||||
|| game.canPlaySorcery(playerId), null);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
@ -376,7 +377,7 @@ class SuspendPlayCardEffect extends OneShotEffect {
|
|||
card.getAbilities().removeAll(abilitiesToRemove);
|
||||
}
|
||||
// cast the card for free
|
||||
if (player.cast(card.getSpellAbility(), game, true)) {
|
||||
if (player.cast(card.getSpellAbility(), game, true, new MageObjectReference(source.getSourceObject(game), game))) {
|
||||
if (card.isCreature()) {
|
||||
ContinuousEffect effect = new GainHasteEffect();
|
||||
effect.setTargetPointer(new FixedTarget(card.getId(), card.getZoneChangeCounter(game) + 1));
|
||||
|
|
|
|||
|
|
@ -58,7 +58,7 @@ public class ActivateOncePerTurnManaAbility extends ActivatedManaAbilityImpl {
|
|||
|
||||
@Override
|
||||
public boolean activate(Game game, boolean noMana) {
|
||||
if (canActivate(this.controllerId, game)) {
|
||||
if (canActivate(this.controllerId, game).canActivate()) {
|
||||
return super.activate(game, noMana);
|
||||
}
|
||||
return false;
|
||||
|
|
|
|||
|
|
@ -69,21 +69,21 @@ public abstract class ActivatedManaAbilityImpl extends ActivatedAbilityImpl impl
|
|||
}
|
||||
|
||||
@Override
|
||||
public boolean canActivate(UUID playerId, Game game) {
|
||||
public ActivationStatus canActivate(UUID playerId, Game game) {
|
||||
if (!super.hasMoreActivationsThisTurn(game) || !(condition == null || condition.apply(game, this))) {
|
||||
return false;
|
||||
return ActivationStatus.getFalse();
|
||||
}
|
||||
if (!controlsAbility(playerId, game)) {
|
||||
return false;
|
||||
return ActivationStatus.getFalse();
|
||||
}
|
||||
if (timing == TimingRule.SORCERY
|
||||
&& !game.canPlaySorcery(playerId)
|
||||
&& null == game.getContinuousEffects().asThough(sourceId, AsThoughEffectType.ACTIVATE_AS_INSTANT, this, controllerId, game)) {
|
||||
return false;
|
||||
return ActivationStatus.getFalse();
|
||||
}
|
||||
// check if player is in the process of playing spell costs and he is no longer allowed to use activated mana abilities (e.g. because he started to use improvise)
|
||||
//20091005 - 605.3a
|
||||
return costs.canPay(this, sourceId, controllerId, game);
|
||||
return new ActivationStatus(costs.canPay(this, sourceId, controllerId, game), null);
|
||||
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -61,7 +61,7 @@ class BlockTappedPredicate implements Predicate<Permanent> {
|
|||
|
||||
@Override
|
||||
public boolean apply(Permanent input, Game game) {
|
||||
return !input.isTapped() || null != game.getState().getContinuousEffects().asThough(input.getId(), AsThoughEffectType.BLOCK_TAPPED, input.getControllerId(), game);
|
||||
return !input.isTapped() || null != game.getState().getContinuousEffects().asThough(input.getId(), AsThoughEffectType.BLOCK_TAPPED, null, input.getControllerId(), game);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
|||
|
|
@ -31,6 +31,7 @@ import java.io.Serializable;
|
|||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
import mage.MageObjectReference;
|
||||
import mage.constants.Zone;
|
||||
|
||||
/**
|
||||
|
|
@ -48,6 +49,7 @@ public class GameEvent implements Serializable {
|
|||
protected String data;
|
||||
protected Zone zone;
|
||||
protected List<UUID> appliedEffects = new ArrayList<>();
|
||||
protected MageObjectReference reference; // e.g. the permitting object for casting a spell from non hand zone
|
||||
protected UUID customEventType = null;
|
||||
|
||||
public enum EventType {
|
||||
|
|
@ -232,7 +234,7 @@ public class GameEvent implements Serializable {
|
|||
FLIP_COIN, COIN_FLIPPED, SCRY, FATESEAL,
|
||||
ROLL_DICE, DICE_ROLLED,
|
||||
ROLL_PLANAR_DIE, PLANAR_DIE_ROLLED,
|
||||
PLANESWALK, PLANESWALKED,
|
||||
PLANESWALK, PLANESWALKED,
|
||||
PAID_CUMULATIVE_UPKEEP,
|
||||
DIDNT_PAY_CUMULATIVE_UPKEEP,
|
||||
//permanent events
|
||||
|
|
@ -334,21 +336,14 @@ public class GameEvent implements Serializable {
|
|||
CUSTOM_EVENT
|
||||
}
|
||||
|
||||
private GameEvent(EventType type, UUID customEventType,
|
||||
UUID targetId, UUID sourceId, UUID playerId, int amount, boolean flag) {
|
||||
this.type = type;
|
||||
this.customEventType = customEventType;
|
||||
this.targetId = targetId;
|
||||
this.sourceId = sourceId;
|
||||
this.amount = amount;
|
||||
this.playerId = playerId;
|
||||
this.flag = flag;
|
||||
}
|
||||
|
||||
public GameEvent(EventType type, UUID targetId, UUID sourceId, UUID playerId) {
|
||||
this(type, null, targetId, sourceId, playerId, 0, false);
|
||||
}
|
||||
|
||||
public GameEvent(EventType type, UUID targetId, UUID sourceId, UUID playerId, MageObjectReference reference) {
|
||||
this(type, null, targetId, sourceId, playerId, 0, false, reference);
|
||||
}
|
||||
|
||||
public GameEvent(EventType type, UUID targetId, UUID sourceId, UUID playerId, int amount, boolean flag) {
|
||||
this(type, null, targetId, sourceId, playerId, amount, flag);
|
||||
}
|
||||
|
|
@ -369,6 +364,10 @@ public class GameEvent implements Serializable {
|
|||
return new GameEvent(type, targetId, sourceId, playerId);
|
||||
}
|
||||
|
||||
public static GameEvent getEvent(EventType type, UUID targetId, UUID sourceId, UUID playerId, MageObjectReference reference) {
|
||||
return new GameEvent(type, targetId, sourceId, playerId, reference);
|
||||
}
|
||||
|
||||
public static GameEvent getEvent(EventType type, UUID targetId, UUID playerId) {
|
||||
return new GameEvent(type, targetId, null, playerId);
|
||||
}
|
||||
|
|
@ -399,6 +398,23 @@ public class GameEvent implements Serializable {
|
|||
return event;
|
||||
}
|
||||
|
||||
private GameEvent(EventType type, UUID customEventType,
|
||||
UUID targetId, UUID sourceId, UUID playerId, int amount, boolean flag) {
|
||||
this(type, customEventType, targetId, sourceId, playerId, amount, flag, null);
|
||||
}
|
||||
|
||||
private GameEvent(EventType type, UUID customEventType,
|
||||
UUID targetId, UUID sourceId, UUID playerId, int amount, boolean flag, MageObjectReference reference) {
|
||||
this.type = type;
|
||||
this.customEventType = customEventType;
|
||||
this.targetId = targetId;
|
||||
this.sourceId = sourceId;
|
||||
this.amount = amount;
|
||||
this.playerId = playerId;
|
||||
this.flag = flag;
|
||||
this.reference = reference;
|
||||
}
|
||||
|
||||
public EventType getType() {
|
||||
return type;
|
||||
}
|
||||
|
|
@ -455,6 +471,14 @@ public class GameEvent implements Serializable {
|
|||
this.zone = zone;
|
||||
}
|
||||
|
||||
public MageObjectReference getAdditionalReference() {
|
||||
return reference;
|
||||
}
|
||||
|
||||
public void setAdditionalReference(MageObjectReference additionalReference) {
|
||||
this.reference = additionalReference;
|
||||
}
|
||||
|
||||
/**
|
||||
* used to store which replacement effects were already applied to an event
|
||||
* or or any modified events that may replace it
|
||||
|
|
|
|||
|
|
@ -935,20 +935,20 @@ public abstract class PermanentImpl extends CardImpl implements Permanent {
|
|||
public boolean canBeTargetedBy(MageObject source, UUID sourceControllerId, Game game) {
|
||||
if (source != null) {
|
||||
if (abilities.containsKey(ShroudAbility.getInstance().getId())) {
|
||||
if (null == game.getContinuousEffects().asThough(this.getId(), AsThoughEffectType.SHROUD, sourceControllerId, game)) {
|
||||
if (null == game.getContinuousEffects().asThough(this.getId(), AsThoughEffectType.SHROUD, null, sourceControllerId, game)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if (abilities.containsKey(HexproofAbility.getInstance().getId())) {
|
||||
if (game.getPlayer(this.getControllerId()).hasOpponent(sourceControllerId, game)
|
||||
&& null == game.getContinuousEffects().asThough(this.getId(), AsThoughEffectType.HEXPROOF, sourceControllerId, game)) {
|
||||
&& null == game.getContinuousEffects().asThough(this.getId(), AsThoughEffectType.HEXPROOF, null, sourceControllerId, game)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (abilities.containsKey(HexproofFromBlackAbility.getInstance().getId())) {
|
||||
if (game.getPlayer(this.getControllerId()).hasOpponent(sourceControllerId, game)
|
||||
&& null == game.getContinuousEffects().asThough(this.getId(), AsThoughEffectType.HEXPROOF, sourceControllerId, game)
|
||||
&& null == game.getContinuousEffects().asThough(this.getId(), AsThoughEffectType.HEXPROOF, null, sourceControllerId, game)
|
||||
&& source.getColor(game).isBlack()) {
|
||||
return false;
|
||||
}
|
||||
|
|
@ -956,7 +956,7 @@ public abstract class PermanentImpl extends CardImpl implements Permanent {
|
|||
|
||||
if (abilities.containsKey(HexproofFromWhiteAbility.getInstance().getId())) {
|
||||
if (game.getPlayer(this.getControllerId()).hasOpponent(sourceControllerId, game)
|
||||
&& null == game.getContinuousEffects().asThough(this.getId(), AsThoughEffectType.HEXPROOF, sourceControllerId, game)
|
||||
&& null == game.getContinuousEffects().asThough(this.getId(), AsThoughEffectType.HEXPROOF, null, sourceControllerId, game)
|
||||
&& source.getColor(game).isWhite()) {
|
||||
return false;
|
||||
}
|
||||
|
|
@ -1096,7 +1096,7 @@ public abstract class PermanentImpl extends CardImpl implements Permanent {
|
|||
@Override
|
||||
public boolean canAttackInPrinciple(UUID defenderId, Game game) {
|
||||
if (hasSummoningSickness()
|
||||
&& null == game.getContinuousEffects().asThough(this.objectId, AsThoughEffectType.ATTACK_AS_HASTE, this.getControllerId(), game)) {
|
||||
&& null == game.getContinuousEffects().asThough(this.objectId, AsThoughEffectType.ATTACK_AS_HASTE, null, this.getControllerId(), game)) {
|
||||
return false;
|
||||
}
|
||||
//20101001 - 508.1c
|
||||
|
|
@ -1116,7 +1116,7 @@ public abstract class PermanentImpl extends CardImpl implements Permanent {
|
|||
}
|
||||
|
||||
return !abilities.containsKey(DefenderAbility.getInstance().getId())
|
||||
|| null != game.getContinuousEffects().asThough(this.objectId, AsThoughEffectType.ATTACK, this.getControllerId(), game);
|
||||
|| null != game.getContinuousEffects().asThough(this.objectId, AsThoughEffectType.ATTACK, null, this.getControllerId(), game);
|
||||
}
|
||||
|
||||
private boolean canAttackCheckRestrictionEffects(UUID defenderId, Game game) {
|
||||
|
|
@ -1136,7 +1136,7 @@ public abstract class PermanentImpl extends CardImpl implements Permanent {
|
|||
|
||||
@Override
|
||||
public boolean canBlock(UUID attackerId, Game game) {
|
||||
if (tapped && null == game.getState().getContinuousEffects().asThough(this.getId(), AsThoughEffectType.BLOCK_TAPPED, this.getControllerId(), game)) {
|
||||
if (tapped && null == game.getState().getContinuousEffects().asThough(this.getId(), AsThoughEffectType.BLOCK_TAPPED, null, this.getControllerId(), game)) {
|
||||
return false;
|
||||
}
|
||||
Permanent attacker = game.getPermanent(attackerId);
|
||||
|
|
@ -1169,7 +1169,7 @@ public abstract class PermanentImpl extends CardImpl implements Permanent {
|
|||
|
||||
@Override
|
||||
public boolean canBlockAny(Game game) {
|
||||
if (tapped && null == game.getState().getContinuousEffects().asThough(this.getId(), AsThoughEffectType.BLOCK_TAPPED, this.getControllerId(), game)) {
|
||||
if (tapped && null == game.getState().getContinuousEffects().asThough(this.getId(), AsThoughEffectType.BLOCK_TAPPED, null, this.getControllerId(), game)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -36,6 +36,7 @@ import java.util.Set;
|
|||
import java.util.UUID;
|
||||
import mage.MageItem;
|
||||
import mage.MageObject;
|
||||
import mage.MageObjectReference;
|
||||
import mage.abilities.Abilities;
|
||||
import mage.abilities.Ability;
|
||||
import mage.abilities.ActivatedAbility;
|
||||
|
|
@ -359,7 +360,7 @@ public interface Player extends MageItem, Copyable<Player> {
|
|||
|
||||
int drawCards(int num, Game game, List<UUID> appliedEffects);
|
||||
|
||||
boolean cast(SpellAbility ability, Game game, boolean noMana);
|
||||
boolean cast(SpellAbility ability, Game game, boolean noMana, MageObjectReference reference);
|
||||
|
||||
SpellAbility chooseSpellAbilityForCast(SpellAbility ability, Game game, boolean noMana);
|
||||
|
||||
|
|
@ -399,7 +400,7 @@ public interface Player extends MageItem, Copyable<Player> {
|
|||
* to be the turn of the player playing that card.
|
||||
* @return
|
||||
*/
|
||||
boolean playCard(Card card, Game game, boolean noMana, boolean ignoreTiming);
|
||||
boolean playCard(Card card, Game game, boolean noMana, boolean ignoreTiming, MageObjectReference reference);
|
||||
|
||||
/**
|
||||
*
|
||||
|
|
|
|||
|
|
@ -33,8 +33,10 @@ import java.util.*;
|
|||
import java.util.Map.Entry;
|
||||
import mage.ConditionalMana;
|
||||
import mage.MageObject;
|
||||
import mage.MageObjectReference;
|
||||
import mage.Mana;
|
||||
import mage.abilities.*;
|
||||
import mage.abilities.ActivatedAbility.ActivationStatus;
|
||||
import mage.abilities.common.PassAbility;
|
||||
import mage.abilities.common.WhileSearchingPlayFromLibraryAbility;
|
||||
import mage.abilities.common.delayed.AtTheEndOfTurnStepPostDelayedTriggeredAbility;
|
||||
|
|
@ -610,7 +612,7 @@ public abstract class PlayerImpl implements Player, Serializable {
|
|||
}
|
||||
if (abilities.containsKey(HexproofAbility.getInstance().getId())) {
|
||||
if (sourceControllerId != null && this.hasOpponent(sourceControllerId, game)
|
||||
&& null == game.getContinuousEffects().asThough(this.getId(), AsThoughEffectType.HEXPROOF, this.getId(), game)) {
|
||||
&& null == game.getContinuousEffects().asThough(this.getId(), AsThoughEffectType.HEXPROOF, null, this.getId(), game)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
|
@ -1010,7 +1012,7 @@ public abstract class PlayerImpl implements Player, Serializable {
|
|||
}
|
||||
|
||||
@Override
|
||||
public boolean playCard(Card card, Game game, boolean noMana, boolean ignoreTiming) {
|
||||
public boolean playCard(Card card, Game game, boolean noMana, boolean ignoreTiming, MageObjectReference reference) {
|
||||
if (card == null) {
|
||||
return false;
|
||||
}
|
||||
|
|
@ -1018,7 +1020,7 @@ public abstract class PlayerImpl implements Player, Serializable {
|
|||
if (card.isLand()) {
|
||||
result = playLand(card, game, ignoreTiming);
|
||||
} else {
|
||||
result = cast(card.getSpellAbility(), game, noMana);
|
||||
result = cast(card.getSpellAbility(), game, noMana, reference);
|
||||
}
|
||||
if (!result) {
|
||||
game.informPlayer(this, "You can't play " + card.getIdName() + '.');
|
||||
|
|
@ -1027,7 +1029,7 @@ public abstract class PlayerImpl implements Player, Serializable {
|
|||
}
|
||||
|
||||
@Override
|
||||
public boolean cast(SpellAbility ability, Game game, boolean noMana) {
|
||||
public boolean cast(SpellAbility ability, Game game, boolean noMana, MageObjectReference permittingObject) {
|
||||
if (game == null || ability == null) {
|
||||
return false;
|
||||
}
|
||||
|
|
@ -1046,7 +1048,7 @@ public abstract class PlayerImpl implements Player, Serializable {
|
|||
}
|
||||
Card card = game.getCard(ability.getSourceId());
|
||||
if (card != null) {
|
||||
if (!game.replaceEvent(GameEvent.getEvent(GameEvent.EventType.CAST_SPELL, ability.getId(), ability.getSourceId(), playerId), ability)) {
|
||||
if (!game.replaceEvent(GameEvent.getEvent(GameEvent.EventType.CAST_SPELL, ability.getId(), ability.getSourceId(), playerId, permittingObject), ability)) {
|
||||
int bookmark = game.bookmarkState();
|
||||
Zone fromZone = game.getState().getZone(card.getMainCard().getId());
|
||||
card.cast(game, fromZone, ability, playerId);
|
||||
|
|
@ -1074,10 +1076,10 @@ public abstract class PlayerImpl implements Player, Serializable {
|
|||
}
|
||||
}
|
||||
setCastSourceIdWithAlternateMana(null, null, null);
|
||||
GameEvent event = GameEvent.getEvent(GameEvent.EventType.CAST_SPELL, spell.getSpellAbility().getId(), spell.getSpellAbility().getSourceId(), playerId);
|
||||
GameEvent event = GameEvent.getEvent(GameEvent.EventType.CAST_SPELL, spell.getSpellAbility().getId(), spell.getSpellAbility().getSourceId(), playerId, permittingObject);
|
||||
game.fireEvent(event);
|
||||
if (spell.activate(game, noMana)) {
|
||||
event = GameEvent.getEvent(GameEvent.EventType.SPELL_CAST, spell.getSpellAbility().getId(), spell.getSpellAbility().getSourceId(), playerId);
|
||||
event = GameEvent.getEvent(GameEvent.EventType.SPELL_CAST, spell.getSpellAbility().getId(), spell.getSpellAbility().getSourceId(), playerId, permittingObject);
|
||||
event.setZone(fromZone);
|
||||
game.fireEvent(event);
|
||||
if (!game.isSimulation()) {
|
||||
|
|
@ -1116,7 +1118,7 @@ public abstract class PlayerImpl implements Player, Serializable {
|
|||
SpellAbility spellAbility = new SpellAbility(null, "", game.getState().getZone(card.getId()), SpellAbilityType.FACE_DOWN_CREATURE);
|
||||
spellAbility.setControllerId(this.getId());
|
||||
spellAbility.setSourceId(card.getId());
|
||||
if (cast(spellAbility, game, false)) {
|
||||
if (cast(spellAbility, game, false, null)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
@ -1124,17 +1126,18 @@ public abstract class PlayerImpl implements Player, Serializable {
|
|||
return false;
|
||||
}
|
||||
//20091005 - 114.2a
|
||||
if (!ignoreTiming && !playLandAbility.canActivate(this.playerId, game)) {
|
||||
ActivationStatus activationStatus = playLandAbility.canActivate(this.playerId, game);
|
||||
if (!ignoreTiming && !activationStatus.canActivate()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
//20091005 - 305.1
|
||||
if (!game.replaceEvent(GameEvent.getEvent(GameEvent.EventType.PLAY_LAND, card.getId(), card.getId(), playerId))) {
|
||||
if (!game.replaceEvent(GameEvent.getEvent(GameEvent.EventType.PLAY_LAND, card.getId(), card.getId(), playerId, activationStatus.getPermittingObject()))) {
|
||||
// int bookmark = game.bookmarkState();
|
||||
game.fireEvent(GameEvent.getEvent(GameEvent.EventType.PLAY_LAND, card.getId(), card.getId(), playerId));
|
||||
game.fireEvent(GameEvent.getEvent(GameEvent.EventType.PLAY_LAND, card.getId(), card.getId(), playerId, activationStatus.getPermittingObject()));
|
||||
if (moveCards(card, Zone.BATTLEFIELD, playLandAbility, game, false, false, false, null)) {
|
||||
landsPlayed++;
|
||||
game.fireEvent(GameEvent.getEvent(GameEvent.EventType.LAND_PLAYED, card.getId(), card.getId(), playerId));
|
||||
game.fireEvent(GameEvent.getEvent(GameEvent.EventType.LAND_PLAYED, card.getId(), card.getId(), playerId, activationStatus.getPermittingObject()));
|
||||
game.fireInformEvent(getLogName() + " plays " + card.getLogName());
|
||||
// game.removeBookmark(bookmark);
|
||||
resetStoredBookmark(game); // prevent undo after playing a land
|
||||
|
|
@ -1239,7 +1242,8 @@ public abstract class PlayerImpl implements Player, Serializable {
|
|||
Card card = game.getCard(ability.getSourceId());
|
||||
result = playLand(card, game, false);
|
||||
} else {
|
||||
if (!ability.canActivate(this.playerId, game)) {
|
||||
ActivationStatus activationStatus = ability.canActivate(this.playerId, game);
|
||||
if (!activationStatus.canActivate()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
@ -1251,7 +1255,7 @@ public abstract class PlayerImpl implements Player, Serializable {
|
|||
result = playManaAbility((ActivatedManaAbilityImpl) ability.copy(), game);
|
||||
break;
|
||||
case SPELL:
|
||||
result = cast((SpellAbility) ability.copy(), game, false);
|
||||
result = cast((SpellAbility) ability.copy(), game, false, activationStatus.getPermittingObject());
|
||||
break;
|
||||
default:
|
||||
result = playAbility(ability.copy(), game);
|
||||
|
|
@ -1357,7 +1361,7 @@ public abstract class PlayerImpl implements Player, Serializable {
|
|||
if (ability.getZone().match(zone)) {
|
||||
if (ability instanceof ActivatedAbility) {
|
||||
if (ability instanceof ActivatedManaAbilityImpl) {
|
||||
if (((ActivatedAbility) ability).canActivate(playerId, game)) {
|
||||
if (((ActivatedAbility) ability).canActivate(playerId, game).canActivate()) {
|
||||
output.put(ability.getId(), (ActivatedAbility) ability);
|
||||
}
|
||||
} else if (canPlay(((ActivatedAbility) ability), availableMana, object, game)) {
|
||||
|
|
@ -1379,19 +1383,19 @@ public abstract class PlayerImpl implements Player, Serializable {
|
|||
if (Zone.GRAVEYARD == zone && canPlayCardsFromGraveyard()) {
|
||||
for (ActivatedAbility ability : candidateAbilites.getPlayableAbilities(Zone.HAND)) {
|
||||
if (canUse || ability.getAbilityType() == AbilityType.SPECIAL_ACTION) {
|
||||
if (ability.canActivate(playerId, game)) {
|
||||
if (ability.canActivate(playerId, game).canActivate()) {
|
||||
output.put(ability.getId(), ability);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (zone != Zone.BATTLEFIELD
|
||||
&& null != game.getContinuousEffects().asThough(object.getId(), AsThoughEffectType.PLAY_FROM_NOT_OWN_HAND_ZONE, this.getId(), game)) {
|
||||
&& null != game.getContinuousEffects().asThough(object.getId(), AsThoughEffectType.PLAY_FROM_NOT_OWN_HAND_ZONE, null, this.getId(), game)) {
|
||||
for (Ability ability : candidateAbilites) {
|
||||
if (canUse || ability.getAbilityType() == AbilityType.SPECIAL_ACTION) {
|
||||
ability.setControllerId(this.getId());
|
||||
if (ability instanceof ActivatedAbility && ability.getZone().match(Zone.HAND)
|
||||
&& ((ActivatedAbility) ability).canActivate(playerId, game)) {
|
||||
&& ((ActivatedAbility) ability).canActivate(playerId, game).canActivate()) {
|
||||
output.put(ability.getId(), (ActivatedAbility) ability);
|
||||
}
|
||||
}
|
||||
|
|
@ -1439,7 +1443,7 @@ public abstract class PlayerImpl implements Player, Serializable {
|
|||
flashbackAbility.setControllerId(card.getOwnerId());
|
||||
flashbackAbility.setSpellAbilityType(SpellAbilityType.SPLIT_LEFT);
|
||||
flashbackAbility.setAbilityName(((SplitCard) card).getLeftHalfCard().getName());
|
||||
if (flashbackAbility.canActivate(playerId, game)) {
|
||||
if (flashbackAbility.canActivate(playerId, game).canActivate()) {
|
||||
useable.put(flashbackAbility.getId(), flashbackAbility);
|
||||
}
|
||||
// Right Half
|
||||
|
|
@ -1452,7 +1456,7 @@ public abstract class PlayerImpl implements Player, Serializable {
|
|||
flashbackAbility.setControllerId(card.getOwnerId());
|
||||
flashbackAbility.setSpellAbilityType(SpellAbilityType.SPLIT_RIGHT);
|
||||
flashbackAbility.setAbilityName(((SplitCard) card).getRightHalfCard().getName());
|
||||
if (flashbackAbility.canActivate(playerId, game)) {
|
||||
if (flashbackAbility.canActivate(playerId, game).canActivate()) {
|
||||
useable.put(flashbackAbility.getId(), flashbackAbility);
|
||||
}
|
||||
|
||||
|
|
@ -1469,7 +1473,7 @@ public abstract class PlayerImpl implements Player, Serializable {
|
|||
boolean canUse = !(object instanceof Permanent) || ((Permanent) object).canUseActivatedAbilities(game);
|
||||
for (ActivatedManaAbilityImpl ability : object.getAbilities().getActivatedManaAbilities(zone)) {
|
||||
if (canUse || ability.getAbilityType() == AbilityType.SPECIAL_ACTION) {
|
||||
if (ability.canActivate(playerId, game)) {
|
||||
if (ability.canActivate(playerId, game).canActivate()) {
|
||||
useable.put(ability.getId(), ability);
|
||||
}
|
||||
}
|
||||
|
|
@ -2477,7 +2481,7 @@ public abstract class PlayerImpl implements Player, Serializable {
|
|||
Card card = game.getCard(entry.getKey());
|
||||
if (card != null) {
|
||||
// TODO: fix costs (why is Panglacial Wurm automatically accepting payment?)
|
||||
player.cast(card.getSpellAbility(), game, false);
|
||||
player.cast(card.getSpellAbility(), game, false, null);
|
||||
}
|
||||
chooseCard.clearChoice();
|
||||
libraryCastableCardTracker.clear();
|
||||
|
|
@ -2633,7 +2637,7 @@ public abstract class PlayerImpl implements Player, Serializable {
|
|||
if (canUse == null) {
|
||||
canUse = permanent.canUseActivatedAbilities(game);
|
||||
}
|
||||
if (canUse && ability.canActivate(playerId, game)) {
|
||||
if (canUse && ability.canActivate(playerId, game).canActivate()) {
|
||||
canAdd = true;
|
||||
if (!ability.getManaCosts().isEmpty()) {
|
||||
withCost = true;
|
||||
|
|
@ -2677,7 +2681,7 @@ public abstract class PlayerImpl implements Player, Serializable {
|
|||
if (canUse == null) {
|
||||
canUse = permanent.canUseActivatedAbilities(game);
|
||||
}
|
||||
if (canUse && ability.canActivate(playerId, game)) {
|
||||
if (canUse && ability.canActivate(playerId, game).canActivate()) {
|
||||
canAdd = true;
|
||||
}
|
||||
}
|
||||
|
|
@ -2692,7 +2696,7 @@ public abstract class PlayerImpl implements Player, Serializable {
|
|||
canAdd = false;
|
||||
break;
|
||||
}
|
||||
if (ability.canActivate(playerId, game)) {
|
||||
if (ability.canActivate(playerId, game).canActivate()) {
|
||||
canAdd = true;
|
||||
}
|
||||
}
|
||||
|
|
@ -2712,7 +2716,7 @@ public abstract class PlayerImpl implements Player, Serializable {
|
|||
if (canUse == null) {
|
||||
canUse = permanent.canUseActivatedAbilities(game);
|
||||
}
|
||||
if (canUse && ability.canActivate(playerId, game) && !ability.getManaCosts().isEmpty()) {
|
||||
if (canUse && ability.canActivate(playerId, game).canActivate() && !ability.getManaCosts().isEmpty()) {
|
||||
result.add(permanent);
|
||||
break;
|
||||
}
|
||||
|
|
@ -2732,7 +2736,7 @@ public abstract class PlayerImpl implements Player, Serializable {
|
|||
if (!(ability instanceof ActivatedManaAbilityImpl)) {
|
||||
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)) {
|
||||
if (!copy.canActivate(playerId, game).canActivate()) {
|
||||
return false;
|
||||
}
|
||||
if (available != null) {
|
||||
|
|
@ -2765,10 +2769,10 @@ public abstract class PlayerImpl implements Player, Serializable {
|
|||
if (available == null) {
|
||||
return true;
|
||||
}
|
||||
UUID spendAnyManaSourceId = game.getContinuousEffects().asThough(ability.getSourceId(), AsThoughEffectType.SPEND_OTHER_MANA, ability, ability.getControllerId(), game);
|
||||
MageObjectReference permittingObject = game.getContinuousEffects().asThough(ability.getSourceId(), AsThoughEffectType.SPEND_OTHER_MANA, ability, ability.getControllerId(), game);
|
||||
for (Mana mana : abilityOptions) {
|
||||
for (Mana avail : available) {
|
||||
if (spendAnyManaSourceId != null && mana.count() <= avail.count()) {
|
||||
if (permittingObject != null && mana.count() <= avail.count()) {
|
||||
return true;
|
||||
}
|
||||
if (mana.enough(avail)) { // here we need to check if spend mana as though allow to pay the mana cost
|
||||
|
|
@ -2893,13 +2897,13 @@ public abstract class PlayerImpl implements Player, Serializable {
|
|||
}
|
||||
|
||||
private void getPlayableFromGraveyardCard(Game game, Card card, Abilities<Ability> candidateAbilities, ManaOptions availableMana, List<Ability> output) {
|
||||
UUID asThoughtCastSourceId = game.getContinuousEffects().asThough(card.getId(), AsThoughEffectType.PLAY_FROM_NOT_OWN_HAND_ZONE, this.getId(), game);
|
||||
MageObjectReference permittingObject = game.getContinuousEffects().asThough(card.getId(), AsThoughEffectType.PLAY_FROM_NOT_OWN_HAND_ZONE, null, this.getId(), game);
|
||||
for (ActivatedAbility ability : candidateAbilities.getActivatedAbilities(Zone.ALL)) {
|
||||
boolean possible = false;
|
||||
if (ability.getZone().match(Zone.GRAVEYARD)) {
|
||||
possible = true;
|
||||
} else if (ability.getZone().match(Zone.HAND) && (ability instanceof SpellAbility || ability instanceof PlayLandAbility)) {
|
||||
if (asThoughtCastSourceId != null || canPlayCardsFromGraveyard()) {
|
||||
if (permittingObject != null || canPlayCardsFromGraveyard()) {
|
||||
possible = true;
|
||||
}
|
||||
}
|
||||
|
|
@ -2968,12 +2972,12 @@ public abstract class PlayerImpl implements Player, Serializable {
|
|||
}
|
||||
for (ExileZone exile : game.getExile().getExileZones()) {
|
||||
for (Card card : exile.getCards(game)) {
|
||||
if (null != game.getContinuousEffects().asThough(card.getId(), AsThoughEffectType.PLAY_FROM_NOT_OWN_HAND_ZONE, this.getId(), game)) {
|
||||
if (null != game.getContinuousEffects().asThough(card.getId(), AsThoughEffectType.PLAY_FROM_NOT_OWN_HAND_ZONE, null, 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)) {
|
||||
if (((ActivatedAbility) ability).canActivate(playerId, game).canActivate()) {
|
||||
playable.add(ability);
|
||||
}
|
||||
}
|
||||
|
|
@ -2986,7 +2990,7 @@ public abstract class PlayerImpl implements Player, Serializable {
|
|||
// Check to play revealed cards
|
||||
for (Cards cards : game.getState().getRevealed().values()) {
|
||||
for (Card card : cards.getCards(game)) {
|
||||
if (null != game.getContinuousEffects().asThough(card.getId(), AsThoughEffectType.PLAY_FROM_NOT_OWN_HAND_ZONE, this.getId(), game)) {
|
||||
if (null != game.getContinuousEffects().asThough(card.getId(), AsThoughEffectType.PLAY_FROM_NOT_OWN_HAND_ZONE, null, this.getId(), game)) {
|
||||
for (ActivatedAbility ability : card.getAbilities().getActivatedAbilities(Zone.HAND)) {
|
||||
if (ability instanceof SpellAbility || ability instanceof PlayLandAbility) {
|
||||
playable.add(ability);
|
||||
|
|
@ -3001,7 +3005,7 @@ public abstract class PlayerImpl implements Player, Serializable {
|
|||
if (player != null) {
|
||||
if (/*player.isTopCardRevealed() &&*/player.getLibrary().hasCards()) {
|
||||
Card card = player.getLibrary().getFromTop(game);
|
||||
if (null != game.getContinuousEffects().asThough(card.getId(), AsThoughEffectType.PLAY_FROM_NOT_OWN_HAND_ZONE, getId(), game)) {
|
||||
if (null != game.getContinuousEffects().asThough(card.getId(), AsThoughEffectType.PLAY_FROM_NOT_OWN_HAND_ZONE, null, getId(), game)) {
|
||||
for (ActivatedAbility ability : card.getAbilities().getActivatedAbilities(Zone.HAND)) {
|
||||
if (ability instanceof SpellAbility || ability instanceof PlayLandAbility) {
|
||||
playable.add(ability);
|
||||
|
|
@ -3354,7 +3358,7 @@ public abstract class PlayerImpl implements Player, Serializable {
|
|||
@Override
|
||||
public boolean lookAtFaceDownCard(Card card, Game game
|
||||
) {
|
||||
if (null != game.getContinuousEffects().asThough(card.getId(), AsThoughEffectType.LOOK_AT_FACE_DOWN, this.getId(), game)) {
|
||||
if (null != game.getContinuousEffects().asThough(card.getId(), AsThoughEffectType.LOOK_AT_FACE_DOWN, card.getSpellAbility(), this.getId(), game)) {
|
||||
if (chooseUse(Outcome.Benefit, "Look at that card?", null, game)) {
|
||||
Cards cards = new CardsImpl(card);
|
||||
this.lookAtCards(getName() + " - " + sdf.format(System.currentTimeMillis()), cards, game);
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue