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";
}
private AborothCost(final AborothCost cost) {
super(cost);
}
@Override
public boolean pay(Ability ability, Game game, Ability source, UUID controllerId, boolean noMana, Cost costToPay) {
Permanent permanent = game.getPermanent(source.getSourceId());
@ -66,6 +70,6 @@ class AborothCost extends CostImpl {
@Override
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 {
@Override
public int calculate(Game game, Ability sourceAbility, Effect effect) {
int maxCards = 0;
@ -59,7 +60,7 @@ class MostCardsInOpponentsHandCount implements DynamicValue {
}
@Override
public DynamicValue copy() {
public MostCardsInOpponentsHandCount copy() {
return new MostCardsInOpponentsHandCount();
}

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -27,10 +27,10 @@ public final class CitadelOfPain extends CardImpl {
public CitadelOfPain(UUID ownerId, CardSetInfo setInfo) {
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,
"beginning of the end step", true,
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);
}
@ -48,11 +48,6 @@ class CitadelOfPainEffect extends OneShotEffect {
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 {
filter.add(TappedPredicate.UNTAPPED);
}
@ -61,8 +56,8 @@ class CitadelOfPainEffect extends OneShotEffect {
super(Outcome.Damage);
}
public CitadelOfPainEffect(Outcome outcome) {
super(outcome);
private CitadelOfPainEffect(final CitadelOfPainEffect effect) {
super(effect);
}
@Override
@ -77,7 +72,12 @@ class CitadelOfPainEffect extends OneShotEffect {
}
@Override
public Effect copy() {
return new CitadelOfPainEffect();
public CitadelOfPainEffect copy() {
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 {
public ConquerorsFlailColorCount() {
}
public ConquerorsFlailColorCount(final ConquerorsFlailColorCount dynamicValue) {
}
@Override
public int calculate(Game game, Ability sourceAbility, Effect effect) {
Player controller = game.getPlayer(sourceAbility.getControllerId());
@ -105,7 +99,7 @@ class ConquerorsFlailColorCount implements DynamicValue {
}
@Override
public DynamicValue copy() {
public ConquerorsFlailColorCount copy() {
return new ConquerorsFlailColorCount();
}
}

View file

@ -62,9 +62,8 @@ class CrimsonHonorGuardEffect extends OneShotEffect {
super(Outcome.Damage);
}
@Override
public Effect copy() {
return new CrimsonHonorGuardEffect();
private CrimsonHonorGuardEffect(final CrimsonHonorGuardEffect effect) {
super(effect);
}
@Override
@ -84,4 +83,9 @@ class CrimsonHonorGuardEffect extends OneShotEffect {
public String getText(Mode mode) {
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";
}
private CurfewEffect(final CurfewEffect effect) {
super(effect);
}
@Override
public boolean apply(Game game, Ability source) {
game.informPlayers("Each player returns a creature they control to its owner's hand");
@ -64,7 +68,7 @@ class CurfewEffect extends OneShotEffect {
}
@Override
public Effect copy() {
return new CurfewEffect();
public CurfewEffect copy() {
return new CurfewEffect(this);
}
}

View file

@ -51,17 +51,3 @@ public final class DemonicAppetite extends CardImpl {
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
public DynamicValue copy() {
public DyingWishAttachedPermanentPowerCount copy() {
return new DyingWishAttachedPermanentPowerCount();
}

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -69,7 +69,7 @@ class CreaturesControlledByChosenPlayer implements DynamicValue {
}
@Override
public DynamicValue copy() {
public CreaturesControlledByChosenPlayer copy() {
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";
}
private ManaCacheEffect(final ManaCacheEffect effect) {
super(effect);
}
@Override
public Effect copy() {
return new ManaCacheEffect();
public ManaCacheEffect copy() {
return new ManaCacheEffect(this);
}
@Override

View file

@ -44,12 +44,11 @@ public final class MercadiasDownfall extends CardImpl {
return new MercadiasDownfall(this);
}
class DefendersNonBasicLandCount implements DynamicValue {
UUID defenderId;
static class DefendersNonBasicLandCount implements DynamicValue {
@Override
public int calculate(Game game, Ability sourceAbility, Effect effect) {
UUID defenderId;
for (CombatGroup group : game.getCombat().getGroups()) {
defenderId = group.getDefenderId();
if (group.isDefenderIsPlaneswalker()) {
@ -67,7 +66,7 @@ public final class MercadiasDownfall extends CardImpl {
}
@Override
public DynamicValue copy() {
public DefendersNonBasicLandCount copy() {
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";
}
public MonsoonEffect(Outcome outcome) {
super(outcome);
private MonsoonEffect(final MonsoonEffect effect) {
super(effect);
}
@Override
@ -76,7 +76,7 @@ class MonsoonEffect extends OneShotEffect {
}
@Override
public Effect copy() {
return new MonsoonEffect();
public MonsoonEffect copy() {
return new MonsoonEffect(this);
}
}

View file

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

View file

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

View file

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

View file

@ -25,7 +25,7 @@ public final class ParadigmShift extends CardImpl {
super(ownerId,setInfo,new CardType[]{CardType.SORCERY},"{1}{U}");
// 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) {
@ -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);
staticText = "Exile all cards from your library. Then shuffle your graveyard into your library";
}
private ParadigmShiftExileLibraryEffect(final ParadigmShiftExileLibraryEffect effect) {
super(effect);
}
@Override
public ExileLibraryEffect copy() {
return new ExileLibraryEffect();
public ParadigmShiftExileLibraryEffect copy() {
return new ParadigmShiftExileLibraryEffect(this);
}
@Override

View file

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

View file

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

View file

@ -1,4 +1,3 @@
package mage.cards.p;
import java.util.UUID;
@ -58,6 +57,10 @@ class PsychicVortexCost extends CostImpl {
this.text = "Draw a card";
}
private PsychicVortexCost(final PsychicVortexCost cost) {
super(cost);
}
@Override
public boolean pay(Ability ability, Game game, Ability source, UUID controllerId, boolean noMana, Cost costToPay) {
Player controller = game.getPlayer(controllerId);
@ -77,6 +80,6 @@ class PsychicVortexCost extends CostImpl {
@Override
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 {
@Override
public int calculate(Game game, Ability sourceAbility, Effect effect) {
if (sourceAbility != null) {
@ -77,7 +78,7 @@ class CardsInEnchantedControllerHandCount implements DynamicValue {
}
@Override
public DynamicValue copy() {
public CardsInEnchantedControllerHandCount copy() {
return new CardsInEnchantedControllerHandCount();
}

View file

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

View file

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

View file

@ -72,7 +72,7 @@ class CardsInTargetOpponentsGraveyardCount implements DynamicValue {
}
@Override
public DynamicValue copy() {
public CardsInTargetOpponentsGraveyardCount copy() {
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";
}
private ShelteringAncientCost(final ShelteringAncientCost cost) {
super(cost);
}
@Override
public boolean pay(Ability ability, Game game, Ability source, UUID controllerId, boolean noMana, Cost costToPay) {
Player controller = game.getPlayer(controllerId);
@ -86,6 +90,6 @@ class ShelteringAncientCost extends CostImpl {
@Override
public ShelteringAncientCost copy() {
return new ShelteringAncientCost();
return new ShelteringAncientCost(this);
}
}

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -44,6 +44,15 @@ public final class UrborgJustice extends CardImpl {
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
public UrborgJusticeDynamicValue copy() {
return new UrborgJusticeDynamicValue();
@ -58,13 +67,4 @@ class UrborgJusticeDynamicValue implements DynamicValue {
public String getMessage() {
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;
import java.util.UUID;
@ -40,7 +39,7 @@ public final class WolfOfDevilsBreach extends CardImpl {
Costs toPay = new CostsImpl<>();
toPay.add(new ManaCostsImpl<>("{1}{R}"));
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,
"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.");
@ -58,7 +57,7 @@ public final class WolfOfDevilsBreach extends CardImpl {
}
}
class WolfOfDevilsBreachDiscardCostCardConvertedMana implements DynamicValue {
class WolfOfDevilsBreachDiscardCostCardConvertedManaCount implements DynamicValue {
@Override
public int calculate(Game game, Ability sourceAbility, Effect effect) {
@ -84,8 +83,8 @@ class WolfOfDevilsBreachDiscardCostCardConvertedMana implements DynamicValue {
}
@Override
public WolfOfDevilsBreachDiscardCostCardConvertedMana copy() {
return new WolfOfDevilsBreachDiscardCostCardConvertedMana();
public WolfOfDevilsBreachDiscardCostCardConvertedManaCount copy() {
return new WolfOfDevilsBreachDiscardCostCardConvertedManaCount();
}
@Override

View file

@ -687,7 +687,7 @@ public abstract class CardTestPlayerAPIImpl extends MageTestPlayerBase implement
CardInfo cardInfo = CardRepository.instance.findCard(cardName);
Card card = cardInfo != null ? cardInfo.getCard() : 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);

View file

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

View file

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

View file

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

View file

@ -3,11 +3,19 @@ package mage.abilities.dynamicvalue;
import mage.abilities.Ability;
import mage.abilities.effects.Effect;
import mage.game.Game;
import mage.util.Copyable;
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);
DynamicValue copy();
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.game.Game;
import mage.target.targetpointer.TargetPointer;
import mage.util.Copyable;
import java.io.Serializable;
import java.util.UUID;
@ -13,7 +14,7 @@ import java.util.UUID;
/**
* @author BetaSteward_at_googlemail.com
*/
public interface Effect extends Serializable {
public interface Effect extends Serializable, Copyable<Effect> {
UUID getId();

View file

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

View file

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

View file

@ -24,7 +24,7 @@ public class ExileSpellEffect extends OneShotEffect {
@Override
public ExileSpellEffect copy() {
return new ExileSpellEffect();
return new ExileSpellEffect(this);
}
@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;
import java.util.UUID;
import mage.abilities.Ability;
import mage.abilities.effects.OneShotEffect;
import mage.constants.Outcome;
import mage.game.Game;
import mage.game.turn.TurnMod;
import java.util.UUID;
/**
* @author nantuko
*/
@ -35,6 +35,6 @@ public class ControlTargetPlayerNextTurnEffect extends OneShotEffect {
@Override
public ControlTargetPlayerNextTurnEffect copy() {
return new ControlTargetPlayerNextTurnEffect();
return new ControlTargetPlayerNextTurnEffect(this);
}
}

View file

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