mirror of
https://github.com/magefree/mage.git
synced 2025-12-28 22:42:03 -08:00
* Reworked ENTERS_THE_BATTLEFIELD event for replacement effects. Some rework to card movement.
This commit is contained in:
parent
c642165020
commit
59ef2a2889
247 changed files with 1842 additions and 2287 deletions
|
|
@ -958,6 +958,10 @@ public abstract class AbilityImpl implements Ability {
|
|||
if (object instanceof Permanent) {
|
||||
return false;
|
||||
} else {
|
||||
Permanent permanent = game.getPermanentEntering(getSourceId());
|
||||
if (permanent != null && permanent.getAbilities().contains(this)) {
|
||||
return true;
|
||||
}
|
||||
// check if it's an ability that is temporary gained to a card
|
||||
Abilities<Ability> otherAbilities = game.getState().getAllOtherAbilities(this.getSourceId());
|
||||
if (otherAbilities == null || !otherAbilities.contains(this)) {
|
||||
|
|
|
|||
|
|
@ -71,7 +71,7 @@ public class DiesTriggeredAbility extends ZoneChangeTriggeredAbility {
|
|||
if (super.checkEventType(event, game)) {
|
||||
return ((ZoneChangeEvent) event).getFromZone().equals(Zone.BATTLEFIELD) && ((ZoneChangeEvent) event).getToZone().equals(Zone.GRAVEYARD);
|
||||
}
|
||||
return event.getType() == GameEvent.EventType.ZONE_CHANGE;
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
|||
|
|
@ -40,44 +40,50 @@ import mage.constants.Zone;
|
|||
public class EntersBattlefieldAbility extends StaticAbility {
|
||||
|
||||
protected String abilityRule;
|
||||
protected boolean optional;
|
||||
|
||||
public EntersBattlefieldAbility(Effect effect) {
|
||||
this(effect, true);
|
||||
this(effect, false);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param effect effect that happens when the permanent enters the
|
||||
* battlefield
|
||||
* @param showRule show the rule for this ability
|
||||
* battlefiely
|
||||
* @param optional
|
||||
*/
|
||||
public EntersBattlefieldAbility(Effect effect, Boolean showRule) {
|
||||
this(effect, null, showRule, null, null);
|
||||
public EntersBattlefieldAbility(Effect effect, boolean optional) {
|
||||
this(effect, optional, null, null, null);
|
||||
}
|
||||
|
||||
public EntersBattlefieldAbility(Effect effect, String effectText) {
|
||||
this(effect, null, true, null, effectText);
|
||||
this(effect, null, null, effectText);
|
||||
}
|
||||
|
||||
public EntersBattlefieldAbility(Effect effect, Condition condition, String abilityRule, String effectText) {
|
||||
this(effect, false, condition, abilityRule, effectText);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param effect effect that happens when the permanent enters the
|
||||
* battlefield
|
||||
* @param optional
|
||||
* @param condition only if this condition is true, the effect will happen
|
||||
* @param ruleVisible show the rule for this ability
|
||||
* @param abilityRule rule for this ability (no text from effects will be
|
||||
* added)
|
||||
* @param effectText this text will be used for the EnterBattlefieldEffect
|
||||
*/
|
||||
public EntersBattlefieldAbility(Effect effect, Condition condition, Boolean ruleVisible, String abilityRule, String effectText) {
|
||||
super(Zone.ALL, new EntersBattlefieldEffect(effect, condition, effectText));
|
||||
this.setRuleVisible(ruleVisible);
|
||||
public EntersBattlefieldAbility(Effect effect, boolean optional, Condition condition, String abilityRule, String effectText) {
|
||||
super(Zone.ALL, new EntersBattlefieldEffect(effect, condition, effectText, true, optional));
|
||||
this.abilityRule = abilityRule;
|
||||
this.optional = optional;
|
||||
}
|
||||
|
||||
public EntersBattlefieldAbility(final EntersBattlefieldAbility ability) {
|
||||
super(ability);
|
||||
this.abilityRule = ability.abilityRule;
|
||||
this.optional = ability.optional;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
@ -99,12 +105,9 @@ public class EntersBattlefieldAbility extends StaticAbility {
|
|||
|
||||
@Override
|
||||
public String getRule() {
|
||||
if (!ruleVisible) {
|
||||
return "";
|
||||
}
|
||||
if (abilityRule != null && !abilityRule.isEmpty()) {
|
||||
return abilityRule;
|
||||
}
|
||||
return "{this} enters the battlefield " + super.getRule();
|
||||
return (optional ? "you may have " : "") + "{this} enter" + (optional ? "" : "s") + " the battlefield " + super.getRule();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,30 @@
|
|||
/*
|
||||
* 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.abilities.common;
|
||||
|
||||
import mage.abilities.effects.common.counter.AddCountersSourceEffect;
|
||||
import mage.counters.CounterType;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author LevelX2
|
||||
*/
|
||||
public class PlanswalkerEntersWithLoyalityCountersAbility extends EntersBattlefieldAbility {
|
||||
|
||||
public PlanswalkerEntersWithLoyalityCountersAbility(int loyality) {
|
||||
super(new AddCountersSourceEffect(CounterType.LOYALTY.createInstance(loyality)));
|
||||
setRuleVisible(false);
|
||||
}
|
||||
|
||||
public PlanswalkerEntersWithLoyalityCountersAbility(final PlanswalkerEntersWithLoyalityCountersAbility ability) {
|
||||
super(ability);
|
||||
}
|
||||
|
||||
@Override
|
||||
public EntersBattlefieldAbility copy() {
|
||||
return new PlanswalkerEntersWithLoyalityCountersAbility(this);
|
||||
}
|
||||
}
|
||||
|
|
@ -12,10 +12,14 @@ import mage.watchers.Watcher;
|
|||
* @author Loki
|
||||
*/
|
||||
public class CastFromHandCondition implements Condition {
|
||||
|
||||
@Override
|
||||
public boolean apply(Game game, Ability source) {
|
||||
Permanent p = game.getPermanent(source.getSourceId());
|
||||
if (p != null) {
|
||||
Permanent permanent = game.getPermanent(source.getSourceId());
|
||||
if (permanent == null) {
|
||||
permanent = game.getPermanentEntering(source.getSourceId());
|
||||
}
|
||||
if (permanent != null) {
|
||||
Watcher watcher = game.getState().getWatchers().get("CastFromHand", source.getSourceId());
|
||||
if (watcher != null && watcher.conditionMet()) {
|
||||
return true;
|
||||
|
|
@ -29,5 +33,4 @@ public class CastFromHandCondition implements Condition {
|
|||
return "you cast it from your hand";
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -125,8 +125,6 @@ public class AlternativeCost2Impl<T extends AlternativeCost2Impl<T>> extends Cos
|
|||
activated = true;
|
||||
}
|
||||
|
||||
;
|
||||
|
||||
/**
|
||||
* Reset the activate and count information
|
||||
*
|
||||
|
|
|
|||
|
|
@ -879,7 +879,7 @@ public class ContinuousEffects implements Serializable {
|
|||
// For example: Vesuva copying a Dark Depth (VesuvaTest:testDarkDepth)
|
||||
// This call should be removed if possible as replacement effects of EntersTheBattlefield events
|
||||
// do no longer work correctly because the entering permanents are not yet on the battlefield (before they were).
|
||||
game.applyEffects();
|
||||
// game.applyEffects();
|
||||
} while (true);
|
||||
return caught;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -34,7 +34,6 @@ import mage.abilities.condition.Condition;
|
|||
import mage.constants.Duration;
|
||||
import mage.constants.Zone;
|
||||
import mage.game.Game;
|
||||
import mage.game.events.EntersTheBattlefieldEvent;
|
||||
import mage.game.events.GameEvent;
|
||||
import mage.game.events.GameEvent.EventType;
|
||||
import mage.game.stack.Spell;
|
||||
|
|
@ -52,7 +51,6 @@ public class EntersBattlefieldEffect extends ReplacementEffectImpl {
|
|||
protected Condition condition;
|
||||
protected boolean optional;
|
||||
|
||||
public static final String ENTERING_PERMANENT = "enteringPermanent";
|
||||
public static final String SOURCE_CAST_SPELL_ABILITY = "sourceCastSpellAbility";
|
||||
|
||||
public EntersBattlefieldEffect(Effect baseEffect) {
|
||||
|
|
@ -67,10 +65,6 @@ public class EntersBattlefieldEffect extends ReplacementEffectImpl {
|
|||
this(baseEffect, null, text, true, optional);
|
||||
}
|
||||
|
||||
public EntersBattlefieldEffect(Effect baseEffect, Condition condition, String text) {
|
||||
this(baseEffect, condition, text, true, false);
|
||||
}
|
||||
|
||||
public EntersBattlefieldEffect(Effect baseEffect, Condition condition, String text, boolean selfScope, boolean optional) {
|
||||
super(Duration.WhileOnBattlefield, baseEffect.getOutcome(), selfScope);
|
||||
this.baseEffects.add(baseEffect);
|
||||
|
|
@ -126,18 +120,16 @@ public class EntersBattlefieldEffect extends ReplacementEffectImpl {
|
|||
}
|
||||
}
|
||||
for (Effect effect : baseEffects) {
|
||||
if (source.activate(game, false)) {
|
||||
if (effect instanceof ContinuousEffect) {
|
||||
game.addEffect((ContinuousEffect) effect, source);
|
||||
} else {
|
||||
if (spell != null) {
|
||||
effect.setValue(SOURCE_CAST_SPELL_ABILITY, spell.getSpellAbility());
|
||||
}
|
||||
// Because the permanent is not on the battlefield yet, it has to be taken from the event
|
||||
effect.setValue(ENTERING_PERMANENT, ((EntersTheBattlefieldEvent) event).getTarget());
|
||||
effect.apply(game, source);
|
||||
// if (source.activate(game, false)) { // Why is this needed????
|
||||
if (effect instanceof ContinuousEffect) {
|
||||
game.addEffect((ContinuousEffect) effect, source);
|
||||
} else {
|
||||
if (spell != null) {
|
||||
effect.setValue(SOURCE_CAST_SPELL_ABILITY, spell.getSpellAbility());
|
||||
}
|
||||
effect.apply(game, source);
|
||||
}
|
||||
// }
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -25,7 +25,6 @@
|
|||
* 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.ArrayList;
|
||||
|
|
@ -62,17 +61,17 @@ public class AddManaInAnyCombinationEffect extends ManaEffect {
|
|||
this.amount = amount;
|
||||
this.staticText = setText();
|
||||
}
|
||||
|
||||
|
||||
public AddManaInAnyCombinationEffect(int amount, String text) {
|
||||
this(amount);
|
||||
this.staticText = text;
|
||||
}
|
||||
|
||||
|
||||
public AddManaInAnyCombinationEffect(int amount, String text, ColoredManaSymbol... coloredManaSymbols) {
|
||||
this(amount, coloredManaSymbols);
|
||||
this.staticText = text;
|
||||
}
|
||||
|
||||
|
||||
public AddManaInAnyCombinationEffect(DynamicValue amount, String text, ColoredManaSymbol... coloredManaSymbols) {
|
||||
this(amount, coloredManaSymbols);
|
||||
this.staticText = text;
|
||||
|
|
@ -92,13 +91,13 @@ public class AddManaInAnyCombinationEffect extends ManaEffect {
|
|||
@Override
|
||||
public boolean apply(Game game, Ability source) {
|
||||
Player player = game.getPlayer(source.getControllerId());
|
||||
if (player != null){
|
||||
if (player != null) {
|
||||
Mana mana = new Mana();
|
||||
int amountOfManaLeft = amount.calculate(game, source, this);
|
||||
|
||||
while (amountOfManaLeft > 0 && player.canRespond()) {
|
||||
for (ColoredManaSymbol coloredManaSymbol: manaSymbols) {
|
||||
int number = player.getAmount(0, amountOfManaLeft, new StringBuilder("How many ").append(coloredManaSymbol.name()).append(" mana?").toString(), game);
|
||||
for (ColoredManaSymbol coloredManaSymbol : manaSymbols) {
|
||||
int number = player.getAmount(0, amountOfManaLeft, "How many " + coloredManaSymbol.getColorName() + " mana?", game);
|
||||
if (number > 0) {
|
||||
for (int i = 0; i < number; i++) {
|
||||
mana.add(new Mana(coloredManaSymbol));
|
||||
|
|
@ -111,7 +110,7 @@ public class AddManaInAnyCombinationEffect extends ManaEffect {
|
|||
}
|
||||
}
|
||||
checkToFirePossibleEvents(mana, game, source);
|
||||
player.getManaPool().addMana(mana, game, source);
|
||||
player.getManaPool().addMana(mana, game, source);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
|
|
@ -130,7 +129,7 @@ public class AddManaInAnyCombinationEffect extends ManaEffect {
|
|||
sb.append("colors");
|
||||
} else {
|
||||
int i = 0;
|
||||
for (ColoredManaSymbol coloredManaSymbol: manaSymbols) {
|
||||
for (ColoredManaSymbol coloredManaSymbol : manaSymbols) {
|
||||
i++;
|
||||
if (i > 1) {
|
||||
sb.append(" and/or ");
|
||||
|
|
|
|||
|
|
@ -19,6 +19,7 @@ import mage.filter.common.FilterCreatureCard;
|
|||
import mage.filter.predicate.Predicates;
|
||||
import mage.filter.predicate.mageobject.SubtypePredicate;
|
||||
import mage.game.Game;
|
||||
import mage.game.events.EntersTheBattlefieldEvent;
|
||||
import mage.game.events.GameEvent;
|
||||
import mage.game.permanent.Permanent;
|
||||
import mage.players.Player;
|
||||
|
|
@ -27,15 +28,13 @@ import mage.target.common.TargetCardInHand;
|
|||
/**
|
||||
* Effect for the AmplifyAbility
|
||||
*
|
||||
* 702.37. Amplify
|
||||
* 702.37a Amplify is a static ability. “Amplify N” means “As
|
||||
* this object enters the battlefield, reveal any number of cards from your hand
|
||||
* that share a creature type with it. This permanent enters the battlefield
|
||||
* with N +1/+1 counters on it for each card revealed this way. You can’t reveal
|
||||
* this card or any other cards that are entering the battlefield at the same
|
||||
* time as this card.”
|
||||
* 702.37b If a creature has multiple instances of amplify,
|
||||
* each one works separately.
|
||||
* 702.37. Amplify 702.37a Amplify is a static ability. “Amplify N” means “As
|
||||
* this object enters the battlefield, reveal any number of cards from your hand
|
||||
* that share a creature type with it. This permanent enters the battlefield
|
||||
* with N +1/+1 counters on it for each card revealed this way. You can’t reveal
|
||||
* this card or any other cards that are entering the battlefield at the same
|
||||
* time as this card.” 702.37b If a creature has multiple instances of amplify,
|
||||
* each one works separately.
|
||||
*
|
||||
*
|
||||
* @author FenrisulfrX
|
||||
|
|
@ -45,6 +44,7 @@ public class AmplifyEffect extends ReplacementEffectImpl {
|
|||
private final AmplifyFactor amplifyFactor;
|
||||
|
||||
public enum AmplifyFactor {
|
||||
|
||||
Amplify1("Amplify 1", "put one +1/+1 counters on it", 1),
|
||||
Amplify2("Amplify 2", "put two +1/+1 counters on it", 2),
|
||||
Amplify3("Amplify 3", "put three +1/+1 counters on it", 3);
|
||||
|
|
@ -95,7 +95,7 @@ public class AmplifyEffect extends ReplacementEffectImpl {
|
|||
|
||||
@Override
|
||||
public boolean replaceEvent(GameEvent event, Ability source, Game game) {
|
||||
Permanent sourceCreature = game.getPermanent(event.getTargetId());
|
||||
Permanent sourceCreature = ((EntersTheBattlefieldEvent) event).getTarget();
|
||||
Player controller = game.getPlayer(source.getControllerId());
|
||||
if (controller != null && sourceCreature != null) {
|
||||
FilterCreatureCard filter = new FilterCreatureCard("creatures cards to reveal");
|
||||
|
|
@ -108,7 +108,7 @@ public class AmplifyEffect extends ReplacementEffectImpl {
|
|||
} else if (filterSubtypes.size() == 1) {
|
||||
filter.add(filterSubtypes.get(0));
|
||||
}
|
||||
if (controller.getHand().count(filter, source.getSourceId(), source.getControllerId(), game) > 0){
|
||||
if (controller.getHand().count(filter, source.getSourceId(), source.getControllerId(), game) > 0) {
|
||||
if (controller.chooseUse(outcome, "Reveal cards to Amplify?", source, game)) {
|
||||
TargetCardInHand target = new TargetCardInHand(0, Integer.MAX_VALUE, filter);
|
||||
if (controller.chooseTarget(outcome, target, source, game) && !target.getTargets().isEmpty()) {
|
||||
|
|
@ -128,11 +128,11 @@ public class AmplifyEffect extends ReplacementEffectImpl {
|
|||
public String getText(Mode mode) {
|
||||
StringBuilder sb = new StringBuilder(amplifyFactor.toString());
|
||||
sb.append("<i>(As this enter the battlefield, ");
|
||||
sb.append(amplifyFactor.getRuleText()).append(" for each card" +
|
||||
" you reveal that shares a type with it in your hand.)</i>");
|
||||
sb.append(amplifyFactor.getRuleText()).append(" for each card"
|
||||
+ " you reveal that shares a type with it in your hand.)</i>");
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public AmplifyEffect copy() {
|
||||
return new AmplifyEffect(this);
|
||||
|
|
|
|||
|
|
@ -7,7 +7,6 @@ package mage.abilities.effects.common;
|
|||
|
||||
import mage.MageObject;
|
||||
import mage.abilities.Ability;
|
||||
import mage.abilities.effects.EntersBattlefieldEffect;
|
||||
import mage.abilities.effects.OneShotEffect;
|
||||
import mage.choices.ChoiceImpl;
|
||||
import mage.constants.Outcome;
|
||||
|
|
@ -41,7 +40,7 @@ public class ChooseBasicLandTypeEffect extends OneShotEffect {
|
|||
@Override
|
||||
public boolean apply(Game game, Ability source) {
|
||||
Player controller = game.getPlayer(source.getControllerId());
|
||||
MageObject mageObject = (Permanent) getValue(EntersBattlefieldEffect.ENTERING_PERMANENT);
|
||||
MageObject mageObject = game.getPermanentEntering(source.getSourceId());
|
||||
if (mageObject == null) {
|
||||
mageObject = game.getObject(source.getSourceId());
|
||||
}
|
||||
|
|
|
|||
|
|
@ -29,7 +29,6 @@ package mage.abilities.effects.common;
|
|||
|
||||
import mage.MageObject;
|
||||
import mage.abilities.Ability;
|
||||
import mage.abilities.effects.EntersBattlefieldEffect;
|
||||
import mage.abilities.effects.OneShotEffect;
|
||||
import mage.choices.ChoiceColor;
|
||||
import mage.constants.Outcome;
|
||||
|
|
@ -56,7 +55,7 @@ public class ChooseColorEffect extends OneShotEffect {
|
|||
@Override
|
||||
public boolean apply(Game game, Ability source) {
|
||||
Player controller = game.getPlayer(source.getControllerId());
|
||||
MageObject mageObject = (Permanent) getValue(EntersBattlefieldEffect.ENTERING_PERMANENT);
|
||||
MageObject mageObject = game.getPermanentEntering(source.getSourceId());
|
||||
if (mageObject == null) {
|
||||
mageObject = game.getObject(source.getSourceId());
|
||||
}
|
||||
|
|
|
|||
|
|
@ -29,7 +29,6 @@ package mage.abilities.effects.common;
|
|||
|
||||
import mage.MageObject;
|
||||
import mage.abilities.Ability;
|
||||
import mage.abilities.effects.EntersBattlefieldEffect;
|
||||
import mage.abilities.effects.OneShotEffect;
|
||||
import mage.cards.repository.CardRepository;
|
||||
import mage.choices.Choice;
|
||||
|
|
@ -58,7 +57,7 @@ public class ChooseCreatureTypeEffect extends OneShotEffect {
|
|||
@Override
|
||||
public boolean apply(Game game, Ability source) {
|
||||
Player controller = game.getPlayer(source.getControllerId());
|
||||
MageObject mageObject = (Permanent) getValue(EntersBattlefieldEffect.ENTERING_PERMANENT);
|
||||
MageObject mageObject = game.getPermanentEntering(source.getSourceId());
|
||||
if (mageObject == null) {
|
||||
mageObject = game.getObject(source.getSourceId());
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,7 +7,6 @@ package mage.abilities.effects.common;
|
|||
|
||||
import mage.MageObject;
|
||||
import mage.abilities.Ability;
|
||||
import mage.abilities.effects.EntersBattlefieldEffect;
|
||||
import mage.abilities.effects.OneShotEffect;
|
||||
import mage.cards.repository.CardRepository;
|
||||
import mage.choices.Choice;
|
||||
|
|
@ -36,7 +35,7 @@ public class ChooseLandTypeEffect extends OneShotEffect {
|
|||
@Override
|
||||
public boolean apply(Game game, Ability source) {
|
||||
Player controller = game.getPlayer(source.getControllerId());
|
||||
MageObject mageObject = (Permanent) getValue(EntersBattlefieldEffect.ENTERING_PERMANENT);
|
||||
MageObject mageObject = game.getPermanentEntering(source.getSourceId());
|
||||
if (mageObject == null) {
|
||||
mageObject = game.getObject(source.getSourceId());
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,7 +7,6 @@ package mage.abilities.effects.common;
|
|||
|
||||
import mage.MageObject;
|
||||
import mage.abilities.Ability;
|
||||
import mage.abilities.effects.EntersBattlefieldEffect;
|
||||
import mage.abilities.effects.OneShotEffect;
|
||||
import mage.constants.Outcome;
|
||||
import mage.game.Game;
|
||||
|
|
@ -41,7 +40,7 @@ public class ChooseOpponentEffect extends OneShotEffect {
|
|||
@Override
|
||||
public boolean apply(Game game, Ability source) {
|
||||
Player controller = game.getPlayer(source.getControllerId());
|
||||
MageObject mageObject = (Permanent) getValue(EntersBattlefieldEffect.ENTERING_PERMANENT);
|
||||
MageObject mageObject = game.getPermanentEntering(source.getSourceId());
|
||||
if (mageObject == null) {
|
||||
mageObject = game.getObject(source.getSourceId());
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,7 +7,6 @@ package mage.abilities.effects.common;
|
|||
|
||||
import mage.MageObject;
|
||||
import mage.abilities.Ability;
|
||||
import mage.abilities.effects.EntersBattlefieldEffect;
|
||||
import mage.abilities.effects.OneShotEffect;
|
||||
import mage.constants.Outcome;
|
||||
import mage.game.Game;
|
||||
|
|
@ -39,7 +38,7 @@ public class ChoosePlayerEffect extends OneShotEffect {
|
|||
@Override
|
||||
public boolean apply(Game game, Ability source) {
|
||||
Player controller = game.getPlayer(source.getControllerId());
|
||||
MageObject mageObject = (Permanent) getValue(EntersBattlefieldEffect.ENTERING_PERMANENT);
|
||||
MageObject mageObject = game.getPermanentEntering(source.getSourceId());
|
||||
if (mageObject == null) {
|
||||
mageObject = game.getObject(source.getSourceId());
|
||||
}
|
||||
|
|
|
|||
|
|
@ -33,6 +33,7 @@ import mage.MageObjectReference;
|
|||
import mage.abilities.Ability;
|
||||
import mage.abilities.effects.ContinuousEffectImpl;
|
||||
import mage.cards.Card;
|
||||
import mage.constants.AbilityType;
|
||||
import mage.constants.CardType;
|
||||
import mage.constants.Duration;
|
||||
import mage.constants.Layer;
|
||||
|
|
@ -54,10 +55,10 @@ public class CopyEffect extends ContinuousEffectImpl {
|
|||
/**
|
||||
* Object we copy from
|
||||
*/
|
||||
private MageObject copyFromObject;
|
||||
protected MageObject copyFromObject;
|
||||
|
||||
private UUID copyToObjectId;
|
||||
private ApplyToPermanent applier;
|
||||
protected UUID copyToObjectId;
|
||||
protected ApplyToPermanent applier;
|
||||
|
||||
public CopyEffect(MageObject copyFromObject, UUID copyToObjectId) {
|
||||
this(Duration.Custom, copyFromObject, copyToObjectId);
|
||||
|
|
@ -82,14 +83,23 @@ public class CopyEffect extends ContinuousEffectImpl {
|
|||
if (!(copyFromObject instanceof Permanent) && (copyFromObject instanceof Card)) {
|
||||
this.copyFromObject = new PermanentCard((Card) copyFromObject, source.getControllerId(), game);
|
||||
}
|
||||
|
||||
Permanent permanent = game.getPermanent(copyToObjectId);
|
||||
if (permanent != null) {
|
||||
affectedObjectList.add(new MageObjectReference(permanent, game));
|
||||
} else if (source.getAbilityType().equals(AbilityType.STATIC)) {
|
||||
// for replacement effects that let a permanent enter the battlefield as a copy of another permanent we need to apply that copy
|
||||
// before the permanent is added to the battlefield
|
||||
permanent = game.getPermanentEntering(copyToObjectId);
|
||||
if (permanent != null) {
|
||||
copyToPermanent(permanent, game, source);
|
||||
// set reference to the permanent later on the battlefield so we have to add already one to the zone change counter
|
||||
affectedObjectList.add(new MageObjectReference(permanent.getId(), game.getState().getZoneChangeCounter(copyToObjectId) + 1, game));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean apply(Game game, Ability source) {
|
||||
if (affectedObjectList.isEmpty()) {
|
||||
affectedObjectList.add(new MageObjectReference(getSourceId(), game));
|
||||
}
|
||||
Permanent permanent = affectedObjectList.get(0).getPermanent(game);
|
||||
if (permanent == null) {
|
||||
permanent = (Permanent) game.getLastKnownInformation(getSourceId(), Zone.BATTLEFIELD, source.getSourceObjectZoneChangeCounter());
|
||||
|
|
@ -99,6 +109,10 @@ public class CopyEffect extends ContinuousEffectImpl {
|
|||
return false;
|
||||
}
|
||||
}
|
||||
return copyToPermanent(permanent, game, source);
|
||||
}
|
||||
|
||||
protected boolean copyToPermanent(Permanent permanent, Game game, Ability source) {
|
||||
permanent.setCopy(true);
|
||||
permanent.setName(copyFromObject.getName());
|
||||
permanent.getColor(game).setColor(copyFromObject.getColor(game));
|
||||
|
|
|
|||
|
|
@ -73,7 +73,7 @@ public class CopyPermanentEffect extends OneShotEffect {
|
|||
this.applier = applier;
|
||||
this.filter = filter;
|
||||
this.useTargetOfAbility = useTarget;
|
||||
this.staticText = "You may have {this} enter the battlefield as a copy of any " + filter.getMessage() + " on the battlefield";
|
||||
this.staticText = "as a copy of any " + filter.getMessage() + " on the battlefield";
|
||||
}
|
||||
|
||||
public CopyPermanentEffect(final CopyPermanentEffect effect) {
|
||||
|
|
@ -87,7 +87,10 @@ public class CopyPermanentEffect extends OneShotEffect {
|
|||
@Override
|
||||
public boolean apply(Game game, Ability source) {
|
||||
Player player = game.getPlayer(source.getControllerId());
|
||||
MageObject sourceObject = game.getObject(source.getSourceId());
|
||||
MageObject sourceObject = game.getPermanentEntering(source.getSourceId());
|
||||
if (sourceObject == null) {
|
||||
sourceObject = game.getObject(source.getSourceId());
|
||||
}
|
||||
if (player != null && sourceObject != null) {
|
||||
Permanent copyFromPermanent = null;
|
||||
if (useTargetOfAbility) {
|
||||
|
|
|
|||
|
|
@ -47,30 +47,32 @@ import mage.target.common.TargetControlledCreaturePermanent;
|
|||
|
||||
/**
|
||||
* Effect for the DevourAbility
|
||||
*
|
||||
* 702.81. Devour
|
||||
* 702.81a Devour is a static ability. "Devour N" means "As this object enters the battlefield,
|
||||
* you may sacrifice any number of creatures. This permanent enters the battlefield with N +1/+1
|
||||
* counters on it for each creature sacrificed this way."
|
||||
* 702.81b Some objects have abilities that refer to the number of creatures the permanent devoured.
|
||||
* "It devoured" means "sacrificed as a result of its devour ability as it entered the battlefield."
|
||||
*
|
||||
*
|
||||
* 702.81. Devour 702.81a Devour is a static ability. "Devour N" means "As this
|
||||
* object enters the battlefield, you may sacrifice any number of creatures.
|
||||
* This permanent enters the battlefield with N +1/+1 counters on it for each
|
||||
* creature sacrificed this way." 702.81b Some objects have abilities that refer
|
||||
* to the number of creatures the permanent devoured. "It devoured" means
|
||||
* "sacrificed as a result of its devour ability as it entered the battlefield."
|
||||
*
|
||||
*
|
||||
* @author LevelX2
|
||||
*/
|
||||
public class DevourEffect extends ReplacementEffectImpl {
|
||||
|
||||
private static final FilterControlledCreaturePermanent filter = new FilterControlledCreaturePermanent("creatures to devour");
|
||||
|
||||
static {
|
||||
filter.add(new AnotherPredicate());
|
||||
}
|
||||
private final DevourFactor devourFactor;
|
||||
|
||||
public enum DevourFactor {
|
||||
Devour1 ("Devour 1", "that many +1/+1 counters on it", 1),
|
||||
Devour2 ("Devour 2", "twice that many +1/+1 counters on it", 2),
|
||||
Devour3 ("Devour 3", "three times that many +1/+1 counters on it", 3),
|
||||
DevourX ("Devour X, where X is the number of creatures devoured this way", "X +1/+1 counters on it for each of those creatures", Integer.MAX_VALUE);
|
||||
|
||||
Devour1("Devour 1", "that many +1/+1 counters on it", 1),
|
||||
Devour2("Devour 2", "twice that many +1/+1 counters on it", 2),
|
||||
Devour3("Devour 3", "three times that many +1/+1 counters on it", 3),
|
||||
DevourX("Devour X, where X is the number of creatures devoured this way", "X +1/+1 counters on it for each of those creatures", Integer.MAX_VALUE);
|
||||
|
||||
private final String text;
|
||||
private final String ruleText;
|
||||
|
|
@ -114,9 +116,9 @@ public class DevourEffect extends ReplacementEffectImpl {
|
|||
@Override
|
||||
public boolean applies(GameEvent event, Ability source, Game game) {
|
||||
if (event.getTargetId().equals(source.getSourceId())) {
|
||||
Permanent sourcePermanent = game.getPermanent(source.getSourceId());
|
||||
game.getState().setValue(sourcePermanent.getId().toString() + "devoured", null);
|
||||
return true;
|
||||
Permanent sourcePermanent = game.getPermanentEntering(source.getSourceId());
|
||||
game.getState().setValue(sourcePermanent.getId().toString() + "devoured", null);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
|
@ -128,7 +130,7 @@ public class DevourEffect extends ReplacementEffectImpl {
|
|||
|
||||
@Override
|
||||
public boolean replaceEvent(GameEvent event, Ability source, Game game) {
|
||||
Permanent creature = game.getPermanent(event.getTargetId());
|
||||
Permanent creature = game.getPermanentEntering(event.getTargetId());
|
||||
Player controller = game.getPlayer(source.getControllerId());
|
||||
if (creature != null && controller != null) {
|
||||
Target target = new TargetControlledCreaturePermanent(1, Integer.MAX_VALUE, filter, true);
|
||||
|
|
@ -141,9 +143,10 @@ public class DevourEffect extends ReplacementEffectImpl {
|
|||
if (target.getTargets().size() > 0) {
|
||||
List<ArrayList<String>> cardSubtypes = new ArrayList<>();
|
||||
int devouredCreatures = target.getTargets().size();
|
||||
if (!game.isSimulation())
|
||||
game.informPlayers(new StringBuilder(creature.getName()).append(" devours ").append(devouredCreatures).append(" creatures").toString());
|
||||
for (UUID targetId: target.getTargets()) {
|
||||
if (!game.isSimulation()) {
|
||||
game.informPlayers(creature.getLogName() + " devours " + devouredCreatures + " creatures");
|
||||
}
|
||||
for (UUID targetId : target.getTargets()) {
|
||||
Permanent targetCreature = game.getPermanent(targetId);
|
||||
if (targetCreature != null) {
|
||||
cardSubtypes.add((ArrayList<String>) targetCreature.getSubtype());
|
||||
|
|
@ -172,7 +175,7 @@ public class DevourEffect extends ReplacementEffectImpl {
|
|||
StringBuilder sb = new StringBuilder(devourFactor.toString());
|
||||
sb.append(" <i>(As this enters the battlefield, you may sacrifice any number of creatures. This creature enters the battlefield with ");
|
||||
sb.append(devourFactor.getRuleText()).append(")</i>");
|
||||
return sb.toString();
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
public List<ArrayList<String>> getSubtypes(Game game, UUID permanentId) {
|
||||
|
|
|
|||
|
|
@ -34,8 +34,8 @@ import mage.constants.Duration;
|
|||
import mage.constants.Outcome;
|
||||
import mage.constants.Zone;
|
||||
import mage.game.Game;
|
||||
import mage.game.events.GameEvent.EventType;
|
||||
import mage.game.events.GameEvent;
|
||||
import mage.game.events.GameEvent.EventType;
|
||||
import mage.game.events.ZoneChangeEvent;
|
||||
import mage.game.stack.StackObject;
|
||||
import mage.players.Player;
|
||||
|
|
@ -85,7 +85,7 @@ public class DiscardOntoBattlefieldEffect extends ReplacementEffectImpl {
|
|||
if (card != null) {
|
||||
Player owner = game.getPlayer(card.getOwnerId());
|
||||
if (owner != null) {
|
||||
if (owner.putOntoBattlefieldWithInfo(card, game, Zone.HAND, source.getSourceId())) {
|
||||
if (owner.moveCards(card, Zone.BATTLEFIELD, source, game)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -31,6 +31,7 @@ import mage.abilities.Ability;
|
|||
import mage.abilities.SpellAbility;
|
||||
import mage.abilities.effects.EntersBattlefieldEffect;
|
||||
import mage.abilities.effects.OneShotEffect;
|
||||
import mage.constants.AbilityType;
|
||||
import mage.constants.Outcome;
|
||||
import mage.counters.Counter;
|
||||
import mage.game.Game;
|
||||
|
|
@ -60,13 +61,15 @@ public class EntersBattlefieldWithXCountersEffect extends OneShotEffect {
|
|||
public boolean apply(Game game, Ability source) {
|
||||
Permanent permanent = game.getPermanent(source.getSourceId());
|
||||
if (permanent == null) {
|
||||
permanent = (Permanent) getValue(EntersBattlefieldEffect.ENTERING_PERMANENT);
|
||||
if (permanent == null && source.getAbilityType().equals(AbilityType.STATIC)) {
|
||||
permanent = game.getPermanentEntering(source.getSourceId());
|
||||
}
|
||||
}
|
||||
if (permanent != null) {
|
||||
SpellAbility spellAbility = (SpellAbility) getValue(EntersBattlefieldEffect.SOURCE_CAST_SPELL_ABILITY);
|
||||
if (spellAbility != null
|
||||
&& spellAbility.getSourceId().equals(source.getSourceId())
|
||||
&& permanent.getZoneChangeCounter(game) - 1 == spellAbility.getSourceObjectZoneChangeCounter()) {
|
||||
&& permanent.getZoneChangeCounter(game) == spellAbility.getSourceObjectZoneChangeCounter()) {
|
||||
if (spellAbility.getSourceId().equals(source.getSourceId())) { // put into play by normal cast
|
||||
int amount = spellAbility.getManaCostsToPay().getX();
|
||||
if (amount > 0) {
|
||||
|
|
|
|||
|
|
@ -66,7 +66,7 @@ public class ExileAndReturnTransformedSourceEffect extends OneShotEffect {
|
|||
Player owner = game.getPlayer(card.getOwnerId());
|
||||
if (owner != null) {
|
||||
game.getState().setValue(TransformAbility.VALUE_KEY_ENTER_TRANSFORMED + source.getSourceId(), Boolean.TRUE);
|
||||
owner.putOntoBattlefieldWithInfo(card, game, Zone.EXILED, source.getSourceId());
|
||||
owner.moveCards(card, Zone.BATTLEFIELD, source, game);
|
||||
if (additionalEffect != null) {
|
||||
if (additionalEffect instanceof ContinuousEffect) {
|
||||
game.addEffect((ContinuousEffect) additionalEffect, source);
|
||||
|
|
|
|||
|
|
@ -29,7 +29,6 @@
|
|||
*/
|
||||
package mage.abilities.effects.common;
|
||||
|
||||
import java.util.UUID;
|
||||
import mage.abilities.Ability;
|
||||
import mage.abilities.Mode;
|
||||
import mage.abilities.dynamicvalue.DynamicValue;
|
||||
|
|
@ -128,28 +127,13 @@ public class LookLibraryAndPickControllerEffect extends LookLibraryControllerEff
|
|||
if (!optional || player.chooseUse(Outcome.DrawCard, getMayText(), source, game)) {
|
||||
FilterCard pickFilter = filter.copy();
|
||||
pickFilter.setMessage(getPickText());
|
||||
TargetCard target = new TargetCard((upTo ? 0 : numberToPick.calculate(game, source, this)), numberToPick.calculate(game, source, this), Zone.PICK, pickFilter);
|
||||
TargetCard target = new TargetCard((upTo ? 0 : numberToPick.calculate(game, source, this)), numberToPick.calculate(game, source, this), Zone.LIBRARY, pickFilter);
|
||||
if (player.choose(Outcome.DrawCard, cards, target, game)) {
|
||||
Cards reveal = new CardsImpl();
|
||||
for (UUID cardId : target.getTargets()) {
|
||||
Card card = cards.get(cardId, game);
|
||||
if (card != null) {
|
||||
cards.remove(card);
|
||||
if (targetZoneLookedCards.equals(Zone.BATTLEFIELD)) {
|
||||
player.putOntoBattlefieldWithInfo(card, game, Zone.LIBRARY, source.getSourceId());
|
||||
} else {
|
||||
card.moveToZone(targetPickedCards, source.getSourceId(), game, false);
|
||||
if (!game.isSimulation()) {
|
||||
game.informPlayers(player.getLogName() + " moves a card to " + targetPickedCards.toString().toLowerCase());
|
||||
}
|
||||
}
|
||||
if (revealPickedCards) {
|
||||
reveal.add(card);
|
||||
}
|
||||
}
|
||||
}
|
||||
Cards pickedCards = new CardsImpl(target.getTargets());
|
||||
cards.removeAll(pickedCards);
|
||||
player.moveCards(pickedCards.getCards(game), targetPickedCards, source, game);
|
||||
if (revealPickedCards) {
|
||||
player.revealCards(windowName, reveal, game);
|
||||
player.revealCards(windowName, pickedCards, game);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -29,7 +29,6 @@ package mage.abilities.effects.common;
|
|||
|
||||
import mage.MageObject;
|
||||
import mage.abilities.Ability;
|
||||
import mage.abilities.effects.EntersBattlefieldEffect;
|
||||
import mage.abilities.effects.OneShotEffect;
|
||||
import mage.cards.repository.CardRepository;
|
||||
import mage.choices.Choice;
|
||||
|
|
@ -72,7 +71,7 @@ public class NameACardEffect extends OneShotEffect {
|
|||
@Override
|
||||
public boolean apply(Game game, Ability source) {
|
||||
Player controller = game.getPlayer(source.getControllerId());
|
||||
MageObject sourceObject = (Permanent) getValue(EntersBattlefieldEffect.ENTERING_PERMANENT);
|
||||
MageObject sourceObject = game.getPermanentEntering(source.getSourceId());
|
||||
if (sourceObject == null) {
|
||||
game.getObject(source.getSourceId());
|
||||
}
|
||||
|
|
|
|||
|
|
@ -48,10 +48,9 @@ public class PutPermanentOnBattlefieldEffect extends OneShotEffect {
|
|||
@Override
|
||||
public boolean apply(Game game, Ability source) {
|
||||
Player player;
|
||||
if(useTargetController) {
|
||||
if (useTargetController) {
|
||||
player = game.getPlayer(getTargetPointer().getFirst(game, source));
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
player = game.getPlayer(source.getControllerId());
|
||||
}
|
||||
String choiceText = "Put " + filter.getMessage() + " from your hand onto the battlefield?";
|
||||
|
|
@ -63,23 +62,21 @@ public class PutPermanentOnBattlefieldEffect extends OneShotEffect {
|
|||
if (player.choose(Outcome.PutCreatureInPlay, target, source.getSourceId(), game)) {
|
||||
Card card = game.getCard(target.getFirstTarget());
|
||||
if (card != null) {
|
||||
player.putOntoBattlefieldWithInfo(card, game, Zone.HAND, source.getSourceId());
|
||||
return true;
|
||||
return player.moveCards(card, Zone.BATTLEFIELD, source, game);
|
||||
}
|
||||
}
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getText(Mode mode) {
|
||||
if(this.staticText != null && !this.staticText.isEmpty()) {
|
||||
if (this.staticText != null && !this.staticText.isEmpty()) {
|
||||
return staticText;
|
||||
}
|
||||
|
||||
if(useTargetController) {
|
||||
if (useTargetController) {
|
||||
return "that player may put " + filter.getMessage() + " from his or her hand onto the battlefield";
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
return "you may put " + filter.getMessage() + " from your hand onto the battlefield";
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -88,8 +88,7 @@ public class ReturnToBattlefieldUnderYourControlTargetEffect extends OneShotEffe
|
|||
card = game.getCard(getTargetPointer().getFirst(game, source));
|
||||
}
|
||||
if (card != null) {
|
||||
Zone currentZone = game.getState().getZone(card.getId());
|
||||
controller.putOntoBattlefieldWithInfo(card, game, currentZone, source.getSourceId());
|
||||
controller.moveCards(card, Zone.BATTLEFIELD, source, game);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -28,7 +28,6 @@
|
|||
package mage.abilities.effects.common;
|
||||
|
||||
import mage.abilities.Ability;
|
||||
import mage.abilities.effects.EntersBattlefieldEffect;
|
||||
import mage.abilities.effects.OneShotEffect;
|
||||
import mage.constants.Outcome;
|
||||
import mage.game.Game;
|
||||
|
|
@ -66,7 +65,7 @@ public class TapSourceEffect extends OneShotEffect {
|
|||
public boolean apply(Game game, Ability source) {
|
||||
Permanent permanent = game.getPermanent(source.getSourceId());
|
||||
if (permanent == null) {
|
||||
permanent = (Permanent) getValue(EntersBattlefieldEffect.ENTERING_PERMANENT);
|
||||
permanent = game.getPermanentEntering(source.getSourceId());
|
||||
}
|
||||
if (permanent != null) {
|
||||
if (withoutTrigger) {
|
||||
|
|
|
|||
|
|
@ -29,8 +29,8 @@ package mage.abilities.effects.common;
|
|||
|
||||
import mage.abilities.Ability;
|
||||
import mage.abilities.costs.Cost;
|
||||
import mage.abilities.effects.EntersBattlefieldEffect;
|
||||
import mage.abilities.effects.OneShotEffect;
|
||||
import mage.constants.AbilityType;
|
||||
import mage.constants.Outcome;
|
||||
import mage.game.Game;
|
||||
import mage.game.permanent.Permanent;
|
||||
|
|
@ -59,8 +59,8 @@ public class TapSourceUnlessPaysEffect extends OneShotEffect {
|
|||
public boolean apply(Game game, Ability source) {
|
||||
Player player = game.getPlayer(source.getControllerId());
|
||||
Permanent permanent = game.getPermanent(source.getSourceId());
|
||||
if (permanent == null) {
|
||||
permanent = (Permanent) getValue(EntersBattlefieldEffect.ENTERING_PERMANENT);
|
||||
if (permanent == null && source.getAbilityType().equals(AbilityType.STATIC)) {
|
||||
permanent = game.getPermanentEntering(source.getSourceId());
|
||||
}
|
||||
if (player != null && permanent != null) {
|
||||
if (cost.canPay(source, source.getSourceId(), source.getControllerId(), game)
|
||||
|
|
|
|||
|
|
@ -30,7 +30,6 @@ package mage.abilities.effects.common.continuous;
|
|||
import mage.MageObjectReference;
|
||||
import mage.abilities.Ability;
|
||||
import mage.abilities.effects.ContinuousEffectImpl;
|
||||
import mage.abilities.effects.EntersBattlefieldEffect;
|
||||
import mage.cards.Card;
|
||||
import mage.constants.Duration;
|
||||
import mage.constants.Layer;
|
||||
|
|
@ -94,7 +93,7 @@ public class GainAbilitySourceEffect extends ContinuousEffectImpl implements Sou
|
|||
public void init(Ability source, Game game) {
|
||||
super.init(source, game);
|
||||
if (affectedObjectsSet) {
|
||||
Permanent permanent = (Permanent) getValue(EntersBattlefieldEffect.ENTERING_PERMANENT);
|
||||
Permanent permanent = game.getPermanentEntering(source.getSourceId());
|
||||
if (permanent != null) {
|
||||
affectedObjectList.add(new MageObjectReference(source.getSourceId(), game.getState().getZoneChangeCounter(source.getSourceId()) + 1, game));
|
||||
} else {
|
||||
|
|
|
|||
|
|
@ -30,9 +30,9 @@ package mage.abilities.effects.common.counter;
|
|||
import mage.abilities.Ability;
|
||||
import mage.abilities.dynamicvalue.DynamicValue;
|
||||
import mage.abilities.dynamicvalue.common.StaticValue;
|
||||
import mage.abilities.effects.EntersBattlefieldEffect;
|
||||
import mage.abilities.effects.OneShotEffect;
|
||||
import mage.cards.Card;
|
||||
import mage.constants.AbilityType;
|
||||
import mage.constants.Outcome;
|
||||
import mage.counters.Counter;
|
||||
import mage.game.Game;
|
||||
|
|
@ -115,8 +115,8 @@ public class AddCountersSourceEffect extends OneShotEffect {
|
|||
}
|
||||
} else {
|
||||
Permanent permanent = game.getPermanent(source.getSourceId());
|
||||
if (permanent == null) {
|
||||
permanent = (Permanent) getValue(EntersBattlefieldEffect.ENTERING_PERMANENT);
|
||||
if (permanent == null && source.getAbilityType().equals(AbilityType.STATIC)) {
|
||||
permanent = game.getPermanentEntering(source.getSourceId());
|
||||
}
|
||||
if (permanent != null) {
|
||||
if (counter != null) {
|
||||
|
|
|
|||
|
|
@ -39,13 +39,13 @@ import mage.constants.Zone;
|
|||
public class AmplifyAbility extends SimpleStaticAbility {
|
||||
|
||||
public AmplifyAbility(AmplifyFactor amplifyFactor) {
|
||||
super(Zone.BATTLEFIELD, new AmplifyEffect(amplifyFactor));
|
||||
super(Zone.ALL, new AmplifyEffect(amplifyFactor));
|
||||
}
|
||||
|
||||
|
||||
public AmplifyAbility(final AmplifyAbility ability) {
|
||||
super(ability);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public AmplifyAbility copy() {
|
||||
return new AmplifyAbility(this);
|
||||
|
|
|
|||
|
|
@ -104,9 +104,9 @@ class AuraSwapEffect extends OneShotEffect {
|
|||
if (controller.choose(Outcome.PutCardInPlay, target, source.getSourceId(), game)) {
|
||||
Card auraInHand = game.getCard(target.getFirstTarget());
|
||||
if (auraInHand != null) {
|
||||
controller.putOntoBattlefieldWithInfo(auraInHand, game, Zone.HAND, source.getSourceId());
|
||||
controller.moveCards(auraInHand, Zone.BATTLEFIELD, source, game);
|
||||
enchantedPermanent.addAttachment(auraInHand.getId(), game);
|
||||
controller.moveCards(auraPermanent, null, Zone.HAND, source, game);
|
||||
controller.moveCards(auraPermanent, Zone.HAND, source, game);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,7 +2,6 @@ package mage.abilities.keyword;
|
|||
|
||||
import mage.abilities.Ability;
|
||||
import mage.abilities.common.EntersBattlefieldAbility;
|
||||
import mage.abilities.effects.EntersBattlefieldEffect;
|
||||
import mage.abilities.effects.OneShotEffect;
|
||||
import mage.constants.Outcome;
|
||||
import mage.counters.CounterType;
|
||||
|
|
@ -56,7 +55,7 @@ class BloodthirstEffect extends OneShotEffect {
|
|||
BloodthirstEffect(int amount) {
|
||||
super(Outcome.BoostCreature);
|
||||
this.amount = amount;
|
||||
staticText = new StringBuilder("this permanent comes into play with ").append(this.amount).append(" +1/+1 counters on it").toString();
|
||||
staticText = "this permanent comes into play with " + this.amount + " +1/+1 counters on it";
|
||||
}
|
||||
|
||||
BloodthirstEffect(final BloodthirstEffect effect) {
|
||||
|
|
@ -70,10 +69,9 @@ class BloodthirstEffect extends OneShotEffect {
|
|||
if (player != null) {
|
||||
BloodthirstWatcher watcher = (BloodthirstWatcher) game.getState().getWatchers().get("DamagedOpponents", source.getControllerId());
|
||||
if (watcher != null && watcher.conditionMet()) {
|
||||
Permanent permanent = (Permanent) getValue(EntersBattlefieldEffect.ENTERING_PERMANENT);
|
||||
Permanent permanent = game.getPermanentEntering(source.getSourceId());
|
||||
if (permanent != null) {
|
||||
permanent.addCounters(CounterType.P1P1.createInstance(amount), game);
|
||||
|
||||
}
|
||||
}
|
||||
return true;
|
||||
|
|
|
|||
|
|
@ -76,10 +76,10 @@ public class DashAbility extends StaticAbility implements AlternativeSourceCosts
|
|||
this.addDashCost(manaString);
|
||||
Ability ability = new EntersBattlefieldAbility(
|
||||
new GainAbilitySourceEffect(HasteAbility.getInstance(), Duration.Custom, false),
|
||||
DashedCondition.getInstance(), false, "", "");
|
||||
DashedCondition.getInstance(), "", "");
|
||||
ability.addEffect(new DashAddDelayedTriggeredAbilityEffect());
|
||||
addSubAbility(ability);
|
||||
|
||||
|
||||
}
|
||||
|
||||
public DashAbility(final DashAbility ability) {
|
||||
|
|
@ -226,16 +226,18 @@ class DashAddDelayedTriggeredAbilityEffect extends OneShotEffect {
|
|||
|
||||
@Override
|
||||
public boolean apply(Game game, Ability source) {
|
||||
Effect effect = new ReturnToHandTargetEffect();
|
||||
effect.setText("return the dashed creature from the battlefield to its owner's hand");
|
||||
effect.setTargetPointer(new FixedTarget(source.getSourceId()));
|
||||
// init target pointer now because the dashed creature will only be returned from current zone
|
||||
effect.getTargetPointer().init(game, source);
|
||||
DelayedTriggeredAbility delayedAbility = new AtTheBeginOfNextEndStepDelayedTriggeredAbility(effect);
|
||||
delayedAbility.setSourceId(source.getSourceId());
|
||||
delayedAbility.setControllerId(source.getControllerId());
|
||||
delayedAbility.setSourceObject(source.getSourceObject(game), game);
|
||||
game.addDelayedTriggeredAbility(delayedAbility);
|
||||
if (game.getPermanentEntering(source.getSourceId()) != null) {
|
||||
Effect effect = new ReturnToHandTargetEffect();
|
||||
effect.setText("return the dashed creature from the battlefield to its owner's hand");
|
||||
// init target pointer now because the dashed creature will only be returned from battlefield zone (now in entering state so zone change counter is not raised yet)
|
||||
effect.setTargetPointer(new FixedTarget(source.getSourceId(), game.getState().getZoneChangeCounter(source.getSourceId()) + 1));
|
||||
DelayedTriggeredAbility delayedAbility = new AtTheBeginOfNextEndStepDelayedTriggeredAbility(effect);
|
||||
delayedAbility.setSourceId(source.getSourceId());
|
||||
delayedAbility.setControllerId(source.getControllerId());
|
||||
delayedAbility.setSourceObject(source.getSourceObject(game), game);
|
||||
game.addDelayedTriggeredAbility(delayedAbility);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -27,51 +27,51 @@
|
|||
*/
|
||||
package mage.abilities.keyword;
|
||||
|
||||
import mage.constants.Zone;
|
||||
import mage.abilities.common.SimpleStaticAbility;
|
||||
import mage.abilities.effects.common.DevourEffect;
|
||||
import mage.abilities.effects.common.DevourEffect.DevourFactor;
|
||||
import mage.constants.Zone;
|
||||
|
||||
/**
|
||||
* 502.82. Devour
|
||||
*
|
||||
* 502.82a Devour is a static ability. "Devour N" means "As this object comes into play,
|
||||
* you may sacrifice any number of creatures. This permanent comes into play with N +1/+1
|
||||
* counters on it for each creature sacrificed this way."
|
||||
* 502.82a Devour is a static ability. "Devour N" means "As this object comes
|
||||
* into play, you may sacrifice any number of creatures. This permanent comes
|
||||
* into play with N +1/+1 counters on it for each creature sacrificed this way."
|
||||
*
|
||||
* 502.82b Some objects have abilities that refer to the number of creatures the permanent
|
||||
* devoured. "It devoured" means "sacrificed as a result of its devour ability as it came
|
||||
* into play."
|
||||
* 502.82b Some objects have abilities that refer to the number of creatures the
|
||||
* permanent devoured. "It devoured" means "sacrificed as a result of its devour
|
||||
* ability as it came into play."
|
||||
*
|
||||
* Devour appears only on creature cards.
|
||||
*
|
||||
* A creature with devour can devour other creatures no matter how it comes into play.
|
||||
* A creature with devour can devour other creatures no matter how it comes into
|
||||
* play.
|
||||
*
|
||||
* You may choose to not sacrifice any creatures.
|
||||
*
|
||||
* If you play a creature with devour as a spell, you choose how many and which creatures
|
||||
* to devour as part of the resolution of that spell. (It can't be countered at this point.)
|
||||
* The same is true of a spell or ability that lets you put a creature with devour into play.
|
||||
* If you play a creature with devour as a spell, you choose how many and which
|
||||
* creatures to devour as part of the resolution of that spell. (It can't be
|
||||
* countered at this point.) The same is true of a spell or ability that lets
|
||||
* you put a creature with devour into play.
|
||||
*
|
||||
* You may sacrifice only creatures that are already in play. If a creature with devour and
|
||||
* another creature are coming into play under your control at the same time, the creature
|
||||
* with devour can't devour that other creature. The creature with devour also can't devour
|
||||
* itself.
|
||||
* You may sacrifice only creatures that are already in play. If a creature with
|
||||
* devour and another creature are coming into play under your control at the
|
||||
* same time, the creature with devour can't devour that other creature. The
|
||||
* creature with devour also can't devour itself.
|
||||
*
|
||||
* If multiple creatures with devour are coming into play under your control at the same time,
|
||||
* you may use each one's devour ability. A creature you already control can be devoured by
|
||||
* only one of them, however. (In other words, you can't sacrifice the same creature to satisfy
|
||||
* multiple devour abilities.) All creatures devoured this way are sacrificed at the same time.
|
||||
* If multiple creatures with devour are coming into play under your control at
|
||||
* the same time, you may use each one's devour ability. A creature you already
|
||||
* control can be devoured by only one of them, however. (In other words, you
|
||||
* can't sacrifice the same creature to satisfy multiple devour abilities.) All
|
||||
* creatures devoured this way are sacrificed at the same time.
|
||||
*
|
||||
* @author LevelX2
|
||||
*/
|
||||
public class DevourAbility extends SimpleStaticAbility {
|
||||
|
||||
public class DevourAbility extends SimpleStaticAbility {
|
||||
|
||||
|
||||
|
||||
public DevourAbility(DevourFactor devourFactor) {
|
||||
super(Zone.BATTLEFIELD, new DevourEffect(devourFactor));
|
||||
public DevourAbility(DevourFactor devourFactor) {
|
||||
super(Zone.ALL, new DevourEffect(devourFactor));
|
||||
}
|
||||
|
||||
public DevourAbility(final DevourAbility ability) {
|
||||
|
|
@ -82,4 +82,4 @@ import mage.abilities.effects.common.DevourEffect.DevourFactor;
|
|||
public DevourAbility copy() {
|
||||
return new DevourAbility(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -25,7 +25,6 @@
|
|||
* 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.Ability;
|
||||
|
|
@ -44,46 +43,53 @@ import mage.target.targetpointer.FixedTarget;
|
|||
* FAQ 2013/01/11
|
||||
*
|
||||
* 702.98. Evolve
|
||||
*
|
||||
* 702.98a Evolve is a triggered ability. "Evolve" means "Whenever a creature enters
|
||||
* the battlefield under your control, if that creature's power is greater than this
|
||||
* creature's power and/or that creature's toughness is greater than this creature's
|
||||
* toughness, put a +1/+1 counter on this creature."
|
||||
*
|
||||
* 702.98b If a creature has multiple instances of evolve, each triggers separately
|
||||
*
|
||||
* 702.98a Evolve is a triggered ability. "Evolve" means "Whenever a creature
|
||||
* enters the battlefield under your control, if that creature's power is
|
||||
* greater than this creature's power and/or that creature's toughness is
|
||||
* greater than this creature's toughness, put a +1/+1 counter on this
|
||||
* creature."
|
||||
*
|
||||
* 702.98b If a creature has multiple instances of evolve, each triggers
|
||||
* separately
|
||||
*
|
||||
* Rulings
|
||||
*
|
||||
* When comparing the stats of the two creatures, you always compare power to power and toughness to toughness.
|
||||
* Whenever a creature enters the battlefield under your control, check its power and toughness against
|
||||
* the power and toughness of the creature with evolve. If neither stat of the new creature is greater,
|
||||
* evolve won't trigger at all. For example, if you control a 2/3 creature with evolve and a 2/2 creature
|
||||
* enters the battlefield under your control, you won't have the opportunity to cast a spell like Giant Growth
|
||||
* to make the 2/2 creature large enough to cause evolve to trigger.
|
||||
* If evolve triggers, the stat comparison will happen again when the ability tries to resolve. If
|
||||
* neither stat of the new creature is greater, the ability will do nothing. If the creature that
|
||||
* entered the battlefield leaves the battlefield before evolve tries to resolve, use its last known
|
||||
* power and toughness to compare the stats.
|
||||
* If a creature enters the battlefield with +1/+1 counters on it, consider those counters when determining
|
||||
* if evolve will trigger. For example, a 1/1 creature that enters the battlefield with two +1/+1 counters
|
||||
* on it will cause the evolve ability of a 2/2 creature to trigger.
|
||||
* If multiple creatures enter the battlefield at the same time, evolve may trigger multiple times, although the stat
|
||||
* comparison will take place each time one of those abilities tries to resolve. For example, if you control a 2/2
|
||||
* creature with evolve and two 3/3 creatures enter the battlefield, evolve will trigger twice. The first ability
|
||||
* will resolve and put a +1/+1 counter on the creature with evolve. When the second ability tries to resolve,
|
||||
* neither the power nor the toughness of the new creature is greater than that of the creature with evolve,
|
||||
* so that ability does nothing.
|
||||
* When comparing the stats as the evolve ability resolves, it's possible that the stat that's greater changes
|
||||
* from power to toughness or vice versa. If this happens, the ability will still resolve and you'll put a +1/+1
|
||||
* counter on the creature with evolve. For example, if you control a 2/2 creature with evolve and a 1/3 creature
|
||||
* enters the battlefield under your control, it toughness is greater so evolve will trigger. In response, the 1/3
|
||||
* creature gets +2/-2. When the evolve trigger tries to resolve, its power is greater. You'll put a +1/+1
|
||||
* counter on the creature with evolve.
|
||||
*
|
||||
*
|
||||
* When comparing the stats of the two creatures, you always compare power to
|
||||
* power and toughness to toughness. Whenever a creature enters the battlefield
|
||||
* under your control, check its power and toughness against the power and
|
||||
* toughness of the creature with evolve. If neither stat of the new creature is
|
||||
* greater, evolve won't trigger at all. For example, if you control a 2/3
|
||||
* creature with evolve and a 2/2 creature enters the battlefield under your
|
||||
* control, you won't have the opportunity to cast a spell like Giant Growth to
|
||||
* make the 2/2 creature large enough to cause evolve to trigger. If evolve
|
||||
* triggers, the stat comparison will happen again when the ability tries to
|
||||
* resolve. If neither stat of the new creature is greater, the ability will do
|
||||
* nothing. If the creature that entered the battlefield leaves the battlefield
|
||||
* before evolve tries to resolve, use its last known power and toughness to
|
||||
* compare the stats. If a creature enters the battlefield with +1/+1 counters
|
||||
* on it, consider those counters when determining if evolve will trigger. For
|
||||
* example, a 1/1 creature that enters the battlefield with two +1/+1 counters
|
||||
* on it will cause the evolve ability of a 2/2 creature to trigger. If multiple
|
||||
* creatures enter the battlefield at the same time, evolve may trigger multiple
|
||||
* times, although the stat comparison will take place each time one of those
|
||||
* abilities tries to resolve. For example, if you control a 2/2 creature with
|
||||
* evolve and two 3/3 creatures enter the battlefield, evolve will trigger
|
||||
* twice. The first ability will resolve and put a +1/+1 counter on the creature
|
||||
* with evolve. When the second ability tries to resolve, neither the power nor
|
||||
* the toughness of the new creature is greater than that of the creature with
|
||||
* evolve, so that ability does nothing. When comparing the stats as the evolve
|
||||
* ability resolves, it's possible that the stat that's greater changes from
|
||||
* power to toughness or vice versa. If this happens, the ability will still
|
||||
* resolve and you'll put a +1/+1 counter on the creature with evolve. For
|
||||
* example, if you control a 2/2 creature with evolve and a 1/3 creature enters
|
||||
* the battlefield under your control, it toughness is greater so evolve will
|
||||
* trigger. In response, the 1/3 creature gets +2/-2. When the evolve trigger
|
||||
* tries to resolve, its power is greater. You'll put a +1/+1 counter on the
|
||||
* creature with evolve.
|
||||
*
|
||||
* @author LevelX2
|
||||
*/
|
||||
|
||||
|
||||
public class EvolveAbility extends TriggeredAbilityImpl {
|
||||
|
||||
public EvolveAbility() {
|
||||
|
|
@ -169,4 +175,3 @@ class EvolveEffect extends OneShotEffect {
|
|||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,30 +1,30 @@
|
|||
/*
|
||||
* 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.
|
||||
*/
|
||||
* 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.Locale;
|
||||
|
|
@ -48,18 +48,19 @@ import mage.target.targetpointer.FixedTarget;
|
|||
import mage.util.CardUtil;
|
||||
|
||||
/**
|
||||
* 702.56. Graft
|
||||
* 702.56a. Graft represents both a static ability and a triggered ability. Graft N means,
|
||||
* "This permanent enters the battlefield with N +1/+1 counters on it" and, "Whenever
|
||||
* another creature enters the battlefield, if this permanent has a +1/+1 counter on it,
|
||||
* you may move a +1/+1 counter from this permanent onto that creature."
|
||||
* 702.56. Graft 702.56a. Graft represents both a static ability and a triggered
|
||||
* ability. Graft N means, "This permanent enters the battlefield with N +1/+1
|
||||
* counters on it" and, "Whenever another creature enters the battlefield, if
|
||||
* this permanent has a +1/+1 counter on it, you may move a +1/+1 counter from
|
||||
* this permanent onto that creature."
|
||||
*
|
||||
* 702.56b. If a creature has multiple instances of graft, each one works separately.
|
||||
* 702.56b. If a creature has multiple instances of graft, each one works
|
||||
* separately.
|
||||
*
|
||||
* @author LevelX2
|
||||
*/
|
||||
|
||||
public class GraftAbility extends TriggeredAbilityImpl {
|
||||
|
||||
private static final FilterCreaturePermanent filter = new FilterCreaturePermanent();
|
||||
|
||||
private int amount;
|
||||
|
|
@ -112,10 +113,10 @@ public class GraftAbility extends TriggeredAbilityImpl {
|
|||
@Override
|
||||
public String getRule() {
|
||||
StringBuilder sb = new StringBuilder("Graft");
|
||||
sb.append(" ").append(amount).append(" <i>(This ").append(cardtype).append(" enters the battlefield with ")
|
||||
.append(amount == 1 ? "a": CardUtil.numberToText(amount))
|
||||
.append(" +1/+1 counter on it. Whenever a creature enters the battlefield, you may move a +1/+1 counter from this ")
|
||||
.append(cardtype).append(" onto it.)</i>");
|
||||
sb.append(" ").append(amount).append(" <i>(This ").append(cardtype).append(" enters the battlefield with ")
|
||||
.append(amount == 1 ? "a" : CardUtil.numberToText(amount))
|
||||
.append(" +1/+1 counter on it. Whenever a creature enters the battlefield, you may move a +1/+1 counter from this ")
|
||||
.append(cardtype).append(" onto it.)</i>");
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
|
|
@ -126,7 +127,7 @@ class GraftStaticAbility extends StaticAbility {
|
|||
private String ruleText;
|
||||
|
||||
public GraftStaticAbility(int amount) {
|
||||
super(Zone.BATTLEFIELD, new EntersBattlefieldEffect(new AddCountersSourceEffect(CounterType.P1P1.createInstance(amount))));
|
||||
super(Zone.ALL, new EntersBattlefieldEffect(new AddCountersSourceEffect(CounterType.P1P1.createInstance(amount))));
|
||||
ruleText = new StringBuilder("This enters the battlefield with ").append(amount).append(" +1/+1 counter on it.").toString();
|
||||
this.setRuleVisible(false);
|
||||
}
|
||||
|
|
@ -147,7 +148,6 @@ class GraftStaticAbility extends StaticAbility {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
class GraftDistributeCounterEffect extends OneShotEffect {
|
||||
|
||||
public GraftDistributeCounterEffect() {
|
||||
|
|
|
|||
|
|
@ -65,7 +65,7 @@ import mage.util.CardUtil;
|
|||
public class HideawayAbility extends StaticAbility {
|
||||
|
||||
public HideawayAbility() {
|
||||
super(Zone.BATTLEFIELD, new EntersBattlefieldEffect(new TapSourceEffect(true)));
|
||||
super(Zone.ALL, new EntersBattlefieldEffect(new TapSourceEffect(true)));
|
||||
Ability ability = new EntersBattlefieldTriggeredAbility(new HideawayExileEffect(), false);
|
||||
ability.setRuleVisible(false);
|
||||
addSubAbility(ability);
|
||||
|
|
@ -115,17 +115,17 @@ class HideawayExileEffect extends OneShotEffect {
|
|||
if (hideawaySource == null || controller == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
Cards cards = new CardsImpl(Zone.LIBRARY);
|
||||
cards.addAll(controller.getLibrary().getTopCards(game, 4));
|
||||
cards.addAll(controller.getLibrary().getTopCards(game, 4));
|
||||
if (cards.size() > 0) {
|
||||
TargetCard target1 = new TargetCard(Zone.LIBRARY, filter1);
|
||||
if (controller.choose(Outcome.Detriment, cards, target1, game)) {
|
||||
Card card = cards.get(target1.getFirstTarget(), game);
|
||||
if (card != null) {
|
||||
cards.remove(card);
|
||||
controller.moveCardToExileWithInfo(card, CardUtil.getCardExileZoneId(game, source),
|
||||
"Hideaway (" + hideawaySource.getIdName() +")", source.getSourceId(), game, Zone.LIBRARY, false);
|
||||
controller.moveCardToExileWithInfo(card, CardUtil.getCardExileZoneId(game, source),
|
||||
"Hideaway (" + hideawaySource.getIdName() + ")", source.getSourceId(), game, Zone.LIBRARY, false);
|
||||
card.setFaceDown(true, game);
|
||||
}
|
||||
}
|
||||
|
|
@ -159,7 +159,7 @@ class HideawayLookAtFaceDownCardEffect extends AsThoughEffectImpl {
|
|||
|
||||
@Override
|
||||
public boolean applies(UUID objectId, Ability source, UUID affectedControllerId, Game game) {
|
||||
if (game.getState().getZone(objectId) != Zone.EXILED
|
||||
if (game.getState().getZone(objectId) != Zone.EXILED
|
||||
|| !game.getState().getCardState(objectId).isFaceDown()) {
|
||||
return false;
|
||||
}
|
||||
|
|
@ -180,4 +180,3 @@ class HideawayLookAtFaceDownCardEffect extends AsThoughEffectImpl {
|
|||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -203,7 +203,7 @@ public class KickerAbility extends StaticAbility implements OptionalAdditionalSo
|
|||
if (zcc == 0) {
|
||||
zcc = game.getState().getZoneChangeCounter(source.getSourceId());
|
||||
}
|
||||
if (zcc > 0 && (source.getAbilityType().equals(AbilityType.TRIGGERED) || source.getAbilityType().equals(AbilityType.STATIC))) {
|
||||
if (zcc > 0 && (source.getAbilityType().equals(AbilityType.TRIGGERED))) {
|
||||
--zcc;
|
||||
}
|
||||
return String.valueOf(zcc) + ((kickerCosts.size() > 1) ? costText : "");
|
||||
|
|
|
|||
|
|
@ -108,7 +108,7 @@ class ModularStaticAbility extends StaticAbility {
|
|||
private String ruleText;
|
||||
|
||||
public ModularStaticAbility(int amount) {
|
||||
super(Zone.BATTLEFIELD, new EntersBattlefieldEffect(new AddCountersSourceEffect(CounterType.P1P1.createInstance(amount))));
|
||||
super(Zone.ALL, new EntersBattlefieldEffect(new AddCountersSourceEffect(CounterType.P1P1.createInstance(amount))));
|
||||
ruleText = "This enters the battlefield with " + CardUtil.numberToText(amount, "a") + " +1/+1 counter" + (amount != 1 ? "s" : "") + " on it.";
|
||||
this.setRuleVisible(false);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -31,7 +31,6 @@ import mage.abilities.Ability;
|
|||
import mage.abilities.common.EntersBattlefieldAbility;
|
||||
import mage.abilities.dynamicvalue.DynamicValue;
|
||||
import mage.abilities.dynamicvalue.common.SunburstCount;
|
||||
import mage.abilities.effects.EntersBattlefieldEffect;
|
||||
import mage.abilities.effects.OneShotEffect;
|
||||
import mage.cards.Card;
|
||||
import mage.constants.CardType;
|
||||
|
|
@ -89,7 +88,7 @@ class SunburstEffect extends OneShotEffect {
|
|||
|
||||
@Override
|
||||
public boolean apply(Game game, Ability source) {
|
||||
Permanent permanent = (Permanent) getValue(EntersBattlefieldEffect.ENTERING_PERMANENT);
|
||||
Permanent permanent = game.getPermanentEntering(source.getSourceId());
|
||||
if (permanent != null) {
|
||||
Counter counter;
|
||||
if (permanent.getCardType().contains(CardType.CREATURE)) {
|
||||
|
|
|
|||
|
|
@ -30,7 +30,6 @@ package mage.abilities.keyword;
|
|||
import java.util.UUID;
|
||||
import mage.abilities.Ability;
|
||||
import mage.abilities.common.EntersBattlefieldAbility;
|
||||
import mage.abilities.effects.EntersBattlefieldEffect;
|
||||
import mage.abilities.effects.OneShotEffect;
|
||||
import mage.abilities.effects.common.counter.AddCountersSourceEffect;
|
||||
import mage.constants.Outcome;
|
||||
|
|
@ -51,7 +50,7 @@ public class TributeAbility extends EntersBattlefieldAbility {
|
|||
private int tributeValue;
|
||||
|
||||
public TributeAbility(int tributeValue) {
|
||||
super(new TributeEffect(tributeValue), false);
|
||||
super(new TributeEffect(tributeValue));
|
||||
this.tributeValue = tributeValue;
|
||||
}
|
||||
|
||||
|
|
@ -98,7 +97,7 @@ class TributeEffect extends OneShotEffect {
|
|||
@Override
|
||||
public boolean apply(Game game, Ability source) {
|
||||
Player controller = game.getPlayer(source.getControllerId());
|
||||
Permanent sourcePermanent = (Permanent) getValue(EntersBattlefieldEffect.ENTERING_PERMANENT);
|
||||
Permanent sourcePermanent = game.getPermanentEntering(source.getSourceId());
|
||||
if (controller != null && sourcePermanent != null) {
|
||||
UUID opponentId;
|
||||
if (game.getOpponents(controller.getId()).size() == 1) {
|
||||
|
|
|
|||
|
|
@ -26,14 +26,14 @@
|
|||
* or implied, of BetaSteward_at_googlemail.com.
|
||||
*/
|
||||
package mage.abilities.keyword;
|
||||
|
||||
import mage.constants.Duration;
|
||||
import mage.constants.Outcome;
|
||||
|
||||
import mage.abilities.Ability;
|
||||
import mage.abilities.Mode;
|
||||
import mage.abilities.common.SimpleStaticAbility;
|
||||
import mage.abilities.effects.ReplacementEffectImpl;
|
||||
import mage.abilities.effects.RestrictionEffect;
|
||||
import mage.constants.Duration;
|
||||
import mage.constants.Outcome;
|
||||
import mage.constants.Zone;
|
||||
import mage.counters.CounterType;
|
||||
import mage.game.Game;
|
||||
|
|
@ -41,49 +41,41 @@ import mage.game.events.GameEvent;
|
|||
import mage.game.events.GameEvent.EventType;
|
||||
import mage.game.permanent.Permanent;
|
||||
import mage.players.Player;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author LevelX2
|
||||
*/
|
||||
|
||||
|
||||
//
|
||||
// 702.96. Unleash
|
||||
//
|
||||
// 702.96a Unleash is a keyword that represents two static abilities.
|
||||
// 702.96a Unleash is a keyword that represents two static abilities.
|
||||
// "Unleash" means "You may have this permanent enter the battlefield with an additional +1/+1 counter on it"
|
||||
// and "This permanent can’t block as long as it has a +1/+1 counter on it."
|
||||
public class UnleashAbility extends SimpleStaticAbility {
|
||||
|
||||
|
||||
public class UnleashAbility extends SimpleStaticAbility {
|
||||
|
||||
public UnleashAbility() {
|
||||
super(Zone.ALL, new UnleashReplacementEffect());
|
||||
this.addEffect(new UnleashRestrictionEffect());
|
||||
}
|
||||
|
||||
|
||||
public UnleashAbility(final UnleashAbility ability) {
|
||||
super(ability);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public UnleashAbility copy() {
|
||||
return new UnleashAbility(this);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public String getRule() {
|
||||
return "Unleash <i>(You may have this creature enter the battlefield with a +1/+1 counter on it. It can't block as long as it has a +1/+1 counter on it.)</i>";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
class UnleashReplacementEffect extends ReplacementEffectImpl {
|
||||
|
||||
|
||||
public UnleashReplacementEffect() {
|
||||
super(Duration.EndOfGame, Outcome.Detriment);
|
||||
}
|
||||
|
||||
|
||||
public UnleashReplacementEffect(UnleashReplacementEffect effect) {
|
||||
super(effect);
|
||||
}
|
||||
|
|
@ -95,53 +87,51 @@ class UnleashReplacementEffect extends ReplacementEffectImpl {
|
|||
|
||||
@Override
|
||||
public boolean applies(GameEvent event, Ability source, Game game) {
|
||||
if (event.getTargetId().equals(source.getSourceId())) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
return event.getTargetId().equals(source.getSourceId());
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public boolean apply(Game game, Ability source) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public boolean replaceEvent(GameEvent event, Ability source, Game game) {
|
||||
Permanent creature = game.getPermanent(event.getTargetId());
|
||||
Permanent creature = game.getPermanentEntering(source.getSourceId());
|
||||
Player controller = game.getPlayer(source.getControllerId());
|
||||
if (creature != null && controller != null) {
|
||||
if (controller.chooseUse(outcome, "Unleash "+ creature.getName() +"?", source, game)) {
|
||||
if (!game.isSimulation())
|
||||
if (controller.chooseUse(outcome, "Unleash " + creature.getName() + "?", source, game)) {
|
||||
if (!game.isSimulation()) {
|
||||
game.informPlayers(controller.getLogName() + " unleashes " + creature.getName());
|
||||
}
|
||||
creature.addCounters(CounterType.P1P1.createInstance(), game);
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public String getText(Mode mode) {
|
||||
return staticText;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public UnleashReplacementEffect copy() {
|
||||
return new UnleashReplacementEffect(this);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
class UnleashRestrictionEffect extends RestrictionEffect {
|
||||
|
||||
|
||||
public UnleashRestrictionEffect() {
|
||||
super(Duration.WhileOnBattlefield);
|
||||
}
|
||||
|
||||
|
||||
public UnleashRestrictionEffect(final UnleashRestrictionEffect effect) {
|
||||
super(effect);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public boolean applies(Permanent permanent, Ability source, Game game) {
|
||||
if (permanent != null && permanent.getId().equals(source.getSourceId())) {
|
||||
|
|
@ -151,14 +141,14 @@ class UnleashRestrictionEffect extends RestrictionEffect {
|
|||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public boolean canBlock(Permanent attacker, Permanent blocker, Ability source, Game game) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public UnleashRestrictionEffect copy() {
|
||||
return new UnleashRestrictionEffect(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -512,7 +512,12 @@ public abstract class CardImpl extends MageObjectImpl implements Card {
|
|||
}
|
||||
break;
|
||||
case STACK:
|
||||
StackObject stackObject = game.getStack().getSpell(getSpellAbility().getId());
|
||||
StackObject stackObject;
|
||||
if (getSpellAbility() != null) {
|
||||
stackObject = game.getStack().getSpell(getSpellAbility().getId());
|
||||
} else {
|
||||
stackObject = game.getStack().getSpell(this.getId());
|
||||
}
|
||||
if (stackObject == null && (this instanceof SplitCard)) { // handle if half of Split cast is on the stack
|
||||
stackObject = game.getStack().getSpell(((SplitCard) this).getLeftHalfCard().getId());
|
||||
if (stackObject == null) {
|
||||
|
|
|
|||
|
|
@ -115,6 +115,10 @@ public interface Game extends MageItem, Serializable {
|
|||
|
||||
Permanent getPermanentOrLKIBattlefield(UUID permanentId);
|
||||
|
||||
Permanent getPermanentEntering(UUID permanentId);
|
||||
|
||||
Map<UUID, Permanent> getPermanentsEntering();
|
||||
|
||||
Map<Zone, HashMap<UUID, MageObject>> getLKI();
|
||||
|
||||
Card getCard(UUID cardId);
|
||||
|
|
|
|||
|
|
@ -176,6 +176,9 @@ public abstract class GameImpl implements Game, Serializable {
|
|||
// Used to check if an object was moved by the current effect in resolution (so Wrath like effect can be handled correctly)
|
||||
protected Map<Zone, Set<UUID>> shortLivingLKI = new EnumMap<>(Zone.class);
|
||||
|
||||
// Permanents entering the Battlefield while handling replacement effects before they are added to the battlefield
|
||||
protected Map<UUID, Permanent> permanentsEntering = new HashMap<>();
|
||||
|
||||
protected GameState state;
|
||||
private transient Stack<Integer> savedStates = new Stack<>();
|
||||
protected transient GameStates gameStates = new GameStates();
|
||||
|
|
@ -244,6 +247,7 @@ public abstract class GameImpl implements Game, Serializable {
|
|||
this.lki.putAll(game.lki);
|
||||
this.lkiExtended.putAll(game.lkiExtended);
|
||||
this.shortLivingLKI.putAll(game.shortLivingLKI);
|
||||
this.permanentsEntering.putAll(game.permanentsEntering);
|
||||
if (logger.isDebugEnabled()) {
|
||||
copyCount++;
|
||||
copyTime += (System.currentTimeMillis() - t1);
|
||||
|
|
@ -501,6 +505,16 @@ public abstract class GameImpl implements Game, Serializable {
|
|||
return permanent;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Permanent getPermanentEntering(UUID permanentId) {
|
||||
return permanentsEntering.get(permanentId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<UUID, Permanent> getPermanentsEntering() {
|
||||
return permanentsEntering;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Card getCard(UUID cardId) {
|
||||
if (cardId == null) {
|
||||
|
|
@ -891,7 +905,7 @@ public abstract class GameImpl implements Game, Serializable {
|
|||
return;
|
||||
}
|
||||
getState().setChoosingPlayerId(choosingPlayerId); // needed to start/stop the timer if active
|
||||
if (choosingPlayer != null && choosingPlayer.choose(Outcome.Benefit, targetPlayer, null, this)) {
|
||||
if (choosingPlayer.choose(Outcome.Benefit, targetPlayer, null, this)) {
|
||||
startingPlayerId = targetPlayer.getTargets().get(0);
|
||||
} else if (getState().getPlayers().size() < 3) {
|
||||
// not possible to choose starting player, choosing player has probably conceded, so stop here
|
||||
|
|
@ -2539,8 +2553,10 @@ public abstract class GameImpl implements Game, Serializable {
|
|||
card.setZone(Zone.BATTLEFIELD, this);
|
||||
card.setOwnerId(ownerId);
|
||||
PermanentCard permanent = new PermanentCard(card.getCard(), ownerId, this);
|
||||
getBattlefield().addPermanent(permanent);
|
||||
getPermanentsEntering().put(permanent.getId(), permanent);
|
||||
permanent.entersBattlefield(permanent.getId(), this, Zone.OUTSIDE, false);
|
||||
getBattlefield().addPermanent(permanent);
|
||||
getPermanentsEntering().remove(permanent.getId());
|
||||
((PermanentImpl) permanent).removeSummoningSickness();
|
||||
if (card.isTapped()) {
|
||||
permanent.setTapped(true);
|
||||
|
|
|
|||
|
|
@ -647,6 +647,9 @@ public abstract class PermanentImpl extends CardImpl implements Permanent {
|
|||
if (!game.replaceEvent(new GameEvent(GameEvent.EventType.ATTACH, objectId, permanentId, controllerId))) {
|
||||
this.attachments.add(permanentId);
|
||||
Permanent attachment = game.getPermanent(permanentId);
|
||||
if (attachment == null) {
|
||||
attachment = game.getPermanentEntering(permanentId);
|
||||
}
|
||||
if (attachment != null) {
|
||||
attachment.attachTo(objectId, game);
|
||||
game.fireEvent(new GameEvent(GameEvent.EventType.ATTACHED, objectId, permanentId, controllerId));
|
||||
|
|
|
|||
|
|
@ -42,6 +42,7 @@ import mage.game.Game;
|
|||
import mage.game.events.GameEvent;
|
||||
import mage.game.events.GameEvent.EventType;
|
||||
import mage.game.events.ZoneChangeEvent;
|
||||
import mage.game.permanent.Permanent;
|
||||
import mage.game.permanent.PermanentToken;
|
||||
import mage.players.Player;
|
||||
|
||||
|
|
@ -148,31 +149,43 @@ public class Token extends MageObjectImpl {
|
|||
GameEvent event = new GameEvent(EventType.CREATE_TOKEN, null, sourceId, controllerId, amount, this.getCardType().contains(CardType.CREATURE));
|
||||
if (!game.replaceEvent(event)) {
|
||||
amount = event.getAmount();
|
||||
|
||||
List<Permanent> permanents = new ArrayList<>();
|
||||
List<Permanent> permanentsEntered = new ArrayList<>();
|
||||
|
||||
for (int i = 0; i < amount; i++) {
|
||||
PermanentToken newToken = new PermanentToken(this, event.getPlayerId(), setCode, game); // use event.getPlayerId() because it can be replaced by replacement effect
|
||||
game.getState().addCard(newToken);
|
||||
game.addPermanent(newToken);
|
||||
if (tapped) {
|
||||
newToken.setTapped(true);
|
||||
}
|
||||
this.lastAddedTokenIds.add(newToken.getId());
|
||||
this.lastAddedTokenId = newToken.getId();
|
||||
game.setScopeRelevant(true);
|
||||
game.applyEffects();
|
||||
boolean entered = newToken.entersBattlefield(sourceId, game, Zone.OUTSIDE, true);
|
||||
game.setScopeRelevant(false);
|
||||
game.applyEffects();
|
||||
if (entered) {
|
||||
game.fireEvent(new ZoneChangeEvent(newToken, event.getPlayerId(), Zone.OUTSIDE, Zone.BATTLEFIELD));
|
||||
if (attacking && game.getCombat() != null) {
|
||||
game.getCombat().addAttackingCreature(newToken.getId(), game);
|
||||
}
|
||||
if (!game.isSimulation()) {
|
||||
game.informPlayers(controller.getLogName() + " puts a " + newToken.getLogName() + " token onto the battlefield");
|
||||
}
|
||||
permanents.add(newToken);
|
||||
game.getPermanentsEntering().put(newToken.getId(), newToken);
|
||||
newToken.setTapped(tapped);
|
||||
}
|
||||
game.setScopeRelevant(true);
|
||||
for (Permanent permanent : permanents) {
|
||||
if (permanent.entersBattlefield(sourceId, game, Zone.OUTSIDE, true)) {
|
||||
permanentsEntered.add(permanent);
|
||||
} else {
|
||||
game.getPermanentsEntering().remove(permanent.getId());
|
||||
}
|
||||
}
|
||||
game.setScopeRelevant(false);
|
||||
for (Permanent permanent : permanentsEntered) {
|
||||
game.addPermanent(permanent);
|
||||
permanent.setZone(Zone.BATTLEFIELD, game);
|
||||
game.getPermanentsEntering().remove(permanent.getId());
|
||||
|
||||
this.lastAddedTokenIds.add(permanent.getId());
|
||||
this.lastAddedTokenId = permanent.getId();
|
||||
game.addSimultaneousEvent(new ZoneChangeEvent(permanent, permanent.getControllerId(), Zone.OUTSIDE, Zone.BATTLEFIELD));
|
||||
if (attacking && game.getCombat() != null) {
|
||||
game.getCombat().addAttackingCreature(permanent.getId(), game);
|
||||
}
|
||||
if (!game.isSimulation()) {
|
||||
game.informPlayers(controller.getLogName() + " puts a " + permanent.getLogName() + " token onto the battlefield");
|
||||
}
|
||||
|
||||
}
|
||||
game.applyEffects();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
|
|
|
|||
|
|
@ -232,7 +232,7 @@ public class Spell extends StackObjImpl implements Card {
|
|||
card.getCardType().remove(CardType.CREATURE);
|
||||
card.getSubtype().add("Aura");
|
||||
}
|
||||
if (card.putOntoBattlefield(game, Zone.STACK, ability.getSourceId(), controllerId)) {
|
||||
if (controller.moveCards(card, Zone.BATTLEFIELD, ability, game, false, faceDown, false, null)) {
|
||||
if (bestow) {
|
||||
// card will be copied during putOntoBattlefield, so the card of CardPermanent has to be changed
|
||||
// TODO: Find a better way to prevent bestow creatures from being effected by creature affecting abilities
|
||||
|
|
@ -253,8 +253,7 @@ public class Spell extends StackObjImpl implements Card {
|
|||
// Aura has no legal target and its a bestow enchantment -> Add it to battlefield as creature
|
||||
if (this.getSpellAbility() instanceof BestowAbility) {
|
||||
updateOptionalCosts(0);
|
||||
result = card.putOntoBattlefield(game, Zone.STACK, ability.getSourceId(), controllerId);
|
||||
return result;
|
||||
return controller.moveCards(card, Zone.BATTLEFIELD, ability, game, false, faceDown, false, null);
|
||||
} else {
|
||||
//20091005 - 608.2b
|
||||
if (!game.isSimulation()) {
|
||||
|
|
@ -265,9 +264,7 @@ public class Spell extends StackObjImpl implements Card {
|
|||
}
|
||||
} else {
|
||||
updateOptionalCosts(0);
|
||||
// return controller.moveCards(card, Zone.BATTLEFIELD, ability, game, false, faceDown, false, null);
|
||||
result = card.putOntoBattlefield(game, Zone.STACK, ability.getSourceId(), controllerId, false, faceDown);
|
||||
return result;
|
||||
return controller.moveCards(card, Zone.BATTLEFIELD, ability, game, false, faceDown, false, null);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -629,15 +629,26 @@ public interface Player extends MageItem, Copyable<Player> {
|
|||
* @param game
|
||||
* @return
|
||||
*/
|
||||
@Deprecated
|
||||
boolean moveCards(Cards cards, Zone fromZone, Zone toZone, Ability source, Game game);
|
||||
|
||||
@Deprecated
|
||||
boolean moveCards(Card card, Zone fromZone, Zone toZone, Ability source, Game game);
|
||||
|
||||
@Deprecated
|
||||
boolean moveCards(Set<Card> cards, Zone fromZone, Zone toZone, Ability source, Game game);
|
||||
|
||||
boolean moveCards(Card card, Zone toZone, Ability source, Game game);
|
||||
|
||||
boolean moveCards(Card card, Zone toZone, Ability source, Game game, boolean tapped, boolean faceDown, boolean byOwner, ArrayList<UUID> appliedEffects);
|
||||
|
||||
boolean moveCards(Cards cards, Zone toZone, Ability source, Game game);
|
||||
|
||||
boolean moveCards(Set<Card> cards, Zone toZone, Ability source, Game game);
|
||||
|
||||
/**
|
||||
* Iniversal method to move cards from one zone to another. Do not mix
|
||||
* objects from different from zones to move.
|
||||
*
|
||||
* @param cards
|
||||
* @param toZone
|
||||
|
|
@ -740,6 +751,7 @@ public interface Player extends MageItem, Copyable<Player> {
|
|||
* @param sourceId
|
||||
* @return
|
||||
*/
|
||||
@Deprecated
|
||||
boolean putOntoBattlefieldWithInfo(Card card, Game game, Zone fromZone, UUID sourceId);
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -773,6 +773,9 @@ public abstract class PlayerImpl implements Player, Serializable {
|
|||
public boolean addAttachment(UUID permanentId, Game game) {
|
||||
if (!this.attachments.contains(permanentId)) {
|
||||
Permanent aura = game.getPermanent(permanentId);
|
||||
if (aura == null) {
|
||||
aura = game.getPermanentEntering(permanentId);
|
||||
}
|
||||
if (aura != null) {
|
||||
if (!game.replaceEvent(new GameEvent(GameEvent.EventType.ENCHANT_PLAYER, playerId, permanentId, aura.getControllerId()))) {
|
||||
this.attachments.add(permanentId);
|
||||
|
|
@ -1016,8 +1019,7 @@ public abstract class PlayerImpl implements Player, Serializable {
|
|||
//20091005 - 305.1
|
||||
if (!game.replaceEvent(GameEvent.getEvent(GameEvent.EventType.PLAY_LAND, card.getId(), card.getId(), playerId))) {
|
||||
// int bookmark = game.bookmarkState();
|
||||
Zone zone = game.getState().getZone(card.getId());
|
||||
if (card.putOntoBattlefield(game, zone, null, playerId)) {
|
||||
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.fireInformEvent(getLogName() + " plays " + card.getLogName());
|
||||
|
|
@ -2980,40 +2982,12 @@ public abstract class PlayerImpl implements Player, Serializable {
|
|||
|
||||
@Override
|
||||
public boolean moveCards(Set<Card> cards, Zone fromZone, Zone toZone, Ability source, Game game) {
|
||||
if (cards.isEmpty()) {
|
||||
return true;
|
||||
}
|
||||
Set<Card> successfulMovedCards = new LinkedHashSet<>();
|
||||
switch (toZone) {
|
||||
case EXILED:
|
||||
for (Card card : cards) {
|
||||
fromZone = game.getState().getZone(card.getId());
|
||||
boolean withName = (fromZone.equals(Zone.BATTLEFIELD) || fromZone.equals(Zone.STACK)) || !card.isFaceDown(game);
|
||||
if (moveCardToExileWithInfo(card, null, "", source == null ? null : source.getSourceId(), game, fromZone, withName)) {
|
||||
successfulMovedCards.add(card);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case GRAVEYARD:
|
||||
successfulMovedCards = moveCardsToGraveyardWithInfo(cards, source, game, fromZone);
|
||||
break;
|
||||
case HAND:
|
||||
case BATTLEFIELD:
|
||||
return moveCards(cards, toZone, source, game, false, false, false, null);
|
||||
case LIBRARY:
|
||||
for (Card card : cards) {
|
||||
fromZone = game.getState().getZone(card.getId());
|
||||
boolean hideCard = fromZone.equals(Zone.HAND) || fromZone.equals(Zone.LIBRARY);
|
||||
if (moveCardToLibraryWithInfo(card, source == null ? null : source.getSourceId(), game, fromZone, true, !hideCard)) {
|
||||
successfulMovedCards.add(card);
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
throw new UnsupportedOperationException("to Zone not supported yet");
|
||||
}
|
||||
game.fireEvent(new ZoneChangeGroupEvent(successfulMovedCards, source == null ? null : source.getSourceId(), this.getId(), fromZone, toZone));
|
||||
return successfulMovedCards.size() > 0;
|
||||
return moveCards(cards, toZone, source, game, false, false, false, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean moveCards(Card card, Zone toZone, Ability source, Game game) {
|
||||
return moveCards(card, toZone, source, game, false, false, false, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
@ -3025,6 +2999,16 @@ public abstract class PlayerImpl implements Player, Serializable {
|
|||
return moveCards(cardList, toZone, source, game, tapped, faceDown, byOwner, appliedEffects);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean moveCards(Cards cards, Zone toZone, Ability source, Game game) {
|
||||
return moveCards(cards.getCards(game), toZone, source, game);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean moveCards(Set<Card> cards, Zone toZone, Ability source, Game game) {
|
||||
return moveCards(cards, toZone, source, game, false, false, false, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean moveCards(Set<Card> cards, Zone toZone, Ability source, Game game, boolean tapped, boolean faceDown, boolean byOwner, ArrayList<UUID> appliedEffects) {
|
||||
if (cards.isEmpty()) {
|
||||
|
|
@ -3033,7 +3017,11 @@ public abstract class PlayerImpl implements Player, Serializable {
|
|||
Set<Card> successfulMovedCards = new LinkedHashSet<>();
|
||||
Zone fromZone = null;
|
||||
switch (toZone) {
|
||||
case BATTLEFIELD:
|
||||
case GRAVEYARD:
|
||||
fromZone = game.getState().getZone(cards.iterator().next().getId());
|
||||
successfulMovedCards = moveCardsToGraveyardWithInfo(cards, source, game, fromZone);
|
||||
break;
|
||||
case BATTLEFIELD: // new logic that does not yet add the permanents to battlefield while replacement effects are handled
|
||||
List<Permanent> permanents = new ArrayList<>();
|
||||
List<Permanent> permanentsEntered = new ArrayList<>();
|
||||
for (Card card : cards) {
|
||||
|
|
@ -3047,6 +3035,7 @@ public abstract class PlayerImpl implements Player, Serializable {
|
|||
// get permanent
|
||||
Permanent permanent = new PermanentCard(card, event.getPlayerId(), game);// controlling player can be replaced so use event player now
|
||||
permanents.add(permanent);
|
||||
game.getPermanentsEntering().put(permanent.getId(), permanent);
|
||||
card.checkForCountersToAdd(permanent, game);
|
||||
permanent.setTapped(tapped);
|
||||
permanent.setFaceDown(faceDown, game);
|
||||
|
|
@ -3060,6 +3049,8 @@ public abstract class PlayerImpl implements Player, Serializable {
|
|||
fromZone = game.getState().getZone(permanent.getId());
|
||||
if (permanent.entersBattlefield(source.getSourceId(), game, fromZone, true)) {
|
||||
permanentsEntered.add(permanent);
|
||||
} else {
|
||||
game.getPermanentsEntering().remove(permanent.getId());
|
||||
}
|
||||
}
|
||||
game.setScopeRelevant(false);
|
||||
|
|
@ -3071,11 +3062,16 @@ public abstract class PlayerImpl implements Player, Serializable {
|
|||
game.getContinuousEffects().setController(permanent.getId(), permanent.getControllerId());
|
||||
game.addPermanent(permanent);
|
||||
permanent.setZone(Zone.BATTLEFIELD, game);
|
||||
// check if there are counters to add to the permanent (e.g. from non replacement effects like Persist)
|
||||
|
||||
game.getPermanentsEntering().remove(permanent.getId());
|
||||
game.setScopeRelevant(true);
|
||||
successfulMovedCards.add(permanent);
|
||||
game.addSimultaneousEvent(new ZoneChangeEvent(permanent, permanent.getControllerId(), fromZone, Zone.BATTLEFIELD));
|
||||
if (!game.isSimulation()) {
|
||||
game.informPlayers(this.getLogName() + " puts " + (faceDown ? "a card face down " : permanent.getLogName())
|
||||
+ " from " + fromZone.toString().toLowerCase(Locale.ENGLISH) + " onto the Battlefield");
|
||||
}
|
||||
} else {
|
||||
game.getPermanentsEntering().remove(permanent.getId());
|
||||
}
|
||||
}
|
||||
game.applyEffects();
|
||||
|
|
@ -3090,8 +3086,26 @@ public abstract class PlayerImpl implements Player, Serializable {
|
|||
}
|
||||
}
|
||||
break;
|
||||
case EXILED:
|
||||
for (Card card : cards) {
|
||||
fromZone = game.getState().getZone(card.getId());
|
||||
boolean withName = (fromZone.equals(Zone.BATTLEFIELD) || fromZone.equals(Zone.STACK)) || !card.isFaceDown(game);
|
||||
if (moveCardToExileWithInfo(card, null, "", source == null ? null : source.getSourceId(), game, fromZone, withName)) {
|
||||
successfulMovedCards.add(card);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case LIBRARY:
|
||||
for (Card card : cards) {
|
||||
fromZone = game.getState().getZone(card.getId());
|
||||
boolean hideCard = fromZone.equals(Zone.HAND) || fromZone.equals(Zone.LIBRARY);
|
||||
if (moveCardToLibraryWithInfo(card, source == null ? null : source.getSourceId(), game, fromZone, true, !hideCard)) {
|
||||
successfulMovedCards.add(card);
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
throw new UnsupportedOperationException("to Zone not supported yet");
|
||||
throw new UnsupportedOperationException("to Zone" + toZone.toString() + " not supported yet");
|
||||
}
|
||||
|
||||
game.fireEvent(new ZoneChangeGroupEvent(successfulMovedCards, source == null ? null : source.getSourceId(), this.getId(), fromZone, toZone));
|
||||
|
|
@ -3293,16 +3307,19 @@ public abstract class PlayerImpl implements Player, Serializable {
|
|||
return result;
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
@Override
|
||||
public boolean putOntoBattlefieldWithInfo(Card card, Game game, Zone fromZone, UUID sourceId) {
|
||||
return this.putOntoBattlefieldWithInfo(card, game, fromZone, sourceId, false, false);
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
@Override
|
||||
public boolean putOntoBattlefieldWithInfo(Card card, Game game, Zone fromZone, UUID sourceId, boolean tapped) {
|
||||
return this.putOntoBattlefieldWithInfo(card, game, fromZone, sourceId, tapped, false);
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
@Override
|
||||
public boolean putOntoBattlefieldWithInfo(Card card, Game game, Zone fromZone, UUID sourceId, boolean tapped, boolean facedown) {
|
||||
boolean result = false;
|
||||
|
|
|
|||
40
Mage/src/mage/util/functions/AddSubtypeApplier.java
Normal file
40
Mage/src/mage/util/functions/AddSubtypeApplier.java
Normal file
|
|
@ -0,0 +1,40 @@
|
|||
/*
|
||||
* 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.util.functions;
|
||||
|
||||
import mage.MageObject;
|
||||
import mage.game.Game;
|
||||
import mage.game.permanent.Permanent;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author LevelX2
|
||||
*/
|
||||
public class AddSubtypeApplier extends ApplyToPermanent {
|
||||
|
||||
private final String subtype;
|
||||
|
||||
public AddSubtypeApplier(String subtype) {
|
||||
this.subtype = subtype;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Boolean apply(Game game, Permanent permanent) {
|
||||
if (!permanent.getSubtype().contains(subtype)) {
|
||||
permanent.getSubtype().add(subtype);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Boolean apply(Game game, MageObject mageObject) {
|
||||
if (!mageObject.getSubtype().contains(subtype)) {
|
||||
mageObject.getSubtype().add(subtype);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -27,10 +27,36 @@
|
|||
*/
|
||||
package mage.util.functions;
|
||||
|
||||
import mage.MageObject;
|
||||
import mage.constants.CardType;
|
||||
import mage.game.Game;
|
||||
import mage.game.permanent.Permanent;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author LevelX2
|
||||
*/
|
||||
public class CardTypeApplier {
|
||||
public class CardTypeApplier extends ApplyToPermanent {
|
||||
|
||||
private final CardType cardType;
|
||||
|
||||
public CardTypeApplier(CardType cardType) {
|
||||
this.cardType = cardType;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Boolean apply(Game game, Permanent permanent) {
|
||||
if (!permanent.getCardType().contains(cardType)) {
|
||||
permanent.getCardType().add(cardType);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Boolean apply(Game game, MageObject mageObject) {
|
||||
if (!mageObject.getCardType().contains(cardType)) {
|
||||
mageObject.getCardType().add(cardType);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue