mirror of
https://github.com/magefree/mage.git
synced 2025-12-24 20:41:58 -08:00
Merge branch 'master' into changeToFinal
This commit is contained in:
commit
e7a5fd9979
573 changed files with 11915 additions and 2778 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,10 +178,10 @@ 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:
|
||||
|
|
@ -188,24 +189,28 @@ public abstract class ActivatedAbilityImpl extends AbilityImpl implements Activa
|
|||
|
||||
case NOT_YOU:
|
||||
if (controlsAbility(playerId, game)) {
|
||||
return false;
|
||||
return ActivationStatus.getFalse();
|
||||
}
|
||||
break;
|
||||
case TEAM:
|
||||
if (game.getPlayer(controllerId).hasOpponent(playerId, game)) {
|
||||
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:
|
||||
|
|
@ -216,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
|
||||
|
|
@ -307,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
|
||||
|
|
|
|||
|
|
@ -0,0 +1,69 @@
|
|||
/*
|
||||
* 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.common;
|
||||
|
||||
import mage.abilities.TriggeredAbilityImpl;
|
||||
import mage.abilities.effects.Effect;
|
||||
import mage.constants.Zone;
|
||||
import mage.game.Game;
|
||||
import mage.game.events.GameEvent;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author TheElk801
|
||||
*/
|
||||
public class WinsCoinFlipTriggeredAbility extends TriggeredAbilityImpl {
|
||||
|
||||
public WinsCoinFlipTriggeredAbility(Effect effect) {
|
||||
super(Zone.BATTLEFIELD, effect, false);
|
||||
}
|
||||
|
||||
public WinsCoinFlipTriggeredAbility(final WinsCoinFlipTriggeredAbility ability) {
|
||||
super(ability);
|
||||
}
|
||||
|
||||
@Override
|
||||
public WinsCoinFlipTriggeredAbility copy() {
|
||||
return new WinsCoinFlipTriggeredAbility(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean checkEventType(GameEvent event, Game game) {
|
||||
return event.getType() == GameEvent.EventType.COIN_FLIPPED;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean checkTrigger(GameEvent event, Game game) {
|
||||
return event.getFlag();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getRule() {
|
||||
return "Whenever a player wins a coin flip, " + super.getRule();
|
||||
}
|
||||
}
|
||||
|
|
@ -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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -45,7 +45,7 @@ public class ManaTypeInManaPoolCount implements DynamicValue {
|
|||
|
||||
@Override
|
||||
public String getMessage() {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
StringBuilder sb = new StringBuilder("unspent ");
|
||||
switch (manaType) {
|
||||
case BLACK:
|
||||
sb.append("black");
|
||||
|
|
@ -66,7 +66,7 @@ public class ManaTypeInManaPoolCount implements DynamicValue {
|
|||
sb.append("colorless");
|
||||
break;
|
||||
}
|
||||
sb.append(" mana in your mana pool");
|
||||
sb.append(" mana you have");
|
||||
return sb.toString();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -51,6 +51,8 @@ public interface ContinuousEffect extends Effect {
|
|||
|
||||
void discard();
|
||||
|
||||
void setDuration(Duration duration);
|
||||
|
||||
Duration getDuration();
|
||||
|
||||
long getOrder();
|
||||
|
|
|
|||
|
|
@ -112,6 +112,11 @@ public abstract class ContinuousEffectImpl extends EffectImpl implements Continu
|
|||
this.characterDefining = effect.characterDefining;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setDuration(Duration duration) {
|
||||
this.duration = duration;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Duration getDuration() {
|
||||
return duration;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
@ -347,7 +348,8 @@ public class ContinuousEffects implements Serializable {
|
|||
}
|
||||
// boolean checkLKI = event.getType().equals(EventType.ZONE_CHANGE) || event.getType().equals(EventType.DESTROYED_PERMANENT);
|
||||
//get all applicable transient Replacement effects
|
||||
for (ReplacementEffect effect : replacementEffects) {
|
||||
for (Iterator<ReplacementEffect> iterator = replacementEffects.iterator(); iterator.hasNext();) {
|
||||
ReplacementEffect effect = iterator.next();
|
||||
if (!effect.checksEventType(event, game)) {
|
||||
continue;
|
||||
}
|
||||
|
|
@ -378,7 +380,8 @@ public class ContinuousEffects implements Serializable {
|
|||
replaceEffects.put(effect, applicableAbilities);
|
||||
}
|
||||
}
|
||||
for (PreventionEffect effect : preventionEffects) {
|
||||
for (Iterator<PreventionEffect> iterator = preventionEffects.iterator(); iterator.hasNext();) {
|
||||
PreventionEffect effect = iterator.next();
|
||||
if (!effect.checksEventType(event, game)) {
|
||||
continue;
|
||||
}
|
||||
|
|
@ -500,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
|
||||
|
|
@ -523,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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -849,6 +839,9 @@ public class ContinuousEffects implements Serializable {
|
|||
if (rEffect != null) {
|
||||
event.getAppliedEffects().add(rEffect.getId());
|
||||
caught = rEffect.replaceEvent(event, rAbility, game);
|
||||
if (Duration.OneUse.equals(rEffect.getDuration())) {
|
||||
rEffect.discard();
|
||||
}
|
||||
}
|
||||
if (caught) { // Event was completely replaced -> stop applying effects to it
|
||||
break;
|
||||
|
|
@ -932,8 +925,7 @@ public class ContinuousEffects implements Serializable {
|
|||
System.out.println(game.getTurn() + ", " + game.getPhase() + ": " + "need apply " + layer.stream()
|
||||
.map((eff) -> {return eff.getClass().getName().replaceAll(".+\\.(.+)", "$1");})
|
||||
.collect(Collectors.joining(", ")));
|
||||
*/
|
||||
|
||||
*/
|
||||
for (ContinuousEffect effect : layer) {
|
||||
if (activeLayerEffects.contains(effect) && !appliedEffects.contains(effect.getId())) { // Effect does still exist and was not applied yet
|
||||
Set<UUID> dependentTo = effect.isDependentTo(layer);
|
||||
|
|
|
|||
|
|
@ -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));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -43,20 +43,27 @@ import mage.players.Player;
|
|||
*/
|
||||
public class CopyTargetSpellEffect extends OneShotEffect {
|
||||
|
||||
private boolean useLKI = false;
|
||||
private final boolean useController;
|
||||
private final boolean useLKI;
|
||||
|
||||
public CopyTargetSpellEffect() {
|
||||
super(Outcome.Copy);
|
||||
this(false);
|
||||
}
|
||||
|
||||
public CopyTargetSpellEffect(boolean useLKI) {
|
||||
this(false, useLKI);
|
||||
}
|
||||
|
||||
public CopyTargetSpellEffect(boolean useController, boolean useLKI) {
|
||||
super(Outcome.Copy);
|
||||
this.useController = useController;
|
||||
this.useLKI = useLKI;
|
||||
}
|
||||
|
||||
public CopyTargetSpellEffect(final CopyTargetSpellEffect effect) {
|
||||
super(effect);
|
||||
this.useLKI = effect.useLKI;
|
||||
this.useController = effect.useController;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
@ -71,7 +78,7 @@ public class CopyTargetSpellEffect extends OneShotEffect {
|
|||
spell = (Spell) game.getLastKnownInformation(targetPointer.getFirst(game, source), Zone.STACK);
|
||||
}
|
||||
if (spell != null) {
|
||||
StackObject newStackObject = spell.createCopyOnStack(game, source, source.getControllerId(), true);
|
||||
StackObject newStackObject = spell.createCopyOnStack(game, source, useController ? spell.getControllerId() : source.getControllerId(), true);
|
||||
Player player = game.getPlayer(source.getControllerId());
|
||||
if (player != null && newStackObject != null && newStackObject instanceof Spell) {
|
||||
String activateMessage = ((Spell) newStackObject).getActivatedMessage(game);
|
||||
|
|
|
|||
|
|
@ -81,19 +81,7 @@ public class CreateTokenCopyTargetEffect extends OneShotEffect {
|
|||
}
|
||||
|
||||
public CreateTokenCopyTargetEffect() {
|
||||
super(Outcome.PutCreatureInPlay);
|
||||
this.playerId = null;
|
||||
this.additionalCardType = null;
|
||||
this.addedTokenPermanents = new ArrayList<>();
|
||||
this.number = 1;
|
||||
this.additionalSubType = null;
|
||||
this.onlySubType = null;
|
||||
this.attackedPlayer = null;
|
||||
this.tokenPower = Integer.MIN_VALUE;
|
||||
this.tokenToughness = Integer.MIN_VALUE;
|
||||
this.gainsFlying = false;
|
||||
this.becomesArtifact = false;
|
||||
this.color = null;
|
||||
this((UUID) null);
|
||||
}
|
||||
|
||||
public CreateTokenCopyTargetEffect(UUID playerId) {
|
||||
|
|
|
|||
|
|
@ -115,7 +115,7 @@ public class DrawCardTargetEffect extends OneShotEffect {
|
|||
} else {
|
||||
target = mode.getTargets().get(0);
|
||||
}
|
||||
sb.append("Target ").append(target.getTargetName());
|
||||
sb.append("target ").append(target.getTargetName());
|
||||
} else {
|
||||
sb.append("that player");
|
||||
}
|
||||
|
|
|
|||
|
|
@ -29,68 +29,40 @@ package mage.abilities.effects.common;
|
|||
|
||||
import mage.abilities.Ability;
|
||||
import mage.abilities.effects.OneShotEffect;
|
||||
import mage.cards.Card;
|
||||
import mage.constants.Outcome;
|
||||
import mage.constants.Zone;
|
||||
import mage.filter.FilterCard;
|
||||
import mage.filter.common.FilterLandCard;
|
||||
import mage.game.Game;
|
||||
import mage.players.Player;
|
||||
import mage.target.Target;
|
||||
import mage.target.common.TargetCardInHand;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author LevelX2
|
||||
* @author TheElk801
|
||||
*/
|
||||
public class PutLandFromHandOntoBattlefieldEffect extends OneShotEffect {
|
||||
public class FlipUntilLoseEffect extends OneShotEffect {
|
||||
|
||||
private FilterCard filter;
|
||||
private boolean tapped;
|
||||
|
||||
public PutLandFromHandOntoBattlefieldEffect() {
|
||||
this(false);
|
||||
public FlipUntilLoseEffect() {
|
||||
super(Outcome.Benefit);
|
||||
this.staticText = "flip a coin until you lose a flip";
|
||||
}
|
||||
|
||||
public PutLandFromHandOntoBattlefieldEffect(boolean tapped) {
|
||||
this(tapped, new FilterLandCard());
|
||||
}
|
||||
|
||||
public PutLandFromHandOntoBattlefieldEffect(boolean tapped, FilterCard filter) {
|
||||
super(Outcome.PutLandInPlay);
|
||||
this.tapped = tapped;
|
||||
this.filter = filter;
|
||||
staticText = "you may put a " + filter.getMessage() + " from your hand onto the battlefield" + (tapped ? " tapped" : "");
|
||||
}
|
||||
|
||||
public PutLandFromHandOntoBattlefieldEffect(final PutLandFromHandOntoBattlefieldEffect effect) {
|
||||
public FlipUntilLoseEffect(final FlipUntilLoseEffect effect) {
|
||||
super(effect);
|
||||
this.tapped = effect.tapped;
|
||||
this.filter = effect.filter;
|
||||
}
|
||||
|
||||
@Override
|
||||
public FlipUntilLoseEffect copy() {
|
||||
return new FlipUntilLoseEffect(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean apply(Game game, Ability source) {
|
||||
Player controller = game.getPlayer(source.getControllerId());
|
||||
if (controller != null) {
|
||||
Target target = new TargetCardInHand(filter);
|
||||
if (target.canChoose(source.getSourceId(), source.getControllerId(), game)
|
||||
&& controller.chooseUse(outcome, "Put land onto battlefield?", source, game)
|
||||
&& controller.choose(outcome, target, source.getSourceId(), game)) {
|
||||
Card card = game.getCard(target.getFirstTarget());
|
||||
if (card != null) {
|
||||
controller.moveCards(card, Zone.BATTLEFIELD, source, game, tapped, false, false, null);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
Player player = game.getPlayer(source.getControllerId());
|
||||
if (player == null) {
|
||||
return false;
|
||||
}
|
||||
while (true) {
|
||||
if (!player.flipCoin(game)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public PutLandFromHandOntoBattlefieldEffect copy() {
|
||||
return new PutLandFromHandOntoBattlefieldEffect(this);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -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");
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -15,34 +15,41 @@ import mage.target.common.TargetCardInHand;
|
|||
/**
|
||||
* @author magenoxx_at_gmail.com
|
||||
*/
|
||||
public class PutPermanentOnBattlefieldEffect extends OneShotEffect {
|
||||
public class PutCardFromHandOntoBattlefieldEffect extends OneShotEffect {
|
||||
|
||||
private final FilterCard filter;
|
||||
private final boolean useTargetController;
|
||||
private final boolean tapped;
|
||||
|
||||
public PutPermanentOnBattlefieldEffect() {
|
||||
public PutCardFromHandOntoBattlefieldEffect() {
|
||||
this(new FilterPermanentCard("a permanent card"), false);
|
||||
}
|
||||
|
||||
public PutPermanentOnBattlefieldEffect(FilterCard filter) {
|
||||
public PutCardFromHandOntoBattlefieldEffect(FilterCard filter) {
|
||||
this(filter, false);
|
||||
}
|
||||
|
||||
public PutPermanentOnBattlefieldEffect(FilterCard filter, boolean useTargetController) {
|
||||
public PutCardFromHandOntoBattlefieldEffect(FilterCard filter, boolean useTargetController) {
|
||||
this(filter, useTargetController, false);
|
||||
}
|
||||
|
||||
public PutCardFromHandOntoBattlefieldEffect(FilterCard filter, boolean useTargetController, boolean tapped) {
|
||||
super(Outcome.PutCardInPlay);
|
||||
this.filter = filter;
|
||||
this.useTargetController = useTargetController;
|
||||
this.tapped = tapped;
|
||||
}
|
||||
|
||||
public PutPermanentOnBattlefieldEffect(final PutPermanentOnBattlefieldEffect effect) {
|
||||
public PutCardFromHandOntoBattlefieldEffect(final PutCardFromHandOntoBattlefieldEffect effect) {
|
||||
super(effect);
|
||||
this.filter = effect.filter.copy();
|
||||
this.useTargetController = effect.useTargetController;
|
||||
this.tapped = effect.tapped;
|
||||
}
|
||||
|
||||
@Override
|
||||
public PutPermanentOnBattlefieldEffect copy() {
|
||||
return new PutPermanentOnBattlefieldEffect(this);
|
||||
public PutCardFromHandOntoBattlefieldEffect copy() {
|
||||
return new PutCardFromHandOntoBattlefieldEffect(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
@ -58,10 +65,10 @@ public class PutPermanentOnBattlefieldEffect extends OneShotEffect {
|
|||
}
|
||||
if (player.chooseUse(Outcome.PutCardInPlay, "Put " + filter.getMessage() + " from your hand onto the battlefield?", source, game)) {
|
||||
TargetCardInHand target = new TargetCardInHand(filter);
|
||||
if (player.choose(Outcome.PutCreatureInPlay, target, source.getSourceId(), game)) {
|
||||
if (player.choose(Outcome.PutCardInPlay, target, source.getSourceId(), game)) {
|
||||
Card card = game.getCard(target.getFirstTarget());
|
||||
if (card != null) {
|
||||
return player.moveCards(card, Zone.BATTLEFIELD, source, game);
|
||||
return player.moveCards(card, Zone.BATTLEFIELD, source, game, tapped, false, false, null);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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,22 +20,21 @@
|
|||
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
||||
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
*
|
||||
* The views and conclusions contained in the software and documentation are those of the
|
||||
* authors and should not be interpreted as representing official policies, either expressed
|
||||
* or implied, of BetaSteward_at_googlemail.com.
|
||||
*/
|
||||
package mage.abilities.effects.common;
|
||||
|
||||
import mage.constants.Outcome;
|
||||
import mage.constants.Zone;
|
||||
import mage.abilities.Ability;
|
||||
import mage.abilities.effects.OneShotEffect;
|
||||
import mage.cards.Card;
|
||||
import mage.constants.Outcome;
|
||||
import mage.constants.Zone;
|
||||
import mage.game.Game;
|
||||
|
||||
|
||||
import mage.game.permanent.Permanent;
|
||||
import mage.players.Player;
|
||||
|
||||
/**
|
||||
*
|
||||
|
|
@ -59,12 +58,15 @@ public class ReturnToBattlefieldUnderOwnerControlAttachedEffect extends OneShotE
|
|||
|
||||
@Override
|
||||
public boolean apply(Game game, Ability source) {
|
||||
Player controller = game.getPlayer(source.getControllerId());
|
||||
if (controller == null) {
|
||||
return false;
|
||||
}
|
||||
Object object = getValue("attachedTo");
|
||||
if (object != null && object instanceof Permanent) {
|
||||
Card card = game.getCard(((Permanent) object).getId());
|
||||
if (card != null) {
|
||||
Zone currentZone = game.getState().getZone(card.getId());
|
||||
if (card.putOntoBattlefield(game, currentZone, source.getSourceId(), card.getOwnerId())) {
|
||||
if (controller.moveCards(card, Zone.BATTLEFIELD, source, game, false, false, true, null)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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,22 +20,22 @@
|
|||
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
||||
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
*
|
||||
* The views and conclusions contained in the software and documentation are those of the
|
||||
* authors and should not be interpreted as representing official policies, either expressed
|
||||
* or implied, of BetaSteward_at_googlemail.com.
|
||||
*/
|
||||
|
||||
package mage.abilities.effects.common;
|
||||
|
||||
import java.util.UUID;
|
||||
import mage.constants.Outcome;
|
||||
import mage.abilities.Ability;
|
||||
import mage.abilities.effects.OneShotEffect;
|
||||
import mage.cards.Card;
|
||||
import mage.constants.Outcome;
|
||||
import mage.constants.Zone;
|
||||
import mage.game.ExileZone;
|
||||
import mage.game.Game;
|
||||
import mage.players.Player;
|
||||
import mage.util.CardUtil;
|
||||
|
||||
/**
|
||||
|
|
@ -60,11 +60,16 @@ public class ReturnToBattlefieldUnderYourControlSourceEffect extends OneShotEffe
|
|||
|
||||
@Override
|
||||
public boolean apply(Game game, Ability source) {
|
||||
Player controller = game.getPlayer(source.getControllerId());
|
||||
if (controller == null) {
|
||||
return false;
|
||||
}
|
||||
UUID exileZoneId = CardUtil.getExileZoneId(game, source.getSourceId(), source.getSourceObjectZoneChangeCounter());
|
||||
ExileZone exileZone = game.getExile().getExileZone(exileZoneId);
|
||||
if (exileZone != null && exileZone.contains(source.getSourceId())) {
|
||||
Card card = game.getCard(source.getSourceId());
|
||||
if (card != null && card.putOntoBattlefield(game, Zone.EXILED, source.getSourceId(), source.getControllerId())) {
|
||||
Card card = game.getCard(source.getSourceId());
|
||||
if (card != null
|
||||
&& controller.moveCards(card, Zone.BATTLEFIELD, source, game)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,45 @@
|
|||
package mage.abilities.effects.common;
|
||||
|
||||
import java.util.UUID;
|
||||
import mage.abilities.Ability;
|
||||
import mage.abilities.effects.OneShotEffect;
|
||||
import mage.constants.Outcome;
|
||||
import mage.constants.Zone;
|
||||
import mage.game.Game;
|
||||
import mage.players.Player;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author BetaSteward_at_googlemail.com
|
||||
*/
|
||||
public class ShuffleHandGraveyardAllEffect extends OneShotEffect {
|
||||
|
||||
public ShuffleHandGraveyardAllEffect() {
|
||||
super(Outcome.Neutral);
|
||||
staticText = "each player shuffles their hand and graveyard into their library";
|
||||
}
|
||||
|
||||
public ShuffleHandGraveyardAllEffect(final ShuffleHandGraveyardAllEffect effect) {
|
||||
super(effect);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean apply(Game game, Ability source) {
|
||||
Player controller = game.getPlayer(source.getControllerId());
|
||||
for (UUID playerId : game.getState().getPlayersInRange(controller.getId(), game)) {
|
||||
Player player = game.getPlayer(playerId);
|
||||
if (player != null) {
|
||||
player.moveCards(player.getHand(), Zone.LIBRARY, source, game);
|
||||
player.moveCards(player.getGraveyard(), Zone.LIBRARY, source, game);
|
||||
player.shuffleLibrary(source, game);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ShuffleHandGraveyardAllEffect copy() {
|
||||
return new ShuffleHandGraveyardAllEffect(this);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -50,6 +50,7 @@ import mage.game.events.ManaEvent;
|
|||
* Commander rule #4 was removed Jan. 18, 2016
|
||||
*
|
||||
*/
|
||||
@Deprecated
|
||||
public class CommanderManaReplacementEffect extends ReplacementEffectImpl {
|
||||
|
||||
private final UUID playerId;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -29,6 +29,7 @@ package mage.abilities.effects.common.cost;
|
|||
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
import mage.Mana;
|
||||
import mage.abilities.Ability;
|
||||
import mage.abilities.ActivatedAbility;
|
||||
|
|
@ -54,6 +55,7 @@ public class SpellsCostReductionAllEffect extends CostModificationEffectImpl {
|
|||
private int amount;
|
||||
private final boolean upTo;
|
||||
private boolean onlyControlled;
|
||||
private UUID controllerId;
|
||||
|
||||
public SpellsCostReductionAllEffect(int amount) {
|
||||
this(new FilterCard("Spells"), amount);
|
||||
|
|
@ -74,6 +76,7 @@ public class SpellsCostReductionAllEffect extends CostModificationEffectImpl {
|
|||
this.upTo = upTo;
|
||||
this.onlyControlled = onlyControlled;
|
||||
this.staticText = filter.getMessage() + " cost " + (upTo ? "up to " : "") + '{' + amount + "} less to cast";
|
||||
this.controllerId = null;
|
||||
}
|
||||
|
||||
protected SpellsCostReductionAllEffect(final SpellsCostReductionAllEffect effect) {
|
||||
|
|
@ -82,6 +85,7 @@ public class SpellsCostReductionAllEffect extends CostModificationEffectImpl {
|
|||
this.amount = effect.amount;
|
||||
this.upTo = effect.upTo;
|
||||
this.onlyControlled = effect.onlyControlled;
|
||||
this.controllerId = effect.controllerId;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
@ -145,6 +149,9 @@ public class SpellsCostReductionAllEffect extends CostModificationEffectImpl {
|
|||
if (onlyControlled && !abilityToModify.getControllerId().equals(source.getControllerId())) {
|
||||
return false;
|
||||
}
|
||||
if (controllerId != null && !abilityToModify.getControllerId().equals(controllerId)) {
|
||||
return false;
|
||||
}
|
||||
if (abilityToModify instanceof SpellAbility) {
|
||||
Spell spell = (Spell) game.getStack().getStackObject(abilityToModify.getId());
|
||||
if (spell != null) {
|
||||
|
|
@ -158,6 +165,10 @@ public class SpellsCostReductionAllEffect extends CostModificationEffectImpl {
|
|||
return false;
|
||||
}
|
||||
|
||||
public void setControllerId(UUID controllerId) {
|
||||
this.controllerId = controllerId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SpellsCostReductionAllEffect copy() {
|
||||
return new SpellsCostReductionAllEffect(this);
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -45,7 +45,7 @@ public class AddManaAnyColorAttachedControllerEffect extends ManaEffect {
|
|||
|
||||
public AddManaAnyColorAttachedControllerEffect() {
|
||||
super();
|
||||
staticText = "its controller adds one mana of any color to their mana pool";
|
||||
staticText = "its controller adds one mana of any color";
|
||||
}
|
||||
|
||||
public AddManaAnyColorAttachedControllerEffect(final AddManaAnyColorAttachedControllerEffect effect) {
|
||||
|
|
|
|||
|
|
@ -44,7 +44,7 @@ public class AddManaOfAnyTypeProducedEffect extends ManaEffect {
|
|||
|
||||
public AddManaOfAnyTypeProducedEffect() {
|
||||
super();
|
||||
staticText = "that player adds one mana to their mana pool of any type that land produced";
|
||||
staticText = "that player adds one mana of any type that land produced";
|
||||
}
|
||||
|
||||
public AddManaOfAnyTypeProducedEffect(final AddManaOfAnyTypeProducedEffect effect) {
|
||||
|
|
|
|||
|
|
@ -38,7 +38,7 @@ public class AddManaToManaPoolTargetControllerEffect extends ManaEffect {
|
|||
super();
|
||||
this.mana = mana;
|
||||
this.emptyOnlyOnTurnsEnd = emptyOnTurnsEnd;
|
||||
this.staticText = (textManaPoolOwner.equals("their") ? "that player adds " : "add ") + mana.toString() + " to " + textManaPoolOwner + " mana pool";
|
||||
this.staticText = (textManaPoolOwner.equals("their") ? "that player adds " : "add ") + mana.toString();
|
||||
}
|
||||
|
||||
public AddManaToManaPoolTargetControllerEffect(final AddManaToManaPoolTargetControllerEffect effect) {
|
||||
|
|
|
|||
159
Mage/src/main/java/mage/abilities/keyword/AssistAbility.java
Normal file
159
Mage/src/main/java/mage/abilities/keyword/AssistAbility.java
Normal file
|
|
@ -0,0 +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).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;
|
||||
}
|
||||
}
|
||||
|
|
@ -103,11 +103,11 @@ class AuraSwapEffect extends OneShotEffect {
|
|||
Card auraInHand = game.getCard(target.getFirstTarget());
|
||||
if (auraInHand != null) {
|
||||
game.getState().setValue("attachTo:" + auraInHand.getId(), enchantedPermanent);
|
||||
auraInHand.putOntoBattlefield(game, Zone.HAND, source.getSourceId(), controller.getId());
|
||||
controller.moveCards(auraInHand, Zone.BATTLEFIELD, source, game);
|
||||
enchantedPermanent.addAttachment(auraInHand.getId(), game);
|
||||
game.informPlayers(controller.getLogName() + " put " + auraInHand.getLogName() + " on the battlefield attached to " + enchantedPermanent.getLogName() + '.');
|
||||
enchantedPermanent.removeAttachment(auraSourcePermanent.getId(), game);
|
||||
return controller.moveCards(game.getCard(source.getSourceId()), Zone.HAND, source, game);
|
||||
return controller.moveCards(auraSourcePermanent, Zone.HAND, source, game);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -39,7 +39,7 @@ public class BasicLandcyclingAbility extends CyclingAbility{
|
|||
private static final String text = "Basic landcycling";
|
||||
|
||||
public BasicLandcyclingAbility(ManaCosts costs) {
|
||||
super(costs, StaticFilters.FILTER_BASIC_LAND_CARD, text);
|
||||
super(costs, StaticFilters.FILTER_CARD_BASIC_LAND, text);
|
||||
}
|
||||
|
||||
public BasicLandcyclingAbility(final BasicLandcyclingAbility ability) {
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -27,6 +27,7 @@
|
|||
*/
|
||||
package mage.abilities.keyword;
|
||||
|
||||
import java.util.*;
|
||||
import mage.abilities.Ability;
|
||||
import mage.abilities.SpellAbility;
|
||||
import mage.abilities.StaticAbility;
|
||||
|
|
@ -41,8 +42,6 @@ import mage.constants.Zone;
|
|||
import mage.game.Game;
|
||||
import mage.players.Player;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* 20121001 702.31. Kicker 702.31a Kicker is a static ability that functions
|
||||
* while the spell with kicker is on the stack. "Kicker [cost]" means "You may
|
||||
|
|
@ -134,7 +133,8 @@ public class KickerAbility extends StaticAbility implements OptionalAdditionalSo
|
|||
cost.reset();
|
||||
}
|
||||
String key = getActivationKey(source, "", game);
|
||||
for (String activationKey : activations.keySet()) {
|
||||
for (Iterator<String> iterator = activations.keySet().iterator(); iterator.hasNext();) {
|
||||
String activationKey = iterator.next();
|
||||
if (activationKey.startsWith(key) && activations.get(activationKey) > 0) {
|
||||
activations.put(key, 0);
|
||||
}
|
||||
|
|
@ -212,10 +212,10 @@ public class KickerAbility extends StaticAbility implements OptionalAdditionalSo
|
|||
&& player.chooseUse(Outcome.Benefit, "Pay " + times + kickerCost.getText(false) + " ?", ability, game)) {
|
||||
this.activateKicker(kickerCost, ability, game);
|
||||
if (kickerCost instanceof Costs) {
|
||||
for (Iterator itKickerCost = ((Costs) kickerCost).iterator(); itKickerCost.hasNext(); ) {
|
||||
for (Iterator itKickerCost = ((Costs) kickerCost).iterator(); itKickerCost.hasNext();) {
|
||||
Object kickerCostObject = itKickerCost.next();
|
||||
if ((kickerCostObject instanceof Costs) || (kickerCostObject instanceof CostsImpl)) {
|
||||
for (@SuppressWarnings("unchecked") Iterator<Cost> itDetails = ((Costs) kickerCostObject).iterator(); itDetails.hasNext(); ) {
|
||||
for (@SuppressWarnings("unchecked") Iterator<Cost> itDetails = ((Costs) kickerCostObject).iterator(); itDetails.hasNext();) {
|
||||
addKickerCostsToAbility(itDetails.next(), ability, game);
|
||||
}
|
||||
} else {
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -120,9 +120,13 @@ class NinjutsuEffect extends OneShotEffect {
|
|||
|
||||
@Override
|
||||
public boolean apply(Game game, Ability source) {
|
||||
Player controller = game.getPlayer(source.getControllerId());
|
||||
if (controller == null) {
|
||||
return false;
|
||||
}
|
||||
Card card = game.getCard(source.getSourceId());
|
||||
if (card != null) {
|
||||
card.putOntoBattlefield(game, Zone.HAND, source.getSourceId(), source.getControllerId());
|
||||
controller.moveCards(card, Zone.BATTLEFIELD, source, game, true, false, false, null);
|
||||
Permanent permanent = game.getPermanent(source.getSourceId());
|
||||
if (permanent != null) {
|
||||
UUID defendingPlayerId = null;
|
||||
|
|
@ -133,7 +137,6 @@ class NinjutsuEffect extends OneShotEffect {
|
|||
}
|
||||
if (defendingPlayerId != null) {
|
||||
game.getCombat().addAttackerToCombat(permanent.getId(), defendingPlayerId, game);
|
||||
permanent.setTapped(true);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,162 @@
|
|||
/*
|
||||
* 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.Ability;
|
||||
import mage.abilities.common.EntersBattlefieldTriggeredAbility;
|
||||
import mage.abilities.effects.OneShotEffect;
|
||||
import mage.cards.Card;
|
||||
import mage.cards.CardsImpl;
|
||||
import mage.constants.Outcome;
|
||||
import mage.constants.Zone;
|
||||
import mage.filter.FilterCard;
|
||||
import mage.filter.predicate.mageobject.NamePredicate;
|
||||
import mage.game.Game;
|
||||
import mage.players.Player;
|
||||
import mage.target.TargetPlayer;
|
||||
import mage.target.common.TargetCardInLibrary;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author TheElk801
|
||||
*/
|
||||
public class PartnerWithAbility extends EntersBattlefieldTriggeredAbility {
|
||||
|
||||
private final String partnerName;
|
||||
private final String shortName;
|
||||
private final boolean hasReminderText;
|
||||
|
||||
public PartnerWithAbility(String partnerName) {
|
||||
this(partnerName, false);
|
||||
}
|
||||
|
||||
public PartnerWithAbility(String partnerName, boolean isLegendary) {
|
||||
this(partnerName, isLegendary, true);
|
||||
}
|
||||
|
||||
public PartnerWithAbility(String partnerName, boolean isLegendary, boolean hasReminderText) {
|
||||
super(new PartnersWithSearchEffect(partnerName), false);
|
||||
this.addTarget(new TargetPlayer());
|
||||
this.partnerName = partnerName;
|
||||
this.hasReminderText = hasReminderText;
|
||||
if (isLegendary) {
|
||||
this.shortName = shortenName(partnerName);
|
||||
} else {
|
||||
this.shortName = partnerName;
|
||||
}
|
||||
}
|
||||
|
||||
public PartnerWithAbility(final PartnerWithAbility ability) {
|
||||
super(ability);
|
||||
this.partnerName = ability.partnerName;
|
||||
this.shortName = ability.shortName;
|
||||
this.hasReminderText = ability.hasReminderText;
|
||||
}
|
||||
|
||||
@Override
|
||||
public PartnerWithAbility copy() {
|
||||
return new PartnerWithAbility(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getRule() {
|
||||
if (hasReminderText) {
|
||||
return "Partner with " + partnerName
|
||||
+ " <i>(When this creature enters the battlefield, target player may put " + shortName
|
||||
+ " into their hand from their library, then shuffle.)</i>";
|
||||
} else {
|
||||
return "Partner with " + partnerName;
|
||||
}
|
||||
}
|
||||
|
||||
public String getPartnerName() {
|
||||
return partnerName;
|
||||
}
|
||||
|
||||
public static String shortenName(String st) {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
for (char s : st.toCharArray()) {
|
||||
if (s == ' ' || s == ',') {
|
||||
break;
|
||||
} else {
|
||||
sb.append(s);
|
||||
}
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
}
|
||||
|
||||
class PartnersWithSearchEffect extends OneShotEffect {
|
||||
|
||||
private final String partnerName;
|
||||
|
||||
public PartnersWithSearchEffect(String partnerName) {
|
||||
super(Outcome.DrawCard);
|
||||
this.partnerName = partnerName;
|
||||
this.staticText = "";
|
||||
}
|
||||
|
||||
public PartnersWithSearchEffect(final PartnersWithSearchEffect effect) {
|
||||
super(effect);
|
||||
this.partnerName = effect.partnerName;
|
||||
}
|
||||
|
||||
@Override
|
||||
public PartnersWithSearchEffect copy() {
|
||||
return new PartnersWithSearchEffect(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean apply(Game game, Ability source) {
|
||||
Player controller = game.getPlayer(source.getControllerId());
|
||||
if (controller != null) {
|
||||
Player player = game.getPlayer(source.getFirstTarget());
|
||||
if (player != null) {
|
||||
FilterCard filter = new FilterCard("card named " + partnerName);
|
||||
filter.add(new NamePredicate(partnerName));
|
||||
TargetCardInLibrary target = new TargetCardInLibrary(filter);
|
||||
if (player.chooseUse(Outcome.Benefit, "Search your library for a card named " + partnerName + " and put it into your hand?", source, game)) {
|
||||
player.searchLibrary(target, game);
|
||||
for (UUID cardId : target.getTargets()) {
|
||||
Card card = player.getLibrary().getCard(cardId, game);
|
||||
if (card != null) {
|
||||
player.revealCards(source, new CardsImpl(card), game);
|
||||
player.moveCards(card, Zone.HAND, source, game);
|
||||
}
|
||||
}
|
||||
player.shuffleLibrary(source, game);
|
||||
}
|
||||
}
|
||||
// prevent undo
|
||||
controller.resetStoredBookmark(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);
|
||||
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -142,7 +142,7 @@ public class Deck implements Serializable {
|
|||
cardInfo = CardRepository.instance.findCard("Silvercoat Lion");
|
||||
Logger.getLogger(Deck.class).error("Tried to restart the DB: " + (cardInfo == null ? "not successful" : "successful"));
|
||||
}
|
||||
return new GameException("Card not found - " + deckCardInfo.getCardName() + " - " + deckCardInfo.getSetCode() + " for deck - " + deckName + '\n'
|
||||
return new GameException("Card not found - " + deckCardInfo.getCardName() + " - " + deckCardInfo.getSetCode() + "/" + deckCardInfo.getCardNum() + " for deck - " + deckName + '\n'
|
||||
+ "Possible reason is, that you use cards in your deck, that are only supported in newer versions of the server.\n"
|
||||
+ "So it can help to use the same card from another set, that's already supported from this server.");
|
||||
|
||||
|
|
|
|||
|
|
@ -58,7 +58,7 @@ public enum CardRepository {
|
|||
// raise this if db structure was changed
|
||||
private static final long CARD_DB_VERSION = 51;
|
||||
// raise this if new cards were added to the server
|
||||
private static final long CARD_CONTENT_VERSION = 109;
|
||||
private static final long CARD_CONTENT_VERSION = 111;
|
||||
private Dao<CardInfo, Object> cardDao;
|
||||
private Set<String> classNames;
|
||||
|
||||
|
|
|
|||
|
|
@ -29,7 +29,7 @@ public enum ExpansionRepository {
|
|||
private static final String JDBC_URL = "jdbc:h2:file:./db/cards.h2;AUTO_SERVER=TRUE";
|
||||
private static final String VERSION_ENTITY_NAME = "expansion";
|
||||
private static final long EXPANSION_DB_VERSION = 5;
|
||||
private static final long EXPANSION_CONTENT_VERSION = 14;
|
||||
private static final long EXPANSION_CONTENT_VERSION = 15;
|
||||
|
||||
private Dao<ExpansionInfo, Object> expansionDao;
|
||||
|
||||
|
|
@ -88,10 +88,10 @@ public enum ExpansionRepository {
|
|||
try {
|
||||
// only with boosters and cards
|
||||
GenericRawResults<ExpansionInfo> setsList = expansionDao.queryRaw(
|
||||
"select * from expansion e " +
|
||||
" where e.boosters = 1 " +
|
||||
" and exists(select (1) from card c where c.setcode = e.code) " +
|
||||
" order by e.releasedate desc",
|
||||
"select * from expansion e "
|
||||
+ " where e.boosters = 1 "
|
||||
+ " and exists(select (1) from card c where c.setcode = e.code) "
|
||||
+ " order by e.releasedate desc",
|
||||
expansionDao.getRawRowMapper());
|
||||
|
||||
List<ExpansionInfo> resList = new ArrayList<>();
|
||||
|
|
|
|||
51
Mage/src/main/java/mage/choices/ChooseFriendsAndFoes.java
Normal file
51
Mage/src/main/java/mage/choices/ChooseFriendsAndFoes.java
Normal file
|
|
@ -0,0 +1,51 @@
|
|||
/*
|
||||
* To change this license header, choose License Headers in Project Properties.
|
||||
* To change this template file, choose Tools | Templates
|
||||
* and open the template in the editor.
|
||||
*/
|
||||
package mage.choices;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
import mage.abilities.Ability;
|
||||
import mage.constants.Outcome;
|
||||
import mage.game.Game;
|
||||
import mage.players.Player;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author TheElk801
|
||||
*/
|
||||
public class ChooseFriendsAndFoes {
|
||||
|
||||
private List<Player> friends = new ArrayList<>();
|
||||
private List<Player> foes = new ArrayList<>();
|
||||
|
||||
public boolean chooseFriendOrFoe(Player playerChoosing, Ability source, Game game) {
|
||||
if (playerChoosing == null) {
|
||||
return false;
|
||||
}
|
||||
friends.clear();
|
||||
foes.clear();
|
||||
for (UUID playerId : game.getState().getPlayersInRange(playerChoosing.getId(), game)) {
|
||||
Player player = game.getPlayer(playerId);
|
||||
if (player != null) {
|
||||
if (playerChoosing.chooseUse(Outcome.Vote, "Is " + player.getName() + " friend or foe?", null, "Friend", "Foe", source, game)) {
|
||||
friends.add(player);
|
||||
} else {
|
||||
foes.add(player);
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public List<Player> getFriends() {
|
||||
return friends;
|
||||
}
|
||||
|
||||
public List<Player> getFoes() {
|
||||
return foes;
|
||||
}
|
||||
}
|
||||
|
|
@ -61,6 +61,7 @@ public enum SubType {
|
|||
AUROCHS("Aurochs", SubTypeSet.CreatureType),
|
||||
AUTOBOT("Autobot", SubTypeSet.CreatureType, true), // H17, Grimlock
|
||||
AVATAR("Avatar", SubTypeSet.CreatureType),
|
||||
AZRA("Azra", SubTypeSet.CreatureType),
|
||||
// B
|
||||
BADGER("Badger", SubTypeSet.CreatureType),
|
||||
BARBARIAN("Barbarian", SubTypeSet.CreatureType),
|
||||
|
|
@ -389,6 +390,7 @@ public enum SubType {
|
|||
NIXILIS("Nixilis", SubTypeSet.PlaneswalkerType),
|
||||
OBI_WAN("Obi-Wan", SubTypeSet.PlaneswalkerType, true), // Star Wars
|
||||
RAL("Ral", SubTypeSet.PlaneswalkerType),
|
||||
ROWAN("Rowan", SubTypeSet.PlaneswalkerType),
|
||||
SAHEELI("Saheeli", SubTypeSet.PlaneswalkerType),
|
||||
SAMUT("Samut", SubTypeSet.PlaneswalkerType),
|
||||
SARKHAN("Sarkhan", SubTypeSet.PlaneswalkerType),
|
||||
|
|
@ -401,6 +403,7 @@ public enum SubType {
|
|||
UGIN("Ugin", SubTypeSet.PlaneswalkerType),
|
||||
VENSER("Venser", SubTypeSet.PlaneswalkerType),
|
||||
VRASKA("Vraska", SubTypeSet.PlaneswalkerType),
|
||||
WILL("Will", SubTypeSet.PlaneswalkerType),
|
||||
XENAGOS("Xenagos", SubTypeSet.PlaneswalkerType),
|
||||
YANGGU("Yanggu", SubTypeSet.PlaneswalkerType),
|
||||
YANLING("Yanling", SubTypeSet.PlaneswalkerType),
|
||||
|
|
|
|||
|
|
@ -6,5 +6,5 @@ package mage.constants;
|
|||
*/
|
||||
public enum TargetController {
|
||||
|
||||
ACTIVE, ANY, YOU, NOT_YOU, OPPONENT, OWNER, CONTROLLER_ATTACHED_TO, NEXT
|
||||
ACTIVE, ANY, YOU, NOT_YOU, OPPONENT, TEAM, OWNER, CONTROLLER_ATTACHED_TO, NEXT
|
||||
}
|
||||
|
|
|
|||
|
|
@ -104,7 +104,7 @@ public class FilterMana implements Serializable {
|
|||
}
|
||||
|
||||
public boolean isColorless() {
|
||||
return colorless;
|
||||
return !(white || blue || black || red || green) || colorless;
|
||||
}
|
||||
|
||||
public void setColorless(boolean colorless) {
|
||||
|
|
|
|||
|
|
@ -71,6 +71,13 @@ public final class StaticFilters {
|
|||
static {
|
||||
FILTER_CARD_CREATURE.setLockedFilter(true);
|
||||
}
|
||||
|
||||
public static final FilterCreatureCard FILTER_CARD_CREATURE_A = new FilterCreatureCard("a creature card");
|
||||
|
||||
static {
|
||||
FILTER_CARD_CREATURE_A.setLockedFilter(true);
|
||||
}
|
||||
|
||||
public static final FilterCreatureCard FILTER_CARD_CREATURE_YOUR_GRAVEYARD = new FilterCreatureCard("creature card from your graveyard");
|
||||
|
||||
static {
|
||||
|
|
@ -88,6 +95,25 @@ public final class StaticFilters {
|
|||
static {
|
||||
FILTER_CARD_LAND.setLockedFilter(true);
|
||||
}
|
||||
|
||||
public static final FilterLandCard FILTER_CARD_LAND_A = new FilterLandCard("a land card");
|
||||
|
||||
static {
|
||||
FILTER_CARD_LAND_A.setLockedFilter(true);
|
||||
}
|
||||
|
||||
public static final FilterBasicLandCard FILTER_CARD_BASIC_LAND = new FilterBasicLandCard();
|
||||
|
||||
static {
|
||||
FILTER_CARD_BASIC_LAND.setLockedFilter(true);
|
||||
}
|
||||
|
||||
public static final FilterBasicLandCard FILTER_CARD_BASIC_LAND_A = new FilterBasicLandCard("a basic land card");
|
||||
|
||||
static {
|
||||
FILTER_CARD_BASIC_LAND_A.setLockedFilter(true);
|
||||
}
|
||||
|
||||
public static final FilterNonlandCard FILTER_CARD_NON_LAND = new FilterNonlandCard();
|
||||
|
||||
static {
|
||||
|
|
@ -286,12 +312,6 @@ public final class StaticFilters {
|
|||
FILTER_LANDS_NONBASIC.setLockedFilter(true);
|
||||
}
|
||||
|
||||
public static final FilterBasicLandCard FILTER_BASIC_LAND_CARD = new FilterBasicLandCard();
|
||||
|
||||
static {
|
||||
FILTER_BASIC_LAND_CARD.setLockedFilter(true);
|
||||
}
|
||||
|
||||
// Used for sacrifice targets that don't need the "you control" text
|
||||
public static final FilterControlledLandPermanent FILTER_CONTROLLED_LAND_SHORT_TEXT = new FilterControlledLandPermanent("a land");
|
||||
|
||||
|
|
@ -357,6 +377,12 @@ public final class StaticFilters {
|
|||
FILTER_PERMANENT_NON_LAND.setLockedFilter(true);
|
||||
}
|
||||
|
||||
public static final FilterPermanent FILTER_PERMANENTS_NON_LAND = new FilterNonlandPermanent("nonland permanents");
|
||||
|
||||
static {
|
||||
FILTER_PERMANENTS_NON_LAND.setLockedFilter(true);
|
||||
}
|
||||
|
||||
public static final FilterCreatureSpell FILTER_SPELL_A_CREATURE = new FilterCreatureSpell("a creature spell");
|
||||
|
||||
static {
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -0,0 +1,41 @@
|
|||
package mage.filter.common;
|
||||
|
||||
import mage.constants.SubType;
|
||||
import mage.constants.TargetController;
|
||||
import mage.filter.predicate.permanent.ControllerPredicate;
|
||||
|
||||
/*
|
||||
* To change this license header, choose License Headers in Project Properties.
|
||||
* To change this template file, choose Tools | Templates
|
||||
* and open the template in the editor.
|
||||
*/
|
||||
/**
|
||||
*
|
||||
* @author TheElk801
|
||||
*/
|
||||
public class FilterTeamCreaturePermanent extends FilterCreaturePermanent {
|
||||
|
||||
public FilterTeamCreaturePermanent() {
|
||||
this("creature your team controls");
|
||||
}
|
||||
|
||||
public FilterTeamCreaturePermanent(String name) {
|
||||
super(name);
|
||||
this.add(new ControllerPredicate(TargetController.TEAM));
|
||||
|
||||
}
|
||||
|
||||
public FilterTeamCreaturePermanent(SubType subtype, String name) {
|
||||
super(subtype, name);
|
||||
this.add(new ControllerPredicate(TargetController.TEAM));
|
||||
}
|
||||
|
||||
public FilterTeamCreaturePermanent(final FilterTeamCreaturePermanent filter) {
|
||||
super(filter);
|
||||
}
|
||||
|
||||
@Override
|
||||
public FilterTeamCreaturePermanent copy() {
|
||||
return new FilterTeamCreaturePermanent(this);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,42 @@
|
|||
package mage.filter.common;
|
||||
|
||||
import mage.constants.SubType;
|
||||
import mage.constants.TargetController;
|
||||
import mage.filter.FilterPermanent;
|
||||
import mage.filter.predicate.permanent.ControllerPredicate;
|
||||
|
||||
/*
|
||||
* To change this license header, choose License Headers in Project Properties.
|
||||
* To change this template file, choose Tools | Templates
|
||||
* and open the template in the editor.
|
||||
*/
|
||||
/**
|
||||
*
|
||||
* @author TheElk801
|
||||
*/
|
||||
public class FilterTeamPermanent extends FilterPermanent {
|
||||
|
||||
public FilterTeamPermanent() {
|
||||
this("permanent your team controls");
|
||||
}
|
||||
|
||||
public FilterTeamPermanent(String name) {
|
||||
super(name);
|
||||
this.add(new ControllerPredicate(TargetController.TEAM));
|
||||
|
||||
}
|
||||
|
||||
public FilterTeamPermanent(SubType subtype, String name) {
|
||||
super(subtype, name);
|
||||
this.add(new ControllerPredicate(TargetController.TEAM));
|
||||
}
|
||||
|
||||
public FilterTeamPermanent(final FilterTeamPermanent filter) {
|
||||
super(filter);
|
||||
}
|
||||
|
||||
@Override
|
||||
public FilterTeamPermanent copy() {
|
||||
return new FilterTeamPermanent(this);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,56 @@
|
|||
/*
|
||||
* 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.filter.predicate.mageobject;
|
||||
|
||||
import mage.MageObject;
|
||||
import mage.MageObjectReference;
|
||||
import mage.filter.predicate.Predicate;
|
||||
import mage.game.Game;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author TheElk801
|
||||
*/
|
||||
public class MageObjectReferencePredicate implements Predicate<MageObject> {
|
||||
|
||||
private final MageObjectReference mor;
|
||||
|
||||
public MageObjectReferencePredicate(MageObjectReference mor) {
|
||||
this.mor = mor;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean apply(MageObject input, Game game) {
|
||||
return mor.refersTo(input, game);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "MageObjectReference(" + mor.toString() + ')';
|
||||
}
|
||||
}
|
||||
|
|
@ -58,9 +58,14 @@ public class ControllerPredicate implements ObjectPlayerPredicate<ObjectPlayer<C
|
|||
return true;
|
||||
}
|
||||
break;
|
||||
case TEAM:
|
||||
if (!game.getPlayer(playerId).hasOpponent(object.getControllerId(), game)) {
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
case OPPONENT:
|
||||
if (!object.getControllerId().equals(playerId) &&
|
||||
game.getPlayer(playerId).hasOpponent(object.getControllerId(), game)) {
|
||||
if (!object.getControllerId().equals(playerId)
|
||||
&& game.getPlayer(playerId).hasOpponent(object.getControllerId(), game)) {
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
|
|
|
|||
|
|
@ -29,7 +29,6 @@ package mage.game.combat;
|
|||
|
||||
import java.io.Serializable;
|
||||
import java.util.*;
|
||||
|
||||
import mage.abilities.common.ControllerAssignCombatDamageToBlockersAbility;
|
||||
import mage.abilities.common.ControllerDivideCombatDamageAbility;
|
||||
import mage.abilities.common.DamageAsThoughNotBlockedAbility;
|
||||
|
|
@ -178,7 +177,7 @@ public class CombatGroup implements Serializable, Copyable<CombatGroup> {
|
|||
}
|
||||
if (attackers.size() != 1) {
|
||||
multiAttackerDamage(first, game);
|
||||
// } else {
|
||||
// } else {
|
||||
// singleAttackerDamage(first, game);
|
||||
}
|
||||
}
|
||||
|
|
@ -334,7 +333,7 @@ public class CombatGroup implements Serializable, Copyable<CombatGroup> {
|
|||
defenderDamage(attacker, damage, game);
|
||||
} else if (!blockerOrder.isEmpty()) {
|
||||
// Assign the damage left to first blocker
|
||||
assigned.put(blockerOrder.get(0), assigned.get(blockerOrder.get(0)) + damage);
|
||||
assigned.put(blockerOrder.get(0), assigned.get(blockerOrder.get(0)) == null ? 0 : assigned.get(blockerOrder.get(0)) + damage);
|
||||
}
|
||||
}
|
||||
for (UUID blockerId : blockerOrder) {
|
||||
|
|
@ -430,7 +429,7 @@ public class CombatGroup implements Serializable, Copyable<CombatGroup> {
|
|||
}
|
||||
}
|
||||
|
||||
public boolean checkSoleBlockerAfter (Permanent blocker, Game game) {
|
||||
public boolean checkSoleBlockerAfter(Permanent blocker, Game game) {
|
||||
// this solves some corner cases (involving banding) when finding out whether a blocker is blocking alone or not
|
||||
if (blocker.getBlocking() == 1) {
|
||||
if (game.getCombat().blockingGroups.get(blocker.getId()) == null) {
|
||||
|
|
@ -454,9 +453,9 @@ public class CombatGroup implements Serializable, Copyable<CombatGroup> {
|
|||
* {@link #singleBlockerDamage}.
|
||||
*
|
||||
* Handles abilities like "{this} an block any number of creatures.".
|
||||
*
|
||||
* Blocker damage for blockers blocking single creatures is handled in
|
||||
* the single/multi blocker methods, so this shouldn't be used anymore.
|
||||
*
|
||||
* Blocker damage for blockers blocking single creatures is handled in the
|
||||
* single/multi blocker methods, so this shouldn't be used anymore.
|
||||
*
|
||||
* @param first
|
||||
* @param game
|
||||
|
|
@ -782,7 +781,7 @@ public class CombatGroup implements Serializable, Copyable<CombatGroup> {
|
|||
/**
|
||||
* There are effects, that set an attacker to be blocked. Therefore this
|
||||
* setter can be used.
|
||||
*
|
||||
*
|
||||
* This method lacks a band check, use setBlocked(blocked, game) instead.
|
||||
*
|
||||
* @param blocked
|
||||
|
|
@ -870,8 +869,8 @@ public class CombatGroup implements Serializable, Copyable<CombatGroup> {
|
|||
}
|
||||
|
||||
/**
|
||||
* Decides damage distribution for blocking creatures with banding or
|
||||
* if defending player controls the Defensive Formation enchantment.
|
||||
* Decides damage distribution for blocking creatures with banding or if
|
||||
* defending player controls the Defensive Formation enchantment.
|
||||
*
|
||||
* @param game
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -0,0 +1,124 @@
|
|||
/*
|
||||
* 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.game.command.emblems;
|
||||
|
||||
import mage.abilities.Ability;
|
||||
import mage.abilities.TriggeredAbilityImpl;
|
||||
import mage.abilities.effects.OneShotEffect;
|
||||
import mage.abilities.mana.ManaAbility;
|
||||
import mage.constants.Outcome;
|
||||
import mage.constants.Zone;
|
||||
import mage.game.Game;
|
||||
import mage.game.command.Emblem;
|
||||
import mage.game.events.GameEvent;
|
||||
import mage.game.stack.StackAbility;
|
||||
import mage.game.stack.StackObject;
|
||||
import mage.players.Player;
|
||||
import mage.target.targetpointer.FixedTarget;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author TheElk801
|
||||
*/
|
||||
public class RowanKenrithEmblem extends Emblem {
|
||||
// Target player gets an emblem with "Whenever you activate an ability that isn't a mana ability, copy it. You may choose new targets for the copy."
|
||||
|
||||
public RowanKenrithEmblem() {
|
||||
this.setName("Emblem Rowan Kenrith");
|
||||
this.getAbilities().add(new RowanKenrithEmblemTriggeredAbility());
|
||||
}
|
||||
}
|
||||
|
||||
class RowanKenrithEmblemTriggeredAbility extends TriggeredAbilityImpl {
|
||||
|
||||
public RowanKenrithEmblemTriggeredAbility() {
|
||||
super(Zone.COMMAND, new RowanKenrithEmblemCopyEffect(), false);
|
||||
}
|
||||
|
||||
public RowanKenrithEmblemTriggeredAbility(final RowanKenrithEmblemTriggeredAbility ability) {
|
||||
super(ability);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean checkEventType(GameEvent event, Game game) {
|
||||
return event.getType() == GameEvent.EventType.ACTIVATED_ABILITY;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean checkTrigger(GameEvent event, Game game) {
|
||||
if (event.getPlayerId().equals(this.getControllerId())) {
|
||||
StackObject ability = game.getStack().getStackObject(event.getTargetId());
|
||||
if (ability != null && !(ability instanceof ManaAbility)) {
|
||||
this.getEffects().get(0).setTargetPointer(new FixedTarget(ability.getId()));
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getRule() {
|
||||
return "Whenever you activate an ability that isn't a mana ability, copy it. You may choose new targets for the copy.";
|
||||
}
|
||||
|
||||
@Override
|
||||
public RowanKenrithEmblemTriggeredAbility copy() {
|
||||
return new RowanKenrithEmblemTriggeredAbility(this);
|
||||
}
|
||||
}
|
||||
|
||||
class RowanKenrithEmblemCopyEffect extends OneShotEffect {
|
||||
|
||||
public RowanKenrithEmblemCopyEffect() {
|
||||
super(Outcome.Copy);
|
||||
this.staticText = "copy it. You may choose new targets for the copy.";
|
||||
}
|
||||
|
||||
public RowanKenrithEmblemCopyEffect(final RowanKenrithEmblemCopyEffect effect) {
|
||||
super(effect);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean apply(Game game, Ability source) {
|
||||
StackAbility stackAbility = (StackAbility) game.getStack().getStackObject(targetPointer.getFirst(game, source));
|
||||
if (stackAbility != null) {
|
||||
Player controller = game.getPlayer(source.getControllerId());
|
||||
if (controller != null) {
|
||||
stackAbility.createCopyOnStack(game, source, source.getControllerId(), true);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public RowanKenrithEmblemCopyEffect copy() {
|
||||
return new RowanKenrithEmblemCopyEffect(this);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,54 @@
|
|||
/*
|
||||
* 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.game.command.emblems;
|
||||
|
||||
import mage.abilities.common.SpellCastControllerTriggeredAbility;
|
||||
import mage.abilities.effects.common.CopyTargetSpellEffect;
|
||||
import mage.constants.Zone;
|
||||
import mage.filter.StaticFilters;
|
||||
import mage.game.command.Emblem;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author TheElk801
|
||||
*/
|
||||
public class WillKenrithEmblem extends Emblem {
|
||||
// Target player gets an emblem with "Whenever you cast an instant or sorcery spell, copy it. You may choose new targets for the copy."
|
||||
|
||||
public WillKenrithEmblem() {
|
||||
this.setName("Emblem Will Kenrith");
|
||||
this.getAbilities().add(new SpellCastControllerTriggeredAbility(
|
||||
Zone.COMMAND,
|
||||
new CopyTargetSpellEffect(true)
|
||||
.setText("copy that spell. You may choose new targets for the copy"),
|
||||
StaticFilters.FILTER_INSTANT_OR_SORCERY_SPELL,
|
||||
false,
|
||||
true
|
||||
));
|
||||
}
|
||||
}
|
||||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -152,7 +152,7 @@ public abstract class PermanentImpl extends CardImpl implements Permanent {
|
|||
this.blocking = permanent.blocking;
|
||||
this.maxBlocks = permanent.maxBlocks;
|
||||
this.deathtouched = permanent.deathtouched;
|
||||
// this.attachments.addAll(permanent.attachments);
|
||||
|
||||
for (Map.Entry<String, List<UUID>> entry : permanent.connectedCards.entrySet()) {
|
||||
this.connectedCards.put(entry.getKey(), entry.getValue());
|
||||
}
|
||||
|
|
@ -696,7 +696,7 @@ public abstract class PermanentImpl extends CardImpl implements Permanent {
|
|||
for (Iterator<Effect> ite = ability.getEffects(game, EffectType.CONTINUOUS).iterator(); ite.hasNext();) {
|
||||
ContinuousEffect effect = (ContinuousEffect) ite.next();
|
||||
game.getContinuousEffects().setOrder(effect);
|
||||
// It's important is to update timestamp of the copied effect in ContinuousEffects because it does the action
|
||||
// It's important to update the timestamp of the copied effect in ContinuousEffects because it does the action
|
||||
for (ContinuousEffect conEffect : game.getContinuousEffects().getLayeredEffects(game)) {
|
||||
if (conEffect.getId().equals(effect.getId())) {
|
||||
game.getContinuousEffects().setOrder(conEffect);
|
||||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -24,8 +24,7 @@
|
|||
* 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.target.common;
|
||||
|
||||
import mage.constants.Zone;
|
||||
|
|
@ -36,6 +35,7 @@ import mage.game.Game;
|
|||
import mage.target.TargetCard;
|
||||
|
||||
import java.util.UUID;
|
||||
import mage.filter.StaticFilters;
|
||||
import mage.filter.predicate.other.OwnerIdPredicate;
|
||||
|
||||
/**
|
||||
|
|
@ -47,7 +47,7 @@ public class TargetDiscard extends TargetCard {
|
|||
private final UUID playerId;
|
||||
|
||||
public TargetDiscard(UUID playerId) {
|
||||
this(1, 1, new FilterCard(), playerId);
|
||||
this(1, 1, StaticFilters.FILTER_CARD, playerId);
|
||||
}
|
||||
|
||||
public TargetDiscard(FilterCard filter, UUID playerId) {
|
||||
|
|
|
|||
|
|
@ -8,8 +8,12 @@ import java.util.concurrent.ThreadLocalRandom;
|
|||
*/
|
||||
public final class RandomUtil {
|
||||
|
||||
private RandomUtil() {
|
||||
}
|
||||
|
||||
public static Random getRandom() {return ThreadLocalRandom.current();}
|
||||
public static Random getRandom() {
|
||||
return ThreadLocalRandom.current();
|
||||
}
|
||||
|
||||
public static int nextInt() {
|
||||
return ThreadLocalRandom.current().nextInt();
|
||||
|
|
|
|||
|
|
@ -34,6 +34,7 @@ import java.util.UUID;
|
|||
import mage.constants.WatcherScope;
|
||||
import mage.game.Game;
|
||||
import mage.game.events.GameEvent;
|
||||
import mage.players.Player;
|
||||
import mage.watchers.Watcher;
|
||||
|
||||
/*
|
||||
|
|
@ -81,8 +82,9 @@ public class PlayerLostLifeWatcher extends Watcher {
|
|||
public int getAllOppLifeLost(UUID playerId, Game game) {
|
||||
int amount = 0;
|
||||
for (UUID opponentId : this.amountOfLifeLostThisTurn.keySet()) {
|
||||
if (game.getOpponents(playerId).contains(opponentId)) {
|
||||
amount += this.amountOfLifeLostThisTurn.get(playerId);
|
||||
Player opponent = game.getPlayer(opponentId);
|
||||
if (opponent != null && opponent.hasOpponent(playerId, game)) {
|
||||
amount += this.amountOfLifeLostThisTurn.getOrDefault(opponentId, 0);
|
||||
}
|
||||
}
|
||||
return amount;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue