1
0
Fork 0
mirror of https://github.com/correl/mage.git synced 2025-04-11 09:11:12 -09:00

* Planeswalker abilities - fixed that plus cost's counters is not affected by replacement effects (, example combo: Planeswalker + Pir, Imaginative Rascal + Doubling Season);

This commit is contained in:
Oleg Agafonov 2019-05-17 16:10:34 +04:00
parent 144613eed8
commit ffbd5d373b
14 changed files with 176 additions and 169 deletions

View file

@ -1,29 +1,25 @@
package mage.cards.c; package mage.cards.c;
import java.util.UUID;
import mage.MageInt; import mage.MageInt;
import mage.abilities.Ability; import mage.abilities.Ability;
import mage.abilities.common.SimpleStaticAbility; import mage.abilities.common.SimpleStaticAbility;
import mage.abilities.effects.ReplacementEffectImpl; import mage.abilities.effects.ReplacementEffectImpl;
import mage.cards.CardImpl; import mage.cards.CardImpl;
import mage.cards.CardSetInfo; import mage.cards.CardSetInfo;
import mage.constants.CardType; import mage.constants.*;
import mage.constants.SubType;
import mage.constants.Duration;
import mage.constants.Outcome;
import mage.constants.Zone;
import mage.counters.CounterType; import mage.counters.CounterType;
import mage.game.Game; import mage.game.Game;
import mage.game.events.GameEvent; import mage.game.events.GameEvent;
import mage.game.permanent.Permanent; import mage.game.permanent.Permanent;
import java.util.UUID;
/** /**
* http://www.wizards.com/magic/magazine/article.aspx?x=mtg/faq/rtr * http://www.wizards.com/magic/magazine/article.aspx?x=mtg/faq/rtr
* * <p>
* If a creature you control would enter the battlefield with a number of +1/+1 * If a creature you control would enter the battlefield with a number of +1/+1
* counters on it, it enters with twice that many instead. * counters on it, it enters with twice that many instead.
* * <p>
* If you control two Corpsejack Menaces, the number of +1/+1 counters placed is * If you control two Corpsejack Menaces, the number of +1/+1 counters placed is
* four times the original number. Three Corpsejack Menaces multiplies the * four times the original number. Three Corpsejack Menaces multiplies the
* original number by eight, and so on. * original number by eight, and so on.
@ -33,7 +29,7 @@ import mage.game.permanent.Permanent;
public final class CorpsejackMenace extends CardImpl { public final class CorpsejackMenace extends CardImpl {
public CorpsejackMenace(UUID ownerId, CardSetInfo setInfo) { public CorpsejackMenace(UUID ownerId, CardSetInfo setInfo) {
super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{2}{B}{G}"); super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{B}{G}");
this.subtype.add(SubType.FUNGUS); this.subtype.add(SubType.FUNGUS);
this.power = new MageInt(4); this.power = new MageInt(4);
@ -67,7 +63,7 @@ class CorpsejackMenaceReplacementEffect extends ReplacementEffectImpl {
@Override @Override
public boolean replaceEvent(GameEvent event, Ability source, Game game) { public boolean replaceEvent(GameEvent event, Ability source, Game game) {
event.setAmount(event.getAmount() * 2); event.setAmountForCounters(event.getAmount() * 2, true);
return false; return false;
} }
@ -78,15 +74,13 @@ class CorpsejackMenaceReplacementEffect extends ReplacementEffectImpl {
@Override @Override
public boolean applies(GameEvent event, Ability source, Game game) { public boolean applies(GameEvent event, Ability source, Game game) {
if (event.getData().equals(CounterType.P1P1.getName())) { if (event.getData().equals(CounterType.P1P1.getName()) && event.getAmount() > 0) {
Permanent permanent = game.getPermanent(event.getTargetId()); Permanent permanent = game.getPermanent(event.getTargetId());
if (permanent == null) { if (permanent == null) {
permanent = game.getPermanentEntering(event.getTargetId()); permanent = game.getPermanentEntering(event.getTargetId());
} }
if (permanent != null && permanent.isControlledBy(source.getControllerId()) return permanent != null && permanent.isControlledBy(source.getControllerId())
&& permanent.isCreature()) { && permanent.isCreature();
return true;
}
} }
return false; return false;
} }

View file

@ -1,7 +1,5 @@
package mage.cards.d; package mage.cards.d;
import java.util.UUID;
import mage.abilities.Ability; import mage.abilities.Ability;
import mage.abilities.common.SimpleStaticAbility; import mage.abilities.common.SimpleStaticAbility;
import mage.abilities.effects.ReplacementEffectImpl; import mage.abilities.effects.ReplacementEffectImpl;
@ -16,8 +14,9 @@ import mage.game.Game;
import mage.game.events.GameEvent; import mage.game.events.GameEvent;
import mage.game.permanent.Permanent; import mage.game.permanent.Permanent;
import java.util.UUID;
/** /**
*
* @author LevelX2 * @author LevelX2
*/ */
public final class DoublingSeason extends CardImpl { public final class DoublingSeason extends CardImpl {
@ -58,7 +57,7 @@ class DoublingSeasonCounterEffect extends ReplacementEffectImpl {
@Override @Override
public boolean replaceEvent(GameEvent event, Ability source, Game game) { public boolean replaceEvent(GameEvent event, Ability source, Game game) {
event.setAmount(event.getAmount() * 2); event.setAmountForCounters(event.getAmount() * 2, true);
return false; return false;
} }
@ -80,6 +79,7 @@ class DoublingSeasonCounterEffect extends ReplacementEffectImpl {
} }
return permanent != null return permanent != null
&& permanent.isControlledBy(source.getControllerId()) && permanent.isControlledBy(source.getControllerId())
&& event.getAmount() > 0
&& !landPlayed; // example: gemstone mine being played as a land drop && !landPlayed; // example: gemstone mine being played as a land drop
} }

View file

@ -1,7 +1,5 @@
package mage.cards.h; package mage.cards.h;
import java.util.UUID;
import mage.abilities.Ability; import mage.abilities.Ability;
import mage.abilities.common.SimpleStaticAbility; import mage.abilities.common.SimpleStaticAbility;
import mage.abilities.effects.ReplacementEffectImpl; import mage.abilities.effects.ReplacementEffectImpl;
@ -17,14 +15,15 @@ import mage.game.events.GameEvent;
import mage.game.events.GameEvent.EventType; import mage.game.events.GameEvent.EventType;
import mage.game.permanent.Permanent; import mage.game.permanent.Permanent;
import java.util.UUID;
/** /**
*
* @author LevelX2 * @author LevelX2
*/ */
public final class HardenedScales extends CardImpl { public final class HardenedScales extends CardImpl {
public HardenedScales(UUID ownerId, CardSetInfo setInfo) { public HardenedScales(UUID ownerId, CardSetInfo setInfo) {
super(ownerId,setInfo,new CardType[]{CardType.ENCHANTMENT},"{G}"); super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{G}");
// If one or more +1/+1 counters would be put on a creature you control, that many plus one +1/+1 counters are put on it instead. // If one or more +1/+1 counters would be put on a creature you control, that many plus one +1/+1 counters are put on it instead.
this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new HardenedScalesEffect())); this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new HardenedScalesEffect()));
@ -54,10 +53,7 @@ class HardenedScalesEffect extends ReplacementEffectImpl {
@Override @Override
public boolean replaceEvent(GameEvent event, Ability source, Game game) { public boolean replaceEvent(GameEvent event, Ability source, Game game) {
int amount = event.getAmount(); event.setAmountForCounters(event.getAmount() + 1, true);
if (amount >= 1) {
event.setAmount(amount + 1);
}
return false; return false;
} }
@ -68,15 +64,13 @@ class HardenedScalesEffect extends ReplacementEffectImpl {
@Override @Override
public boolean applies(GameEvent event, Ability source, Game game) { public boolean applies(GameEvent event, Ability source, Game game) {
if (event.getData().equals(CounterType.P1P1.getName())) { if (event.getData().equals(CounterType.P1P1.getName()) && event.getAmount() > 0) {
Permanent permanent = game.getPermanent(event.getTargetId()); Permanent permanent = game.getPermanent(event.getTargetId());
if (permanent == null) { if (permanent == null) {
permanent = game.getPermanentEntering(event.getTargetId()); permanent = game.getPermanentEntering(event.getTargetId());
} }
if (permanent != null && permanent.isControlledBy(source.getControllerId()) return permanent != null && permanent.isControlledBy(source.getControllerId())
&& permanent.isCreature()) { && permanent.isCreature();
return true;
}
} }
return false; return false;
} }

View file

@ -1,8 +1,5 @@
package mage.cards.m; package mage.cards.m;
import java.util.Set;
import java.util.UUID;
import mage.MageInt; import mage.MageInt;
import mage.abilities.Ability; import mage.abilities.Ability;
import mage.abilities.common.SimpleStaticAbility; import mage.abilities.common.SimpleStaticAbility;
@ -19,14 +16,16 @@ import mage.game.events.GameEvent;
import mage.game.events.GameEvent.EventType; import mage.game.events.GameEvent.EventType;
import mage.game.permanent.Permanent; import mage.game.permanent.Permanent;
import java.util.Set;
import java.util.UUID;
/** /**
*
* @author BetaSteward * @author BetaSteward
*/ */
public final class MeliraSylvokOutcast extends CardImpl { public final class MeliraSylvokOutcast extends CardImpl {
public MeliraSylvokOutcast(UUID ownerId, CardSetInfo setInfo) { public MeliraSylvokOutcast(UUID ownerId, CardSetInfo setInfo) {
super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{1}{G}"); super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{G}");
this.addSuperType(SuperType.LEGENDARY); this.addSuperType(SuperType.LEGENDARY);
this.subtype.add(SubType.HUMAN); this.subtype.add(SubType.HUMAN);
this.subtype.add(SubType.SCOUT); this.subtype.add(SubType.SCOUT);
@ -78,7 +77,7 @@ class MeliraSylvokOutcastEffect extends ReplacementEffectImpl {
@Override @Override
public boolean checksEventType(GameEvent event, Game game) { public boolean checksEventType(GameEvent event, Game game) {
return event.getType() == EventType.ADD_COUNTER; return event.getType() == EventType.ADD_COUNTERS;
} }
@Override @Override
@ -111,7 +110,7 @@ class MeliraSylvokOutcastEffect2 extends ReplacementEffectImpl {
@Override @Override
public boolean checksEventType(GameEvent event, Game game) { public boolean checksEventType(GameEvent event, Game game) {
return event.getType() == EventType.ADD_COUNTER; return event.getType() == EventType.ADD_COUNTERS;
} }
@Override @Override
@ -121,13 +120,10 @@ class MeliraSylvokOutcastEffect2 extends ReplacementEffectImpl {
if (perm == null) { if (perm == null) {
perm = game.getPermanentEntering(event.getTargetId()); perm = game.getPermanentEntering(event.getTargetId());
} }
if (perm != null && perm.isCreature() && perm.isControlledBy(source.getControllerId())) { return perm != null && perm.isCreature() && perm.isControlledBy(source.getControllerId());
return true;
}
} }
return false; return false;
} }
} }
class MeliraSylvokOutcastEffect3 extends ContinuousEffectImpl { class MeliraSylvokOutcastEffect3 extends ContinuousEffectImpl {

View file

@ -63,10 +63,7 @@ class MowuLoyalCompanionEffect extends ReplacementEffectImpl {
@Override @Override
public boolean replaceEvent(GameEvent event, Ability source, Game game) { public boolean replaceEvent(GameEvent event, Ability source, Game game) {
int amount = event.getAmount(); event.setAmountForCounters(event.getAmount() + 1, true);
if (amount > 0) {
event.setAmount(amount + 1);
}
return false; return false;
} }
@ -77,15 +74,13 @@ class MowuLoyalCompanionEffect extends ReplacementEffectImpl {
@Override @Override
public boolean applies(GameEvent event, Ability source, Game game) { public boolean applies(GameEvent event, Ability source, Game game) {
if (event.getData().equals(CounterType.P1P1.getName())) { if (event.getData().equals(CounterType.P1P1.getName()) && event.getAmount() > 0) {
Permanent permanent = game.getPermanent(event.getTargetId()); Permanent permanent = game.getPermanent(event.getTargetId());
if (permanent == null) { if (permanent == null) {
permanent = game.getPermanentEntering(event.getTargetId()); permanent = game.getPermanentEntering(event.getTargetId());
} }
if (permanent != null && permanent.getId().equals(source.getSourceId()) return permanent != null && permanent.getId().equals(source.getSourceId())
&& permanent.isCreature()) { && permanent.isCreature();
return true;
}
} }
return false; return false;
} }

View file

@ -1,27 +1,21 @@
package mage.cards.p; package mage.cards.p;
import java.util.UUID;
import mage.MageInt; import mage.MageInt;
import mage.abilities.Ability; import mage.abilities.Ability;
import mage.abilities.common.SimpleStaticAbility; import mage.abilities.common.SimpleStaticAbility;
import mage.abilities.effects.ReplacementEffectImpl; import mage.abilities.effects.ReplacementEffectImpl;
import mage.abilities.keyword.PartnerWithAbility; import mage.abilities.keyword.PartnerWithAbility;
import mage.constants.SubType;
import mage.constants.SuperType;
import mage.cards.CardImpl; import mage.cards.CardImpl;
import mage.cards.CardSetInfo; import mage.cards.CardSetInfo;
import mage.constants.CardType; import mage.constants.*;
import mage.constants.Duration;
import mage.constants.Outcome;
import mage.constants.Zone;
import mage.game.Game; import mage.game.Game;
import mage.game.events.GameEvent; import mage.game.events.GameEvent;
import mage.game.permanent.Permanent; import mage.game.permanent.Permanent;
import mage.players.Player; import mage.players.Player;
import java.util.UUID;
/** /**
*
* @author TheElk801 * @author TheElk801
*/ */
public final class PirImaginativeRascal extends CardImpl { public final class PirImaginativeRascal extends CardImpl {
@ -65,10 +59,7 @@ class PirImaginativeRascalEffect extends ReplacementEffectImpl {
@Override @Override
public boolean replaceEvent(GameEvent event, Ability source, Game game) { public boolean replaceEvent(GameEvent event, Ability source, Game game) {
int amount = event.getAmount(); event.setAmountForCounters(event.getAmount() + 1, true);
if (amount >= 1) {
event.setAmount(amount + 1);
}
return false; return false;
} }
@ -84,7 +75,7 @@ class PirImaginativeRascalEffect extends ReplacementEffectImpl {
if (permanent == null) { if (permanent == null) {
permanent = game.getPermanentEntering(event.getTargetId()); permanent = game.getPermanentEntering(event.getTargetId());
} }
return permanent != null && player != null return permanent != null && player != null && event.getAmount() > 0
&& !player.hasOpponent(permanent.getControllerId(), game); && !player.hasOpponent(permanent.getControllerId(), game);
} }

View file

@ -1,7 +1,5 @@
package mage.cards.p; package mage.cards.p;
import java.util.UUID;
import mage.abilities.Ability; import mage.abilities.Ability;
import mage.abilities.common.SimpleStaticAbility; import mage.abilities.common.SimpleStaticAbility;
import mage.abilities.effects.ReplacementEffectImpl; import mage.abilities.effects.ReplacementEffectImpl;
@ -15,14 +13,15 @@ import mage.game.Game;
import mage.game.events.GameEvent; import mage.game.events.GameEvent;
import mage.game.permanent.Permanent; import mage.game.permanent.Permanent;
import java.util.UUID;
/** /**
*
* @author LevelX2 * @author LevelX2
*/ */
public final class PrimalVigor extends CardImpl { public final class PrimalVigor extends CardImpl {
public PrimalVigor(UUID ownerId, CardSetInfo setInfo) { public PrimalVigor(UUID ownerId, CardSetInfo setInfo) {
super(ownerId,setInfo,new CardType[]{CardType.ENCHANTMENT},"{4}{G}"); super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{4}{G}");
// If one or more tokens would be created, twice that many of those tokens are created instead. // If one or more tokens would be created, twice that many of those tokens are created instead.
this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new PrimalVigorTokenEffect())); this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new PrimalVigorTokenEffect()));
@ -93,7 +92,7 @@ class PrimalVigorCounterEffect extends ReplacementEffectImpl {
@Override @Override
public boolean replaceEvent(GameEvent event, Ability source, Game game) { public boolean replaceEvent(GameEvent event, Ability source, Game game) {
event.setAmount(event.getAmount() * 2); event.setAmountForCounters(event.getAmount() * 2, true);
return false; return false;
} }
@ -108,11 +107,8 @@ class PrimalVigorCounterEffect extends ReplacementEffectImpl {
if (permanent == null) { if (permanent == null) {
permanent = game.getPermanentEntering(event.getTargetId()); permanent = game.getPermanentEntering(event.getTargetId());
} }
if (permanent != null && permanent.isCreature() return permanent != null && event.getAmount() > 0 && permanent.isCreature()
&& event.getData() != null && event.getData().equals("+1/+1")) { && event.getData() != null && event.getData().equals("+1/+1");
return true;
}
return false;
} }
@Override @Override

View file

@ -1,7 +1,5 @@
package mage.cards.s; package mage.cards.s;
import java.util.UUID;
import mage.MageObject; import mage.MageObject;
import mage.abilities.Ability; import mage.abilities.Ability;
import mage.abilities.common.SimpleStaticAbility; import mage.abilities.common.SimpleStaticAbility;
@ -21,8 +19,9 @@ import mage.game.events.GameEvent.EventType;
import mage.game.permanent.Permanent; import mage.game.permanent.Permanent;
import mage.players.Player; import mage.players.Player;
import java.util.UUID;
/** /**
*
* @author spjspj * @author spjspj
*/ */
public final class Solemnity extends CardImpl { public final class Solemnity extends CardImpl {
@ -70,7 +69,7 @@ class SolemnityEffect extends ReplacementEffectImpl {
@Override @Override
public boolean checksEventType(GameEvent event, Game game) { public boolean checksEventType(GameEvent event, Game game) {
return event.getType() == EventType.ADD_COUNTER; return event.getType() == EventType.ADD_COUNTERS;
} }
@Override @Override
@ -113,7 +112,7 @@ class SolemnityEffect2 extends ReplacementEffectImpl {
@Override @Override
public boolean checksEventType(GameEvent event, Game game) { public boolean checksEventType(GameEvent event, Game game) {
return event.getType() == EventType.ADD_COUNTER || event.getType() == EventType.ADD_COUNTERS; return event.getType() == EventType.ADD_COUNTERS;
} }
@Override @Override
@ -124,21 +123,13 @@ class SolemnityEffect2 extends ReplacementEffectImpl {
Permanent permanent3 = game.getPermanentEntering(event.getTargetId()); Permanent permanent3 = game.getPermanentEntering(event.getTargetId());
if (object instanceof Permanent) { if (object instanceof Permanent) {
if (filter.match((Permanent) object, game)) { return filter.match((Permanent) object, game);
return true;
}
} else if (permanent != null) { } else if (permanent != null) {
if (filter.match(permanent, game)) { return filter.match(permanent, game);
return true;
}
} else if (permanent2 != null) { } else if (permanent2 != null) {
if (filter.match(permanent2, game)) { return filter.match(permanent2, game);
return true;
}
} else if (permanent3 != null) { } else if (permanent3 != null) {
if (filter.match(permanent3, game)) { return filter.match(permanent3, game);
return true;
}
} }
return false; return false;

View file

@ -1,24 +1,19 @@
package mage.cards.v; package mage.cards.v;
import java.util.UUID;
import mage.MageInt; import mage.MageInt;
import mage.abilities.Ability; import mage.abilities.Ability;
import mage.abilities.common.SimpleStaticAbility; import mage.abilities.common.SimpleStaticAbility;
import mage.abilities.effects.ReplacementEffectImpl; import mage.abilities.effects.ReplacementEffectImpl;
import mage.cards.CardImpl; import mage.cards.CardImpl;
import mage.cards.CardSetInfo; import mage.cards.CardSetInfo;
import mage.constants.CardType; import mage.constants.*;
import mage.constants.SubType;
import mage.constants.Duration;
import mage.constants.Outcome;
import mage.constants.Zone;
import mage.counters.CounterType; import mage.counters.CounterType;
import mage.game.Game; import mage.game.Game;
import mage.game.events.GameEvent; import mage.game.events.GameEvent;
import java.util.UUID;
/** /**
*
* @author Stravant * @author Stravant
*/ */
public final class VizierOfRemedies extends CardImpl { public final class VizierOfRemedies extends CardImpl {
@ -64,7 +59,7 @@ class VizierOfRemediesReplacementEffect extends ReplacementEffectImpl {
@Override @Override
public boolean replaceEvent(GameEvent event, Ability source, Game game) { public boolean replaceEvent(GameEvent event, Ability source, Game game) {
event.setAmount(event.getAmount() - 1); event.setAmountForCounters(event.getAmount() - 1, true);
return false; return false;
} }
@ -76,11 +71,9 @@ class VizierOfRemediesReplacementEffect extends ReplacementEffectImpl {
@Override @Override
public boolean applies(GameEvent event, Ability source, Game game) { public boolean applies(GameEvent event, Ability source, Game game) {
if (source != null && source.getControllerId() != null) { if (source != null && source.getControllerId() != null) {
if (source.isControlledBy(game.getControllerId(event.getTargetId())) return source.isControlledBy(game.getControllerId(event.getTargetId()))
&& event.getData() != null && event.getData().equals(CounterType.M1M1.getName()) && event.getData() != null && event.getData().equals(CounterType.M1M1.getName())
&& event.getAmount() > 0) { && event.getAmount() > 0;
return true;
}
} }
return false; return false;
} }

View file

@ -1,25 +1,20 @@
package mage.cards.w; package mage.cards.w;
import java.util.UUID;
import mage.MageInt; import mage.MageInt;
import mage.abilities.Ability; import mage.abilities.Ability;
import mage.abilities.common.SimpleStaticAbility; import mage.abilities.common.SimpleStaticAbility;
import mage.abilities.effects.ReplacementEffectImpl; import mage.abilities.effects.ReplacementEffectImpl;
import mage.cards.CardImpl; import mage.cards.CardImpl;
import mage.cards.CardSetInfo; import mage.cards.CardSetInfo;
import mage.constants.CardType; import mage.constants.*;
import mage.constants.SubType;
import mage.constants.Duration;
import mage.constants.Outcome;
import mage.constants.Zone;
import mage.game.Game; import mage.game.Game;
import mage.game.events.GameEvent; import mage.game.events.GameEvent;
import mage.game.permanent.Permanent; import mage.game.permanent.Permanent;
import mage.players.Player; import mage.players.Player;
import java.util.UUID;
/** /**
*
* @author LevelX2 * @author LevelX2
*/ */
public final class WindingConstrictor extends CardImpl { public final class WindingConstrictor extends CardImpl {
@ -32,7 +27,7 @@ public final class WindingConstrictor extends CardImpl {
this.toughness = new MageInt(3); this.toughness = new MageInt(3);
// If one or more counters would be put on an artifact or creature you control, that many plus one of each of those kinds of counters are put on that permanent instead. // If one or more counters would be put on an artifact or creature you control, that many plus one of each of those kinds of counters are put on that permanent instead.
this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new WindingConstrictorPermanentEffect())); this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new WindingConstrictorPermanentEffect()));
// If you would get one or more counters, you get that many plus one of each of those kinds of counters instead. // If you would get one or more counters, you get that many plus one of each of those kinds of counters instead.
this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new WindingConstrictorPlayerEffect())); this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new WindingConstrictorPlayerEffect()));
@ -62,7 +57,7 @@ class WindingConstrictorPermanentEffect extends ReplacementEffectImpl {
@Override @Override
public boolean replaceEvent(GameEvent event, Ability source, Game game) { public boolean replaceEvent(GameEvent event, Ability source, Game game) {
event.setAmount(event.getAmount() + 1); event.setAmountForCounters(event.getAmount() + 1, true);
return false; return false;
} }
@ -78,6 +73,7 @@ class WindingConstrictorPermanentEffect extends ReplacementEffectImpl {
permanent = game.getPermanentEntering(event.getTargetId()); permanent = game.getPermanentEntering(event.getTargetId());
} }
return permanent != null return permanent != null
&& event.getAmount() > 0
&& (permanent.isCreature() || permanent.isArtifact()) && (permanent.isCreature() || permanent.isArtifact())
&& permanent.isControlledBy(source.getControllerId()); && permanent.isControlledBy(source.getControllerId());
} }
@ -106,7 +102,7 @@ class WindingConstrictorPlayerEffect extends ReplacementEffectImpl {
@Override @Override
public boolean replaceEvent(GameEvent event, Ability source, Game game) { public boolean replaceEvent(GameEvent event, Ability source, Game game) {
event.setAmount(event.getAmount() + 1); event.setAmountForCounters(event.getAmount() + 1, true);
return false; return false;
} }
@ -118,7 +114,7 @@ class WindingConstrictorPlayerEffect extends ReplacementEffectImpl {
@Override @Override
public boolean applies(GameEvent event, Ability source, Game game) { public boolean applies(GameEvent event, Ability source, Game game) {
Player player = game.getPlayer(event.getTargetId()); Player player = game.getPlayer(event.getTargetId());
return player != null && player.getId().equals(source.getControllerId()); return player != null && player.getId().equals(source.getControllerId()) && event.getAmount() > 0;
} }
@Override @Override

View file

@ -205,7 +205,7 @@ public class DoublingSeasonTest extends CardTestPlayerBase {
addCard(Zone.BATTLEFIELD, playerA, "Doubling Season"); addCard(Zone.BATTLEFIELD, playerA, "Doubling Season");
activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA,"+1: Draw a card, then discard a card at random."); activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "+1: Draw a card, then discard a card at random.");
setStopAt(1, PhaseStep.END_TURN); setStopAt(1, PhaseStep.END_TURN);
execute(); execute();
@ -216,4 +216,38 @@ public class DoublingSeasonTest extends CardTestPlayerBase {
//Should not be doubled //Should not be doubled
assertCounterCount("Tibalt, the Fiend-Blooded", CounterType.LOYALTY, 3); assertCounterCount("Tibalt, the Fiend-Blooded", CounterType.LOYALTY, 3);
} }
/**
* +1 cost is not affected by double, but replace event like Pir, Imaginative Rascal will be affected
* https://github.com/magefree/mage/issues/5802
*/
@Test
public void testPlaneswalkerWithoutReplacementEffect() {
//addCard(Zone.BATTLEFIELD, playerA, "Pir, Imaginative Rascal");
addCard(Zone.BATTLEFIELD, playerA, "Chandra, Fire Artisan");
addCard(Zone.BATTLEFIELD, playerA, "Doubling Season");
activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "+1");
setStopAt(1, PhaseStep.END_TURN);
execute();
assertAllCommandsUsed();
assertCounterCount(playerA, "Chandra, Fire Artisan", CounterType.LOYALTY, 4 + 1);
}
@Test
public void testPlaneswalkerWithReplacementEffect() {
addCard(Zone.BATTLEFIELD, playerA, "Chandra, Fire Artisan");
addCard(Zone.BATTLEFIELD, playerA, "Doubling Season"); // x2 counters
addCard(Zone.BATTLEFIELD, playerA, "Pir, Imaginative Rascal"); // +1 counter
activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "+1");
setStopAt(1, PhaseStep.END_TURN);
execute();
assertAllCommandsUsed();
assertCounterCount(playerA, "Chandra, Fire Artisan", CounterType.LOYALTY, 4 + (1 + 1) * 2);
}
} }

View file

@ -690,27 +690,33 @@ public abstract class CardImpl extends MageObjectImpl implements Card {
sourceId = source.getSourceId(); sourceId = source.getSourceId();
} }
} }
GameEvent countersEvent = GameEvent.getEvent(GameEvent.EventType.ADD_COUNTERS, objectId, sourceId, getControllerOrOwner(), counter.getName(), counter.getCount()); GameEvent addingAllEvent = GameEvent.getEvent(GameEvent.EventType.ADD_COUNTERS, objectId, sourceId, getControllerOrOwner(), counter.getName(), counter.getCount());
countersEvent.setAppliedEffects(appliedEffects); addingAllEvent.setAppliedEffects(appliedEffects);
countersEvent.setFlag(isEffect); addingAllEvent.setFlag(isEffect);
if (!game.replaceEvent(countersEvent)) { if (!game.replaceEvent(addingAllEvent)) {
int amount = countersEvent.getAmount(); int amount = addingAllEvent.getAmount();
boolean isEffectFlag = addingAllEvent.getFlag();
int finalAmount = amount; int finalAmount = amount;
for (int i = 0; i < amount; i++) { for (int i = 0; i < amount; i++) {
Counter eventCounter = counter.copy(); Counter eventCounter = counter.copy();
eventCounter.remove(eventCounter.getCount() - 1); eventCounter.remove(eventCounter.getCount() - 1);
GameEvent event = GameEvent.getEvent(GameEvent.EventType.ADD_COUNTER, objectId, sourceId, getControllerOrOwner(), counter.getName(), 1); GameEvent addingOneEvent = GameEvent.getEvent(GameEvent.EventType.ADD_COUNTER, objectId, sourceId, getControllerOrOwner(), counter.getName(), 1);
event.setAppliedEffects(appliedEffects); addingOneEvent.setAppliedEffects(appliedEffects);
if (!game.replaceEvent(event)) { addingOneEvent.setFlag(isEffectFlag);
if (!game.replaceEvent(addingOneEvent)) {
getCounters(game).addCounter(eventCounter); getCounters(game).addCounter(eventCounter);
game.fireEvent(GameEvent.getEvent(GameEvent.EventType.COUNTER_ADDED, objectId, sourceId, getControllerOrOwner(), counter.getName(), 1)); GameEvent addedOneEvent = GameEvent.getEvent(GameEvent.EventType.COUNTER_ADDED, objectId, sourceId, getControllerOrOwner(), counter.getName(), 1);
addedOneEvent.setFlag(addingOneEvent.getFlag());
game.fireEvent(addedOneEvent);
} else { } else {
finalAmount--; finalAmount--;
returnCode = false; returnCode = false;
} }
} }
if (finalAmount > 0) { if (finalAmount > 0) {
game.fireEvent(GameEvent.getEvent(GameEvent.EventType.COUNTERS_ADDED, objectId, sourceId, getControllerOrOwner(), counter.getName(), amount)); GameEvent addedAllEvent = GameEvent.getEvent(GameEvent.EventType.COUNTERS_ADDED, objectId, sourceId, getControllerOrOwner(), counter.getName(), amount);
addedAllEvent.setFlag(isEffectFlag);
game.fireEvent(addedAllEvent);
} }
} else { } else {
returnCode = false; returnCode = false;

View file

@ -18,6 +18,9 @@ public class GameEvent implements Serializable {
protected UUID sourceId; protected UUID sourceId;
protected UUID playerId; protected UUID playerId;
protected int amount; protected int amount;
// flags:
// for counters: event is result of effect (+1 from planeswalkers is cost, not effect)
// for combat damage: event is preventable damage
protected boolean flag; protected boolean flag;
protected String data; protected String data;
protected Zone zone; protected Zone zone;
@ -433,6 +436,17 @@ public class GameEvent implements Serializable {
this.amount = amount; this.amount = amount;
} }
public void setAmountForCounters(int amount, boolean isEffect) {
this.amount = amount;
// cost event must be "transformed" to effect event, as example:
// planeswalker's +1 cost will be affected by Pir, Imaginative Rascal (1 + 1) and applied as effect by Doubling Season (2 * 2)
// https://github.com/magefree/mage/issues/5802
if (isEffect) {
setFlag(true);
}
}
public boolean getFlag() { public boolean getFlag() {
return flag; return flag;
} }

View file

@ -1,10 +1,6 @@
package mage.players; package mage.players;
import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableMap;
import java.io.Serializable;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.Map.Entry;
import mage.ConditionalMana; import mage.ConditionalMana;
import mage.MageObject; import mage.MageObject;
import mage.MageObjectReference; import mage.MageObjectReference;
@ -70,6 +66,11 @@ import mage.util.GameLog;
import mage.util.RandomUtil; import mage.util.RandomUtil;
import org.apache.log4j.Logger; import org.apache.log4j.Logger;
import java.io.Serializable;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.Map.Entry;
public abstract class PlayerImpl implements Player, Serializable { public abstract class PlayerImpl implements Player, Serializable {
private static final Logger logger = Logger.getLogger(PlayerImpl.class); private static final Logger logger = Logger.getLogger(PlayerImpl.class);
@ -1416,10 +1417,10 @@ public abstract class PlayerImpl implements Player, Serializable {
!= null != null
// if anyone sees an issue with this code, please report it. Worked in my testing. // if anyone sees an issue with this code, please report it. Worked in my testing.
|| game.getContinuousEffects().asThough(object.getId(), || game.getContinuousEffects().asThough(object.getId(),
AsThoughEffectType.PLAY_FROM_NOT_OWN_HAND_ZONE, AsThoughEffectType.PLAY_FROM_NOT_OWN_HAND_ZONE,
ability, ability,
this.getId(), this.getId(),
game) game)
!= null) { != null) {
if (canUse if (canUse
|| ability.getAbilityType() == AbilityType.SPECIAL_ACTION) { || ability.getAbilityType() == AbilityType.SPECIAL_ACTION) {
@ -2009,24 +2010,30 @@ public abstract class PlayerImpl implements Player, Serializable {
@Override @Override
public boolean addCounters(Counter counter, Game game) { public boolean addCounters(Counter counter, Game game) {
boolean returnCode = true; boolean returnCode = true;
GameEvent countersEvent = GameEvent.getEvent(EventType.ADD_COUNTERS, playerId, null, playerId, counter.getName(), counter.getCount()); GameEvent addingAllEvent = GameEvent.getEvent(EventType.ADD_COUNTERS, playerId, null, playerId, counter.getName(), counter.getCount());
if (!game.replaceEvent(countersEvent)) { if (!game.replaceEvent(addingAllEvent)) {
int amount = countersEvent.getAmount(); int amount = addingAllEvent.getAmount();
int finalAmount = amount; int finalAmount = amount;
boolean isEffectFlag = addingAllEvent.getFlag();
for (int i = 0; i < amount; i++) { for (int i = 0; i < amount; i++) {
Counter eventCounter = counter.copy(); Counter eventCounter = counter.copy();
eventCounter.remove(eventCounter.getCount() - 1); eventCounter.remove(eventCounter.getCount() - 1);
GameEvent event = GameEvent.getEvent(EventType.ADD_COUNTER, playerId, null, playerId, counter.getName(), 1); GameEvent addingOneEvent = GameEvent.getEvent(EventType.ADD_COUNTER, playerId, null, playerId, counter.getName(), 1);
if (!game.replaceEvent(event)) { addingOneEvent.setFlag(isEffectFlag);
if (!game.replaceEvent(addingOneEvent)) {
getCounters().addCounter(eventCounter); getCounters().addCounter(eventCounter);
game.fireEvent(GameEvent.getEvent(EventType.COUNTER_ADDED, playerId, null, playerId, counter.getName(), 1)); GameEvent addedOneEvent = GameEvent.getEvent(EventType.COUNTER_ADDED, playerId, null, playerId, counter.getName(), 1);
addedOneEvent.setFlag(addingOneEvent.getFlag());
game.fireEvent(addedOneEvent);
} else { } else {
finalAmount--; finalAmount--;
returnCode = false; returnCode = false;
} }
} }
if (finalAmount > 0) { if (finalAmount > 0) {
game.fireEvent(GameEvent.getEvent(EventType.COUNTERS_ADDED, playerId, null, playerId, counter.getName(), amount)); GameEvent addedAllEvent = GameEvent.getEvent(EventType.COUNTERS_ADDED, playerId, null, playerId, counter.getName(), amount);
addedAllEvent.setFlag(addingAllEvent.getFlag());
game.fireEvent(addedAllEvent);
} }
} else { } else {
returnCode = false; returnCode = false;
@ -2637,7 +2644,7 @@ public abstract class PlayerImpl implements Player, Serializable {
/** /**
* @param game * @param game
* @param appliedEffects * @param appliedEffects
* @param numSides Number of sides the dice has * @param numSides Number of sides the dice has
* @return the number that the player rolled * @return the number that the player rolled
*/ */
@Override @Override
@ -2671,10 +2678,10 @@ public abstract class PlayerImpl implements Player, Serializable {
/** /**
* @param game * @param game
* @param appliedEffects * @param appliedEffects
* @param numberChaosSides The number of chaos sides the planar die * @param numberChaosSides The number of chaos sides the planar die
* currently has (normally 1 but can be 5) * currently has (normally 1 but can be 5)
* @param numberPlanarSides The number of chaos sides the planar die * @param numberPlanarSides The number of chaos sides the planar die
* currently has (normally 1) * currently has (normally 1)
* @return the outcome that the player rolled. Either ChaosRoll, PlanarRoll * @return the outcome that the player rolled. Either ChaosRoll, PlanarRoll
* or NilRoll * or NilRoll
*/ */
@ -2831,7 +2838,7 @@ public abstract class PlayerImpl implements Player, Serializable {
/** /**
* @param ability * @param ability
* @param available if null, it won't be checked if enough mana is available * @param available if null, it won't be checked if enough mana is available
* @param sourceObject * @param sourceObject
* @param game * @param game
* @return * @return
@ -3381,7 +3388,7 @@ public abstract class PlayerImpl implements Player, Serializable {
@Override @Override
public boolean canPaySacrificeCost(Permanent permanent, UUID sourceId, public boolean canPaySacrificeCost(Permanent permanent, UUID sourceId,
UUID controllerId, Game game UUID controllerId, Game game
) { ) {
return sacrificeCostFilter == null || !sacrificeCostFilter.match(permanent, sourceId, controllerId, game); return sacrificeCostFilter == null || !sacrificeCostFilter.match(permanent, sourceId, controllerId, game);
} }
@ -3532,8 +3539,8 @@ public abstract class PlayerImpl implements Player, Serializable {
@Override @Override
public boolean moveCards(Card card, Zone toZone, public boolean moveCards(Card card, Zone toZone,
Ability source, Game game, Ability source, Game game,
boolean tapped, boolean faceDown, boolean byOwner, List<UUID> appliedEffects boolean tapped, boolean faceDown, boolean byOwner, List<UUID> appliedEffects
) { ) {
Set<Card> cardList = new HashSet<>(); Set<Card> cardList = new HashSet<>();
if (card != null) { if (card != null) {
@ -3544,22 +3551,22 @@ public abstract class PlayerImpl implements Player, Serializable {
@Override @Override
public boolean moveCards(Cards cards, Zone toZone, public boolean moveCards(Cards cards, Zone toZone,
Ability source, Game game Ability source, Game game
) { ) {
return moveCards(cards.getCards(game), toZone, source, game); return moveCards(cards.getCards(game), toZone, source, game);
} }
@Override @Override
public boolean moveCards(Set<Card> cards, Zone toZone, public boolean moveCards(Set<Card> cards, Zone toZone,
Ability source, Game game Ability source, Game game
) { ) {
return moveCards(cards, toZone, source, game, false, false, false, null); return moveCards(cards, toZone, source, game, false, false, false, null);
} }
@Override @Override
public boolean moveCards(Set<Card> cards, Zone toZone, public boolean moveCards(Set<Card> cards, Zone toZone,
Ability source, Game game, Ability source, Game game,
boolean tapped, boolean faceDown, boolean byOwner, List<UUID> appliedEffects boolean tapped, boolean faceDown, boolean byOwner, List<UUID> appliedEffects
) { ) {
if (cards.isEmpty()) { if (cards.isEmpty()) {
return true; return true;
@ -3645,8 +3652,8 @@ public abstract class PlayerImpl implements Player, Serializable {
@Override @Override
public boolean moveCardsToExile(Card card, Ability source, public boolean moveCardsToExile(Card card, Ability source,
Game game, boolean withName, UUID exileId, Game game, boolean withName, UUID exileId,
String exileZoneName String exileZoneName
) { ) {
Set<Card> cards = new HashSet<>(); Set<Card> cards = new HashSet<>();
cards.add(card); cards.add(card);
@ -3655,8 +3662,8 @@ public abstract class PlayerImpl implements Player, Serializable {
@Override @Override
public boolean moveCardsToExile(Set<Card> cards, Ability source, public boolean moveCardsToExile(Set<Card> cards, Ability source,
Game game, boolean withName, UUID exileId, Game game, boolean withName, UUID exileId,
String exileZoneName String exileZoneName
) { ) {
if (cards.isEmpty()) { if (cards.isEmpty()) {
return true; return true;
@ -3671,14 +3678,14 @@ public abstract class PlayerImpl implements Player, Serializable {
@Override @Override
public boolean moveCardToHandWithInfo(Card card, UUID sourceId, public boolean moveCardToHandWithInfo(Card card, UUID sourceId,
Game game Game game
) { ) {
return this.moveCardToHandWithInfo(card, sourceId, game, true); return this.moveCardToHandWithInfo(card, sourceId, game, true);
} }
@Override @Override
public boolean moveCardToHandWithInfo(Card card, UUID sourceId, public boolean moveCardToHandWithInfo(Card card, UUID sourceId,
Game game, boolean withName Game game, boolean withName
) { ) {
boolean result = false; boolean result = false;
Zone fromZone = game.getState().getZone(card.getId()); Zone fromZone = game.getState().getZone(card.getId());
@ -3703,7 +3710,7 @@ public abstract class PlayerImpl implements Player, Serializable {
@Override @Override
public Set<Card> moveCardsToGraveyardWithInfo(Set<Card> allCards, Ability source, public Set<Card> moveCardsToGraveyardWithInfo(Set<Card> allCards, Ability source,
Game game, Zone fromZone Game game, Zone fromZone
) { ) {
UUID sourceId = source == null ? null : source.getSourceId(); UUID sourceId = source == null ? null : source.getSourceId();
Set<Card> movedCards = new LinkedHashSet<>(); Set<Card> movedCards = new LinkedHashSet<>();
@ -3711,7 +3718,7 @@ public abstract class PlayerImpl implements Player, Serializable {
// identify cards from one owner // identify cards from one owner
Cards cards = new CardsImpl(); Cards cards = new CardsImpl();
UUID ownerId = null; UUID ownerId = null;
for (Iterator<Card> it = allCards.iterator(); it.hasNext();) { for (Iterator<Card> it = allCards.iterator(); it.hasNext(); ) {
Card card = it.next(); Card card = it.next();
if (cards.isEmpty()) { if (cards.isEmpty()) {
ownerId = card.getOwnerId(); ownerId = card.getOwnerId();
@ -3772,7 +3779,7 @@ public abstract class PlayerImpl implements Player, Serializable {
@Override @Override
public boolean moveCardToGraveyardWithInfo(Card card, UUID sourceId, public boolean moveCardToGraveyardWithInfo(Card card, UUID sourceId,
Game game, Zone fromZone Game game, Zone fromZone
) { ) {
if (card == null) { if (card == null) {
return false; return false;
@ -3801,8 +3808,8 @@ public abstract class PlayerImpl implements Player, Serializable {
@Override @Override
public boolean moveCardToLibraryWithInfo(Card card, UUID sourceId, public boolean moveCardToLibraryWithInfo(Card card, UUID sourceId,
Game game, Zone fromZone, Game game, Zone fromZone,
boolean toTop, boolean withName boolean toTop, boolean withName
) { ) {
if (card == null) { if (card == null) {
return false; return false;
@ -3836,7 +3843,7 @@ public abstract class PlayerImpl implements Player, Serializable {
@Override @Override
public boolean moveCardToExileWithInfo(Card card, UUID exileId, String exileName, UUID sourceId, public boolean moveCardToExileWithInfo(Card card, UUID exileId, String exileName, UUID sourceId,
Game game, Zone fromZone, boolean withName) { Game game, Zone fromZone, boolean withName) {
if (card == null) { if (card == null) {
return false; return false;
} }