Game: fixed rare bugs in some cards after rollback or cancel actions:

* Cumulative upkeep cost - fixed that it can lost payed state (cards: Aboroth, Karplusan Minotaur, Psychic Vortex, Sheltering Ancient);
 * Effects - fixed that it can lost selected targets or other settings (cards: Citadel of Pain, Crimson Honor Guard, Curfew, Leveler, Mana Cache, Monsoon, Paradigm Shift, Saprazzan Bailiff);
 * Exile all cards from graveyard ability - fixed that it can lost targets (example: Agent of Erebos);
 * Melee ability - fixed that it can lost targets (example: Adriana, Captain of the Guard).
This commit is contained in:
Oleg Agafonov 2021-07-07 16:51:53 +04:00
parent 82cc789534
commit 07ddad6e48
60 changed files with 163 additions and 224 deletions

View file

@ -48,6 +48,10 @@ class AborothCost extends CostImpl {
this.text = "Put a -1/-1 counter on Aboroth"; this.text = "Put a -1/-1 counter on Aboroth";
} }
private AborothCost(final AborothCost cost) {
super(cost);
}
@Override @Override
public boolean pay(Ability ability, Game game, Ability source, UUID controllerId, boolean noMana, Cost costToPay) { public boolean pay(Ability ability, Game game, Ability source, UUID controllerId, boolean noMana, Cost costToPay) {
Permanent permanent = game.getPermanent(source.getSourceId()); Permanent permanent = game.getPermanent(source.getSourceId());
@ -66,6 +70,6 @@ class AborothCost extends CostImpl {
@Override @Override
public AborothCost copy() { public AborothCost copy() {
return new AborothCost(); return new AborothCost(this);
} }
} }

View file

@ -43,6 +43,7 @@ public final class AdamaroFirstToDesire extends CardImpl {
} }
class MostCardsInOpponentsHandCount implements DynamicValue { class MostCardsInOpponentsHandCount implements DynamicValue {
@Override @Override
public int calculate(Game game, Ability sourceAbility, Effect effect) { public int calculate(Game game, Ability sourceAbility, Effect effect) {
int maxCards = 0; int maxCards = 0;
@ -59,7 +60,7 @@ class MostCardsInOpponentsHandCount implements DynamicValue {
} }
@Override @Override
public DynamicValue copy() { public MostCardsInOpponentsHandCount copy() {
return new MostCardsInOpponentsHandCount(); return new MostCardsInOpponentsHandCount();
} }

View file

@ -72,7 +72,7 @@ class AlphaStatusDynamicValue implements DynamicValue {
} }
@Override @Override
public DynamicValue copy() { public AlphaStatusDynamicValue copy() {
return new AlphaStatusDynamicValue(); return new AlphaStatusDynamicValue();
} }

View file

@ -69,7 +69,7 @@ class AnathemancerCount implements DynamicValue {
} }
@Override @Override
public DynamicValue copy() { public AnathemancerCount copy() {
return new AnathemancerCount(); return new AnathemancerCount();
} }

View file

@ -61,7 +61,7 @@ class AncientOozePowerToughnessValue implements DynamicValue {
} }
@Override @Override
public DynamicValue copy() { public AncientOozePowerToughnessValue copy() {
return new AncientOozePowerToughnessValue(); return new AncientOozePowerToughnessValue();
} }

View file

@ -59,12 +59,11 @@ class HalfForestsDownCount implements DynamicValue {
@Override @Override
public int calculate(Game game, Ability sourceAbility, Effect effect) { public int calculate(Game game, Ability sourceAbility, Effect effect) {
int amount = game.getBattlefield().countAll(filter, sourceAbility.getControllerId(), game) / 2; return game.getBattlefield().countAll(filter, sourceAbility.getControllerId(), game) / 2;
return amount;
} }
@Override @Override
public DynamicValue copy() { public HalfForestsDownCount copy() {
return new HalfForestsDownCount(); return new HalfForestsDownCount();
} }
@ -94,7 +93,7 @@ class HalfForestsUpCount implements DynamicValue {
} }
@Override @Override
public DynamicValue copy() { public HalfForestsUpCount copy() {
return new HalfForestsUpCount(); return new HalfForestsUpCount();
} }

View file

@ -54,7 +54,7 @@ class BurdenOfGreedCount implements DynamicValue {
} }
@Override @Override
public DynamicValue copy() { public BurdenOfGreedCount copy() {
return new BurdenOfGreedCount(); return new BurdenOfGreedCount();
} }

View file

@ -60,7 +60,7 @@ class SourceControllerLostLifeCount implements DynamicValue {
} }
@Override @Override
public DynamicValue copy() { public SourceControllerLostLifeCount copy() {
return new SourceControllerLostLifeCount(); return new SourceControllerLostLifeCount();
} }

View file

@ -27,10 +27,10 @@ public final class CitadelOfPain extends CardImpl {
public CitadelOfPain(UUID ownerId, CardSetInfo setInfo) { public CitadelOfPain(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{2}{R}"); super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{2}{R}");
// At the beginning of each player's end step, Citadel of Pain deals X damage to that player, where X is the number of untapped lands they control.
TriggeredAbility triggered = new OnEventTriggeredAbility(GameEvent.EventType.END_TURN_STEP_PRE, TriggeredAbility triggered = new OnEventTriggeredAbility(GameEvent.EventType.END_TURN_STEP_PRE,
"beginning of the end step", true, "beginning of the end step", true,
new CitadelOfPainEffect()); new CitadelOfPainEffect());
// At the beginning of each player's end step, Citadel of Pain deals X damage to that player, where X is the number of untapped lands they control.
this.addAbility(triggered); this.addAbility(triggered);
} }
@ -48,11 +48,6 @@ class CitadelOfPainEffect extends OneShotEffect {
private static final FilterPermanent filter = new FilterControlledLandPermanent(); private static final FilterPermanent filter = new FilterControlledLandPermanent();
@Override
public String getText(Mode mode) {
return "{this} deals X damage to that player, where X is the number of untapped lands they control.";
}
static { static {
filter.add(TappedPredicate.UNTAPPED); filter.add(TappedPredicate.UNTAPPED);
} }
@ -61,8 +56,8 @@ class CitadelOfPainEffect extends OneShotEffect {
super(Outcome.Damage); super(Outcome.Damage);
} }
public CitadelOfPainEffect(Outcome outcome) { private CitadelOfPainEffect(final CitadelOfPainEffect effect) {
super(outcome); super(effect);
} }
@Override @Override
@ -77,7 +72,12 @@ class CitadelOfPainEffect extends OneShotEffect {
} }
@Override @Override
public Effect copy() { public CitadelOfPainEffect copy() {
return new CitadelOfPainEffect(); return new CitadelOfPainEffect(this);
}
@Override
public String getText(Mode mode) {
return "{this} deals X damage to that player, where X is the number of untapped lands they control.";
} }
} }

View file

@ -56,12 +56,6 @@ public final class ConquerorsFlail extends CardImpl {
class ConquerorsFlailColorCount implements DynamicValue { class ConquerorsFlailColorCount implements DynamicValue {
public ConquerorsFlailColorCount() {
}
public ConquerorsFlailColorCount(final ConquerorsFlailColorCount dynamicValue) {
}
@Override @Override
public int calculate(Game game, Ability sourceAbility, Effect effect) { public int calculate(Game game, Ability sourceAbility, Effect effect) {
Player controller = game.getPlayer(sourceAbility.getControllerId()); Player controller = game.getPlayer(sourceAbility.getControllerId());
@ -105,7 +99,7 @@ class ConquerorsFlailColorCount implements DynamicValue {
} }
@Override @Override
public DynamicValue copy() { public ConquerorsFlailColorCount copy() {
return new ConquerorsFlailColorCount(); return new ConquerorsFlailColorCount();
} }
} }

View file

@ -62,9 +62,8 @@ class CrimsonHonorGuardEffect extends OneShotEffect {
super(Outcome.Damage); super(Outcome.Damage);
} }
@Override private CrimsonHonorGuardEffect(final CrimsonHonorGuardEffect effect) {
public Effect copy() { super(effect);
return new CrimsonHonorGuardEffect();
} }
@Override @Override
@ -84,4 +83,9 @@ class CrimsonHonorGuardEffect extends OneShotEffect {
public String getText(Mode mode) { public String getText(Mode mode) {
return "{this} deals 4 damage to that player unless they control a commander"; return "{this} deals 4 damage to that player unless they control a commander";
} }
@Override
public CrimsonHonorGuardEffect copy() {
return new CrimsonHonorGuardEffect(this);
}
} }

View file

@ -46,6 +46,10 @@ class CurfewEffect extends OneShotEffect {
staticText = "Each player returns a creature they control to its owner's hand"; staticText = "Each player returns a creature they control to its owner's hand";
} }
private CurfewEffect(final CurfewEffect effect) {
super(effect);
}
@Override @Override
public boolean apply(Game game, Ability source) { public boolean apply(Game game, Ability source) {
game.informPlayers("Each player returns a creature they control to its owner's hand"); game.informPlayers("Each player returns a creature they control to its owner's hand");
@ -64,7 +68,7 @@ class CurfewEffect extends OneShotEffect {
} }
@Override @Override
public Effect copy() { public CurfewEffect copy() {
return new CurfewEffect(); return new CurfewEffect(this);
} }
} }

View file

@ -51,17 +51,3 @@ public final class DemonicAppetite extends CardImpl {
return new DemonicAppetite(this); return new DemonicAppetite(this);
} }
} }
class DemonicAppetiteEffect extends SacrificeTargetEffect {
DemonicAppetiteEffect() {
super();
staticText = "sacrifice a creature";
}
@Override
public DemonicAppetiteEffect copy() {
return new DemonicAppetiteEffect();
}
}

View file

@ -78,7 +78,7 @@ class DyingWishAttachedPermanentPowerCount implements DynamicValue {
} }
@Override @Override
public DynamicValue copy() { public DyingWishAttachedPermanentPowerCount copy() {
return new DyingWishAttachedPermanentPowerCount(); return new DyingWishAttachedPermanentPowerCount();
} }

View file

@ -62,7 +62,7 @@ class CurrentHourCount implements DynamicValue {
} }
@Override @Override
public DynamicValue copy() { public CurrentHourCount copy() {
return new CurrentHourCount(); return new CurrentHourCount();
} }

View file

@ -58,7 +58,7 @@ class EmissaryOfDespairCount implements DynamicValue {
} }
@Override @Override
public DynamicValue copy() { public EmissaryOfDespairCount copy() {
return new EmissaryOfDespairCount(); return new EmissaryOfDespairCount();
} }

View file

@ -57,7 +57,7 @@ class HalfZombiesCount implements DynamicValue {
} }
@Override @Override
public DynamicValue copy() { public HalfZombiesCount copy() {
return new HalfZombiesCount(); return new HalfZombiesCount();
} }

View file

@ -62,7 +62,7 @@ class CardsInControllerLibraryCount implements DynamicValue {
} }
@Override @Override
public DynamicValue copy() { public CardsInControllerLibraryCount copy() {
return new CardsInControllerLibraryCount(); return new CardsInControllerLibraryCount();
} }

View file

@ -134,6 +134,10 @@ class KarplusanMinotaurCost extends CostImpl {
this.text = "Flip a coin"; this.text = "Flip a coin";
} }
private KarplusanMinotaurCost(final KarplusanMinotaurCost cost) {
super(cost);
}
@Override @Override
public boolean pay(Ability ability, Game game, Ability source, UUID controllerId, boolean noMana, Cost costToPay) { public boolean pay(Ability ability, Game game, Ability source, UUID controllerId, boolean noMana, Cost costToPay) {
Player controller = game.getPlayer(controllerId); Player controller = game.getPlayer(controllerId);
@ -158,7 +162,7 @@ class KarplusanMinotaurCost extends CostImpl {
@Override @Override
public KarplusanMinotaurCost copy() { public KarplusanMinotaurCost copy() {
return new KarplusanMinotaurCost(); return new KarplusanMinotaurCost(this);
} }
} }

View file

@ -73,7 +73,7 @@ class AllCountersCount implements DynamicValue {
} }
@Override @Override
public DynamicValue copy() { public AllCountersCount copy() {
return new AllCountersCount(); return new AllCountersCount();
} }

View file

@ -50,9 +50,8 @@ class LevelerExileLibraryEffect extends OneShotEffect {
staticText = "exile all cards from your library"; staticText = "exile all cards from your library";
} }
@Override private LevelerExileLibraryEffect(final LevelerExileLibraryEffect effect) {
public LevelerExileLibraryEffect copy() { super(effect);
return new LevelerExileLibraryEffect();
} }
@Override @Override
@ -66,4 +65,9 @@ class LevelerExileLibraryEffect extends OneShotEffect {
} }
return false; return false;
} }
@Override
public LevelerExileLibraryEffect copy() {
return new LevelerExileLibraryEffect(this);
}
} }

View file

@ -59,7 +59,7 @@ class LordOfExtinctionDynamicCount implements DynamicValue {
} }
@Override @Override
public DynamicValue copy() { public LordOfExtinctionDynamicCount copy() {
return new LordOfExtinctionDynamicCount(); return new LordOfExtinctionDynamicCount();
} }

View file

@ -69,7 +69,7 @@ class CreaturesControlledByChosenPlayer implements DynamicValue {
} }
@Override @Override
public DynamicValue copy() { public CreaturesControlledByChosenPlayer copy() {
return new CreaturesControlledByChosenPlayer(); return new CreaturesControlledByChosenPlayer();
} }

View file

@ -66,9 +66,13 @@ class ManaCacheEffect extends OneShotEffect {
this.staticText = "put a charge counter on {this} for each untapped land that player controls"; this.staticText = "put a charge counter on {this} for each untapped land that player controls";
} }
private ManaCacheEffect(final ManaCacheEffect effect) {
super(effect);
}
@Override @Override
public Effect copy() { public ManaCacheEffect copy() {
return new ManaCacheEffect(); return new ManaCacheEffect(this);
} }
@Override @Override

View file

@ -44,12 +44,11 @@ public final class MercadiasDownfall extends CardImpl {
return new MercadiasDownfall(this); return new MercadiasDownfall(this);
} }
class DefendersNonBasicLandCount implements DynamicValue { static class DefendersNonBasicLandCount implements DynamicValue {
UUID defenderId;
@Override @Override
public int calculate(Game game, Ability sourceAbility, Effect effect) { public int calculate(Game game, Ability sourceAbility, Effect effect) {
UUID defenderId;
for (CombatGroup group : game.getCombat().getGroups()) { for (CombatGroup group : game.getCombat().getGroups()) {
defenderId = group.getDefenderId(); defenderId = group.getDefenderId();
if (group.isDefenderIsPlaneswalker()) { if (group.isDefenderIsPlaneswalker()) {
@ -67,7 +66,7 @@ public final class MercadiasDownfall extends CardImpl {
} }
@Override @Override
public DynamicValue copy() { public DefendersNonBasicLandCount copy() {
return new DefendersNonBasicLandCount(); return new DefendersNonBasicLandCount();
} }

View file

@ -56,8 +56,8 @@ class MonsoonEffect extends OneShotEffect {
this.staticText = "tap all untapped Islands that player controls and {this} deals X damage to the player, where X is the number of Islands tapped this way"; this.staticText = "tap all untapped Islands that player controls and {this} deals X damage to the player, where X is the number of Islands tapped this way";
} }
public MonsoonEffect(Outcome outcome) { private MonsoonEffect(final MonsoonEffect effect) {
super(outcome); super(effect);
} }
@Override @Override
@ -76,7 +76,7 @@ class MonsoonEffect extends OneShotEffect {
} }
@Override @Override
public Effect copy() { public MonsoonEffect copy() {
return new MonsoonEffect(); return new MonsoonEffect(this);
} }
} }

View file

@ -72,7 +72,7 @@ class AttachedPermanentPowerCount implements DynamicValue {
} }
@Override @Override
public DynamicValue copy() { public AttachedPermanentPowerCount copy() {
return new AttachedPermanentPowerCount(); return new AttachedPermanentPowerCount();
} }

View file

@ -68,7 +68,7 @@ class CardsInChosenPlayerHandCount implements DynamicValue {
} }
@Override @Override
public DynamicValue copy() { public CardsInChosenPlayerHandCount copy() {
return new CardsInChosenPlayerHandCount(); return new CardsInChosenPlayerHandCount();
} }

View file

@ -70,7 +70,7 @@ class AnathemancerCount implements DynamicValue {
} }
@Override @Override
public DynamicValue copy() { public AnathemancerCount copy() {
return new AnathemancerCount(); return new AnathemancerCount();
} }

View file

@ -25,7 +25,7 @@ public final class ParadigmShift extends CardImpl {
super(ownerId,setInfo,new CardType[]{CardType.SORCERY},"{1}{U}"); super(ownerId,setInfo,new CardType[]{CardType.SORCERY},"{1}{U}");
// Exile all cards from your library. Then shuffle your graveyard into your library. // Exile all cards from your library. Then shuffle your graveyard into your library.
this.getSpellAbility().addEffect(new ExileLibraryEffect()); this.getSpellAbility().addEffect(new ParadigmShiftExileLibraryEffect());
} }
private ParadigmShift(final ParadigmShift card) { private ParadigmShift(final ParadigmShift card) {
@ -38,16 +38,20 @@ public final class ParadigmShift extends CardImpl {
} }
} }
class ExileLibraryEffect extends OneShotEffect { class ParadigmShiftExileLibraryEffect extends OneShotEffect {
public ExileLibraryEffect() { public ParadigmShiftExileLibraryEffect() {
super(Outcome.Exile); super(Outcome.Exile);
staticText = "Exile all cards from your library. Then shuffle your graveyard into your library"; staticText = "Exile all cards from your library. Then shuffle your graveyard into your library";
} }
private ParadigmShiftExileLibraryEffect(final ParadigmShiftExileLibraryEffect effect) {
super(effect);
}
@Override @Override
public ExileLibraryEffect copy() { public ParadigmShiftExileLibraryEffect copy() {
return new ExileLibraryEffect(); return new ParadigmShiftExileLibraryEffect(this);
} }
@Override @Override

View file

@ -53,7 +53,7 @@ class TargetPermanentPowerPlusToughnessCount implements DynamicValue {
} }
@Override @Override
public DynamicValue copy() { public TargetPermanentPowerPlusToughnessCount copy() {
return new TargetPermanentPowerPlusToughnessCount(); return new TargetPermanentPowerPlusToughnessCount();
} }

View file

@ -68,7 +68,7 @@ class GreatestPowerCount implements DynamicValue {
} }
@Override @Override
public DynamicValue copy() { public GreatestPowerCount copy() {
return new GreatestPowerCount(); return new GreatestPowerCount();
} }

View file

@ -1,4 +1,3 @@
package mage.cards.p; package mage.cards.p;
import java.util.UUID; import java.util.UUID;
@ -58,6 +57,10 @@ class PsychicVortexCost extends CostImpl {
this.text = "Draw a card"; this.text = "Draw a card";
} }
private PsychicVortexCost(final PsychicVortexCost cost) {
super(cost);
}
@Override @Override
public boolean pay(Ability ability, Game game, Ability source, UUID controllerId, boolean noMana, Cost costToPay) { public boolean pay(Ability ability, Game game, Ability source, UUID controllerId, boolean noMana, Cost costToPay) {
Player controller = game.getPlayer(controllerId); Player controller = game.getPlayer(controllerId);
@ -77,6 +80,6 @@ class PsychicVortexCost extends CostImpl {
@Override @Override
public PsychicVortexCost copy() { public PsychicVortexCost copy() {
return new PsychicVortexCost(); return new PsychicVortexCost(this);
} }
} }

View file

@ -59,6 +59,7 @@ public final class RighteousAuthority extends CardImpl {
class CardsInEnchantedControllerHandCount implements DynamicValue { class CardsInEnchantedControllerHandCount implements DynamicValue {
@Override @Override
public int calculate(Game game, Ability sourceAbility, Effect effect) { public int calculate(Game game, Ability sourceAbility, Effect effect) {
if (sourceAbility != null) { if (sourceAbility != null) {
@ -77,7 +78,7 @@ class CardsInEnchantedControllerHandCount implements DynamicValue {
} }
@Override @Override
public DynamicValue copy() { public CardsInEnchantedControllerHandCount copy() {
return new CardsInEnchantedControllerHandCount(); return new CardsInEnchantedControllerHandCount();
} }

View file

@ -61,7 +61,7 @@ class TargetPlayerCardsInHandCount implements DynamicValue {
} }
@Override @Override
public DynamicValue copy() { public TargetPlayerCardsInHandCount copy() {
return new TargetPlayerCardsInHandCount(); return new TargetPlayerCardsInHandCount();
} }

View file

@ -64,9 +64,13 @@ class SaprazzanBailiffEffect extends OneShotEffect {
staticText = "exile all artifact and enchantment cards from all graveyards"; staticText = "exile all artifact and enchantment cards from all graveyards";
} }
private SaprazzanBailiffEffect(final SaprazzanBailiffEffect effect) {
super(effect);
}
@Override @Override
public SaprazzanBailiffEffect copy() { public SaprazzanBailiffEffect copy() {
return new SaprazzanBailiffEffect(); return new SaprazzanBailiffEffect(this);
} }
@Override @Override

View file

@ -72,7 +72,7 @@ class CardsInTargetOpponentsGraveyardCount implements DynamicValue {
} }
@Override @Override
public DynamicValue copy() { public CardsInTargetOpponentsGraveyardCount copy() {
return new CardsInTargetOpponentsGraveyardCount(); return new CardsInTargetOpponentsGraveyardCount();
} }

View file

@ -62,6 +62,10 @@ class ShelteringAncientCost extends CostImpl {
this.text = "Put a +1/+1 counter on a creature an opponent controls"; this.text = "Put a +1/+1 counter on a creature an opponent controls";
} }
private ShelteringAncientCost(final ShelteringAncientCost cost) {
super(cost);
}
@Override @Override
public boolean pay(Ability ability, Game game, Ability source, UUID controllerId, boolean noMana, Cost costToPay) { public boolean pay(Ability ability, Game game, Ability source, UUID controllerId, boolean noMana, Cost costToPay) {
Player controller = game.getPlayer(controllerId); Player controller = game.getPlayer(controllerId);
@ -86,6 +90,6 @@ class ShelteringAncientCost extends CostImpl {
@Override @Override
public ShelteringAncientCost copy() { public ShelteringAncientCost copy() {
return new ShelteringAncientCost(); return new ShelteringAncientCost(this);
} }
} }

View file

@ -67,7 +67,7 @@ class SoullessOneDynamicCount implements DynamicValue {
} }
@Override @Override
public DynamicValue copy() { public SoullessOneDynamicCount copy() {
return new SoullessOneDynamicCount(); return new SoullessOneDynamicCount();
} }

View file

@ -102,7 +102,7 @@ class GreatestPowerCountCreatureYouControl implements DynamicValue {
} }
@Override @Override
public DynamicValue copy() { public GreatestPowerCountCreatureYouControl copy() {
return new GreatestPowerCountCreatureYouControl(); return new GreatestPowerCountCreatureYouControl();
} }

View file

@ -62,7 +62,7 @@ class OtherSpellsCastThisTurnCount implements DynamicValue {
} }
@Override @Override
public DynamicValue copy() { public OtherSpellsCastThisTurnCount copy() {
return new OtherSpellsCastThisTurnCount(); return new OtherSpellsCastThisTurnCount();
} }

View file

@ -104,7 +104,7 @@ class OpponentNoncombatLostLifeCount implements DynamicValue {
} }
@Override @Override
public DynamicValue copy() { public OpponentNoncombatLostLifeCount copy() {
return new OpponentNoncombatLostLifeCount(); return new OpponentNoncombatLostLifeCount();
} }

View file

@ -77,7 +77,7 @@ class TappedCreaturesControlledByTargetCount implements DynamicValue {
} }
@Override @Override
public DynamicValue copy() { public TappedCreaturesControlledByTargetCount copy() {
return new TappedCreaturesControlledByTargetCount(); return new TappedCreaturesControlledByTargetCount();
} }

View file

@ -68,7 +68,7 @@ class TerraRavagerLandCount implements DynamicValue {
} }
@Override @Override
public DynamicValue copy() { public TerraRavagerLandCount copy() {
return new TerraRavagerLandCount(); return new TerraRavagerLandCount();
} }

View file

@ -66,7 +66,7 @@ class ChromaUmbraStalkerCount implements DynamicValue {
} }
@Override @Override
public DynamicValue copy() { public ChromaUmbraStalkerCount copy() {
return new ChromaUmbraStalkerCount(); return new ChromaUmbraStalkerCount();
} }

View file

@ -44,6 +44,15 @@ public final class UrborgJustice extends CardImpl {
class UrborgJusticeDynamicValue implements DynamicValue { class UrborgJusticeDynamicValue implements DynamicValue {
@Override
public int calculate(Game game, Ability sourceAbility, Effect effect) {
CreaturesDiedWatcher watcher = game.getState().getWatcher(CreaturesDiedWatcher.class);
if (watcher != null) {
return watcher.getAmountOfCreaturesDiedThisTurnByOwner(sourceAbility.getControllerId());
}
return 0;
}
@Override @Override
public UrborgJusticeDynamicValue copy() { public UrborgJusticeDynamicValue copy() {
return new UrborgJusticeDynamicValue(); return new UrborgJusticeDynamicValue();
@ -58,13 +67,4 @@ class UrborgJusticeDynamicValue implements DynamicValue {
public String getMessage() { public String getMessage() {
return "creature put into your graveyard from the battlefield this turn"; return "creature put into your graveyard from the battlefield this turn";
} }
@Override
public int calculate(Game game, Ability sourceAbility, Effect effect) {
CreaturesDiedWatcher watcher = game.getState().getWatcher(CreaturesDiedWatcher.class);
if (watcher != null) {
return watcher.getAmountOfCreaturesDiedThisTurnByOwner(sourceAbility.getControllerId());
}
return 0;
}
} }

View file

@ -1,4 +1,3 @@
package mage.cards.w; package mage.cards.w;
import java.util.UUID; import java.util.UUID;
@ -40,7 +39,7 @@ public final class WolfOfDevilsBreach extends CardImpl {
Costs toPay = new CostsImpl<>(); Costs toPay = new CostsImpl<>();
toPay.add(new ManaCostsImpl<>("{1}{R}")); toPay.add(new ManaCostsImpl<>("{1}{R}"));
toPay.add(new DiscardCardCost()); toPay.add(new DiscardCardCost());
Ability ability = new AttacksTriggeredAbility(new DoIfCostPaid(new DamageTargetEffect(new WolfOfDevilsBreachDiscardCostCardConvertedMana()), toPay, Ability ability = new AttacksTriggeredAbility(new DoIfCostPaid(new DamageTargetEffect(new WolfOfDevilsBreachDiscardCostCardConvertedManaCount()), toPay,
"Pay {1}{R} and discard a card to let {this} do damage to target creature or planeswalker equal to the discarded card's mana value?", true), false, "Pay {1}{R} and discard a card to let {this} do damage to target creature or planeswalker equal to the discarded card's mana value?", true), false,
"Whenever {this} attacks, you may pay {1}{R} and discard a card. If you do, {this} deals damage to target creature or planeswalker " "Whenever {this} attacks, you may pay {1}{R} and discard a card. If you do, {this} deals damage to target creature or planeswalker "
+ "equal to the discarded card's mana value."); + "equal to the discarded card's mana value.");
@ -58,7 +57,7 @@ public final class WolfOfDevilsBreach extends CardImpl {
} }
} }
class WolfOfDevilsBreachDiscardCostCardConvertedMana implements DynamicValue { class WolfOfDevilsBreachDiscardCostCardConvertedManaCount implements DynamicValue {
@Override @Override
public int calculate(Game game, Ability sourceAbility, Effect effect) { public int calculate(Game game, Ability sourceAbility, Effect effect) {
@ -84,8 +83,8 @@ class WolfOfDevilsBreachDiscardCostCardConvertedMana implements DynamicValue {
} }
@Override @Override
public WolfOfDevilsBreachDiscardCostCardConvertedMana copy() { public WolfOfDevilsBreachDiscardCostCardConvertedManaCount copy() {
return new WolfOfDevilsBreachDiscardCostCardConvertedMana(); return new WolfOfDevilsBreachDiscardCostCardConvertedManaCount();
} }
@Override @Override

View file

@ -687,7 +687,7 @@ public abstract class CardTestPlayerAPIImpl extends MageTestPlayerBase implement
CardInfo cardInfo = CardRepository.instance.findCard(cardName); CardInfo cardInfo = CardRepository.instance.findCard(cardName);
Card card = cardInfo != null ? cardInfo.getCard() : null; Card card = cardInfo != null ? cardInfo.getCard() : null;
if (card == null) { if (card == null) {
throw new AssertionError("Couldn't find a card: " + cardName); throw new AssertionError("Couldn't find a card in db: " + cardName);
} }
cards.add(card); cards.add(card);

View file

@ -3,11 +3,12 @@ package mage.abilities.costs;
import mage.abilities.Ability; import mage.abilities.Ability;
import mage.game.Game; import mage.game.Game;
import mage.target.Targets; import mage.target.Targets;
import mage.util.Copyable;
import java.io.Serializable; import java.io.Serializable;
import java.util.UUID; import java.util.UUID;
public interface Cost extends Serializable { public interface Cost extends Serializable, Copyable<Cost> {
UUID getId(); UUID getId();

View file

@ -1,4 +1,3 @@
package mage.abilities.costs; package mage.abilities.costs;
import java.util.UUID; import java.util.UUID;
@ -72,5 +71,4 @@ public abstract class CostImpl implements Cost {
public UUID getId() { public UUID getId() {
return this.id; return this.id;
} }
} }

View file

@ -5,7 +5,7 @@ import mage.util.Copyable;
/** /**
* @author LevelX2 * @author LevelX2
*/ */
public interface OptionalAdditionalCost extends Cost, Copyable<OptionalAdditionalCost> { public interface OptionalAdditionalCost extends Cost {
String getName(); String getName();
@ -77,4 +77,6 @@ public interface OptionalAdditionalCost extends Cost, Copyable<OptionalAdditiona
*/ */
int getActivateCount(); int getActivateCount();
@Override
OptionalAdditionalCost copy();
} }

View file

@ -3,11 +3,19 @@ package mage.abilities.dynamicvalue;
import mage.abilities.Ability; import mage.abilities.Ability;
import mage.abilities.effects.Effect; import mage.abilities.effects.Effect;
import mage.game.Game; import mage.game.Game;
import mage.util.Copyable;
import java.io.Serializable; import java.io.Serializable;
public interface DynamicValue extends Serializable { /**
* Dynamic value can be called multiple times from different places, so don't use inner/changeable fields. If you
* use it then think x100 times and override Copy method with copy constructor.
*/
public interface DynamicValue extends Serializable, Copyable<DynamicValue> {
int calculate(Game game, Ability sourceAbility, Effect effect); int calculate(Game game, Ability sourceAbility, Effect effect);
DynamicValue copy(); DynamicValue copy();
String getMessage(); String getMessage();
} }

View file

@ -1,57 +0,0 @@
package mage.abilities.dynamicvalue.common;
import mage.abilities.Ability;
import mage.abilities.dynamicvalue.DynamicValue;
import mage.abilities.effects.Effect;
import mage.constants.Zone;
import mage.game.Game;
import mage.game.permanent.Permanent;
import java.io.ObjectStreamException;
/**
*
* @author LevelX2
*/
public class TargetPermanenToughnessValue implements DynamicValue {
private static final TargetPermanenToughnessValue instance = new TargetPermanenToughnessValue();
private Object readResolve() throws ObjectStreamException {
return instance;
}
public static TargetPermanenToughnessValue getInstance() {
return instance;
}
@Override
public int calculate(Game game, Ability sourceAbility, Effect effect) {
Permanent sourcePermanent = game.getPermanent(sourceAbility.getFirstTarget());
if (sourcePermanent == null) {
sourcePermanent = (Permanent) game.getLastKnownInformation(sourceAbility.getFirstTarget(), Zone.BATTLEFIELD);
}
if (sourcePermanent != null) {
return sourcePermanent.getToughness().getValue();
}
return 0;
}
@Override
public TargetPermanenToughnessValue copy() {
return new TargetPermanenToughnessValue();
}
@Override
public String toString() {
return "X";
}
@Override
public String getMessage() {
return "target creature's toughness";
}
}

View file

@ -6,6 +6,7 @@ import mage.constants.EffectType;
import mage.constants.Outcome; import mage.constants.Outcome;
import mage.game.Game; import mage.game.Game;
import mage.target.targetpointer.TargetPointer; import mage.target.targetpointer.TargetPointer;
import mage.util.Copyable;
import java.io.Serializable; import java.io.Serializable;
import java.util.UUID; import java.util.UUID;
@ -13,7 +14,7 @@ import java.util.UUID;
/** /**
* @author BetaSteward_at_googlemail.com * @author BetaSteward_at_googlemail.com
*/ */
public interface Effect extends Serializable { public interface Effect extends Serializable, Copyable<Effect> {
UUID getId(); UUID getId();

View file

@ -19,5 +19,4 @@ public abstract class OneShotEffect extends EffectImpl {
public OneShotEffect(final OneShotEffect effect) { public OneShotEffect(final OneShotEffect effect) {
super(effect); super(effect);
} }
} }

View file

@ -1,5 +1,3 @@
package mage.abilities.effects.common; package mage.abilities.effects.common;
import mage.abilities.Ability; import mage.abilities.Ability;
@ -21,9 +19,13 @@ public class ExileGraveyardAllTargetPlayerEffect extends OneShotEffect {
staticText = "exile all cards from target player's graveyard"; staticText = "exile all cards from target player's graveyard";
} }
private ExileGraveyardAllTargetPlayerEffect(final ExileGraveyardAllTargetPlayerEffect effect) {
super(effect);
}
@Override @Override
public ExileGraveyardAllTargetPlayerEffect copy() { public ExileGraveyardAllTargetPlayerEffect copy() {
return new ExileGraveyardAllTargetPlayerEffect(); return new ExileGraveyardAllTargetPlayerEffect(this);
} }
@Override @Override

View file

@ -24,7 +24,7 @@ public class ExileSpellEffect extends OneShotEffect {
@Override @Override
public ExileSpellEffect copy() { public ExileSpellEffect copy() {
return new ExileSpellEffect(); return new ExileSpellEffect(this);
} }
@Override @Override

View file

@ -1,42 +0,0 @@
package mage.abilities.effects.common;
import mage.abilities.Ability;
import mage.abilities.effects.OneShotEffect;
import mage.constants.Outcome;
import mage.constants.TurnPhase;
import mage.game.Game;
import mage.game.turn.TurnMod;
import mage.players.Player;
/**
*
* @author escplan9 (Derek Monturo - dmontur1 at gmail dot com)
*/
public class SkipNextCombatEffect extends OneShotEffect {
public SkipNextCombatEffect() {
super(Outcome.Detriment);
staticText = "target opponent skips their next combat phase";
}
public SkipNextCombatEffect(SkipNextCombatEffect effect) {
super(effect);
}
@Override
public boolean apply(Game game, Ability source) {
if (targetPointer != null) {
Player player = game.getPlayer(targetPointer.getFirst(game, source));
if (player != null) {
game.getState().getTurnMods().add(new TurnMod(player.getId(), TurnPhase.COMBAT, null, true));
return true;
}
}
return false;
}
@Override
public SkipNextCombatEffect copy() {
return new SkipNextCombatEffect();
}
}

View file

@ -1,13 +1,13 @@
package mage.abilities.effects.common.turn; package mage.abilities.effects.common.turn;
import java.util.UUID;
import mage.abilities.Ability; import mage.abilities.Ability;
import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.OneShotEffect;
import mage.constants.Outcome; import mage.constants.Outcome;
import mage.game.Game; import mage.game.Game;
import mage.game.turn.TurnMod; import mage.game.turn.TurnMod;
import java.util.UUID;
/** /**
* @author nantuko * @author nantuko
*/ */
@ -35,6 +35,6 @@ public class ControlTargetPlayerNextTurnEffect extends OneShotEffect {
@Override @Override
public ControlTargetPlayerNextTurnEffect copy() { public ControlTargetPlayerNextTurnEffect copy() {
return new ControlTargetPlayerNextTurnEffect(); return new ControlTargetPlayerNextTurnEffect(this);
} }
} }

View file

@ -1,4 +1,3 @@
package mage.abilities.keyword; package mage.abilities.keyword;
import java.util.*; import java.util.*;
@ -71,9 +70,19 @@ class MeleeWatcher extends Watcher {
class MeleeDynamicValue implements DynamicValue { class MeleeDynamicValue implements DynamicValue {
private boolean valueChecked = false; private boolean valueChecked;
private int lockedInValue; private int lockedInValue;
public MeleeDynamicValue() {
super();
}
protected MeleeDynamicValue(final MeleeDynamicValue dynamicValue) {
super();
valueChecked = dynamicValue.valueChecked;
lockedInValue = dynamicValue.lockedInValue;
}
@Override @Override
public int calculate(Game game, Ability sourceAbility, Effect effect) { public int calculate(Game game, Ability sourceAbility, Effect effect) {
MeleeWatcher watcher = game.getState().getWatcher(MeleeWatcher.class); MeleeWatcher watcher = game.getState().getWatcher(MeleeWatcher.class);
@ -89,7 +98,7 @@ class MeleeDynamicValue implements DynamicValue {
@Override @Override
public MeleeDynamicValue copy() { public MeleeDynamicValue copy() {
return new MeleeDynamicValue(); return new MeleeDynamicValue(this);
} }
@Override @Override