diff --git a/Mage.Sets/src/mage/sets/avacynrestored/ArcaneMelee.java b/Mage.Sets/src/mage/sets/avacynrestored/ArcaneMelee.java index 83605b77b65..98adf18c308 100644 --- a/Mage.Sets/src/mage/sets/avacynrestored/ArcaneMelee.java +++ b/Mage.Sets/src/mage/sets/avacynrestored/ArcaneMelee.java @@ -33,7 +33,6 @@ import mage.abilities.SpellAbility; import mage.abilities.common.SimpleStaticAbility; import mage.abilities.effects.common.cost.CostModificationEffectImpl; import mage.abilities.keyword.FlashbackAbility; -import mage.abilities.keyword.RetraceAbility; import mage.cards.Card; import mage.cards.CardImpl; import mage.game.Game; @@ -51,8 +50,6 @@ public class ArcaneMelee extends CardImpl { super(ownerId, 44, "Arcane Melee", Rarity.RARE, new CardType[]{CardType.ENCHANTMENT}, "{4}{U}"); this.expansionSetCode = "AVR"; - this.color.setBlue(true); - // Instant and sorcery spells cost {2} less to cast. this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new ArcaneMeleeCostReductionEffect())); } @@ -87,7 +84,7 @@ class ArcaneMeleeCostReductionEffect extends CostModificationEffectImpl { @Override public boolean applies(Ability abilityToModify, Ability source, Game game) { - if ( abilityToModify instanceof SpellAbility || abilityToModify instanceof FlashbackAbility || abilityToModify instanceof RetraceAbility) { + if ( abilityToModify instanceof SpellAbility || abilityToModify instanceof FlashbackAbility) { Card sourceCard = game.getCard(((SpellAbility)abilityToModify).getSourceId()); if ( sourceCard != null && (sourceCard.getCardType().contains(CardType.INSTANT) || sourceCard.getCardType().contains(CardType.SORCERY))) { return true; diff --git a/Mage.Sets/src/mage/sets/avacynrestored/DarkImpostor.java b/Mage.Sets/src/mage/sets/avacynrestored/DarkImpostor.java index 81475eee33c..999597a7aa9 100644 --- a/Mage.Sets/src/mage/sets/avacynrestored/DarkImpostor.java +++ b/Mage.Sets/src/mage/sets/avacynrestored/DarkImpostor.java @@ -105,7 +105,7 @@ class DarkImpostorContinuousEffect extends ContinuousEffectImpl { if (card != null) { for (Ability ability: card.getAbilities()) { if (ability instanceof ActivatedAbility) { - perm.addAbility(ability, game); + perm.addAbility(ability, source.getSourceId(), game); } } } diff --git a/Mage.Sets/src/mage/sets/avacynrestored/HeraldOfWar.java b/Mage.Sets/src/mage/sets/avacynrestored/HeraldOfWar.java index a4b8b09d863..30e25ad36b8 100644 --- a/Mage.Sets/src/mage/sets/avacynrestored/HeraldOfWar.java +++ b/Mage.Sets/src/mage/sets/avacynrestored/HeraldOfWar.java @@ -37,7 +37,6 @@ import mage.abilities.effects.common.cost.CostModificationEffectImpl; import mage.abilities.effects.common.counter.AddCountersSourceEffect; import mage.abilities.keyword.FlashbackAbility; import mage.abilities.keyword.FlyingAbility; -import mage.abilities.keyword.RetraceAbility; import mage.cards.Card; import mage.cards.CardImpl; import mage.counters.CounterType; @@ -57,7 +56,6 @@ public class HeraldOfWar extends CardImpl { this.expansionSetCode = "AVR"; this.subtype.add("Angel"); - this.color.setWhite(true); this.power = new MageInt(3); this.toughness = new MageInt(3); @@ -107,7 +105,7 @@ class HeraldOfWarCostReductionEffect extends CostModificationEffectImpl { @Override public boolean applies(Ability abilityToModify, Ability source, Game game) { - if (abilityToModify instanceof SpellAbility || abilityToModify instanceof FlashbackAbility || abilityToModify instanceof RetraceAbility) { + if (abilityToModify instanceof SpellAbility || abilityToModify instanceof FlashbackAbility) { Card sourceCard = game.getCard(abilityToModify.getSourceId()); if (sourceCard != null && abilityToModify.getControllerId().equals(source.getControllerId()) && (sourceCard.hasSubtype("Angel") || sourceCard.hasSubtype("Human"))) { return true; diff --git a/Mage.Sets/src/mage/sets/avacynrestored/RidersOfGavony.java b/Mage.Sets/src/mage/sets/avacynrestored/RidersOfGavony.java index 50801312830..702354bcafd 100644 --- a/Mage.Sets/src/mage/sets/avacynrestored/RidersOfGavony.java +++ b/Mage.Sets/src/mage/sets/avacynrestored/RidersOfGavony.java @@ -110,7 +110,7 @@ class RidersOfGavonyEffect extends OneShotEffect { if (typeChoice.getChoice() != null) { game.informPlayers(permanent.getName() + ": " + player.getLogName() + " has chosen " + typeChoice.getChoice()); game.getState().setValue(permanent.getId() + "_type", typeChoice.getChoice()); - permanent.addInfo("chosen type", "Chosen type: " + typeChoice.getChoice().toString() + "", game); + permanent.addInfo("chosen type", "Chosen type: " + typeChoice.getChoice() + "", game); } } return false; @@ -162,7 +162,7 @@ class RidersOfGavonyGainAbilityControlledEffect extends ContinuousEffectImpl { } if (protectionFilter != null) { for (Permanent perm: game.getBattlefield().getAllActivePermanents(filter, source.getControllerId(), game)) { - perm.addAbility(new ProtectionAbility(protectionFilter), game); + perm.addAbility(new ProtectionAbility(protectionFilter), source.getSourceId(), game); } return true; } diff --git a/Mage.Sets/src/mage/sets/betrayersofkamigawa/NekoTe.java b/Mage.Sets/src/mage/sets/betrayersofkamigawa/NekoTe.java index e11c07bc384..2fb9c0dfdf1 100644 --- a/Mage.Sets/src/mage/sets/betrayersofkamigawa/NekoTe.java +++ b/Mage.Sets/src/mage/sets/betrayersofkamigawa/NekoTe.java @@ -31,7 +31,7 @@ import java.util.UUID; import mage.abilities.Ability; import mage.abilities.common.DealsDamageToACreatureAttachedTriggeredAbility; import mage.abilities.common.DealsDamageToAPlayerAttachedTriggeredAbility; -import mage.abilities.condition.common.SourceOnBattelfieldCondition; +import mage.abilities.condition.common.SourceOnBattlefieldCondition; import mage.abilities.costs.mana.GenericManaCost; import mage.abilities.decorator.ConditionalContinuousRuleModifyingEffect; import mage.abilities.effects.ContinuousRuleModifyingEffect; @@ -59,7 +59,7 @@ public class NekoTe extends CardImpl { // Whenever equipped creature deals damage to a creature, tap that creature. That creature doesn't untap during its controller's untap step for as long as Neko-Te remains on the battlefield. ContinuousRuleModifyingEffect skipUntapEffect = new DontUntapInControllersUntapStepTargetEffect(Duration.WhileOnBattlefield); skipUntapEffect.setText("That creature doesn't untap during its controller's untap step for as long as {this} remains on the battlefield"); - ConditionalContinuousRuleModifyingEffect effect = new ConditionalContinuousRuleModifyingEffect(skipUntapEffect, new SourceOnBattelfieldCondition()); + ConditionalContinuousRuleModifyingEffect effect = new ConditionalContinuousRuleModifyingEffect(skipUntapEffect, new SourceOnBattlefieldCondition()); Ability ability = new DealsDamageToACreatureAttachedTriggeredAbility(new TapTargetEffect("that creature"), false, "equipped creature", false, true); ability.addEffect(effect); this.addAbility(ability); diff --git a/Mage.Sets/src/mage/sets/betrayersofkamigawa/SkullmaneBaku.java b/Mage.Sets/src/mage/sets/betrayersofkamigawa/SkullmaneBaku.java index 4fa455c7986..8b6f6c1d390 100644 --- a/Mage.Sets/src/mage/sets/betrayersofkamigawa/SkullmaneBaku.java +++ b/Mage.Sets/src/mage/sets/betrayersofkamigawa/SkullmaneBaku.java @@ -110,7 +110,7 @@ public class SkullmaneBaku extends CardImpl { } Permanent creature = game.getPermanent(targetPointer.getFirst(game, source)); if (creature != null && numberToUnboost != 0) { - creature.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new BoostSourceEffect(numberToUnboost, numberToUnboost, Duration.EndOfTurn)), game); + creature.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new BoostSourceEffect(numberToUnboost, numberToUnboost, Duration.EndOfTurn)), source.getSourceId(), game, false); } return true; } diff --git a/Mage.Sets/src/mage/sets/bornofthegods/SatyrFiredancer.java b/Mage.Sets/src/mage/sets/bornofthegods/SatyrFiredancer.java index ee73a251b4f..7ba3689bbd8 100644 --- a/Mage.Sets/src/mage/sets/bornofthegods/SatyrFiredancer.java +++ b/Mage.Sets/src/mage/sets/bornofthegods/SatyrFiredancer.java @@ -126,15 +126,18 @@ class SatyrFiredancerTriggeredAbility extends TriggeredAbilityImpl { MageObject damageSource = game.getObject(event.getSourceId()); if (damageSource != null) { if (game.getOpponents(getControllerId()).contains(event.getTargetId())) { - if (!(damageSource instanceof StackObject) || !handledStackObjects.contains(damageSource.getId())) { - if (damageSource instanceof StackObject) { - handledStackObjects.add(damageSource.getId()); + MageObject object = game.getObject(event.getSourceId()); + if (object.getCardType().contains(CardType.INSTANT) || object.getCardType().contains(CardType.SORCERY)) { + if (!(damageSource instanceof StackObject) || !handledStackObjects.contains(damageSource.getId())) { + if (damageSource instanceof StackObject) { + handledStackObjects.add(damageSource.getId()); + } + for (Effect effect: this.getEffects()) { + effect.setTargetPointer(new FixedTarget(event.getTargetId())); // used by adjust targets + effect.setValue("damage", event.getAmount()); + } + return true; } - for (Effect effect: this.getEffects()) { - effect.setTargetPointer(new FixedTarget(event.getTargetId())); // used by adjust targets - effect.setValue("damage", event.getAmount()); - } - return true; } } } diff --git a/Mage.Sets/src/mage/sets/commander/AnimarSoulOfElements.java b/Mage.Sets/src/mage/sets/commander/AnimarSoulOfElements.java index ea891aa902c..f22a8ccd02b 100644 --- a/Mage.Sets/src/mage/sets/commander/AnimarSoulOfElements.java +++ b/Mage.Sets/src/mage/sets/commander/AnimarSoulOfElements.java @@ -38,7 +38,6 @@ import mage.abilities.effects.common.cost.CostModificationEffectImpl; import mage.abilities.effects.common.counter.AddCountersSourceEffect; import mage.abilities.keyword.FlashbackAbility; import mage.abilities.keyword.ProtectionAbility; -import mage.abilities.keyword.RetraceAbility; import mage.cards.Card; import mage.cards.CardImpl; import mage.constants.CardType; @@ -78,9 +77,6 @@ public class AnimarSoulOfElements extends CardImpl { this.supertype.add("Legendary"); this.subtype.add("Elemental"); - this.color.setRed(true); - this.color.setBlue(true); - this.color.setGreen(true); this.power = new MageInt(1); this.toughness = new MageInt(1); @@ -132,7 +128,7 @@ class AnimarCostReductionEffect extends CostModificationEffectImpl { @Override public boolean applies(Ability abilityToModify, Ability source, Game game) { - if (abilityToModify instanceof SpellAbility || abilityToModify instanceof FlashbackAbility || abilityToModify instanceof RetraceAbility) { + if (abilityToModify instanceof SpellAbility || abilityToModify instanceof FlashbackAbility) { Card sourceCard = game.getCard(abilityToModify.getSourceId()); if (sourceCard != null && abilityToModify.getControllerId().equals(source.getControllerId()) && (sourceCard.getCardType().contains(CardType.CREATURE))) { return true; diff --git a/Mage.Sets/src/mage/sets/commander/CallTheSkybreaker.java b/Mage.Sets/src/mage/sets/commander/CallTheSkybreaker.java index 95694235f7b..3c4906036ca 100644 --- a/Mage.Sets/src/mage/sets/commander/CallTheSkybreaker.java +++ b/Mage.Sets/src/mage/sets/commander/CallTheSkybreaker.java @@ -29,17 +29,13 @@ package mage.sets.commander; import java.util.UUID; import mage.MageInt; -import mage.abilities.costs.common.DiscardTargetCost; import mage.abilities.effects.common.CreateTokenEffect; import mage.abilities.keyword.FlyingAbility; import mage.abilities.keyword.RetraceAbility; import mage.cards.CardImpl; import mage.constants.CardType; import mage.constants.Rarity; -import mage.constants.TimingRule; -import mage.filter.common.FilterLandCard; import mage.game.permanent.token.Token; -import mage.target.common.TargetCardInHand; /** * @@ -52,14 +48,11 @@ public class CallTheSkybreaker extends CardImpl { super(ownerId, 188, "Call the Skybreaker", Rarity.RARE, new CardType[]{CardType.SORCERY}, "{5}{U/R}{U/R}"); this.expansionSetCode = "CMD"; - this.color.setRed(true); - this.color.setBlue(true); - // Put a 5/5 blue and red Elemental creature token with flying onto the battlefield. this.getSpellAbility().addEffect(new CreateTokenEffect(new ElementalToken())); // Retrace - this.addAbility(new RetraceAbility(getSpellAbility().getManaCosts(), TimingRule.SORCERY)); + this.addAbility(new RetraceAbility(this)); } diff --git a/Mage.Sets/src/mage/sets/commander/KaradorGhostChieftain.java b/Mage.Sets/src/mage/sets/commander/KaradorGhostChieftain.java index 742bec871bb..d466c65ca49 100644 --- a/Mage.Sets/src/mage/sets/commander/KaradorGhostChieftain.java +++ b/Mage.Sets/src/mage/sets/commander/KaradorGhostChieftain.java @@ -36,8 +36,6 @@ import mage.abilities.effects.AsThoughEffectImpl; import mage.abilities.effects.ContinuousEffect; import mage.abilities.effects.ContinuousEffectImpl; import mage.abilities.effects.common.cost.CostModificationEffectImpl; -import mage.abilities.keyword.FlashbackAbility; -import mage.abilities.keyword.RetraceAbility; import mage.cards.Card; import mage.cards.CardImpl; import mage.constants.AsThoughEffectType; @@ -72,9 +70,6 @@ public class KaradorGhostChieftain extends CardImpl { this.subtype.add("Centaur"); this.subtype.add("Spirit"); - this.color.setWhite(true); - this.color.setGreen(true); - this.color.setBlack(true); this.power = new MageInt(3); this.toughness = new MageInt(4); diff --git a/Mage.Sets/src/mage/sets/commander/Stranglehold.java b/Mage.Sets/src/mage/sets/commander/Stranglehold.java index d62ba853452..e129b6c3108 100644 --- a/Mage.Sets/src/mage/sets/commander/Stranglehold.java +++ b/Mage.Sets/src/mage/sets/commander/Stranglehold.java @@ -52,10 +52,9 @@ public class Stranglehold extends CardImpl { super(ownerId, 136, "Stranglehold", Rarity.RARE, new CardType[]{CardType.ENCHANTMENT}, "{3}{R}"); this.expansionSetCode = "CMD"; - this.color.setRed(true); - // Your opponents can't search libraries. this.getSpellAbility().addEffect(new OpponentsCantSearchLibarariesEffect()); + // If an opponent would begin an extra turn, that player skips that turn instead. this.getSpellAbility().addEffect(new StrangleholdSkipExtraTurnsEffect()); } @@ -73,7 +72,7 @@ public class Stranglehold extends CardImpl { class OpponentsCantSearchLibarariesEffect extends ContinuousRuleModifyingEffectImpl { public OpponentsCantSearchLibarariesEffect() { - super(Duration.EndOfTurn, Outcome.Benefit, true, false); + super(Duration.WhileOnBattlefield, Outcome.Benefit, true, false); staticText = "Your opponents can't search libraries"; } diff --git a/Mage.Sets/src/mage/sets/commander2013/CurseOfChaos.java b/Mage.Sets/src/mage/sets/commander2013/CurseOfChaos.java index 16f9688bc06..9665dca1958 100644 --- a/Mage.Sets/src/mage/sets/commander2013/CurseOfChaos.java +++ b/Mage.Sets/src/mage/sets/commander2013/CurseOfChaos.java @@ -140,7 +140,7 @@ class CurseOfChaosEffect extends OneShotEffect { Player attacker = game.getPlayer(this.getTargetPointer().getFirst(game, source)); if (attacker != null) { if (attacker.getHand().size() > 0 && attacker.chooseUse(outcome, "Discard a card and draw a card?", game)){ - attacker.discard(1, source, game); + attacker.discard(1, false, source, game); attacker.drawCards(1, game); } return true; diff --git a/Mage.Sets/src/mage/sets/conflux/KnightOfTheReliquary.java b/Mage.Sets/src/mage/sets/conflux/KnightOfTheReliquary.java index 171461f566b..64d23934189 100644 --- a/Mage.Sets/src/mage/sets/conflux/KnightOfTheReliquary.java +++ b/Mage.Sets/src/mage/sets/conflux/KnightOfTheReliquary.java @@ -36,6 +36,7 @@ import mage.constants.Zone; import mage.MageInt; import mage.abilities.common.SimpleActivatedAbility; import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.costs.Cost; import mage.abilities.costs.Costs; import mage.abilities.costs.CostsImpl; import mage.abilities.costs.common.SacrificeTargetCost; @@ -81,7 +82,7 @@ public class KnightOfTheReliquary extends CardImpl { // {T}, Sacrifice a Forest or Plains: Search your library for a land card, put it onto the battlefield, then shuffle your library. TargetCardInLibrary target = new TargetCardInLibrary(new FilterLandCard()); - Costs costs = new CostsImpl(); + Costs costs = new CostsImpl<>(); costs.add(new TapSourceCost()); costs.add(new SacrificeTargetCost(new TargetControlledPermanent(1, 1, filter, false))); this.addAbility(new SimpleActivatedAbility(Zone.BATTLEFIELD, new SearchLibraryPutInPlayEffect(target, false, Outcome.PutLandInPlay), costs)); diff --git a/Mage.Sets/src/mage/sets/darkascension/ThaliaGuardianOfThraben.java b/Mage.Sets/src/mage/sets/darkascension/ThaliaGuardianOfThraben.java index 4385c9cbdec..0e8cd3bc8e3 100644 --- a/Mage.Sets/src/mage/sets/darkascension/ThaliaGuardianOfThraben.java +++ b/Mage.Sets/src/mage/sets/darkascension/ThaliaGuardianOfThraben.java @@ -27,7 +27,7 @@ */ package mage.sets.darkascension; -import mage.constants.*; +import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.SpellAbility; @@ -35,14 +35,17 @@ import mage.abilities.common.SimpleStaticAbility; import mage.abilities.effects.common.cost.CostModificationEffectImpl; import mage.abilities.keyword.FirstStrikeAbility; import mage.abilities.keyword.FlashbackAbility; -import mage.abilities.keyword.RetraceAbility; import mage.cards.Card; import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.CostModificationType; +import mage.constants.Duration; +import mage.constants.Outcome; +import mage.constants.Rarity; +import mage.constants.Zone; import mage.game.Game; import mage.util.CardUtil; -import java.util.UUID; - /** * * @author BetaSteward @@ -56,7 +59,6 @@ public class ThaliaGuardianOfThraben extends CardImpl { this.subtype.add("Human"); this.subtype.add("Soldier"); - this.color.setWhite(true); this.power = new MageInt(2); this.toughness = new MageInt(1); @@ -96,7 +98,7 @@ class ThaliaGuardianOfThrabenCostReductionEffect extends CostModificationEffectI @Override public boolean applies(Ability abilityToModify, Ability source, Game game) { - if (abilityToModify instanceof SpellAbility || abilityToModify instanceof FlashbackAbility || abilityToModify instanceof RetraceAbility) { + if (abilityToModify instanceof SpellAbility || abilityToModify instanceof FlashbackAbility) { Card card = game.getCard(abilityToModify.getSourceId()); if (card != null && !card.getCardType().contains(CardType.CREATURE)) { return true; diff --git a/Mage.Sets/src/mage/sets/dissension/CytoplastManipulator.java b/Mage.Sets/src/mage/sets/dissension/CytoplastManipulator.java index 8020d97bc27..156ac9a5148 100644 --- a/Mage.Sets/src/mage/sets/dissension/CytoplastManipulator.java +++ b/Mage.Sets/src/mage/sets/dissension/CytoplastManipulator.java @@ -31,7 +31,7 @@ import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.SimpleActivatedAbility; -import mage.abilities.condition.common.SourceOnBattelfieldCondition; +import mage.abilities.condition.common.SourceOnBattlefieldCondition; import mage.abilities.costs.common.TapSourceCost; import mage.abilities.costs.mana.ManaCostsImpl; import mage.abilities.decorator.ConditionalContinuousEffect; @@ -73,7 +73,7 @@ public class CytoplastManipulator extends CardImpl { // {U}, {tap}: Gain control of target creature with a +1/+1 counter on it for as long as Cytoplast Manipulator remains on the battlefield. ConditionalContinuousEffect effect = new ConditionalContinuousEffect( new GainControlTargetEffect(Duration.Custom, true), - new SourceOnBattelfieldCondition(), + new SourceOnBattlefieldCondition(), "gain control of target creature with a +1/+1 counter on it for as long as {this} remains on the battlefield"); Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, effect, new ManaCostsImpl("{U}")); ability.addCost(new TapSourceCost()); diff --git a/Mage.Sets/src/mage/sets/dragonsmaze/BloodBaronOfVizkopa.java b/Mage.Sets/src/mage/sets/dragonsmaze/BloodBaronOfVizkopa.java index 6275f095d34..794af59b736 100644 --- a/Mage.Sets/src/mage/sets/dragonsmaze/BloodBaronOfVizkopa.java +++ b/Mage.Sets/src/mage/sets/dragonsmaze/BloodBaronOfVizkopa.java @@ -126,7 +126,7 @@ class BloodBaronOfVizkopaEffect extends ContinuousEffectImpl { break; case AbilityAddingRemovingEffects_6: if (sublayer == SubLayer.NA) { - creature.addAbility(FlyingAbility.getInstance(), game); + creature.addAbility(FlyingAbility.getInstance(), source.getSourceId(), game); } break; default: diff --git a/Mage.Sets/src/mage/sets/dragonsmaze/RotFarmSkeleton.java b/Mage.Sets/src/mage/sets/dragonsmaze/RotFarmSkeleton.java index c53b2ecbae3..7d10546df5c 100644 --- a/Mage.Sets/src/mage/sets/dragonsmaze/RotFarmSkeleton.java +++ b/Mage.Sets/src/mage/sets/dragonsmaze/RotFarmSkeleton.java @@ -53,13 +53,13 @@ public class RotFarmSkeleton extends CardImpl { this.expansionSetCode = "DGM"; this.subtype.add("Plant"); this.subtype.add("Skeleton"); - this.color.setBlack(true); - this.color.setGreen(true); + this.power = new MageInt(4); this.toughness = new MageInt(1); // Rot Farm Skeleton can't block. this.addAbility(new CantBlockAbility()); + // 2{B}{G}, Put the top four cards of your library into your graveyard: Return Rot Farm Skeleton from your graveyard to the battlefield. Activate this ability only any time you could cast a sorcery. Ability ability = new ActivateAsSorceryActivatedAbility(Zone.GRAVEYARD, new ReturnSourceFromGraveyardToBattlefieldEffect(), new ManaCostsImpl("{2}{B}{G}")); ability.addCost(new PutTopCardOfYourLibraryToGraveyardCost(4)); diff --git a/Mage.Sets/src/mage/sets/eventide/CennsEnlistment.java b/Mage.Sets/src/mage/sets/eventide/CennsEnlistment.java index 59821a9b6cf..3bbb84df53c 100644 --- a/Mage.Sets/src/mage/sets/eventide/CennsEnlistment.java +++ b/Mage.Sets/src/mage/sets/eventide/CennsEnlistment.java @@ -48,12 +48,11 @@ public class CennsEnlistment extends CardImpl { super(ownerId, 3, "Cenn's Enlistment", Rarity.COMMON, new CardType[]{CardType.SORCERY}, "{3}{W}"); this.expansionSetCode = "EVE"; - this.color.setWhite(true); - // Put two 1/1 white Kithkin Soldier creature tokens onto the battlefield. this.getSpellAbility().addEffect(new CreateTokenEffect(new KithkinToken(), 2)); + // Retrace - this.addAbility(new RetraceAbility(new ManaCostsImpl("{3}{W}"), TimingRule.SORCERY)); + this.addAbility(new RetraceAbility(this)); } public CennsEnlistment(final CennsEnlistment card) { diff --git a/Mage.Sets/src/mage/sets/eventide/FlameJab.java b/Mage.Sets/src/mage/sets/eventide/FlameJab.java index c6fc890c2be..46ffe6acefc 100644 --- a/Mage.Sets/src/mage/sets/eventide/FlameJab.java +++ b/Mage.Sets/src/mage/sets/eventide/FlameJab.java @@ -31,11 +31,9 @@ import java.util.UUID; import mage.constants.CardType; import mage.constants.Rarity; -import mage.abilities.costs.mana.ManaCostsImpl; import mage.abilities.effects.common.DamageTargetEffect; import mage.abilities.keyword.RetraceAbility; import mage.cards.CardImpl; -import mage.constants.TimingRule; import mage.target.common.TargetCreatureOrPlayer; /** @@ -48,13 +46,11 @@ public class FlameJab extends CardImpl { super(ownerId, 53, "Flame Jab", Rarity.COMMON, new CardType[]{CardType.SORCERY}, "{R}"); this.expansionSetCode = "EVE"; - this.color.setRed(true); - // Flame Jab deals 1 damage to target creature or player. this.getSpellAbility().addEffect(new DamageTargetEffect(1)); this.getSpellAbility().addTarget(new TargetCreatureOrPlayer()); // Retrace - this.addAbility(new RetraceAbility(new ManaCostsImpl("{R}"), TimingRule.SORCERY)); + this.addAbility(new RetraceAbility(this)); } public FlameJab(final FlameJab card) { diff --git a/Mage.Sets/src/mage/sets/eventide/Flickerwisp.java b/Mage.Sets/src/mage/sets/eventide/Flickerwisp.java index 0c49b7ba81f..596fd51524e 100644 --- a/Mage.Sets/src/mage/sets/eventide/Flickerwisp.java +++ b/Mage.Sets/src/mage/sets/eventide/Flickerwisp.java @@ -53,7 +53,8 @@ import mage.target.TargetPermanent; */ public class Flickerwisp extends CardImpl { - private static final FilterPermanent filter = new FilterPermanent(); + private static final FilterPermanent filter = new FilterPermanent("another target permanent"); + static{ filter.add(new AnotherPredicate()); } @@ -63,15 +64,15 @@ public class Flickerwisp extends CardImpl { this.expansionSetCode = "EVE"; this.subtype.add("Elemental"); - this.color.setWhite(true); this.power = new MageInt(3); this.toughness = new MageInt(1); // Flying this.addAbility(FlyingAbility.getInstance()); + // When Flickerwisp enters the battlefield, exile another target permanent. Return that card to the battlefield under its owner's control at the beginning of the next end step. Ability ability = new EntersBattlefieldTriggeredAbility(new FlickerwispEffect()); - ability.addTarget(new TargetPermanent()); + ability.addTarget(new TargetPermanent(filter)); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/sets/eventide/Monstrify.java b/Mage.Sets/src/mage/sets/eventide/Monstrify.java index b8f9690d0f6..d8ab5208db2 100644 --- a/Mage.Sets/src/mage/sets/eventide/Monstrify.java +++ b/Mage.Sets/src/mage/sets/eventide/Monstrify.java @@ -31,12 +31,10 @@ import java.util.UUID; import mage.constants.CardType; import mage.constants.Rarity; -import mage.abilities.costs.mana.ManaCostsImpl; import mage.abilities.effects.common.continuous.BoostTargetEffect; import mage.abilities.keyword.RetraceAbility; import mage.cards.CardImpl; import mage.constants.Duration; -import mage.constants.TimingRule; import mage.target.common.TargetCreaturePermanent; /** @@ -49,13 +47,11 @@ public class Monstrify extends CardImpl { super(ownerId, 70, "Monstrify", Rarity.COMMON, new CardType[]{CardType.SORCERY}, "{3}{G}"); this.expansionSetCode = "EVE"; - this.color.setGreen(true); - // Target creature gets +4/+4 until end of turn. this.getSpellAbility().addEffect(new BoostTargetEffect(4, 4, Duration.EndOfTurn)); this.getSpellAbility().addTarget(new TargetCreaturePermanent()); // Retrace - this.addAbility(new RetraceAbility(new ManaCostsImpl("{3}{G}"), TimingRule.SORCERY)); + this.addAbility(new RetraceAbility(this)); } public Monstrify(final Monstrify card) { diff --git a/Mage.Sets/src/mage/sets/eventide/NeedleSpecter.java b/Mage.Sets/src/mage/sets/eventide/NeedleSpecter.java index a492fdefcde..f7c487815e1 100644 --- a/Mage.Sets/src/mage/sets/eventide/NeedleSpecter.java +++ b/Mage.Sets/src/mage/sets/eventide/NeedleSpecter.java @@ -98,7 +98,7 @@ class NeedleSpecterEffect extends OneShotEffect { Player targetPlayer = game.getPlayer(targetPointer.getFirst(game, source)); if (targetPlayer != null) { int damage = (Integer)getValue("damage"); - targetPlayer.discard(damage, source, game); + targetPlayer.discard(damage, false, source, game); game.informPlayers(targetPlayer.getLogName() + "discards " + damage + " card(s)"); return true; } diff --git a/Mage.Sets/src/mage/sets/eventide/OonasGrace.java b/Mage.Sets/src/mage/sets/eventide/OonasGrace.java index 4ea53ad7c3a..5b598ef3f3d 100644 --- a/Mage.Sets/src/mage/sets/eventide/OonasGrace.java +++ b/Mage.Sets/src/mage/sets/eventide/OonasGrace.java @@ -31,11 +31,9 @@ import java.util.UUID; import mage.constants.CardType; import mage.constants.Rarity; -import mage.abilities.costs.mana.ManaCostsImpl; import mage.abilities.effects.common.DrawCardTargetEffect; import mage.abilities.keyword.RetraceAbility; import mage.cards.CardImpl; -import mage.constants.TimingRule; import mage.target.TargetPlayer; /** @@ -48,13 +46,11 @@ public class OonasGrace extends CardImpl { super(ownerId, 27, "Oona's Grace", Rarity.COMMON, new CardType[]{CardType.INSTANT}, "{2}{U}"); this.expansionSetCode = "EVE"; - this.color.setBlue(true); - // Target player draws a card. this.getSpellAbility().addEffect(new DrawCardTargetEffect(1)); this.getSpellAbility().addTarget(new TargetPlayer()); // Retrace - this.addAbility(new RetraceAbility(new ManaCostsImpl("{2}{U}"), TimingRule.INSTANT)); + this.addAbility(new RetraceAbility(this)); } public OonasGrace(final OonasGrace card) { diff --git a/Mage.Sets/src/mage/sets/eventide/RavensCrime.java b/Mage.Sets/src/mage/sets/eventide/RavensCrime.java index 44f5357bd9a..ebf73bba3e8 100644 --- a/Mage.Sets/src/mage/sets/eventide/RavensCrime.java +++ b/Mage.Sets/src/mage/sets/eventide/RavensCrime.java @@ -31,11 +31,9 @@ import java.util.UUID; import mage.constants.CardType; import mage.constants.Rarity; -import mage.abilities.costs.mana.ManaCostsImpl; import mage.abilities.effects.common.discard.DiscardTargetEffect; import mage.abilities.keyword.RetraceAbility; import mage.cards.CardImpl; -import mage.constants.TimingRule; import mage.target.TargetPlayer; /** @@ -48,13 +46,12 @@ public class RavensCrime extends CardImpl { super(ownerId, 41, "Raven's Crime", Rarity.COMMON, new CardType[]{CardType.SORCERY}, "{B}"); this.expansionSetCode = "EVE"; - this.color.setBlack(true); - // Target player discards a card. this.getSpellAbility().getEffects().add(new DiscardTargetEffect(1)); this.getSpellAbility().getTargets().add(new TargetPlayer()); + // Retrace - this.addAbility(new RetraceAbility(new ManaCostsImpl("{B}"), TimingRule.SORCERY)); + this.addAbility(new RetraceAbility(this)); } public RavensCrime(final RavensCrime card) { diff --git a/Mage.Sets/src/mage/sets/eventide/RiseOfTheHobgoblins.java b/Mage.Sets/src/mage/sets/eventide/RiseOfTheHobgoblins.java index d68d371e389..7a250eb7d96 100644 --- a/Mage.Sets/src/mage/sets/eventide/RiseOfTheHobgoblins.java +++ b/Mage.Sets/src/mage/sets/eventide/RiseOfTheHobgoblins.java @@ -34,6 +34,7 @@ import mage.abilities.Ability; import mage.abilities.common.EntersBattlefieldTriggeredAbility; import mage.abilities.common.SimpleActivatedAbility; import mage.abilities.costs.mana.GenericManaCost; +import mage.abilities.costs.mana.ManaCost; import mage.abilities.costs.mana.ManaCosts; import mage.abilities.costs.mana.ManaCostsImpl; import mage.abilities.effects.OneShotEffect; @@ -116,7 +117,7 @@ class RiseOfTheHobgoblinsEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { Player you = game.getPlayer(source.getControllerId()); - ManaCosts cost = new ManaCostsImpl("{X}"); + ManaCosts cost = new ManaCostsImpl<>("{X}"); if (you != null && you.chooseUse(Outcome.Neutral, "Do you want to to pay {X}?", game)) { int costX = you.announceXMana(0, Integer.MAX_VALUE, "Announce the value for {X}", game, source); cost.add(new GenericManaCost(costX)); diff --git a/Mage.Sets/src/mage/sets/eventide/SavageConception.java b/Mage.Sets/src/mage/sets/eventide/SavageConception.java index 401dd904b39..edeff47740c 100644 --- a/Mage.Sets/src/mage/sets/eventide/SavageConception.java +++ b/Mage.Sets/src/mage/sets/eventide/SavageConception.java @@ -31,11 +31,9 @@ import java.util.UUID; import mage.constants.CardType; import mage.constants.Rarity; -import mage.abilities.costs.mana.ManaCostsImpl; import mage.abilities.effects.common.CreateTokenEffect; import mage.abilities.keyword.RetraceAbility; import mage.cards.CardImpl; -import mage.constants.TimingRule; import mage.game.permanent.token.BeastToken; /** @@ -48,12 +46,10 @@ public class SavageConception extends CardImpl { super(ownerId, 75, "Savage Conception", Rarity.UNCOMMON, new CardType[]{CardType.SORCERY}, "{3}{G}{G}"); this.expansionSetCode = "EVE"; - this.color.setGreen(true); - // Put a 3/3 green Beast creature token onto the battlefield. this.getSpellAbility().addEffect(new CreateTokenEffect(new BeastToken())); // Retrace - this.addAbility(new RetraceAbility(new ManaCostsImpl("{3}{G}{G}"), TimingRule.SORCERY)); + this.addAbility(new RetraceAbility(this)); } public SavageConception(final SavageConception card) { diff --git a/Mage.Sets/src/mage/sets/eventide/SpittingImage.java b/Mage.Sets/src/mage/sets/eventide/SpittingImage.java index 3bc14b66be1..a9eda3c7deb 100644 --- a/Mage.Sets/src/mage/sets/eventide/SpittingImage.java +++ b/Mage.Sets/src/mage/sets/eventide/SpittingImage.java @@ -29,21 +29,16 @@ package mage.sets.eventide; import java.util.UUID; import mage.abilities.Ability; -import mage.abilities.costs.common.DiscardTargetCost; -import mage.abilities.costs.mana.ManaCostsImpl; import mage.abilities.effects.OneShotEffect; import mage.abilities.keyword.RetraceAbility; import mage.cards.CardImpl; import mage.constants.CardType; import mage.constants.Outcome; import mage.constants.Rarity; -import mage.constants.TimingRule; import mage.constants.Zone; -import mage.filter.common.FilterLandCard; import mage.game.Game; import mage.game.permanent.Permanent; import mage.game.permanent.token.EmptyToken; -import mage.target.common.TargetCardInHand; import mage.target.common.TargetCreaturePermanent; import mage.util.CardUtil; @@ -58,15 +53,12 @@ public class SpittingImage extends CardImpl { super(ownerId, 162, "Spitting Image", Rarity.RARE, new CardType[]{CardType.SORCERY}, "{4}{G/U}{G/U}"); this.expansionSetCode = "EVE"; - this.color.setBlue(true); - this.color.setGreen(true); - // Put a token that's a copy of target creature onto the battlefield. this.getSpellAbility().addEffect(new SpittingImageEffect()); this.getSpellAbility().addTarget(new TargetCreaturePermanent()); // Retrace (You may cast this card from your graveyard by discarding a land card in addition to paying its other costs.) - this.addAbility(new RetraceAbility(getSpellAbility().getManaCosts(), TimingRule.SORCERY)); + this.addAbility(new RetraceAbility(this)); } diff --git a/Mage.Sets/src/mage/sets/eventide/SyphonLife.java b/Mage.Sets/src/mage/sets/eventide/SyphonLife.java index 2f465218597..1b0c65a53f2 100644 --- a/Mage.Sets/src/mage/sets/eventide/SyphonLife.java +++ b/Mage.Sets/src/mage/sets/eventide/SyphonLife.java @@ -56,7 +56,7 @@ public class SyphonLife extends CardImpl { this.getSpellAbility().addTarget(new TargetPlayer()); this.getSpellAbility().addEffect(new GainLifeEffect(2)); // Retrace - this.addAbility(new RetraceAbility(new ManaCostsImpl("{1}{B}{B}"), TimingRule.SORCERY)); + this.addAbility(new RetraceAbility(this)); } public SyphonLife(final SyphonLife card) { diff --git a/Mage.Sets/src/mage/sets/eventide/WavesOfAggression.java b/Mage.Sets/src/mage/sets/eventide/WavesOfAggression.java index 8e1380b2827..c41dc5fdfa7 100644 --- a/Mage.Sets/src/mage/sets/eventide/WavesOfAggression.java +++ b/Mage.Sets/src/mage/sets/eventide/WavesOfAggression.java @@ -31,7 +31,6 @@ import java.util.Set; import java.util.UUID; import mage.abilities.Ability; import mage.abilities.DelayedTriggeredAbility; -import mage.abilities.costs.mana.ManaCostsImpl; import mage.abilities.effects.OneShotEffect; import mage.abilities.keyword.RetraceAbility; import mage.cards.CardImpl; @@ -39,7 +38,6 @@ import mage.constants.CardType; import mage.constants.Duration; import mage.constants.Outcome; import mage.constants.Rarity; -import mage.constants.TimingRule; import mage.constants.TurnPhase; import mage.game.Game; import mage.game.events.GameEvent; @@ -58,15 +56,12 @@ public class WavesOfAggression extends CardImpl { super(ownerId, 148, "Waves of Aggression", Rarity.RARE, new CardType[]{CardType.SORCERY}, "{3}{R/W}{R/W}"); this.expansionSetCode = "EVE"; - this.color.setRed(true); - this.color.setWhite(true); - // Untap all creatures that attacked this turn. After this main phase, there is an additional combat phase followed by an additional main phase. this.getSpellAbility().addWatcher(new AttackedThisTurnWatcher()); this.getSpellAbility().addEffect(new WavesOfAggressionUntapEffect()); this.getSpellAbility().addEffect(new WavesOfAggressionAddPhasesEffect()); // Retrace - this.addAbility(new RetraceAbility(new ManaCostsImpl("{3}{R/W}{R/W}"), TimingRule.SORCERY)); + this.addAbility(new RetraceAbility(this)); } public WavesOfAggression(final WavesOfAggression card) { diff --git a/Mage.Sets/src/mage/sets/eventide/WormHarvest.java b/Mage.Sets/src/mage/sets/eventide/WormHarvest.java index 3356d30e0fe..c8b69d3e8ac 100644 --- a/Mage.Sets/src/mage/sets/eventide/WormHarvest.java +++ b/Mage.Sets/src/mage/sets/eventide/WormHarvest.java @@ -29,14 +29,12 @@ package mage.sets.eventide; import java.util.UUID; import mage.MageInt; -import mage.abilities.costs.mana.ManaCostsImpl; import mage.abilities.dynamicvalue.common.CardsInControllerGraveyardCount; import mage.abilities.effects.common.CreateTokenEffect; import mage.abilities.keyword.RetraceAbility; import mage.cards.CardImpl; import mage.constants.CardType; import mage.constants.Rarity; -import mage.constants.TimingRule; import mage.filter.common.FilterLandCard; import mage.game.permanent.token.Token; @@ -50,15 +48,12 @@ public class WormHarvest extends CardImpl { super(ownerId, 131, "Worm Harvest", Rarity.RARE, new CardType[]{CardType.SORCERY}, "{2}{B/G}{B/G}{B/G}"); this.expansionSetCode = "EVE"; - this.color.setGreen(true); - this.color.setBlack(true); - // Put a 1/1 black and green Worm creature token onto the battlefield for each land card in your graveyard. CardsInControllerGraveyardCount value = new CardsInControllerGraveyardCount(new FilterLandCard()); this.getSpellAbility().addEffect(new CreateTokenEffect(new WormHarvestToken(), value)); // Retrace - this.addAbility(new RetraceAbility(new ManaCostsImpl("{2}{B/G}{B/G}{B/G}"), TimingRule.SORCERY)); + this.addAbility(new RetraceAbility(this)); } public WormHarvest(final WormHarvest card) { diff --git a/Mage.Sets/src/mage/sets/fallenempires/Derelor.java b/Mage.Sets/src/mage/sets/fallenempires/Derelor.java index c5977aa2a92..92c58eecddf 100644 --- a/Mage.Sets/src/mage/sets/fallenempires/Derelor.java +++ b/Mage.Sets/src/mage/sets/fallenempires/Derelor.java @@ -62,7 +62,7 @@ public class Derelor extends CardImpl { this.toughness = new MageInt(4); // Black spells you cast cost {B} more to cast. - this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new SpellsCostIncreasementControllerEffect(filter, new ManaCostsImpl("B")))); + this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new SpellsCostIncreasementControllerEffect(filter, new ManaCostsImpl<>("{B}")))); } public Derelor(final Derelor card) { diff --git a/Mage.Sets/src/mage/sets/fifthdawn/MyrServitor.java b/Mage.Sets/src/mage/sets/fifthdawn/MyrServitor.java index bc536e9b885..f284a356e4c 100644 --- a/Mage.Sets/src/mage/sets/fifthdawn/MyrServitor.java +++ b/Mage.Sets/src/mage/sets/fifthdawn/MyrServitor.java @@ -31,7 +31,7 @@ import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.BeginningOfUpkeepTriggeredAbility; -import mage.abilities.condition.common.SourceOnBattelfieldCondition; +import mage.abilities.condition.common.SourceOnBattlefieldCondition; import mage.abilities.decorator.ConditionalTriggeredAbility; import mage.abilities.effects.OneShotEffect; import mage.cards.Card; @@ -63,7 +63,7 @@ public class MyrServitor extends CardImpl { // At the beginning of your upkeep, if Myr Servitor is on the battlefield, each player returns all cards named Myr Servitor from his or her graveyard to the battlefield. this.addAbility(new ConditionalTriggeredAbility( new BeginningOfUpkeepTriggeredAbility(new MyrServitorReturnEffect(), TargetController.YOU, false), - SourceOnBattelfieldCondition.getInstance(), + SourceOnBattlefieldCondition.getInstance(), "At the beginning of your upkeep, if {this} is on the battlefield, each player returns all cards named Myr Servitor from his or her graveyard to the battlefield" )); diff --git a/Mage.Sets/src/mage/sets/fifthedition/Recall.java b/Mage.Sets/src/mage/sets/fifthedition/Recall.java index 31793865e2c..c24e5aae09c 100644 --- a/Mage.Sets/src/mage/sets/fifthedition/Recall.java +++ b/Mage.Sets/src/mage/sets/fifthedition/Recall.java @@ -93,7 +93,7 @@ class RecallEffect extends OneShotEffect { // Discard X cards int amount = source.getManaCostsToPay().getX(); int discarded = Math.min(amount, player.getHand().size()); - player.discard(amount, source, game); + player.discard(amount, false, source, game); // then return a card from your graveyard to your hand for each card discarded this way TargetCardInYourGraveyard target = new TargetCardInYourGraveyard(discarded, new FilterCard()); diff --git a/Mage.Sets/src/mage/sets/futuresight/Sliversmith.java b/Mage.Sets/src/mage/sets/futuresight/Sliversmith.java new file mode 100644 index 00000000000..3de55d8d333 --- /dev/null +++ b/Mage.Sets/src/mage/sets/futuresight/Sliversmith.java @@ -0,0 +1,85 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.sets.futuresight; + +import java.util.UUID; +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.costs.common.DiscardCardCost; +import mage.abilities.costs.common.TapSourceCost; +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.effects.common.CreateTokenEffect; +import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.Rarity; +import mage.constants.Zone; +import mage.game.permanent.token.Token; + +/** + * + * @author anonymous + */ +public class Sliversmith extends CardImpl { + + public Sliversmith(UUID ownerId) { + super(ownerId, 163, "Sliversmith", Rarity.UNCOMMON, new CardType[]{CardType.ARTIFACT, CardType.CREATURE}, "{2}"); + this.expansionSetCode = "FUT"; + this.subtype.add("Spellshaper"); + this.power = new MageInt(1); + this.toughness = new MageInt(1); + + // {1}, {tap}, Discard a card: Put a 1/1 colorless Sliver artifact creature token named Metallic Sliver onto the battlefield. + Ability ability = new SimpleActivatedAbility(Zone.HAND, new CreateTokenEffect(new MetallicSliverToken()), new ManaCostsImpl("{1}")); + ability.addCost(new TapSourceCost()); + ability.addCost(new DiscardCardCost()); + this.addAbility(ability); + } + + public Sliversmith(final Sliversmith card) { + super(card); + } + + @Override + public Sliversmith copy() { + return new Sliversmith(this); + } +} + +class MetallicSliverToken extends Token { + + MetallicSliverToken() { + super("Metallic Sliver", "a 1/1 colorless Sliver creature token"); + cardType.add(CardType.CREATURE); + cardType.add(CardType.ARTIFACT); + subtype.add("Sliver"); + power = new MageInt(1); + toughness = new MageInt(1); + this.setOriginalExpansionSetCode("FUT"); + } +} diff --git a/Mage.Sets/src/mage/sets/iceage/DanceOfTheDead.java b/Mage.Sets/src/mage/sets/iceage/DanceOfTheDead.java index f7bff5c9f84..603de287e5c 100644 --- a/Mage.Sets/src/mage/sets/iceage/DanceOfTheDead.java +++ b/Mage.Sets/src/mage/sets/iceage/DanceOfTheDead.java @@ -35,7 +35,7 @@ import mage.abilities.common.BeginningOfUpkeepTriggeredAbility; import mage.abilities.common.EntersBattlefieldTriggeredAbility; import mage.abilities.common.LeavesBattlefieldTriggeredAbility; import mage.abilities.common.SimpleStaticAbility; -import mage.abilities.condition.common.SourceOnBattelfieldCondition; +import mage.abilities.condition.common.SourceOnBattlefieldCondition; import mage.abilities.costs.mana.ManaCostsImpl; import mage.abilities.decorator.ConditionalTriggeredAbility; import mage.abilities.effects.ContinuousEffectImpl; @@ -89,7 +89,7 @@ public class DanceOfTheDead extends CardImpl { // When Dance of the Dead enters the battlefield, if it's on the battlefield, it loses "enchant creature card in a graveyard" and gains "enchant creature put onto the battlefield with Dance of the Dead." Put enchanted creature card to the battlefield tapped under your control and attach Dance of the Dead to it. When Dance of the Dead leaves the battlefield, that creature's controller sacrifices it. Ability ability = new ConditionalTriggeredAbility( new EntersBattlefieldTriggeredAbility(new DanceOfTheDeadReAttachEffect(), false), - SourceOnBattelfieldCondition.getInstance(), + SourceOnBattlefieldCondition.getInstance(), "When {this} enters the battlefield, if it's on the battlefield, it loses \"enchant creature card in a graveyard\" and gains \"enchant creature put onto the battlefield with {this}.\" Return enchanted creature card to the battlefield under your control and attach {this} to it."); ability.addEffect(new DanceOfTheDeadChangeAbilityEffect()); this.addAbility(ability); diff --git a/Mage.Sets/src/mage/sets/innistrad/BlasphemousAct.java b/Mage.Sets/src/mage/sets/innistrad/BlasphemousAct.java index 4c39dbfe48e..b5e4ec63f31 100644 --- a/Mage.Sets/src/mage/sets/innistrad/BlasphemousAct.java +++ b/Mage.Sets/src/mage/sets/innistrad/BlasphemousAct.java @@ -36,8 +36,6 @@ import mage.abilities.SpellAbility; import mage.abilities.common.SimpleStaticAbility; import mage.abilities.effects.common.DamageAllEffect; import mage.abilities.effects.common.cost.CostModificationEffectImpl; -import mage.abilities.keyword.FlashbackAbility; -import mage.abilities.keyword.RetraceAbility; import mage.cards.CardImpl; import mage.constants.CostModificationType; import mage.constants.Duration; diff --git a/Mage.Sets/src/mage/sets/innistrad/DerangedAssistant.java b/Mage.Sets/src/mage/sets/innistrad/DerangedAssistant.java index 7cb3cc89a7b..39db94f380a 100644 --- a/Mage.Sets/src/mage/sets/innistrad/DerangedAssistant.java +++ b/Mage.Sets/src/mage/sets/innistrad/DerangedAssistant.java @@ -47,13 +47,13 @@ public class DerangedAssistant extends CardImpl { this.subtype.add("Human"); this.subtype.add("Wizard"); - this.color.setBlue(true); this.power = new MageInt(1); this.toughness = new MageInt(1); - // {tap}, Put the top card of your library into your graveyard: Add {1} to your mana pool. + // {T}, Put the top card of your library into your graveyard: Add {1} to your mana pool. ColorlessManaAbility ability = new ColorlessManaAbility(); ability.addCost(new PutTopCardOfYourLibraryToGraveyardCost()); + ability.setUndoPossible(false); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/sets/innistrad/FrightfulDelusion.java b/Mage.Sets/src/mage/sets/innistrad/FrightfulDelusion.java index 37fbd1b747d..0f175f01d60 100644 --- a/Mage.Sets/src/mage/sets/innistrad/FrightfulDelusion.java +++ b/Mage.Sets/src/mage/sets/innistrad/FrightfulDelusion.java @@ -94,7 +94,7 @@ class FrightfulDelusionEffect extends OneShotEffect { if (player != null) { cost.clearPaid(); game.getPlayer(spell.getControllerId()).discard( - 1, source, game); + 1, false, source, game); if (!cost.pay(source, game, spell.getControllerId(), spell.getControllerId(), false)) { return game.getStack().counter(source.getFirstTarget(), diff --git a/Mage.Sets/src/mage/sets/innistrad/RooftopStorm.java b/Mage.Sets/src/mage/sets/innistrad/RooftopStorm.java index 5ebe0a57873..d68c3e38571 100644 --- a/Mage.Sets/src/mage/sets/innistrad/RooftopStorm.java +++ b/Mage.Sets/src/mage/sets/innistrad/RooftopStorm.java @@ -34,7 +34,6 @@ import mage.abilities.common.SimpleStaticAbility; import mage.abilities.costs.mana.ManaCostsImpl; import mage.abilities.effects.common.cost.CostModificationEffectImpl; import mage.abilities.keyword.FlashbackAbility; -import mage.abilities.keyword.RetraceAbility; import mage.cards.Card; import mage.cards.CardImpl; import mage.game.Game; @@ -42,7 +41,6 @@ import mage.players.Player; import mage.util.CardUtil; import java.util.UUID; -import mage.abilities.ActivatedAbility; /** * @@ -54,8 +52,6 @@ public class RooftopStorm extends CardImpl { super(ownerId, 71, "Rooftop Storm", Rarity.RARE, new CardType[]{CardType.ENCHANTMENT}, "{5}{U}"); this.expansionSetCode = "ISD"; - this.color.setBlue(true); - // You may pay {0} rather than pay the mana cost for Zombie creature spells you cast. this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new RooftopStormCostReductionEffect())); @@ -95,7 +91,7 @@ class RooftopStormCostReductionEffect extends CostModificationEffectImpl { @Override public boolean applies(Ability abilityToModify, Ability source, Game game) { - if (abilityToModify instanceof SpellAbility || abilityToModify instanceof FlashbackAbility || abilityToModify instanceof RetraceAbility) { + if (abilityToModify instanceof SpellAbility || abilityToModify instanceof FlashbackAbility) { Ability spell = abilityToModify; if (spell.getControllerId().equals(source.getControllerId())) { Card sourceCard = game.getCard(spell.getSourceId()); diff --git a/Mage.Sets/src/mage/sets/journeyintonyx/TormentedThoughts.java b/Mage.Sets/src/mage/sets/journeyintonyx/TormentedThoughts.java index c2e3e3c24ef..9bcd23a386e 100644 --- a/Mage.Sets/src/mage/sets/journeyintonyx/TormentedThoughts.java +++ b/Mage.Sets/src/mage/sets/journeyintonyx/TormentedThoughts.java @@ -105,7 +105,7 @@ class TormentedThoughtsDiscardEffect extends OneShotEffect { } } if (power > 0) { - targetPlayer.discard(power, source, game); + targetPlayer.discard(power, false, source, game); } return true; } diff --git a/Mage.Sets/src/mage/sets/khansoftarkir/KinTreeInvocation.java b/Mage.Sets/src/mage/sets/khansoftarkir/KinTreeInvocation.java index d6036ec47f4..2a82a4252b5 100644 --- a/Mage.Sets/src/mage/sets/khansoftarkir/KinTreeInvocation.java +++ b/Mage.Sets/src/mage/sets/khansoftarkir/KinTreeInvocation.java @@ -102,7 +102,7 @@ class KinTreeInvocationCreateTokenEffect extends OneShotEffect { objectColor.setBlack(true); objectColor.setGreen(true); Token token = new Token("Spirit Warrior", "X/X black and green Spirit Warrior creature token onto the battlefield, where X is the greatest toughness among creatures you control", - objectColor, list, value, value, new AbilitiesImpl()); + objectColor, list, value, value, new AbilitiesImpl<>()); token.getAbilities().newId(); // neccessary if token has ability like DevourAbility() token.putOntoBattlefield(1, game, source.getSourceId(), source.getControllerId()); return true; diff --git a/Mage.Sets/src/mage/sets/khansoftarkir/ZurgoHelmsmasher.java b/Mage.Sets/src/mage/sets/khansoftarkir/ZurgoHelmsmasher.java index 52ebd8a8c8f..e003a002255 100644 --- a/Mage.Sets/src/mage/sets/khansoftarkir/ZurgoHelmsmasher.java +++ b/Mage.Sets/src/mage/sets/khansoftarkir/ZurgoHelmsmasher.java @@ -58,9 +58,6 @@ public class ZurgoHelmsmasher extends CardImpl { this.subtype.add("Orc"); this.subtype.add("Warrior"); - this.color.setRed(true); - this.color.setBlack(true); - this.color.setWhite(true); this.power = new MageInt(7); this.toughness = new MageInt(2); diff --git a/Mage.Sets/src/mage/sets/legends/ChainsOfMephistopheles.java b/Mage.Sets/src/mage/sets/legends/ChainsOfMephistopheles.java index 7ec80af1ea2..8f0595c04bb 100644 --- a/Mage.Sets/src/mage/sets/legends/ChainsOfMephistopheles.java +++ b/Mage.Sets/src/mage/sets/legends/ChainsOfMephistopheles.java @@ -103,7 +103,7 @@ class ChainsOfMephistophelesReplacementEffect extends ReplacementEffectImpl { return true; } else { // discards a card instead. If the player discards a card this way, he or she draws a card. - player.discard(1, source, game); + player.discard(1, false, source, game); return false; // because player draws a card, the draw event is kept } } diff --git a/Mage.Sets/src/mage/sets/limitedalpha/AnimateDead.java b/Mage.Sets/src/mage/sets/limitedalpha/AnimateDead.java index f964e0ca389..c868a3738dc 100644 --- a/Mage.Sets/src/mage/sets/limitedalpha/AnimateDead.java +++ b/Mage.Sets/src/mage/sets/limitedalpha/AnimateDead.java @@ -33,7 +33,7 @@ import mage.abilities.Ability; import mage.abilities.common.EntersBattlefieldTriggeredAbility; import mage.abilities.common.LeavesBattlefieldTriggeredAbility; import mage.abilities.common.SimpleStaticAbility; -import mage.abilities.condition.common.SourceOnBattelfieldCondition; +import mage.abilities.condition.common.SourceOnBattlefieldCondition; import mage.abilities.decorator.ConditionalTriggeredAbility; import mage.abilities.effects.ContinuousEffectImpl; import mage.abilities.effects.OneShotEffect; @@ -83,7 +83,7 @@ public class AnimateDead extends CardImpl { // under your control and attach Animate Dead to it. When Animate Dead leaves the battlefield, that creature's controller sacrifices it. Ability ability = new ConditionalTriggeredAbility( new EntersBattlefieldTriggeredAbility(new AnimateDeadReAttachEffect(), false), - SourceOnBattelfieldCondition.getInstance(), + SourceOnBattlefieldCondition.getInstance(), "When {this} enters the battlefield, if it's on the battlefield, it loses \"enchant creature card in a graveyard\" and gains \"enchant creature put onto the battlefield with {this}.\" Return enchanted creature card to the battlefield under your control and attach {this} to it."); ability.addEffect(new AnimateDeadChangeAbilityEffect()); this.addAbility(ability); diff --git a/Mage.Sets/src/mage/sets/lorwyn/SowerOfTemptation.java b/Mage.Sets/src/mage/sets/lorwyn/SowerOfTemptation.java index a6f35a6c4d6..b31c6761bfe 100644 --- a/Mage.Sets/src/mage/sets/lorwyn/SowerOfTemptation.java +++ b/Mage.Sets/src/mage/sets/lorwyn/SowerOfTemptation.java @@ -31,7 +31,7 @@ import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.EntersBattlefieldTriggeredAbility; -import mage.abilities.condition.common.SourceOnBattelfieldCondition; +import mage.abilities.condition.common.SourceOnBattlefieldCondition; import mage.abilities.decorator.ConditionalContinuousEffect; import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.continuous.GainControlTargetEffect; @@ -66,7 +66,7 @@ public class SowerOfTemptation extends CardImpl { // remains on the battlefield, even if a different player gains control of Sower of Temptation itself. ConditionalContinuousEffect effect = new ConditionalContinuousEffect( new GainControlTargetEffect(Duration.Custom, true), - new SourceOnBattelfieldCondition(), + new SourceOnBattlefieldCondition(), "gain control of target creature for as long as {this} remains on the battlefield"); Ability ability = new EntersBattlefieldTriggeredAbility(effect, false); ability.addTarget(new TargetCreaturePermanent()); @@ -104,7 +104,7 @@ class SowerOfTemptationGainControlEffect extends OneShotEffect { public boolean apply(Game game, Ability source) { ConditionalContinuousEffect effect = new ConditionalContinuousEffect( new GainControlTargetEffect(Duration.Custom), - new SourceOnBattelfieldCondition(), + new SourceOnBattlefieldCondition(), "gain control of target creature for as long as {this} remains on the battlefield"); game.addEffect(effect, source); return false; diff --git a/Mage.Sets/src/mage/sets/magic2011/DryadsFavor.java b/Mage.Sets/src/mage/sets/magic2011/DryadsFavor.java index 07de7d14a90..c54d93456b0 100644 --- a/Mage.Sets/src/mage/sets/magic2011/DryadsFavor.java +++ b/Mage.Sets/src/mage/sets/magic2011/DryadsFavor.java @@ -1,127 +1,127 @@ -/* - * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without modification, are - * permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, this list of - * conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright notice, this list - * of conditions and the following disclaimer in the documentation and/or other materials - * provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND - * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON - * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * The views and conclusions contained in the software and documentation are those of the - * authors and should not be interpreted as representing official policies, either expressed - * or implied, of BetaSteward_at_googlemail.com. - */ - -package mage.sets.magic2011; - -import java.util.UUID; -import mage.constants.CardType; -import mage.constants.Duration; -import mage.constants.Layer; -import mage.constants.Outcome; -import mage.constants.Rarity; -import mage.constants.SubLayer; -import mage.constants.Zone; -import mage.abilities.Ability; -import mage.abilities.common.SimpleStaticAbility; -import mage.abilities.effects.ContinuousEffectImpl; -import mage.abilities.effects.common.AttachEffect; -import mage.abilities.keyword.EnchantAbility; -import mage.abilities.keyword.ForestwalkAbility; -import mage.cards.CardImpl; -import mage.game.Game; -import mage.game.permanent.Permanent; -import mage.target.TargetPermanent; -import mage.target.common.TargetCreaturePermanent; - -/** - * - * @author BetaSteward_at_googlemail.com - */ -public class DryadsFavor extends CardImpl { - - public DryadsFavor(UUID ownerId) { - super(ownerId, 169, "Dryad's Favor", Rarity.COMMON, new CardType[]{CardType.ENCHANTMENT}, "{G}"); - this.expansionSetCode = "M11"; - this.color.setGreen(true); - this.subtype.add("Aura"); - - TargetPermanent auraTarget = new TargetCreaturePermanent(); - this.getSpellAbility().addTarget(auraTarget); - this.getSpellAbility().addEffect(new AttachEffect(Outcome.Benefit)); - Ability ability = new EnchantAbility(auraTarget.getTargetName()); - this.addAbility(ability); - this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new DryadsFavorEffect())); - - } - - public DryadsFavor(final DryadsFavor card) { - super(card); - } - - @Override - public DryadsFavor copy() { - return new DryadsFavor(this); - } -} - -class DryadsFavorEffect extends ContinuousEffectImpl { - - public DryadsFavorEffect() { - super(Duration.WhileOnBattlefield, Outcome.Detriment); - staticText = "Enchanted creature has forestwalk"; - } - - public DryadsFavorEffect(final DryadsFavorEffect effect) { - super(effect); - } - - @Override - public DryadsFavorEffect copy() { - return new DryadsFavorEffect(this); - } - - @Override - public boolean apply(Layer layer, SubLayer sublayer, Ability source, Game game) { - Permanent enchantment = game.getPermanent(source.getSourceId()); - if (enchantment != null && enchantment.getAttachedTo() != null) { - Permanent creature = game.getPermanent(enchantment.getAttachedTo()); - if (creature != null) { - switch (layer) { - case AbilityAddingRemovingEffects_6: - if (sublayer == SubLayer.NA) { - creature.addAbility(new ForestwalkAbility(), game); - } - break; - } - return true; - } - } - return false; - } - - @Override - public boolean apply(Game game, Ability source) { - return false; - } - - @Override - public boolean hasLayer(Layer layer) { - return layer == Layer.AbilityAddingRemovingEffects_6; - } - -} \ No newline at end of file +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ + +package mage.sets.magic2011; + +import java.util.UUID; +import mage.abilities.Ability; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.effects.ContinuousEffectImpl; +import mage.abilities.effects.common.AttachEffect; +import mage.abilities.keyword.EnchantAbility; +import mage.abilities.keyword.ForestwalkAbility; +import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.Layer; +import mage.constants.Outcome; +import mage.constants.Rarity; +import mage.constants.SubLayer; +import mage.constants.Zone; +import mage.game.Game; +import mage.game.permanent.Permanent; +import mage.target.TargetPermanent; +import mage.target.common.TargetCreaturePermanent; + +/** + * + * @author BetaSteward_at_googlemail.com + */ +public class DryadsFavor extends CardImpl { + + public DryadsFavor(UUID ownerId) { + super(ownerId, 169, "Dryad's Favor", Rarity.COMMON, new CardType[]{CardType.ENCHANTMENT}, "{G}"); + this.expansionSetCode = "M11"; + this.subtype.add("Aura"); + + // Enchant creature + TargetPermanent auraTarget = new TargetCreaturePermanent(); + this.getSpellAbility().addTarget(auraTarget); + this.getSpellAbility().addEffect(new AttachEffect(Outcome.Benefit)); + Ability ability = new EnchantAbility(auraTarget.getTargetName()); + this.addAbility(ability); + // Enchanted creature has forestwalk. + this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new DryadsFavorEffect())); + } + + public DryadsFavor(final DryadsFavor card) { + super(card); + } + + @Override + public DryadsFavor copy() { + return new DryadsFavor(this); + } +} + +class DryadsFavorEffect extends ContinuousEffectImpl { + + public DryadsFavorEffect() { + super(Duration.WhileOnBattlefield, Outcome.Detriment); + staticText = "Enchanted creature has forestwalk"; + } + + public DryadsFavorEffect(final DryadsFavorEffect effect) { + super(effect); + } + + @Override + public DryadsFavorEffect copy() { + return new DryadsFavorEffect(this); + } + + @Override + public boolean apply(Layer layer, SubLayer sublayer, Ability source, Game game) { + Permanent enchantment = game.getPermanent(source.getSourceId()); + if (enchantment != null && enchantment.getAttachedTo() != null) { + Permanent creature = game.getPermanent(enchantment.getAttachedTo()); + if (creature != null) { + switch (layer) { + case AbilityAddingRemovingEffects_6: + if (sublayer == SubLayer.NA) { + creature.addAbility(new ForestwalkAbility(), source.getSourceId(), game); + } + break; + } + return true; + } + } + return false; + } + + @Override + public boolean apply(Game game, Ability source) { + return false; + } + + @Override + public boolean hasLayer(Layer layer) { + return layer == Layer.AbilityAddingRemovingEffects_6; + } + +} diff --git a/Mage.Sets/src/mage/sets/magic2011/OverwhelmingStampede.java b/Mage.Sets/src/mage/sets/magic2011/OverwhelmingStampede.java index 28075fe853c..6cf440320d6 100644 --- a/Mage.Sets/src/mage/sets/magic2011/OverwhelmingStampede.java +++ b/Mage.Sets/src/mage/sets/magic2011/OverwhelmingStampede.java @@ -28,17 +28,22 @@ package mage.sets.magic2011; +import java.util.UUID; import mage.abilities.Ability; -import mage.abilities.effects.ContinuousEffectImpl; +import mage.abilities.effects.ContinuousEffect; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.continuous.BoostControlledEffect; +import mage.abilities.effects.common.continuous.GainAbilityControlledEffect; import mage.abilities.keyword.TrampleAbility; import mage.cards.CardImpl; -import mage.constants.*; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.Outcome; +import mage.constants.Rarity; import mage.filter.common.FilterCreaturePermanent; import mage.game.Game; import mage.game.permanent.Permanent; -import java.util.UUID; - /** * * @author BetaSteward_at_googlemail.com @@ -48,8 +53,9 @@ public class OverwhelmingStampede extends CardImpl { public OverwhelmingStampede(UUID ownerId) { super(ownerId, 189, "Overwhelming Stampede", Rarity.RARE, new CardType[]{CardType.SORCERY}, "{3}{G}{G}"); this.expansionSetCode = "M11"; - this.color.setGreen(true); - this.getSpellAbility().addEffect(new OverwhelmingStampedeEffect()); + + // Until end of turn, creatures you control gain trample and get +X/+X, where X is the greatest power among creatures you control. + this.getSpellAbility().addEffect(new OverwhelmingStampedeInitEffect()); } public OverwhelmingStampede(final OverwhelmingStampede card) { @@ -62,55 +68,36 @@ public class OverwhelmingStampede extends CardImpl { } } -class OverwhelmingStampedeEffect extends ContinuousEffectImpl { - - public OverwhelmingStampedeEffect() { - super(Duration.EndOfTurn, Outcome.AddAbility); - staticText = "Until end of turn, creatures you control gain trample and get +X/+X, where X is the greatest power among creatures you control."; +class OverwhelmingStampedeInitEffect extends OneShotEffect { + + public OverwhelmingStampedeInitEffect() { + super(Outcome.BoostCreature); + this.staticText = "Until end of turn, creatures you control gain trample and get +X/+X, where X is the greatest power among creatures you control"; } - - public OverwhelmingStampedeEffect(final OverwhelmingStampedeEffect effect) { + + public OverwhelmingStampedeInitEffect(final OverwhelmingStampedeInitEffect effect) { super(effect); } - + @Override - public OverwhelmingStampedeEffect copy() { - return new OverwhelmingStampedeEffect(this); + public OverwhelmingStampedeInitEffect copy() { + return new OverwhelmingStampedeInitEffect(this); } - + @Override - public boolean apply(Layer layer, SubLayer sublayer, Ability source, Game game) { + public boolean apply(Game game, Ability source) { int maxPower = 0; for (Permanent perm: game.getBattlefield().getAllActivePermanents(new FilterCreaturePermanent(), source.getControllerId(), game)) { - if (perm.getPower().getValue() > maxPower) + if (perm.getPower().getValue() > maxPower) { maxPower = perm.getPower().getValue(); - } - for (Permanent perm: game.getBattlefield().getAllActivePermanents(new FilterCreaturePermanent(), source.getControllerId(), game)) { - switch (layer) { - case PTChangingEffects_7: - if (sublayer == SubLayer.ModifyPT_7c) { - perm.addPower(maxPower); - perm.addToughness(maxPower); - } - break; - case AbilityAddingRemovingEffects_6: - if (sublayer == SubLayer.NA) { - perm.addAbility(TrampleAbility.getInstance(), game); - } - break; } } + ContinuousEffect effect = new GainAbilityControlledEffect(TrampleAbility.getInstance(), Duration.EndOfStep, new FilterCreaturePermanent()); + game.addEffect(effect, source); + if (maxPower != 0) { + effect = new BoostControlledEffect(maxPower, maxPower, Duration.EndOfTurn); + game.addEffect(effect, source); + } return true; } - - @Override - public boolean apply(Game game, Ability source) { - return false; - } - - @Override - public boolean hasLayer(Layer layer) { - return layer == Layer.AbilityAddingRemovingEffects_6 || layer == Layer.PTChangingEffects_7; - } - -} \ No newline at end of file +} diff --git a/Mage.Sets/src/mage/sets/magic2011/VolcanicStrength.java b/Mage.Sets/src/mage/sets/magic2011/VolcanicStrength.java index b1942502673..59e1dc44269 100644 --- a/Mage.Sets/src/mage/sets/magic2011/VolcanicStrength.java +++ b/Mage.Sets/src/mage/sets/magic2011/VolcanicStrength.java @@ -1,133 +1,132 @@ -/* - * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without modification, are - * permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, this list of - * conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright notice, this list - * of conditions and the following disclaimer in the documentation and/or other materials - * provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND - * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON - * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * The views and conclusions contained in the software and documentation are those of the - * authors and should not be interpreted as representing official policies, either expressed - * or implied, of BetaSteward_at_googlemail.com. - */ - -package mage.sets.magic2011; - -import java.util.UUID; -import mage.constants.CardType; -import mage.constants.Duration; -import mage.constants.Layer; -import mage.constants.Outcome; -import mage.constants.Rarity; -import mage.constants.SubLayer; -import mage.constants.Zone; -import mage.abilities.Ability; -import mage.abilities.common.SimpleStaticAbility; -import mage.abilities.effects.ContinuousEffectImpl; -import mage.abilities.effects.common.AttachEffect; -import mage.abilities.keyword.EnchantAbility; -import mage.abilities.keyword.MountainwalkAbility; -import mage.cards.CardImpl; -import mage.game.Game; -import mage.game.permanent.Permanent; -import mage.target.TargetPermanent; -import mage.target.common.TargetCreaturePermanent; - -/** - * - * @author BetaSteward_at_googlemail.com - */ -public class VolcanicStrength extends CardImpl { - - public VolcanicStrength(UUID ownerId) { - super(ownerId, 158, "Volcanic Strength", Rarity.COMMON, new CardType[]{CardType.ENCHANTMENT}, "{1}{R}"); - this.expansionSetCode = "M11"; - this.color.setRed(true); - this.subtype.add("Aura"); - - TargetPermanent auraTarget = new TargetCreaturePermanent(); - this.getSpellAbility().addTarget(auraTarget); - this.getSpellAbility().addEffect(new AttachEffect(Outcome.BoostCreature)); - Ability ability = new EnchantAbility(auraTarget.getTargetName()); - this.addAbility(ability); - this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new VolcanicStrengthEffect())); - - } - - public VolcanicStrength(final VolcanicStrength card) { - super(card); - } - - @Override - public VolcanicStrength copy() { - return new VolcanicStrength(this); - } -} - -class VolcanicStrengthEffect extends ContinuousEffectImpl { - - public VolcanicStrengthEffect() { - super(Duration.WhileOnBattlefield, Outcome.BoostCreature); - staticText = "Enchanted creature gets +2/+2 and has mountainwalk"; - } - - public VolcanicStrengthEffect(final VolcanicStrengthEffect effect) { - super(effect); - } - - @Override - public VolcanicStrengthEffect copy() { - return new VolcanicStrengthEffect(this); - } - - @Override - public boolean apply(Layer layer, SubLayer sublayer, Ability source, Game game) { - Permanent enchantment = game.getPermanent(source.getSourceId()); - if (enchantment != null && enchantment.getAttachedTo() != null) { - Permanent creature = game.getPermanent(enchantment.getAttachedTo()); - if (creature != null) { - switch (layer) { - case PTChangingEffects_7: - if (sublayer == SubLayer.ModifyPT_7c) { - creature.addPower(2); - creature.addToughness(2); - } - break; - case AbilityAddingRemovingEffects_6: - if (sublayer == SubLayer.NA) { - creature.addAbility(new MountainwalkAbility(), game); - } - break; - } - return true; - } - } - return false; - } - - @Override - public boolean apply(Game game, Ability source) { - return false; - } - - @Override - public boolean hasLayer(Layer layer) { - return layer == Layer.AbilityAddingRemovingEffects_6 || layer == layer.PTChangingEffects_7; - } - -} \ No newline at end of file +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.sets.magic2011; + +import java.util.UUID; +import mage.abilities.Ability; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.effects.ContinuousEffectImpl; +import mage.abilities.effects.common.AttachEffect; +import mage.abilities.keyword.EnchantAbility; +import mage.abilities.keyword.MountainwalkAbility; +import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.Layer; +import mage.constants.Outcome; +import mage.constants.Rarity; +import mage.constants.SubLayer; +import mage.constants.Zone; +import mage.game.Game; +import mage.game.permanent.Permanent; +import mage.target.TargetPermanent; +import mage.target.common.TargetCreaturePermanent; + +/** + * + * @author BetaSteward_at_googlemail.com + */ +public class VolcanicStrength extends CardImpl { + + public VolcanicStrength(UUID ownerId) { + super(ownerId, 158, "Volcanic Strength", Rarity.COMMON, new CardType[]{CardType.ENCHANTMENT}, "{1}{R}"); + this.expansionSetCode = "M11"; + this.subtype.add("Aura"); + + // Enchant creature + TargetPermanent auraTarget = new TargetCreaturePermanent(); + this.getSpellAbility().addTarget(auraTarget); + this.getSpellAbility().addEffect(new AttachEffect(Outcome.BoostCreature)); + Ability ability = new EnchantAbility(auraTarget.getTargetName()); + // Enchanted creature gets +2/+2 and has mountainwalk. + this.addAbility(ability); + this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new VolcanicStrengthEffect())); + } + + public VolcanicStrength(final VolcanicStrength card) { + super(card); + } + + @Override + public VolcanicStrength copy() { + return new VolcanicStrength(this); + } +} + +class VolcanicStrengthEffect extends ContinuousEffectImpl { + + public VolcanicStrengthEffect() { + super(Duration.WhileOnBattlefield, Outcome.BoostCreature); + staticText = "Enchanted creature gets +2/+2 and has mountainwalk"; + } + + public VolcanicStrengthEffect(final VolcanicStrengthEffect effect) { + super(effect); + } + + @Override + public VolcanicStrengthEffect copy() { + return new VolcanicStrengthEffect(this); + } + + @Override + public boolean apply(Layer layer, SubLayer sublayer, Ability source, Game game) { + Permanent enchantment = game.getPermanent(source.getSourceId()); + if (enchantment != null && enchantment.getAttachedTo() != null) { + Permanent creature = game.getPermanent(enchantment.getAttachedTo()); + if (creature != null) { + switch (layer) { + case PTChangingEffects_7: + if (sublayer == SubLayer.ModifyPT_7c) { + creature.addPower(2); + creature.addToughness(2); + } + break; + case AbilityAddingRemovingEffects_6: + if (sublayer == SubLayer.NA) { + creature.addAbility(new MountainwalkAbility(), game); + } + break; + } + return true; + } + } + return false; + } + + @Override + public boolean apply(Game game, Ability source) { + return false; + } + + @Override + public boolean hasLayer(Layer layer) { + return layer == Layer.AbilityAddingRemovingEffects_6 || layer == Layer.PTChangingEffects_7; + } + +} diff --git a/Mage.Sets/src/mage/sets/magic2013/VolcanicStrength.java b/Mage.Sets/src/mage/sets/magic2013/VolcanicStrength.java index a5bcc5b6dc3..2874dd130ec 100644 --- a/Mage.Sets/src/mage/sets/magic2013/VolcanicStrength.java +++ b/Mage.Sets/src/mage/sets/magic2013/VolcanicStrength.java @@ -31,7 +31,7 @@ import java.util.UUID; /** * - * @author North + * @author anonymous */ public class VolcanicStrength extends mage.sets.magic2011.VolcanicStrength { diff --git a/Mage.Sets/src/mage/sets/magic2015/Quickling.java b/Mage.Sets/src/mage/sets/magic2015/Quickling.java index 3a36f8013f5..ec85face6d8 100644 --- a/Mage.Sets/src/mage/sets/magic2015/Quickling.java +++ b/Mage.Sets/src/mage/sets/magic2015/Quickling.java @@ -105,10 +105,9 @@ class QuicklingEffect extends OneShotEffect { boolean targetChosen = false; TargetPermanent target = new TargetPermanent(1, 1, filter, false); - if (target.canChoose(controller.getId(), game)) { - controller.choose(Outcome.ReturnToHand, target, source.getSourceId(), game); + if (target.canChoose(controller.getId(), game) && controller.chooseUse(outcome, "Return another creature you control to its owner's hand?", game)) { + controller.chooseTarget(Outcome.ReturnToHand, target, source, game); Permanent permanent = game.getPermanent(target.getFirstTarget()); - if ( permanent != null ) { targetChosen = true; controller.moveCardToHandWithInfo(permanent, source.getSourceId(), game, Zone.BATTLEFIELD); diff --git a/Mage.Sets/src/mage/sets/mirage/GoblinTinkerer.java b/Mage.Sets/src/mage/sets/mirage/GoblinTinkerer.java index 8b32ad935df..b4ed9b18009 100644 --- a/Mage.Sets/src/mage/sets/mirage/GoblinTinkerer.java +++ b/Mage.Sets/src/mage/sets/mirage/GoblinTinkerer.java @@ -30,12 +30,16 @@ package mage.sets.mirage; import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.costs.common.TapSourceCost; +import mage.abilities.costs.mana.ManaCostsImpl; import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.DestroyTargetEffect; import mage.cards.CardImpl; import mage.constants.CardType; import mage.constants.Outcome; import mage.constants.Rarity; +import mage.constants.Zone; import mage.game.Game; import mage.game.permanent.Permanent; import mage.players.Player; @@ -56,8 +60,11 @@ public class GoblinTinkerer extends CardImpl { this.toughness = new MageInt(2); // {R}, {T}: Destroy target artifact. That artifact deals damage equal to its converted mana cost to Goblin Tinkerer. - this.getSpellAbility().addTarget(new TargetArtifactPermanent()); - this.getSpellAbility().addEffect(new DestroyTargetEffect()); + Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new DestroyTargetEffect(), new ManaCostsImpl<>("{R}")); + ability.addEffect(new GoblinTinkererDamageEffect()); + ability.addCost(new TapSourceCost()); + ability.addTarget(new TargetArtifactPermanent()); + this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/sets/mirrodinbesieged/Mortarpod.java b/Mage.Sets/src/mage/sets/mirrodinbesieged/Mortarpod.java index 461a3c5c566..0092650105e 100644 --- a/Mage.Sets/src/mage/sets/mirrodinbesieged/Mortarpod.java +++ b/Mage.Sets/src/mage/sets/mirrodinbesieged/Mortarpod.java @@ -28,6 +28,7 @@ package mage.sets.mirrodinbesieged; import java.util.UUID; +import mage.abilities.Ability; import mage.constants.AttachmentType; import mage.constants.CardType; import mage.constants.Outcome; @@ -37,6 +38,7 @@ import mage.abilities.common.SimpleActivatedAbility; import mage.abilities.common.SimpleStaticAbility; import mage.abilities.costs.common.SacrificeSourceCost; import mage.abilities.costs.mana.GenericManaCost; +import mage.abilities.effects.Effect; import mage.abilities.effects.common.DamageTargetEffect; import mage.abilities.effects.common.continuous.BoostEquippedEffect; import mage.abilities.effects.common.continuous.GainAbilityAttachedEffect; @@ -56,13 +58,21 @@ public class Mortarpod extends CardImpl { this.expansionSetCode = "MBS"; this.subtype.add("Equipment"); + // Living weapon (When this Equipment enters the battlefield, put a 0/0 black Germ creature token onto the battlefield, then attach this to it.) this.addAbility(new LivingWeaponAbility()); - this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new BoostEquippedEffect(0, 1))); - SimpleActivatedAbility ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, + + // Equipped creature gets +0/+1 and has "Sacrifice this creature: This creature deals 1 damage to target creature or player." + Ability ability = new SimpleStaticAbility(Zone.BATTLEFIELD, new BoostEquippedEffect(0, 1)); + SimpleActivatedAbility abilityToGain = new SimpleActivatedAbility(Zone.BATTLEFIELD, new DamageTargetEffect(1), new SacrificeSourceCost()); - ability.addTarget(new TargetCreatureOrPlayer()); - this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new GainAbilityAttachedEffect(ability, AttachmentType.EQUIPMENT))); + abilityToGain.addTarget(new TargetCreatureOrPlayer()); + Effect effect = new GainAbilityAttachedEffect(abilityToGain, AttachmentType.EQUIPMENT); + effect.setText("and has \"Sacrifice this creature: This creature deals 1 damage to target creature or player.\""); + ability.addEffect(effect); + this.addAbility(ability); + + // Equip {2} this.addAbility(new EquipAbility(Outcome.BoostCreature, new GenericManaCost(2))); } diff --git a/Mage.Sets/src/mage/sets/ninthedition/DefenseGrid.java b/Mage.Sets/src/mage/sets/ninthedition/DefenseGrid.java index 5163ce36c46..29520e32b07 100644 --- a/Mage.Sets/src/mage/sets/ninthedition/DefenseGrid.java +++ b/Mage.Sets/src/mage/sets/ninthedition/DefenseGrid.java @@ -34,7 +34,6 @@ import mage.abilities.common.SimpleStaticAbility; import mage.abilities.costs.mana.GenericManaCost; import mage.abilities.effects.common.cost.CostModificationEffectImpl; import mage.abilities.keyword.FlashbackAbility; -import mage.abilities.keyword.RetraceAbility; import mage.cards.CardImpl; import mage.game.Game; @@ -85,7 +84,7 @@ class DefenseGridCostModificationEffect extends CostModificationEffectImpl { @Override public boolean applies(Ability abilityToModify, Ability source, Game game) { - if (abilityToModify instanceof SpellAbility || abilityToModify instanceof FlashbackAbility || abilityToModify instanceof RetraceAbility) { + if (abilityToModify instanceof SpellAbility || abilityToModify instanceof FlashbackAbility) { if(!abilityToModify.getControllerId().equals(game.getActivePlayerId())) { return true; } diff --git a/Mage.Sets/src/mage/sets/odyssey/AnimalBoneyard.java b/Mage.Sets/src/mage/sets/odyssey/AnimalBoneyard.java new file mode 100644 index 00000000000..1d5d1346d3d --- /dev/null +++ b/Mage.Sets/src/mage/sets/odyssey/AnimalBoneyard.java @@ -0,0 +1,127 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.sets.odyssey; + +import java.util.UUID; +import mage.abilities.Ability; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.costs.Cost; +import mage.abilities.costs.common.SacrificeTargetCost; +import mage.abilities.costs.common.TapSourceCost; +import mage.abilities.effects.Effect; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.AttachEffect; +import mage.abilities.effects.common.continuous.GainAbilityAttachedEffect; +import mage.abilities.keyword.EnchantAbility; +import mage.cards.CardImpl; +import mage.constants.AttachmentType; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.Outcome; +import mage.constants.Rarity; +import mage.constants.Zone; +import mage.game.Game; +import mage.players.Player; +import mage.target.TargetPermanent; +import mage.target.common.TargetControlledCreaturePermanent; +import mage.target.common.TargetLandPermanent; + +/** + * + * @author anonymous + */ +public class AnimalBoneyard extends CardImpl { + + public AnimalBoneyard(UUID ownerId) { + super(ownerId, 4, "Animal Boneyard", Rarity.UNCOMMON, new CardType[]{CardType.ENCHANTMENT}, "{2}{W}"); + this.expansionSetCode = "ODY"; + this.subtype.add("Aura"); + + // Enchant land + TargetPermanent auraTarget = new TargetLandPermanent(); + this.getSpellAbility().addTarget(auraTarget); + this.getSpellAbility().addEffect(new AttachEffect(Outcome.AddAbility)); + Ability ability = new EnchantAbility(auraTarget.getTargetName()); + this.addAbility(ability); + // Enchanted land has "{tap}, Sacrifice a creature: You gain life equal to that creature's toughness." + Ability gainedAbility = new SimpleActivatedAbility(Zone.BATTLEFIELD, new AnimalBoneyardEffect(), new TapSourceCost()); + gainedAbility.addCost(new SacrificeTargetCost(new TargetControlledCreaturePermanent())); + Effect effect = new GainAbilityAttachedEffect(gainedAbility, AttachmentType.AURA, Duration.WhileOnBattlefield, + "Enchanted land has \"{tap}, Sacrifice a creature: You gain life equal to that creature's toughness.\""); + this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, effect)); + } + + public AnimalBoneyard(final AnimalBoneyard card) { + super(card); + } + + @Override + public AnimalBoneyard copy() { + return new AnimalBoneyard(this); + } +} + +class AnimalBoneyardEffect extends OneShotEffect { + + public AnimalBoneyardEffect() { + super(Outcome.GainLife); + staticText = "You gain life equal to that creature's toughness"; + } + + public AnimalBoneyardEffect(final AnimalBoneyardEffect effect) { + super(effect); + } + + @Override + public boolean apply(Game game, Ability source) { + Player controller = game.getPlayer(source.getControllerId()); + if (controller != null) { + + int toughness = 0; + + for (Cost cost : source.getCosts()) { + if (cost instanceof SacrificeTargetCost && ((SacrificeTargetCost) cost).getPermanents().size() > 0) { + toughness = ((SacrificeTargetCost) cost).getPermanents().get(0).getToughness().getValue(); + break; + } + } + if (toughness > 0) { + controller.gainLife(toughness, game); + } + return true; + } + return false; + + } + + @Override + public AnimalBoneyardEffect copy() { + return new AnimalBoneyardEffect(this); + } +} diff --git a/Mage.Sets/src/mage/sets/odyssey/LaquatussCreativity.java b/Mage.Sets/src/mage/sets/odyssey/LaquatussCreativity.java index 7db6b8c9780..540fe64ca40 100644 --- a/Mage.Sets/src/mage/sets/odyssey/LaquatussCreativity.java +++ b/Mage.Sets/src/mage/sets/odyssey/LaquatussCreativity.java @@ -87,7 +87,7 @@ class LaquatussCreativityEffect extends OneShotEffect { Player player = game.getPlayer(source.getFirstTarget()); int handCount = player.getHand().count(new FilterCard(), game); player.drawCards(handCount, game); - player.discard(handCount, source, game); + player.discard(handCount, false, source, game); return false; } } diff --git a/Mage.Sets/src/mage/sets/odyssey/TestamentOfFaith.java b/Mage.Sets/src/mage/sets/odyssey/TestamentOfFaith.java index 825766fcdb2..1b0bbb87b33 100644 --- a/Mage.Sets/src/mage/sets/odyssey/TestamentOfFaith.java +++ b/Mage.Sets/src/mage/sets/odyssey/TestamentOfFaith.java @@ -137,7 +137,7 @@ class TestamentOfFaithBecomesCreatureSourceEffect extends ContinuousEffectImpl i if (sublayer == SubLayer.NA) { if (token.getAbilities().size() > 0) { for (Ability ability: token.getAbilities()) { - permanent.addAbility(ability, game); + permanent.addAbility(ability, source.getSourceId(), game, false); } } } diff --git a/Mage.Sets/src/mage/sets/planarchaos/CauterySliver.java b/Mage.Sets/src/mage/sets/planarchaos/CauterySliver.java new file mode 100644 index 00000000000..5db4c592eee --- /dev/null +++ b/Mage.Sets/src/mage/sets/planarchaos/CauterySliver.java @@ -0,0 +1,104 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.sets.planarchaos; + +import java.util.UUID; +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.costs.common.SacrificeSourceCost; +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.effects.common.DamageTargetEffect; +import mage.abilities.effects.common.PreventDamageToTargetEffect; +import mage.abilities.effects.common.continuous.GainAbilityAllEffect; +import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.Rarity; +import mage.constants.Zone; +import mage.filter.FilterPermanent; +import mage.filter.common.FilterCreatureOrPlayer; +import mage.filter.common.FilterCreaturePermanent; +import mage.target.common.TargetCreatureOrPlayer; + +/** + * + * @author anonymous + */ +public class CauterySliver extends CardImpl { + + private static final FilterPermanent filter = new FilterPermanent("Sliver", "All Slivers"); + + public CauterySliver(UUID ownerId) { + super(ownerId, 154, "Cautery Sliver", Rarity.UNCOMMON, new CardType[]{CardType.CREATURE}, "{R}{W}"); + this.expansionSetCode = "PLC"; + this.subtype.add("Sliver"); + this.power = new MageInt(2); + this.toughness = new MageInt(2); + + // All Slivers have "{1}, Sacrifice this permanent: This permanent deals 1 damage to target creature or player." + Ability ability1 = new SimpleActivatedAbility(Zone.BATTLEFIELD, new DamageTargetEffect(1), new ManaCostsImpl("1")); + ability1.addCost(new SacrificeSourceCost()); + ability1.addTarget(new TargetCreatureOrPlayer()); + this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, + new GainAbilityAllEffect(ability1, Duration.WhileOnBattlefield, filter, + "All Slivers have \"{1}, Sacrifice this permanent: This permanent deals 1 damage to target creature or player.\""))); + // All Slivers have "{1}, Sacrifice this permanent: Prevent the next 1 damage that would be dealt to target Sliver creature or player this turn." + Ability ability2 = new SimpleActivatedAbility(Zone.BATTLEFIELD, new PreventDamageToTargetEffect(Duration.EndOfTurn, 1), new ManaCostsImpl("1")); + ability2.addCost(new SacrificeSourceCost()); + ability2.addTarget(new TargetSliverCreatureOrPlayer()); + this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, + new GainAbilityAllEffect(ability2, Duration.WhileOnBattlefield, filter, + "All Slivers have \"{1}, Sacrifice this permanent: Prevent the next 1 damage that would be dealt to target Sliver creature or player this turn.\""))); + } + + public CauterySliver(final CauterySliver card) { + super(card); + } + + @Override + public CauterySliver copy() { + return new CauterySliver(this); + } +} + + +class TargetSliverCreatureOrPlayer extends TargetCreatureOrPlayer { + public TargetSliverCreatureOrPlayer(){ + super(); + filter = new FilterCreatureOrPlayerByType("Sliver", "Sliver creature or player"); + } +} + +class FilterCreatureOrPlayerByType extends FilterCreatureOrPlayer { + public FilterCreatureOrPlayerByType (String type, String name) { + super(name); + creatureFilter = new FilterCreaturePermanent(type); + } +} diff --git a/Mage.Sets/src/mage/sets/planarchaos/DormantSliver.java b/Mage.Sets/src/mage/sets/planarchaos/DormantSliver.java new file mode 100644 index 00000000000..1029a0dbd10 --- /dev/null +++ b/Mage.Sets/src/mage/sets/planarchaos/DormantSliver.java @@ -0,0 +1,80 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.sets.planarchaos; + +import java.util.UUID; +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.effects.common.DrawCardSourceControllerEffect; +import mage.abilities.effects.common.continuous.GainAbilityAllEffect; +import mage.abilities.keyword.DefenderAbility; +import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.Rarity; +import mage.constants.Zone; +import mage.filter.FilterPermanent; +import mage.filter.common.FilterCreaturePermanent; + +/** + * + * @author anonymous + */ +public class DormantSliver extends CardImpl { + + private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("Sliver", "All Sliver creatures"); + + private static final FilterPermanent filterSlivers = new FilterPermanent("Sliver", "All Slivers"); + + public DormantSliver(UUID ownerId) { + super(ownerId, 156, "Dormant Sliver", Rarity.UNCOMMON, new CardType[]{CardType.CREATURE}, "{2}{G}{U}"); + this.expansionSetCode = "PLC"; + this.subtype.add("Sliver"); + this.power = new MageInt(2); + this.toughness = new MageInt(2); + + // All Sliver creatures have defender. + this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, + new GainAbilityAllEffect(DefenderAbility.getInstance(), Duration.WhileOnBattlefield, filter, "All Sliver creatures have defender."))); + // All Slivers have "When this permanent enters the battlefield, draw a card." + Ability ability2 = new EntersBattlefieldTriggeredAbility(new DrawCardSourceControllerEffect(1)); + this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, + new GainAbilityAllEffect(ability2, Duration.WhileOnBattlefield, filter, "All Slivers have \"When this permanent enters the battlefield, draw a card.\""))); + } + + public DormantSliver(final DormantSliver card) { + super(card); + } + + @Override + public DormantSliver copy() { + return new DormantSliver(this); + } +} diff --git a/Mage.Sets/src/mage/sets/planarchaos/FreneticSliver.java b/Mage.Sets/src/mage/sets/planarchaos/FreneticSliver.java new file mode 100644 index 00000000000..4098b0f065e --- /dev/null +++ b/Mage.Sets/src/mage/sets/planarchaos/FreneticSliver.java @@ -0,0 +1,129 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.sets.planarchaos; + +import java.util.UUID; +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.common.delayed.AtTheBeginOfNextEndStepDelayedTriggeredAbility; +import mage.abilities.condition.common.SourceOnBattlefieldCondition; +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.decorator.ConditionalActivatedAbility; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.ReturnFromExileEffect; +import mage.abilities.effects.common.continuous.GainAbilityAllEffect; +import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.Outcome; +import mage.constants.Rarity; +import mage.constants.Zone; +import mage.filter.FilterPermanent; +import mage.game.Game; +import mage.game.permanent.Permanent; +import mage.players.Player; + +/** + * + * @author anonymous + */ +public class FreneticSliver extends CardImpl { + + private static final FilterPermanent filter = new FilterPermanent("Sliver", "All Slivers"); + + public FreneticSliver(UUID ownerId) { + super(ownerId, 157, "Frenetic Sliver", Rarity.UNCOMMON, new CardType[]{CardType.CREATURE}, "{1}{U}{R}"); + this.expansionSetCode = "PLC"; + this.subtype.add("Sliver"); + this.power = new MageInt(2); + this.toughness = new MageInt(2); + + // All Slivers have "{0}: If this permanent is on the battlefield, flip a coin. If you win the flip, exile this permanent and return it to the battlefield under its owner's control at the beginning of the next end step. If you lose the flip, sacrifice it." + Ability ability = new ConditionalActivatedAbility(Zone.BATTLEFIELD, + new FreneticSliverEffect(), new ManaCostsImpl("{0}"), SourceOnBattlefieldCondition.getInstance(), "{0}: If this permanent is on the battlefield, flip a coin. If you win the flip, exile this permanent and return it to the battlefield under its owner's control at the beginning of the next end step. If you lose the flip, sacrifice it."); + + this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, + new GainAbilityAllEffect(ability, Duration.WhileOnBattlefield, filter, "All Slivers have \"{0}: If this permanent is on the battlefield, flip a coin. If you win the flip, exile this permanent and return it to the battlefield under its owner's control at the beginning of the next end step. If you lose the flip, sacrifice it.\""))); + } + + public FreneticSliver(final FreneticSliver card) { + super(card); + } + + @Override + public FreneticSliver copy() { + return new FreneticSliver(this); + } +} + +class FreneticSliverEffect extends OneShotEffect { + + public FreneticSliverEffect() { + super(Outcome.Neutral); + staticText = "Flip a coin. If you win the flip, exile this permanent and return it to the battlefield under its owner's control at the beginning of the next end step. If you lose the flip, sacrifice it"; + } + + public FreneticSliverEffect(final FreneticSliverEffect effect) { + super(effect); + } + + @Override + public boolean apply(Game game, Ability source) { + Player player = game.getPlayer(source.getControllerId()); + if (player != null) { + if (player.flipCoin(game)) { + Permanent perm = game.getPermanent(source.getSourceId()); + if (perm != null) { + UUID exileZoneId = UUID.randomUUID(); + perm.moveToExile(exileZoneId, perm.getName(), source.getSourceId(), game); + // and return it to the battlefield under its owner's control at the beginning of the next end step. + AtTheBeginOfNextEndStepDelayedTriggeredAbility delayedAbility = new AtTheBeginOfNextEndStepDelayedTriggeredAbility( + new ReturnFromExileEffect(exileZoneId, Zone.BATTLEFIELD)); + delayedAbility.setSourceId(source.getSourceId()); + delayedAbility.setControllerId(source.getControllerId()); + delayedAbility.setSourceObject(source.getSourceObject(game), game); + game.addDelayedTriggeredAbility(delayedAbility); + } + return true; + } else { + Permanent perm = game.getPermanent(source.getSourceId()); + if (perm != null) { + perm.sacrifice(source.getSourceId(), game); + } + return true; + } + } + return false; + } + + @Override + public FreneticSliverEffect copy() { + return new FreneticSliverEffect(this); + } +} diff --git a/Mage.Sets/src/mage/sets/planarchaos/SpittingSliver.java b/Mage.Sets/src/mage/sets/planarchaos/SpittingSliver.java new file mode 100644 index 00000000000..627de7797e2 --- /dev/null +++ b/Mage.Sets/src/mage/sets/planarchaos/SpittingSliver.java @@ -0,0 +1,76 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.sets.planarchaos; + +import java.util.UUID; +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.effects.common.continuous.GainAbilityAllEffect; +import mage.abilities.keyword.FirstStrikeAbility; +import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.Rarity; +import mage.constants.Zone; +import mage.filter.common.FilterCreaturePermanent; +import mage.filter.predicate.mageobject.SubtypePredicate; + +/** + * + * @author anonymous + */ +public class SpittingSliver extends CardImpl { + private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("All Sliver creatures"); + + static { + filter.add(new SubtypePredicate("Sliver")); + } + + public SpittingSliver(UUID ownerId) { + super(ownerId, 80, "Spitting Sliver", Rarity.COMMON, new CardType[]{CardType.CREATURE}, "{4}{B}"); + this.expansionSetCode = "PLC"; + this.subtype.add("Sliver"); + this.power = new MageInt(3); + this.toughness = new MageInt(3); + + // All Sliver creatures have first strike. + Ability gainedAbility = FirstStrikeAbility.getInstance(); + this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, + new GainAbilityAllEffect(gainedAbility, Duration.WhileOnBattlefield, filter, "All Sliver creatures have first strike."))); + } + + public SpittingSliver(final SpittingSliver card) { + super(card); + } + + @Override + public SpittingSliver copy() { + return new SpittingSliver(this); + } +} diff --git a/Mage.Sets/src/mage/sets/planarchaos/SynchronousSliver.java b/Mage.Sets/src/mage/sets/planarchaos/SynchronousSliver.java new file mode 100644 index 00000000000..f9ca8de376c --- /dev/null +++ b/Mage.Sets/src/mage/sets/planarchaos/SynchronousSliver.java @@ -0,0 +1,70 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.sets.planarchaos; + +import java.util.UUID; +import mage.MageInt; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.effects.common.continuous.GainAbilityAllEffect; +import mage.abilities.keyword.VigilanceAbility; +import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.Rarity; +import mage.constants.Zone; +import mage.filter.common.FilterCreaturePermanent; + +/** + * + * @author anonymous + */ +public class SynchronousSliver extends CardImpl { + + private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("Sliver", "All Sliver creatures"); + + public SynchronousSliver(UUID ownerId) { + super(ownerId, 48, "Synchronous Sliver", Rarity.COMMON, new CardType[]{CardType.CREATURE}, "{4}{U}"); + this.expansionSetCode = "PLC"; + this.subtype.add("Sliver"); + this.power = new MageInt(3); + this.toughness = new MageInt(3); + + // All Sliver creatures have vigilance. + this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, + new GainAbilityAllEffect(VigilanceAbility.getInstance(), Duration.WhileOnBattlefield, filter, "All Sliver creatures have vigilance."))); + } + + public SynchronousSliver(final SynchronousSliver card) { + super(card); + } + + @Override + public SynchronousSliver copy() { + return new SynchronousSliver(this); + } +} diff --git a/Mage.Sets/src/mage/sets/planechase2012/ElderwoodScion.java b/Mage.Sets/src/mage/sets/planechase2012/ElderwoodScion.java index 8b6f9cb1d6b..b1821c235af 100644 --- a/Mage.Sets/src/mage/sets/planechase2012/ElderwoodScion.java +++ b/Mage.Sets/src/mage/sets/planechase2012/ElderwoodScion.java @@ -37,7 +37,6 @@ import mage.abilities.common.SimpleStaticAbility; import mage.abilities.effects.common.cost.CostModificationEffectImpl; import mage.abilities.keyword.FlashbackAbility; import mage.abilities.keyword.LifelinkAbility; -import mage.abilities.keyword.RetraceAbility; import mage.abilities.keyword.TrampleAbility; import mage.cards.CardImpl; import mage.constants.Duration; @@ -60,8 +59,6 @@ public class ElderwoodScion extends CardImpl { this.expansionSetCode = "PC2"; this.subtype.add("Elemental"); - this.color.setGreen(true); - this.color.setWhite(true); this.power = new MageInt(4); this.toughness = new MageInt(4); @@ -107,7 +104,7 @@ class ElderwoodScionCostReductionEffect extends CostModificationEffectImpl { @Override public boolean applies(Ability abilityToModify, Ability source, Game game) { - if (abilityToModify instanceof SpellAbility || abilityToModify instanceof FlashbackAbility || abilityToModify instanceof RetraceAbility) { + if (abilityToModify instanceof SpellAbility || abilityToModify instanceof FlashbackAbility) { if (abilityToModify.getControllerId().equals(source.getControllerId())) { for (Target target :abilityToModify.getTargets()) { for (UUID targetUUID :target.getTargets()) { diff --git a/Mage.Sets/src/mage/sets/planechase2012/LastStand.java b/Mage.Sets/src/mage/sets/planechase2012/LastStand.java index 47ae4f17f75..5fb13c4d17a 100644 --- a/Mage.Sets/src/mage/sets/planechase2012/LastStand.java +++ b/Mage.Sets/src/mage/sets/planechase2012/LastStand.java @@ -135,7 +135,7 @@ class LastStandEffect extends OneShotEffect { int islands = game.getBattlefield().count(filterIsland, source.getSourceId(), source.getControllerId(), game); if (islands > 0) { controller.drawCards(islands, game); - controller.discard(islands, source, game); + controller.discard(islands, false, source, game); } } diff --git a/Mage.Sets/src/mage/sets/planeshift/EladamrisCall.java b/Mage.Sets/src/mage/sets/planeshift/EladamrisCall.java index 02770df1c8e..f4c633499b5 100644 --- a/Mage.Sets/src/mage/sets/planeshift/EladamrisCall.java +++ b/Mage.Sets/src/mage/sets/planeshift/EladamrisCall.java @@ -52,9 +52,6 @@ public class EladamrisCall extends CardImpl { super(ownerId, 106, "Eladamri's Call", Rarity.RARE, new CardType[]{CardType.INSTANT}, "{G}{W}"); this.expansionSetCode = "PLS"; - this.color.setGreen(true); - this.color.setWhite(true); - // Search your library for a creature card, reveal that card, and put it into your hand. Then shuffle your library. this.getSpellAbility().addEffect(new SearchLibraryPutInHandEffect(new TargetCardInLibrary(filter), true, true)); } diff --git a/Mage.Sets/src/mage/sets/prophecy/AvatarOfHope.java b/Mage.Sets/src/mage/sets/prophecy/AvatarOfHope.java index 4910c80aa17..13716f9a91c 100644 --- a/Mage.Sets/src/mage/sets/prophecy/AvatarOfHope.java +++ b/Mage.Sets/src/mage/sets/prophecy/AvatarOfHope.java @@ -40,7 +40,6 @@ import mage.abilities.effects.common.cost.CostModificationEffectImpl; import mage.abilities.effects.common.combat.CanBlockAdditionalCreatureEffect; import mage.abilities.keyword.FlashbackAbility; import mage.abilities.keyword.FlyingAbility; -import mage.abilities.keyword.RetraceAbility; import mage.cards.CardImpl; import mage.constants.Duration; import mage.constants.Outcome; @@ -63,7 +62,6 @@ public class AvatarOfHope extends CardImpl { this.expansionSetCode = "PCY"; this.subtype.add("Avatar"); - this.color.setWhite(true); this.power = new MageInt(4); this.toughness = new MageInt(9); @@ -146,7 +144,7 @@ class AdjustingCostsEffect extends CostModificationEffectImpl { @Override public boolean applies(Ability abilityToModify, Ability source, Game game) { - if ((abilityToModify instanceof SpellAbility || abilityToModify instanceof FlashbackAbility || abilityToModify instanceof RetraceAbility) + if ((abilityToModify instanceof SpellAbility || abilityToModify instanceof FlashbackAbility) && abilityToModify.getSourceId().equals(source.getSourceId())) { return true; } diff --git a/Mage.Sets/src/mage/sets/prophecy/Thrive.java b/Mage.Sets/src/mage/sets/prophecy/Thrive.java index 35b51c3e060..695d4ef348c 100644 --- a/Mage.Sets/src/mage/sets/prophecy/Thrive.java +++ b/Mage.Sets/src/mage/sets/prophecy/Thrive.java @@ -30,6 +30,7 @@ package mage.sets.prophecy; import java.util.UUID; import mage.abilities.Ability; import mage.abilities.SpellAbility; +import mage.abilities.effects.Effect; import mage.abilities.effects.common.counter.AddCountersTargetEffect; import mage.cards.CardImpl; import mage.constants.CardType; @@ -49,7 +50,9 @@ public class Thrive extends CardImpl { this.expansionSetCode = "PCY"; // Put a +1/+1 counter on each of X target creatures. - this.getSpellAbility().addEffect(new AddCountersTargetEffect(CounterType.P1P1.createInstance())); + Effect effect = new AddCountersTargetEffect(CounterType.P1P1.createInstance()); + effect.setText("Put a +1/+1 counter on each of X target creatures"); + this.getSpellAbility().addEffect(effect); this.getSpellAbility().addTarget(new TargetCreaturePermanent(0, 1)); } diff --git a/Mage.Sets/src/mage/sets/ravnica/CompulsiveResearch.java b/Mage.Sets/src/mage/sets/ravnica/CompulsiveResearch.java index 04e9df90ef5..a0889671ac8 100644 --- a/Mage.Sets/src/mage/sets/ravnica/CompulsiveResearch.java +++ b/Mage.Sets/src/mage/sets/ravnica/CompulsiveResearch.java @@ -94,7 +94,7 @@ class CompulsiveResearchDiscardEffect extends OneShotEffect { if (card != null) { targetPlayer.discard(card, source, game); if (!card.getCardType().contains(CardType.LAND) && !targetPlayer.getHand().isEmpty()) { - targetPlayer.discard(1, source, game); + targetPlayer.discard(1, false, source, game); } return true; } diff --git a/Mage.Sets/src/mage/sets/returntoravnica/AssassinsStrike.java b/Mage.Sets/src/mage/sets/returntoravnica/AssassinsStrike.java index 2e666dd68b3..3f4a3eb22b8 100644 --- a/Mage.Sets/src/mage/sets/returntoravnica/AssassinsStrike.java +++ b/Mage.Sets/src/mage/sets/returntoravnica/AssassinsStrike.java @@ -92,7 +92,7 @@ class AssassinsStrikeEffect extends OneShotEffect { if (permanent != null) { Player player = game.getPlayer(permanent.getControllerId()); if (player != null) { - player.discard(1, source, game); + player.discard(1, false, source, game); return true; } } diff --git a/Mage.Sets/src/mage/sets/returntoravnica/RakdosLordOfRiots.java b/Mage.Sets/src/mage/sets/returntoravnica/RakdosLordOfRiots.java index fdf73f6d5e2..91f26ae1ab5 100644 --- a/Mage.Sets/src/mage/sets/returntoravnica/RakdosLordOfRiots.java +++ b/Mage.Sets/src/mage/sets/returntoravnica/RakdosLordOfRiots.java @@ -37,7 +37,6 @@ import mage.abilities.effects.ContinuousRuleModifyingEffectImpl; import mage.abilities.effects.common.cost.CostModificationEffectImpl; import mage.abilities.keyword.FlashbackAbility; import mage.abilities.keyword.FlyingAbility; -import mage.abilities.keyword.RetraceAbility; import mage.abilities.keyword.TrampleAbility; import mage.cards.Card; import mage.cards.CardImpl; @@ -63,8 +62,7 @@ public class RakdosLordOfRiots extends CardImpl { this.expansionSetCode = "RTR"; this.supertype.add("Legendary"); this.subtype.add("Demon"); - this.color.setBlack(true); - this.color.setRed(true); + this.power = new MageInt(6); this.toughness = new MageInt(6); @@ -153,7 +151,7 @@ class RakdosLordOfRiotsCostReductionEffect extends CostModificationEffectImpl { @Override public boolean applies(Ability abilityToModify, Ability source, Game game) { - if (abilityToModify instanceof SpellAbility || abilityToModify instanceof FlashbackAbility || abilityToModify instanceof RetraceAbility) { + if (abilityToModify instanceof SpellAbility || abilityToModify instanceof FlashbackAbility) { Card sourceCard = game.getCard(abilityToModify.getSourceId()); if (sourceCard != null && abilityToModify.getControllerId().equals(source.getControllerId()) && (sourceCard.getCardType().contains(CardType.CREATURE))) { return true; diff --git a/Mage.Sets/src/mage/sets/returntoravnica/StreetSweeper.java b/Mage.Sets/src/mage/sets/returntoravnica/StreetSweeper.java index 756388df8d7..014161dbadf 100644 --- a/Mage.Sets/src/mage/sets/returntoravnica/StreetSweeper.java +++ b/Mage.Sets/src/mage/sets/returntoravnica/StreetSweeper.java @@ -104,7 +104,7 @@ class StreetSweeperDestroyEffect extends OneShotEffect { Permanent permanent = game.getPermanent(source.getFirstTarget()); if(permanent != null) { - LinkedList attachments = new LinkedList(); + LinkedList attachments = new LinkedList<>(); attachments.addAll(permanent.getAttachments()); for(UUID uuid : attachments) { diff --git a/Mage.Sets/src/mage/sets/riseoftheeldrazi/InduceDespair.java b/Mage.Sets/src/mage/sets/riseoftheeldrazi/InduceDespair.java index cfa55e754c3..b18854a4f88 100644 --- a/Mage.Sets/src/mage/sets/riseoftheeldrazi/InduceDespair.java +++ b/Mage.Sets/src/mage/sets/riseoftheeldrazi/InduceDespair.java @@ -91,7 +91,7 @@ class InduceDespairEffect extends OneShotEffect { if (cost != null) { int CMC = -1 * cost.convertedManaCosts; if (creature != null) { - creature.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new BoostSourceEffect(CMC, CMC, Duration.EndOfTurn)), game); + creature.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new BoostSourceEffect(CMC, CMC, Duration.EndOfTurn)), source.getSourceId(), game, false); } } return true; diff --git a/Mage.Sets/src/mage/sets/riseoftheeldrazi/ThoughtGorger.java b/Mage.Sets/src/mage/sets/riseoftheeldrazi/ThoughtGorger.java index de42a251bdb..c6f6676da98 100644 --- a/Mage.Sets/src/mage/sets/riseoftheeldrazi/ThoughtGorger.java +++ b/Mage.Sets/src/mage/sets/riseoftheeldrazi/ThoughtGorger.java @@ -104,7 +104,7 @@ class ThoughtGorgerEffectEnters extends OneShotEffect { if (player != null && player.getHand().size() > 0 && thoughtGorger != null ) { int cardsInHand = player.getHand().size(); thoughtGorger.addCounters(CounterType.P1P1.createInstance(cardsInHand), game); - player.discard(cardsInHand, source, game); + player.discard(cardsInHand, false, source, game); return true; } return false; diff --git a/Mage.Sets/src/mage/sets/scarsofmirrodin/SemblanceAnvil.java b/Mage.Sets/src/mage/sets/scarsofmirrodin/SemblanceAnvil.java index c7a05c7f746..779e53a1cc9 100644 --- a/Mage.Sets/src/mage/sets/scarsofmirrodin/SemblanceAnvil.java +++ b/Mage.Sets/src/mage/sets/scarsofmirrodin/SemblanceAnvil.java @@ -35,7 +35,6 @@ import mage.abilities.common.SimpleStaticAbility; import mage.abilities.effects.common.cost.CostModificationEffectImpl; import mage.abilities.effects.OneShotEffect; import mage.abilities.keyword.FlashbackAbility; -import mage.abilities.keyword.RetraceAbility; import mage.cards.Card; import mage.cards.CardImpl; import mage.filter.FilterCard; @@ -136,7 +135,7 @@ class SemblanceAnvilCostReductionEffect extends CostModificationEffectImpl { @Override public boolean applies(Ability abilityToModify, Ability source, Game game) { - if (abilityToModify instanceof SpellAbility || abilityToModify instanceof FlashbackAbility || abilityToModify instanceof RetraceAbility) { + if (abilityToModify instanceof SpellAbility || abilityToModify instanceof FlashbackAbility) { Card sourceCard = game.getCard(abilityToModify.getSourceId()); if (sourceCard != null && sourceCard.getOwnerId().equals(source.getControllerId())) { Permanent permanent = game.getPermanent(source.getSourceId()); diff --git a/Mage.Sets/src/mage/sets/scarsofmirrodin/TrigonOfMending.java b/Mage.Sets/src/mage/sets/scarsofmirrodin/TrigonOfMending.java index fc0a7c0876e..024683ea0b7 100644 --- a/Mage.Sets/src/mage/sets/scarsofmirrodin/TrigonOfMending.java +++ b/Mage.Sets/src/mage/sets/scarsofmirrodin/TrigonOfMending.java @@ -45,6 +45,7 @@ import mage.counters.CounterType; import java.util.UUID; import mage.abilities.Ability; +import mage.abilities.costs.Cost; import mage.abilities.costs.mana.GenericManaCost; /** @@ -58,7 +59,7 @@ public class TrigonOfMending extends CardImpl { this.addAbility(new EntersBattlefieldAbility(new AddCountersSourceEffect(CounterType.CHARGE.createInstance(3)), "")); - Costs costs = new CostsImpl(); + Costs costs = new CostsImpl<>(); costs.add(new RemoveCountersSourceCost(CounterType.CHARGE.createInstance())); costs.add(new TapSourceCost()); Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new GainLifeEffect(3), costs); diff --git a/Mage.Sets/src/mage/sets/scourge/SliverOverlord.java b/Mage.Sets/src/mage/sets/scourge/SliverOverlord.java index d1bf984773c..082a5673240 100644 --- a/Mage.Sets/src/mage/sets/scourge/SliverOverlord.java +++ b/Mage.Sets/src/mage/sets/scourge/SliverOverlord.java @@ -65,16 +65,12 @@ public class SliverOverlord extends CardImpl { this.subtype.add("Sliver"); this.subtype.add("Mutant"); - this.color.setRed(true); - this.color.setBlue(true); - this.color.setGreen(true); - this.color.setBlack(true); - this.color.setWhite(true); this.power = new MageInt(7); this.toughness = new MageInt(7); // {3}: Search your library for a Sliver card, reveal that card, and put it into your hand. Then shuffle your library. - this.addAbility(new SimpleActivatedAbility(Zone.BATTLEFIELD, new SearchLibraryPutInHandEffect(new TargetCardInLibrary(filter)), new ManaCostsImpl("{3}"))); + this.addAbility(new SimpleActivatedAbility(Zone.BATTLEFIELD, new SearchLibraryPutInHandEffect(new TargetCardInLibrary(filter), true, true), new ManaCostsImpl("{3}"))); + // {3}: Gain control of target Sliver. Ability ability = (new SimpleActivatedAbility(Zone.BATTLEFIELD, new GainControlTargetEffect(Duration.EndOfGame), new ManaCostsImpl("{3}"))); Target target = new TargetPermanent(new FilterCreaturePermanent("Sliver","Sliver")); diff --git a/Mage.Sets/src/mage/sets/shadowmoor/Gloomlance.java b/Mage.Sets/src/mage/sets/shadowmoor/Gloomlance.java index 968e9e09b5a..507ae581ffb 100644 --- a/Mage.Sets/src/mage/sets/shadowmoor/Gloomlance.java +++ b/Mage.Sets/src/mage/sets/shadowmoor/Gloomlance.java @@ -93,7 +93,7 @@ class GloomlanceEffect extends OneShotEffect { Permanent destroyedCreature = game.getPermanentOrLKIBattlefield(source.getFirstTarget()); if (destroyedCreature.getColor().isGreen() || destroyedCreature.getColor().isWhite()) { - targetController.discard(1, source, game); + targetController.discard(1, false, source, game); return true; } } diff --git a/Mage.Sets/src/mage/sets/shadowmoor/PuppeteerClique.java b/Mage.Sets/src/mage/sets/shadowmoor/PuppeteerClique.java index c9853a17c9e..3fb47b66b54 100644 --- a/Mage.Sets/src/mage/sets/shadowmoor/PuppeteerClique.java +++ b/Mage.Sets/src/mage/sets/shadowmoor/PuppeteerClique.java @@ -69,7 +69,6 @@ public class PuppeteerClique extends CardImpl { this.subtype.add("Faerie"); this.subtype.add("Wizard"); - this.color.setBlack(true); this.power = new MageInt(3); this.toughness = new MageInt(2); @@ -115,7 +114,7 @@ class PuppeteerCliqueEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { boolean result = false; - Card card = game.getCard(source.getFirstTarget()); + Card card = game.getCard(getTargetPointer().getFirst(game, source)); if (card != null) { Player you = game.getPlayer(source.getControllerId()); if (you != null) { @@ -125,7 +124,7 @@ class PuppeteerCliqueEffect extends OneShotEffect { ContinuousEffect hasteEffect = new GainAbilityTargetEffect(HasteAbility.getInstance(), Duration.Custom); hasteEffect.setTargetPointer(new FixedTarget(permanent.getId())); game.addEffect(hasteEffect, source); - ExileTargetEffect exileEffect = new ExileTargetEffect(new StringBuilder("exile ").append(permanent.getName()).toString()); + ExileTargetEffect exileEffect = new ExileTargetEffect("exile " + permanent.getLogName()); exileEffect.setTargetPointer(new FixedTarget(card.getId())); DelayedTriggeredAbility delayedAbility = new AtTheBeginOfNextEndStepDelayedTriggeredAbility(exileEffect, TargetController.YOU); delayedAbility.setSourceId(source.getSourceId()); diff --git a/Mage.Sets/src/mage/sets/shardsofalara/Necrogenesis.java b/Mage.Sets/src/mage/sets/shardsofalara/Necrogenesis.java index af45d308c61..376074a6443 100644 --- a/Mage.Sets/src/mage/sets/shardsofalara/Necrogenesis.java +++ b/Mage.Sets/src/mage/sets/shardsofalara/Necrogenesis.java @@ -51,12 +51,9 @@ public class Necrogenesis extends CardImpl { super(ownerId, 181, "Necrogenesis", Rarity.UNCOMMON, new CardType[]{CardType.ENCHANTMENT}, "{B}{G}"); this.expansionSetCode = "ALA"; - this.color.setGreen(true); - this.color.setBlack(true); - // {2}: Exile target creature card from a graveyard. Put a 1/1 green Saproling creature token onto the battlefield. Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new ExileTargetEffect(), new GenericManaCost(2)); - ability.addTarget(new TargetCardInGraveyard(new FilterCreatureCard())); + ability.addTarget(new TargetCardInGraveyard(new FilterCreatureCard("creature card from a graveyard"))); ability.addEffect(new CreateTokenEffect(new SaprolingToken())); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/sets/shardsofalara/OozeGarden.java b/Mage.Sets/src/mage/sets/shardsofalara/OozeGarden.java index 1104aaf9726..89a9582a132 100644 --- a/Mage.Sets/src/mage/sets/shardsofalara/OozeGarden.java +++ b/Mage.Sets/src/mage/sets/shardsofalara/OozeGarden.java @@ -108,7 +108,7 @@ class OozeGardenCreateTokenEffect extends OneShotEffect { } ArrayList list = new ArrayList<>(); list.add("Ooze"); - Token token = new Token("Ooze", "X/X green Ooze creature token onto the battlefield, where X is the sacrificed creature's power", ObjectColor.GREEN, list, value, value, new AbilitiesImpl()) { + Token token = new Token("Ooze", "X/X green Ooze creature token onto the battlefield, where X is the sacrificed creature's power", ObjectColor.GREEN, list, value, value, new AbilitiesImpl<>()) { }; diff --git a/Mage.Sets/src/mage/sets/tempest/MindwhipSliver.java b/Mage.Sets/src/mage/sets/tempest/MindwhipSliver.java new file mode 100644 index 00000000000..56fb5c5e97a --- /dev/null +++ b/Mage.Sets/src/mage/sets/tempest/MindwhipSliver.java @@ -0,0 +1,82 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.sets.tempest; + +import java.util.UUID; +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.ActivateAsSorceryActivatedAbility; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.costs.common.SacrificeSourceCost; +import mage.abilities.costs.mana.GenericManaCost; +import mage.abilities.effects.common.continuous.GainAbilityAllEffect; +import mage.abilities.effects.common.discard.DiscardTargetEffect; +import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.Rarity; +import mage.constants.Zone; +import mage.filter.FilterPermanent; +import mage.filter.predicate.mageobject.SubtypePredicate; + +/** + * + * @author anonymous + */ +public class MindwhipSliver extends CardImpl { + + private static final FilterPermanent filter = new FilterPermanent("All Slivers"); + + static { + filter.add(new SubtypePredicate("Sliver")); + } + + public MindwhipSliver(UUID ownerId) { + super(ownerId, 39, "Mindwhip Sliver", Rarity.UNCOMMON, new CardType[]{CardType.CREATURE}, "{2}{B}"); + this.expansionSetCode = "TMP"; + this.subtype.add("Sliver"); + this.power = new MageInt(2); + this.toughness = new MageInt(2); + + // All Slivers have "{2}, Sacrifice this permanent: Target player discards a card at random. Activate this ability only any time you could cast a sorcery." + Ability gainedAbility = new ActivateAsSorceryActivatedAbility(Zone.BATTLEFIELD, new DiscardTargetEffect(1, true), new GenericManaCost(2)); + gainedAbility.addCost(new SacrificeSourceCost()); + this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, + new GainAbilityAllEffect(gainedAbility, Duration.WhileOnBattlefield, filter, + "All Slivers have \"{2}, Sacrifice this permanent: Target player discards a card at random. Activate this ability only any time you could cast a sorcery.\""))); + } + + public MindwhipSliver(final MindwhipSliver card) { + super(card); + } + + @Override + public MindwhipSliver copy() { + return new MindwhipSliver(this); + } +} diff --git a/Mage.Sets/src/mage/sets/timespiral/BasalSliver.java b/Mage.Sets/src/mage/sets/timespiral/BasalSliver.java new file mode 100644 index 00000000000..36c5e33aa56 --- /dev/null +++ b/Mage.Sets/src/mage/sets/timespiral/BasalSliver.java @@ -0,0 +1,82 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.sets.timespiral; + +import java.util.UUID; +import mage.MageInt; +import mage.Mana; +import mage.abilities.Ability; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.costs.common.SacrificeSourceCost; +import mage.abilities.effects.common.AddManaToManaPoolSourceControllerEffect; +import mage.abilities.effects.common.continuous.GainAbilityAllEffect; +import mage.abilities.mana.SimpleManaAbility; +import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.Rarity; +import mage.constants.Zone; +import mage.filter.FilterPermanent; +import mage.filter.predicate.mageobject.SubtypePredicate; + +/** + * + * @author anonymous + */ +public class BasalSliver extends CardImpl { + + private static final FilterPermanent filter = new FilterPermanent("All Slivers"); + + static { + filter.add(new SubtypePredicate("Sliver")); + } + + public BasalSliver(UUID ownerId) { + super(ownerId, 96, "Basal Sliver", Rarity.COMMON, new CardType[]{CardType.CREATURE}, "{2}{B}"); + this.expansionSetCode = "TSP"; + this.subtype.add("Sliver"); + this.power = new MageInt(2); + this.toughness = new MageInt(2); + + // All Slivers have "Sacrifice this permanent: Add {B}{B} to your mana pool." + Ability ability = new SimpleManaAbility(Zone.BATTLEFIELD, Mana.BlackMana(2), new SacrificeSourceCost()); + this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new GainAbilityAllEffect( + ability, Duration.WhileOnBattlefield, + filter, "All Slivers have \"Sacrifice this permanent: Add {B}{B} to your mana pool.\""))); + } + + public BasalSliver(final BasalSliver card) { + super(card); + } + + @Override + public BasalSliver copy() { + return new BasalSliver(this); + } +} diff --git a/Mage.Sets/src/mage/sets/timespiral/GemhideSliver.java b/Mage.Sets/src/mage/sets/timespiral/GemhideSliver.java index a056b3b5e36..efff47ee134 100644 --- a/Mage.Sets/src/mage/sets/timespiral/GemhideSliver.java +++ b/Mage.Sets/src/mage/sets/timespiral/GemhideSliver.java @@ -38,8 +38,7 @@ import mage.constants.CardType; import mage.constants.Duration; import mage.constants.Rarity; import mage.constants.Zone; -import mage.filter.common.FilterCreaturePermanent; -import mage.filter.predicate.mageobject.SubtypePredicate; +import mage.filter.FilterPermanent; /** * @@ -47,11 +46,7 @@ import mage.filter.predicate.mageobject.SubtypePredicate; */ public class GemhideSliver extends CardImpl { - private static final FilterCreaturePermanent filter = new FilterCreaturePermanent(); - - static { - filter.add(new SubtypePredicate("Sliver")); - } + private static final FilterPermanent filter = new FilterPermanent("Sliver", "All Slivers"); public GemhideSliver(UUID ownerId) { super(ownerId, 196, "Gemhide Sliver", Rarity.COMMON, new CardType[]{CardType.CREATURE}, "{1}{G}"); diff --git a/Mage.Sets/src/mage/sets/timespiral/GhostflameSliver.java b/Mage.Sets/src/mage/sets/timespiral/GhostflameSliver.java new file mode 100644 index 00000000000..7b1e4be27d7 --- /dev/null +++ b/Mage.Sets/src/mage/sets/timespiral/GhostflameSliver.java @@ -0,0 +1,104 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.sets.timespiral; + +import java.util.UUID; +import mage.MageInt; +import mage.ObjectColor; +import mage.abilities.Ability; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.effects.ContinuousEffectImpl; +import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.Layer; +import mage.constants.Outcome; +import mage.constants.Rarity; +import mage.constants.SubLayer; +import mage.constants.Zone; +import mage.filter.FilterPermanent; +import mage.game.Game; +import mage.game.permanent.Permanent; + +/** + * + * @author anonymous + */ +public class GhostflameSliver extends CardImpl { + + public GhostflameSliver(UUID ownerId) { + super(ownerId, 239, "Ghostflame Sliver", Rarity.UNCOMMON, new CardType[]{CardType.CREATURE}, "{B}{R}"); + this.expansionSetCode = "TSP"; + this.subtype.add("Sliver"); + this.power = new MageInt(2); + this.toughness = new MageInt(2); + + // All Slivers are colorless. + this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new GhostflameSliverEffect())); + } + + public GhostflameSliver(final GhostflameSliver card) { + super(card); + } + + @Override + public GhostflameSliver copy() { + return new GhostflameSliver(this); + } +} + +class GhostflameSliverEffect extends ContinuousEffectImpl { + + private static final FilterPermanent filter = new FilterPermanent("Sliver", "All Slivers"); + + private static ObjectColor colorless = new ObjectColor(); + + public GhostflameSliverEffect() { + super(Duration.WhileOnBattlefield, Layer.ColorChangingEffects_5, SubLayer.NA, Outcome.Benefit); + staticText = "All Slivers are colorless"; + } + + @Override + public boolean apply(Game game, Ability source) { + for (Permanent perm : game.getBattlefield().getActivePermanents(source.getControllerId(), game)) { + if (filter.match(perm, game)) { + perm.getColor().setColor(colorless); + } + } + return true; + } + + @Override + public GhostflameSliverEffect copy() { + return new GhostflameSliverEffect(this); + } + + private GhostflameSliverEffect(final GhostflameSliverEffect effect) { + super(effect); + } +} diff --git a/Mage.Sets/src/mage/sets/timespiral/LocketOfYesterdays.java b/Mage.Sets/src/mage/sets/timespiral/LocketOfYesterdays.java index f58d010281e..75b0398abf0 100644 --- a/Mage.Sets/src/mage/sets/timespiral/LocketOfYesterdays.java +++ b/Mage.Sets/src/mage/sets/timespiral/LocketOfYesterdays.java @@ -36,7 +36,6 @@ import mage.abilities.SpellAbility; import mage.abilities.common.SimpleStaticAbility; import mage.abilities.effects.common.cost.CostModificationEffectImpl; import mage.abilities.keyword.FlashbackAbility; -import mage.abilities.keyword.RetraceAbility; import mage.cards.Card; import mage.cards.CardImpl; import mage.game.Game; @@ -100,7 +99,7 @@ class LocketOfYesterdaysCostReductionEffect extends CostModificationEffectImpl { @Override public boolean applies(Ability abilityToModify, Ability source, Game game) { if (abilityToModify.getControllerId().equals(source.getControllerId()) && - (abilityToModify instanceof SpellAbility || abilityToModify instanceof FlashbackAbility || abilityToModify instanceof RetraceAbility)) { + (abilityToModify instanceof SpellAbility || abilityToModify instanceof FlashbackAbility)) { return true; } return false; diff --git a/Mage.Sets/src/mage/sets/timespiral/OpalineSliver.java b/Mage.Sets/src/mage/sets/timespiral/OpalineSliver.java new file mode 100644 index 00000000000..b891c5f5c31 --- /dev/null +++ b/Mage.Sets/src/mage/sets/timespiral/OpalineSliver.java @@ -0,0 +1,124 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.sets.timespiral; + +import java.util.UUID; +import mage.MageInt; +import mage.abilities.TriggeredAbilityImpl; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.effects.common.DrawCardSourceControllerEffect; +import mage.abilities.effects.common.continuous.GainAbilityAllEffect; +import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.Rarity; +import mage.constants.Zone; +import mage.filter.FilterPermanent; +import mage.filter.FilterSpell; +import mage.filter.predicate.mageobject.SubtypePredicate; +import mage.game.Game; +import mage.game.events.GameEvent; +import mage.game.events.GameEvent.EventType; +import mage.game.stack.StackObject; + +/** + * + * @author anonymous + */ +public class OpalineSliver extends CardImpl { + + private static final FilterPermanent filter = new FilterPermanent("All Slivers"); + + static { + filter.add(new SubtypePredicate("Sliver")); + } + + public OpalineSliver(UUID ownerId) { + super(ownerId, 244, "Opaline Sliver", Rarity.UNCOMMON, new CardType[]{CardType.CREATURE}, "{1}{W}{U}"); + this.expansionSetCode = "TSP"; + this.subtype.add("Sliver"); + this.power = new MageInt(2); + this.toughness = new MageInt(2); + + // All Slivers have "Whenever this permanent becomes the target of a spell an opponent controls, you may draw a card." + this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new GainAbilityAllEffect( + new OpalineSliverTriggeredAbility(), Duration.WhileOnBattlefield, + filter, "All Slivers have \"Whenever this permanent becomes the target of a spell an opponent controls, you may draw a card.\""))); + } + + public OpalineSliver(final OpalineSliver card) { + super(card); + } + + @Override + public OpalineSliver copy() { + return new OpalineSliver(this); + } +} + +class OpalineSliverTriggeredAbility extends TriggeredAbilityImpl { + + private static final FilterSpell spellCard = new FilterSpell("a spell"); + + public OpalineSliverTriggeredAbility() { + super(Zone.BATTLEFIELD, new DrawCardSourceControllerEffect(1), false); + } + + public OpalineSliverTriggeredAbility(final OpalineSliverTriggeredAbility ability) { + super(ability); + } + + @Override + public OpalineSliverTriggeredAbility copy() { + return new OpalineSliverTriggeredAbility(this); + } + + @Override + public boolean checkEventType(GameEvent event, Game game) { + return event.getType() == EventType.TARGETED; + } + + @Override + public boolean checkTrigger(GameEvent event, Game game) { + StackObject spell = game.getStack().getStackObject(event.getSourceId()); + + if (spell == null) { + return false; + } else { + return event.getTargetId().equals(this.getSourceId()) + && game.getOpponents(this.controllerId).contains(event.getPlayerId()) + && spellCard.match(spell, event.getPlayerId(), game); + } + } + + @Override + public String getRule() { + return "Whenever this permanent becomes the target of a spell an opponent controls, you may draw a card."; + } + +} diff --git a/Mage.Sets/src/mage/sets/timespiral/PsionicSliver.java b/Mage.Sets/src/mage/sets/timespiral/PsionicSliver.java new file mode 100644 index 00000000000..19442525b82 --- /dev/null +++ b/Mage.Sets/src/mage/sets/timespiral/PsionicSliver.java @@ -0,0 +1,80 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.sets.timespiral; + +import java.util.UUID; +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.costs.common.TapSourceCost; +import mage.abilities.effects.common.DamageSelfEffect; +import mage.abilities.effects.common.DamageTargetEffect; +import mage.abilities.effects.common.continuous.GainAbilityAllEffect; +import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.Rarity; +import mage.constants.Zone; +import mage.filter.common.FilterCreaturePermanent; +import mage.target.common.TargetCreatureOrPlayer; + +/** + * + * @author anonymous + * @see mage.sets.seventhedition.RecklessEmbermage + */ +public class PsionicSliver extends CardImpl { + + private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("Sliver", "All Sliver creatures"); + + public PsionicSliver(UUID ownerId) { + super(ownerId, 72, "Psionic Sliver", Rarity.RARE, new CardType[]{CardType.CREATURE}, "{4}{U}"); + this.expansionSetCode = "TSP"; + this.subtype.add("Sliver"); + this.power = new MageInt(2); + this.toughness = new MageInt(2); + + // All Sliver creatures have "{tap}: This creature deals 2 damage to target creature or player and 3 damage to itself." + Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new DamageTargetEffect(2), new TapSourceCost()); + ability.addEffect(new DamageSelfEffect(3)); + ability.addTarget(new TargetCreatureOrPlayer()); + this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, + new GainAbilityAllEffect(ability, Duration.WhileOnBattlefield, + filter, "All Sliver creatures have \"{tap}: This creature deals 2 damage to target creature or player and 3 damage to itself.\""))); + } + + public PsionicSliver(final PsionicSliver card) { + super(card); + } + + @Override + public PsionicSliver copy() { + return new PsionicSliver(this); + } +} \ No newline at end of file diff --git a/Mage.Sets/src/mage/sets/timespiral/PulmonicSliver.java b/Mage.Sets/src/mage/sets/timespiral/PulmonicSliver.java new file mode 100644 index 00000000000..f68dd68f0a8 --- /dev/null +++ b/Mage.Sets/src/mage/sets/timespiral/PulmonicSliver.java @@ -0,0 +1,81 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.sets.timespiral; + +import java.util.UUID; +import mage.MageInt; +import mage.abilities.common.PutIntoGraveFromAnywhereSourceAbility; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.effects.common.ReturnToLibrarySpellEffect; +import mage.abilities.effects.common.continuous.GainAbilityAllEffect; +import mage.abilities.keyword.FlyingAbility; +import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.Rarity; +import mage.constants.Zone; +import mage.filter.FilterPermanent; +import mage.filter.common.FilterCreaturePermanent; +import mage.filter.predicate.mageobject.SubtypePredicate; + +/** + * + * @author anonymous + */ +public class PulmonicSliver extends CardImpl { + + private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("Sliver", "All Sliver creatures"); + + private static final FilterPermanent filterSlivers = new FilterPermanent("Sliver", "All Slivers"); + + public PulmonicSliver(UUID ownerId) { + super(ownerId, 36, "Pulmonic Sliver", Rarity.RARE, new CardType[]{CardType.CREATURE}, "{3}{W}{W}"); + this.expansionSetCode = "TSP"; + this.subtype.add("Sliver"); + this.power = new MageInt(3); + this.toughness = new MageInt(3); + + // All Sliver creatures have flying. + this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new GainAbilityAllEffect( + FlyingAbility.getInstance(), Duration.WhileOnBattlefield, + filter, "All Sliver creatures have flying."))); + // All Slivers have "If this permanent would be put into a graveyard, you may put it on top of its owner's library instead." + this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new GainAbilityAllEffect( + new PutIntoGraveFromAnywhereSourceAbility(new ReturnToLibrarySpellEffect(true)), Duration.WhileOnBattlefield, + filterSlivers, "All Slivers have \"If this permanent would be put into a graveyard, you may put it on top of its owner's library instead.\""))); + } + + public PulmonicSliver(final PulmonicSliver card) { + super(card); + } + + @Override + public PulmonicSliver copy() { + return new PulmonicSliver(this); + } +} diff --git a/Mage.Sets/src/mage/sets/timespiral/ScreechingSliver.java b/Mage.Sets/src/mage/sets/timespiral/ScreechingSliver.java new file mode 100644 index 00000000000..e38da3c8a11 --- /dev/null +++ b/Mage.Sets/src/mage/sets/timespiral/ScreechingSliver.java @@ -0,0 +1,77 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.sets.timespiral; + +import java.util.UUID; +import mage.MageInt; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.costs.common.TapSourceCost; +import mage.abilities.effects.common.PutLibraryIntoGraveTargetEffect; +import mage.abilities.effects.common.continuous.GainAbilityAllEffect; +import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.Rarity; +import mage.constants.Zone; +import mage.filter.FilterPermanent; +import mage.target.TargetPlayer; + +/** + * + * @author anonymous + */ +public class ScreechingSliver extends CardImpl { + + private static final FilterPermanent filter = new FilterPermanent("Sliver", "All Slivers"); + + public ScreechingSliver(UUID ownerId) { + super(ownerId, 75, "Screeching Sliver", Rarity.COMMON, new CardType[]{CardType.CREATURE}, "{U}"); + this.expansionSetCode = "TSP"; + this.subtype.add("Sliver"); + this.power = new MageInt(1); + this.toughness = new MageInt(1); + + // All Slivers have "{tap}: Target player puts the top card of his or her library into his or her graveyard." + SimpleActivatedAbility ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new PutLibraryIntoGraveTargetEffect(1), new TapSourceCost()); + ability.addTarget(new TargetPlayer()); + + this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, + new GainAbilityAllEffect(ability, Duration.WhileOnBattlefield, + filter, "All Sliver creatures have \"{tap}: Target player puts the top card of his or her library into his or her graveyard.\""))); + } + + public ScreechingSliver(final ScreechingSliver card) { + super(card); + } + + @Override + public ScreechingSliver copy() { + return new ScreechingSliver(this); + } +} diff --git a/Mage.Sets/src/mage/sets/timespiral/SedgeSliver.java b/Mage.Sets/src/mage/sets/timespiral/SedgeSliver.java new file mode 100644 index 00000000000..a051d046bcf --- /dev/null +++ b/Mage.Sets/src/mage/sets/timespiral/SedgeSliver.java @@ -0,0 +1,86 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.sets.timespiral; + +import java.util.UUID; +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.effects.common.RegenerateSourceEffect; +import mage.abilities.effects.common.continuous.BoostSourceWhileControlsEffect; +import mage.abilities.effects.common.continuous.GainAbilityAllEffect; +import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.Rarity; +import mage.constants.Zone; +import mage.filter.FilterPermanent; +import mage.filter.common.FilterCreaturePermanent; + +/** + * + * @author anonymous + */ +public class SedgeSliver extends CardImpl { + + private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("Sliver", "All Sliver creatures"); + + private static final FilterPermanent filterSlivers = new FilterPermanent("Sliver", "All Slivers"); + + private static final FilterPermanent filterSwamp = new FilterPermanent("Swamp", "Swamp"); + + public SedgeSliver(UUID ownerId) { + super(ownerId, 177, "Sedge Sliver", Rarity.RARE, new CardType[]{CardType.CREATURE}, "{2}{R}"); + this.expansionSetCode = "TSP"; + this.subtype.add("Sliver"); + this.power = new MageInt(2); + this.toughness = new MageInt(2); + + // All Sliver creatures have "This creature gets +1/+1 as long as you control a Swamp." + Ability boost = new SimpleStaticAbility(Zone.BATTLEFIELD, new BoostSourceWhileControlsEffect(filterSwamp, 1, 1)); + this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, + new GainAbilityAllEffect(boost, Duration.WhileOnBattlefield, + filter, "All Sliver creatures have \"This creature gets +1/+1 as long as you control a Swamp.\""))); + // All Slivers have "{B}: Regenerate this permanent." + Ability regenerate = new SimpleActivatedAbility(Zone.BATTLEFIELD, new RegenerateSourceEffect(), new ManaCostsImpl("{B}")); + this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, + new GainAbilityAllEffect(regenerate, Duration.WhileOnBattlefield, + filterSlivers, "All Slivers have \"{B}: Regenerate this permanent.\""))); + } + + public SedgeSliver(final SedgeSliver card) { + super(card); + } + + @Override + public SedgeSliver copy() { + return new SedgeSliver(this); + } +} diff --git a/Mage.Sets/src/mage/sets/timespiral/ShadowSliver.java b/Mage.Sets/src/mage/sets/timespiral/ShadowSliver.java new file mode 100644 index 00000000000..c421939afc0 --- /dev/null +++ b/Mage.Sets/src/mage/sets/timespiral/ShadowSliver.java @@ -0,0 +1,76 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.sets.timespiral; + +import java.util.UUID; +import mage.MageInt; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.effects.common.continuous.GainAbilityAllEffect; +import mage.abilities.keyword.ShadowAbility; +import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.Rarity; +import mage.constants.Zone; +import mage.filter.common.FilterCreaturePermanent; +import mage.filter.predicate.mageobject.SubtypePredicate; + +/** + * + * @author anonymous + */ +public class ShadowSliver extends CardImpl { + + private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("All Sliver creatures"); + + static { + filter.add(new SubtypePredicate("Sliver")); + } + + public ShadowSliver(UUID ownerId) { + super(ownerId, 76, "Shadow Sliver", Rarity.COMMON, new CardType[]{CardType.CREATURE}, "{2}{U}"); + this.expansionSetCode = "TSP"; + this.subtype.add("Sliver"); + this.power = new MageInt(1); + this.toughness = new MageInt(1); + + // All Sliver creatures have shadow. + this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new GainAbilityAllEffect( + ShadowAbility.getInstance(), Duration.WhileOnBattlefield, + filter, "All Sliver creatures have shadow."))); + } + + public ShadowSliver(final ShadowSliver card) { + super(card); + } + + @Override + public ShadowSliver copy() { + return new ShadowSliver(this); + } +} diff --git a/Mage.Sets/src/mage/sets/timespiral/TelekineticSliver.java b/Mage.Sets/src/mage/sets/timespiral/TelekineticSliver.java new file mode 100644 index 00000000000..d92e3eb48dd --- /dev/null +++ b/Mage.Sets/src/mage/sets/timespiral/TelekineticSliver.java @@ -0,0 +1,76 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.sets.timespiral; + +import java.util.UUID; +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.costs.common.TapSourceCost; +import mage.abilities.effects.common.TapTargetEffect; +import mage.abilities.effects.common.continuous.GainAbilityAllEffect; +import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.Rarity; +import mage.constants.Zone; +import mage.filter.FilterPermanent; +import mage.target.TargetPermanent; + +/** + * + * @author anonymous + */ +public class TelekineticSliver extends CardImpl { + + private static final FilterPermanent filter = new FilterPermanent("Sliver", "All Slivers"); + + public TelekineticSliver(UUID ownerId) { + super(ownerId, 84, "Telekinetic Sliver", Rarity.UNCOMMON, new CardType[]{CardType.CREATURE}, "{2}{U}{U}"); + this.expansionSetCode = "TSP"; + this.subtype.add("Sliver"); + this.power = new MageInt(2); + this.toughness = new MageInt(2); + + // All Slivers have "{tap}: Tap target permanent." + Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new TapTargetEffect(), new TapSourceCost()); + ability.addTarget(new TargetPermanent()); + this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, + new GainAbilityAllEffect(ability, Duration.WhileOnBattlefield, filter, "All Slivers have \"{tap}: Tap target permanent.\""))); + } + + public TelekineticSliver(final TelekineticSliver card) { + super(card); + } + + @Override + public TelekineticSliver copy() { + return new TelekineticSliver(this); + } +} diff --git a/Mage.Sets/src/mage/sets/timespiral/WatcherSliver.java b/Mage.Sets/src/mage/sets/timespiral/WatcherSliver.java new file mode 100644 index 00000000000..3fdb468b9a5 --- /dev/null +++ b/Mage.Sets/src/mage/sets/timespiral/WatcherSliver.java @@ -0,0 +1,68 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.sets.timespiral; + +import java.util.UUID; +import mage.MageInt; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.effects.common.continuous.BoostAllEffect; +import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.Rarity; +import mage.constants.Zone; +import mage.filter.common.FilterCreaturePermanent; + +/** + * + * @author anonymous + */ +public class WatcherSliver extends CardImpl { + + private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("Sliver", "All Sliver creatures"); + + public WatcherSliver(UUID ownerId) { + super(ownerId, 45, "Watcher Sliver", Rarity.COMMON, new CardType[]{CardType.CREATURE}, "{3}{W}"); + this.expansionSetCode = "TSP"; + this.subtype.add("Sliver"); + this.power = new MageInt(2); + this.toughness = new MageInt(2); + + // All Sliver creatures get +0/+2. + this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new BoostAllEffect(0, 2, Duration.WhileOnBattlefield, filter, false))); + } + + public WatcherSliver(final WatcherSliver card) { + super(card); + } + + @Override + public WatcherSliver copy() { + return new WatcherSliver(this); + } +} diff --git a/Mage.Sets/src/mage/sets/torment/DeepAnalysis.java b/Mage.Sets/src/mage/sets/torment/DeepAnalysis.java index e772e445d9c..cbb97445284 100644 --- a/Mage.Sets/src/mage/sets/torment/DeepAnalysis.java +++ b/Mage.Sets/src/mage/sets/torment/DeepAnalysis.java @@ -59,7 +59,7 @@ public class DeepAnalysis extends CardImpl { this.getSpellAbility().addTarget(new TargetPlayer()); // Flashback-{1}{U}, Pay 3 life. - CostsImpl costs = new CostsImpl(); + Costs costs = new CostsImpl<>(); costs.add(new ManaCostsImpl("{1}{U}")); costs.add(new PayLifeCost(3)); this.addAbility(new FlashbackAbility(costs, TimingRule.SORCERY)); diff --git a/Mage.Sets/src/mage/sets/urzaslegacy/MemoryJar.java b/Mage.Sets/src/mage/sets/urzaslegacy/MemoryJar.java index d91b6ad1630..6d284d86f59 100644 --- a/Mage.Sets/src/mage/sets/urzaslegacy/MemoryJar.java +++ b/Mage.Sets/src/mage/sets/urzaslegacy/MemoryJar.java @@ -167,7 +167,7 @@ class MemoryJarDelayedEffect extends OneShotEffect { Player player = game.getPlayer(playerId); if (player != null) { - player.discard(player.getHand().size(), source, game); + player.discard(player.getHand().size(), false, source, game); } } //Return to hand diff --git a/Mage.Sets/src/mage/sets/urzassaga/NoRestForTheWicked.java b/Mage.Sets/src/mage/sets/urzassaga/NoRestForTheWicked.java index 13cb200e270..4fc753a2123 100644 --- a/Mage.Sets/src/mage/sets/urzassaga/NoRestForTheWicked.java +++ b/Mage.Sets/src/mage/sets/urzassaga/NoRestForTheWicked.java @@ -120,12 +120,12 @@ class NoRestForTheWickedWatcher extends Watcher { public NoRestForTheWickedWatcher() { super("NoRestForTheWickedWatcher", WatcherScope.GAME); - this.cards = new ArrayList(); + this.cards = new ArrayList<>(); } public NoRestForTheWickedWatcher(final NoRestForTheWickedWatcher watcher) { super(watcher); - this.cards = new ArrayList(); + this.cards = new ArrayList<>(); this.cards.addAll(watcher.cards); } diff --git a/Mage.Sets/src/mage/sets/vintagemasters/DacksDuplicate.java b/Mage.Sets/src/mage/sets/vintagemasters/DacksDuplicate.java index 6abc034de3c..7c2e0602262 100644 --- a/Mage.Sets/src/mage/sets/vintagemasters/DacksDuplicate.java +++ b/Mage.Sets/src/mage/sets/vintagemasters/DacksDuplicate.java @@ -53,17 +53,15 @@ public class DacksDuplicate extends CardImpl { this.expansionSetCode = "VMA"; this.subtype.add("Shapeshifter"); - this.color.setRed(true); - this.color.setBlue(true); this.power = new MageInt(0); this.toughness = new MageInt(0); // You may have Dack's Duplicate enter the battlefield as a copy of any creature on the battlefield except it gains haste and dethrone. this.addAbility(new SimpleStaticAbility( - Zone.BATTLEFIELD, - new EntersBattlefieldEffect(new CopyPermanentEffect(new DacksDuplicateApplyToPermanent()), - "You may have {this} enter the battlefield as a copy of any creature on the battlefield except it gains haste and dethrone", - true))); + Zone.BATTLEFIELD, + new EntersBattlefieldEffect(new CopyPermanentEffect(new DacksDuplicateApplyToPermanent()), + "You may have {this} enter the battlefield as a copy of any creature on the battlefield except it gains haste and dethrone", + true))); } public DacksDuplicate(final DacksDuplicate card) { @@ -77,8 +75,13 @@ public class DacksDuplicate extends CardImpl { } class DacksDuplicateApplyToPermanent extends ApplyToPermanent { + @Override public Boolean apply(Game game, Permanent permanent) { + /** + * 29/05/2014 The ability of Dack’s Duplicate doesn’t target the + * creature. + */ permanent.addAbility(new DethroneAbility(), game); permanent.addAbility(HasteAbility.getInstance(), game); return true; diff --git a/Mage.Sets/src/mage/sets/visions/AnvilOfBogardan.java b/Mage.Sets/src/mage/sets/visions/AnvilOfBogardan.java index 4ca3b9a2767..f9bbf1c5f90 100644 --- a/Mage.Sets/src/mage/sets/visions/AnvilOfBogardan.java +++ b/Mage.Sets/src/mage/sets/visions/AnvilOfBogardan.java @@ -90,7 +90,7 @@ class AnvilOfBogardanEffect extends OneShotEffect { Player targetPlayer = game.getPlayer(targetPointer.getFirst(game, source)); if (targetPlayer != null) { targetPlayer.drawCards(1, game); - targetPlayer.discard(1, source, game); + targetPlayer.discard(1, false, source, game); return true; } return false; diff --git a/Mage.Sets/src/mage/sets/visions/Necromancy.java b/Mage.Sets/src/mage/sets/visions/Necromancy.java index 35c1c5ffc0d..1bab39b2ee5 100644 --- a/Mage.Sets/src/mage/sets/visions/Necromancy.java +++ b/Mage.Sets/src/mage/sets/visions/Necromancy.java @@ -35,7 +35,7 @@ import mage.abilities.common.EntersBattlefieldTriggeredAbility; import mage.abilities.common.LeavesBattlefieldTriggeredAbility; import mage.abilities.common.SimpleStaticAbility; import mage.abilities.common.delayed.AtTheBeginOfNextCleanupDelayedTriggeredAbility; -import mage.abilities.condition.common.SourceOnBattelfieldCondition; +import mage.abilities.condition.common.SourceOnBattlefieldCondition; import mage.abilities.decorator.ConditionalTriggeredAbility; import mage.abilities.effects.AsThoughEffectImpl; import mage.abilities.effects.ContinuousEffectImpl; @@ -87,7 +87,7 @@ public class Necromancy extends CardImpl { // When Necromancy leaves the battlefield, that creature's controller sacrifices it. Ability ability = new ConditionalTriggeredAbility( new EntersBattlefieldTriggeredAbility(new NecromancyReAttachEffect(), false), - SourceOnBattelfieldCondition.getInstance(), + SourceOnBattlefieldCondition.getInstance(), "When {this} enters the battlefield, if it's on the battlefield, it becomes an Aura with \"enchant creature put onto the battlefield with {this}.\" Put target creature card from a graveyard onto the battlefield under your control and attach {this} to it."); ability.addTarget(new TargetCardInGraveyard(new FilterCreatureCard("creature card from a graveyard"))); this.addAbility(ability); diff --git a/Mage.Sets/src/mage/sets/worldwake/LodestoneGolem.java b/Mage.Sets/src/mage/sets/worldwake/LodestoneGolem.java index d749047a133..f94ee11bf3c 100644 --- a/Mage.Sets/src/mage/sets/worldwake/LodestoneGolem.java +++ b/Mage.Sets/src/mage/sets/worldwake/LodestoneGolem.java @@ -27,7 +27,7 @@ */ package mage.sets.worldwake; -import mage.constants.*; +import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.SpellAbility; @@ -35,13 +35,16 @@ import mage.abilities.common.SimpleStaticAbility; import mage.abilities.costs.mana.GenericManaCost; import mage.abilities.effects.common.cost.CostModificationEffectImpl; import mage.abilities.keyword.FlashbackAbility; -import mage.abilities.keyword.RetraceAbility; import mage.cards.Card; import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.CostModificationType; +import mage.constants.Duration; +import mage.constants.Outcome; +import mage.constants.Rarity; +import mage.constants.Zone; import mage.game.Game; -import java.util.UUID; - /** * * @author jeffwadsworth @@ -90,7 +93,7 @@ class LodestoneGolemCostReductionEffect extends CostModificationEffectImpl { @Override public boolean applies(Ability abilityToModify, Ability source, Game game) { - if (abilityToModify instanceof SpellAbility || abilityToModify instanceof FlashbackAbility || abilityToModify instanceof RetraceAbility) { + if (abilityToModify instanceof SpellAbility || abilityToModify instanceof FlashbackAbility) { Card card = game.getCard(abilityToModify.getSourceId()); if (card != null && !card.getCardType().contains(CardType.ARTIFACT)) { return true; diff --git a/Mage.Sets/src/mage/sets/worldwake/PermafrostTrap.java b/Mage.Sets/src/mage/sets/worldwake/PermafrostTrap.java index fdabe4a2e0e..74d476c2018 100644 --- a/Mage.Sets/src/mage/sets/worldwake/PermafrostTrap.java +++ b/Mage.Sets/src/mage/sets/worldwake/PermafrostTrap.java @@ -34,6 +34,7 @@ import mage.constants.Rarity; import mage.ObjectColor; import mage.abilities.Ability; import mage.abilities.costs.AlternativeCostImpl; +import mage.abilities.costs.Cost; import mage.abilities.costs.mana.ColoredManaCost; import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.DontUntapInControllersNextUntapStepTargetEffect; @@ -115,7 +116,7 @@ class PermafrostTrapWatcher extends Watcher { } } -class PermafrostTrapAlternativeCost extends AlternativeCostImpl { +class PermafrostTrapAlternativeCost extends AlternativeCostImpl { public PermafrostTrapAlternativeCost() { super("you may pay {U} rather than pay Permafrost Trap's mana cost"); diff --git a/Mage.Sets/src/mage/sets/worldwake/RicochetTrap.java b/Mage.Sets/src/mage/sets/worldwake/RicochetTrap.java index 3dfe8b14603..953c4ff704a 100644 --- a/Mage.Sets/src/mage/sets/worldwake/RicochetTrap.java +++ b/Mage.Sets/src/mage/sets/worldwake/RicochetTrap.java @@ -34,6 +34,7 @@ import mage.constants.Rarity; import mage.constants.WatcherScope; import mage.abilities.Ability; import mage.abilities.costs.AlternativeCostImpl; +import mage.abilities.costs.Cost; import mage.abilities.costs.mana.ColoredManaCost; import mage.abilities.effects.common.ChooseNewTargetsTargetEffect; import mage.cards.CardImpl; @@ -123,7 +124,7 @@ class RicochetTrapWatcher extends Watcher { } } -class RicochetTrapAlternativeCost extends AlternativeCostImpl { +class RicochetTrapAlternativeCost extends AlternativeCostImpl { public RicochetTrapAlternativeCost() { super("You may pay {R} rather than pay Ricochet Trap's mana cost"); diff --git a/Mage.Sets/src/mage/sets/worldwake/SlingbowTrap.java b/Mage.Sets/src/mage/sets/worldwake/SlingbowTrap.java index eaed3ae26a4..37abbb3bc83 100644 --- a/Mage.Sets/src/mage/sets/worldwake/SlingbowTrap.java +++ b/Mage.Sets/src/mage/sets/worldwake/SlingbowTrap.java @@ -33,6 +33,7 @@ import mage.constants.CardType; import mage.constants.Rarity; import mage.abilities.Ability; import mage.abilities.costs.AlternativeCostImpl; +import mage.abilities.costs.Cost; import mage.abilities.costs.mana.ManaCostsImpl; import mage.abilities.effects.common.DestroyTargetEffect; import mage.abilities.keyword.FlyingAbility; @@ -80,7 +81,7 @@ public class SlingbowTrap extends CardImpl { } } -class SlingbowTrapAlternativeCost extends AlternativeCostImpl { +class SlingbowTrapAlternativeCost extends AlternativeCostImpl { public SlingbowTrapAlternativeCost() { super("you may pay {G} rather than pay {this}'s mana cost"); diff --git a/Mage.Sets/src/mage/sets/worldwake/StoneIdolTrap.java b/Mage.Sets/src/mage/sets/worldwake/StoneIdolTrap.java index bc6f9e86912..2bab309e9cc 100644 --- a/Mage.Sets/src/mage/sets/worldwake/StoneIdolTrap.java +++ b/Mage.Sets/src/mage/sets/worldwake/StoneIdolTrap.java @@ -37,8 +37,6 @@ import mage.abilities.common.delayed.AtTheBeginOfNextEndStepDelayedTriggeredAbil import mage.abilities.effects.common.cost.CostModificationEffectImpl; import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.ExileTargetEffect; -import mage.abilities.keyword.FlashbackAbility; -import mage.abilities.keyword.RetraceAbility; import mage.abilities.keyword.TrampleAbility; import mage.cards.CardImpl; import mage.filter.common.FilterCreaturePermanent; diff --git a/Mage.Sets/src/mage/sets/zendikar/CobraTrap.java b/Mage.Sets/src/mage/sets/zendikar/CobraTrap.java index fa224904334..d53b32c132a 100644 --- a/Mage.Sets/src/mage/sets/zendikar/CobraTrap.java +++ b/Mage.Sets/src/mage/sets/zendikar/CobraTrap.java @@ -35,6 +35,7 @@ import mage.constants.WatcherScope; import mage.constants.Zone; import mage.abilities.Ability; import mage.abilities.costs.AlternativeCostImpl; +import mage.abilities.costs.Cost; import mage.abilities.costs.mana.ColoredManaCost; import mage.abilities.effects.common.CreateTokenEffect; import mage.cards.CardImpl; @@ -113,7 +114,7 @@ class CobraTrapWatcher extends Watcher { } } -class CobraTrapAlternativeCost extends AlternativeCostImpl { +class CobraTrapAlternativeCost extends AlternativeCostImpl { public CobraTrapAlternativeCost() { super("you may pay {G} rather than pay Cobra Trap's mana cost"); diff --git a/Mage.Sets/src/mage/sets/zendikar/LavaballTrap.java b/Mage.Sets/src/mage/sets/zendikar/LavaballTrap.java index 9630fa052e5..131b62e279b 100644 --- a/Mage.Sets/src/mage/sets/zendikar/LavaballTrap.java +++ b/Mage.Sets/src/mage/sets/zendikar/LavaballTrap.java @@ -35,6 +35,7 @@ import mage.constants.CardType; import mage.constants.Rarity; import mage.abilities.Ability; import mage.abilities.costs.AlternativeCostImpl; +import mage.abilities.costs.Cost; import mage.abilities.costs.mana.ManaCostsImpl; import mage.abilities.effects.common.DamageAllEffect; import mage.abilities.effects.common.DestroyTargetEffect; @@ -83,7 +84,7 @@ public class LavaballTrap extends CardImpl { class LavaballTrapWatcher extends Watcher { - private Map amountOfLandsPlayedThisTurn = new HashMap(); + private Map amountOfLandsPlayedThisTurn = new HashMap<>(); public LavaballTrapWatcher() { super("LavaballTrapWatcher", WatcherScope.GAME); @@ -108,7 +109,7 @@ class LavaballTrapWatcher extends Watcher { if (perm.getCardType().contains(CardType.LAND)) { Integer amount = amountOfLandsPlayedThisTurn.get(perm.getControllerId()); if (amount == null) { - amount = Integer.valueOf(1); + amount = 1; } else { ++amount; } @@ -121,8 +122,8 @@ class LavaballTrapWatcher extends Watcher { int maxLands = 0; for (UUID opponentId : game.getOpponents(playerId)) { Integer amount = amountOfLandsPlayedThisTurn.get(opponentId); - if (amount != null && amount.intValue() > maxLands) { - maxLands = amount.intValue(); + if (amount != null && amount > maxLands) { + maxLands = amount; } } return maxLands; @@ -135,7 +136,7 @@ class LavaballTrapWatcher extends Watcher { } } -class LavaballTrapAlternativeCost extends AlternativeCostImpl { +class LavaballTrapAlternativeCost extends AlternativeCostImpl { public LavaballTrapAlternativeCost() { super("you may pay {3}{R}{R} rather than pay Lavaball Trap's mana cost"); diff --git a/Mage.Sets/src/mage/sets/zendikar/LethargyTrap.java b/Mage.Sets/src/mage/sets/zendikar/LethargyTrap.java index 50d2f7c85ea..15e18f7856a 100644 --- a/Mage.Sets/src/mage/sets/zendikar/LethargyTrap.java +++ b/Mage.Sets/src/mage/sets/zendikar/LethargyTrap.java @@ -33,6 +33,7 @@ import mage.constants.CardType; import mage.constants.Rarity; import mage.abilities.Ability; import mage.abilities.costs.AlternativeCostImpl; +import mage.abilities.costs.Cost; import mage.abilities.costs.mana.ManaCostsImpl; import mage.abilities.effects.common.continuous.BoostAllEffect; import mage.cards.CardImpl; @@ -78,7 +79,7 @@ public class LethargyTrap extends CardImpl { } } -class LethargyTrapAlternativeCost extends AlternativeCostImpl { +class LethargyTrapAlternativeCost extends AlternativeCostImpl { public LethargyTrapAlternativeCost() { super("you may pay {U} rather than pay Lethargy Trap's mana cost"); diff --git a/Mage.Sets/src/mage/sets/zendikar/RuneflareTrap.java b/Mage.Sets/src/mage/sets/zendikar/RuneflareTrap.java index 71621ce4083..2e21963392a 100644 --- a/Mage.Sets/src/mage/sets/zendikar/RuneflareTrap.java +++ b/Mage.Sets/src/mage/sets/zendikar/RuneflareTrap.java @@ -44,6 +44,7 @@ import mage.target.TargetPlayer; import mage.watchers.Watcher; import java.util.UUID; +import mage.abilities.costs.Cost; /** * @@ -142,7 +143,7 @@ class CardsDrawnOpponentWatcher extends Watcher { } } -class RuneflareTrapAlternativeCost extends AlternativeCostImpl { +class RuneflareTrapAlternativeCost extends AlternativeCostImpl { public RuneflareTrapAlternativeCost() { super("you may pay {R} rather than pay Runeflare Trap's mana cost"); diff --git a/Mage.Sets/src/mage/sets/zendikar/SummoningTrap.java b/Mage.Sets/src/mage/sets/zendikar/SummoningTrap.java index c5319ca860b..1c87f79f946 100644 --- a/Mage.Sets/src/mage/sets/zendikar/SummoningTrap.java +++ b/Mage.Sets/src/mage/sets/zendikar/SummoningTrap.java @@ -36,6 +36,7 @@ import mage.constants.WatcherScope; import mage.constants.Zone; import mage.abilities.Ability; import mage.abilities.costs.AlternativeCostImpl; +import mage.abilities.costs.Cost; import mage.abilities.costs.mana.GenericManaCost; import mage.abilities.effects.OneShotEffect; import mage.cards.Card; @@ -126,7 +127,7 @@ class SummoningTrapWatcher extends Watcher { } } -class SummoningTrapAlternativeCost extends AlternativeCostImpl { +class SummoningTrapAlternativeCost extends AlternativeCostImpl { public SummoningTrapAlternativeCost() { super("you may pay {0} rather than pay Summoning Trap's mana cost"); diff --git a/Mage.Sets/src/mage/sets/zendikar/SunspringExpedition.java b/Mage.Sets/src/mage/sets/zendikar/SunspringExpedition.java index 9d8578c211e..6a2e06b5dd0 100644 --- a/Mage.Sets/src/mage/sets/zendikar/SunspringExpedition.java +++ b/Mage.Sets/src/mage/sets/zendikar/SunspringExpedition.java @@ -35,6 +35,7 @@ import mage.constants.Zone; import mage.abilities.ActivatedAbility; import mage.abilities.common.LandfallAbility; import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.costs.Cost; import mage.abilities.costs.Costs; import mage.abilities.costs.CostsImpl; import mage.abilities.costs.common.RemoveCountersSourceCost; @@ -56,7 +57,7 @@ public class SunspringExpedition extends CardImpl { this.color.setWhite(true); this.addAbility(new LandfallAbility(new AddCountersSourceEffect(CounterType.QUEST.createInstance()), true)); - Costs costs = new CostsImpl(); + Costs costs = new CostsImpl<>(); costs.add(new RemoveCountersSourceCost(CounterType.QUEST.createInstance(3))); costs.add(new SacrificeSourceCost()); ActivatedAbility ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new GainLifeEffect(8), costs); diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/abilities/keywords/RetraceTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/abilities/keywords/RetraceTest.java new file mode 100644 index 00000000000..8a056cbecfd --- /dev/null +++ b/Mage.Tests/src/test/java/org/mage/test/cards/abilities/keywords/RetraceTest.java @@ -0,0 +1,125 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package org.mage.test.cards.abilities.keywords; + +import mage.constants.PhaseStep; +import mage.constants.Zone; +import org.junit.Test; +import org.mage.test.serverside.base.CardTestPlayerBase; + +/** + * + * @author LevelX2 + */ + +public class RetraceTest extends CardTestPlayerBase { + + /** + * 702.78. Retrace + * 702.78a Retrace appears on some instants and sorceries. It represents a static ability + * that functions while the card is in a player's graveyard. "Retrace" means "You may cast + * this card from your graveyard by discarding a land card as an additional cost to cast it." + * Casting a spell using its retrace ability follows the rules for paying additional costs + * in rules 601.2b and 601.2e-g. + */ + + + @Test + public void SimpleRetrace() { + addCard(Zone.BATTLEFIELD, playerA, "Swamp", 1); + // Target player discards a card. + // Retrace + addCard(Zone.GRAVEYARD, playerA, "Raven's Crime"); + addCard(Zone.HAND, playerA, "Swamp"); + + addCard(Zone.HAND, playerB, "Silvercoat Lion", 1); + + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Raven's Crime", playerB); + + setStopAt(1, PhaseStep.BEGIN_COMBAT); + execute(); + + assertGraveyardCount(playerA,"Raven's Crime", 1); + assertGraveyardCount(playerA,"Swamp", 1); + + assertGraveyardCount(playerB,"Silvercoat Lion", 1); + } + + /** + * Test that it does cost {B}{1} + land discard + */ + @Test + public void RetraceCostIncreaseCantPay() { + addCard(Zone.BATTLEFIELD, playerA, "Swamp", 1); + // Target player discards a card. + // Retrace + addCard(Zone.GRAVEYARD, playerA, "Raven's Crime"); + addCard(Zone.HAND, playerA, "Swamp"); + + // // Noncreature spells cost {1} more to cast. + addCard(Zone.BATTLEFIELD, playerB, "Thalia, Guardian of Thraben", 1); + addCard(Zone.HAND, playerB, "Silvercoat Lion", 1); + + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Raven's Crime", playerB); + + setStopAt(1, PhaseStep.BEGIN_COMBAT); + execute(); + + assertGraveyardCount(playerA,"Raven's Crime", 1); + assertGraveyardCount(playerA,"Swamp", 0); // because not enough mana + + assertGraveyardCount(playerB,"Silvercoat Lion", 0); // because not enough mana + } + + /** + * Test that it does cost {B}{1} + land discard + */ + @Test + public void RetraceCostIncreaseCanPay() { + addCard(Zone.BATTLEFIELD, playerA, "Swamp", 2); + // Target player discards a card. + // Retrace + addCard(Zone.GRAVEYARD, playerA, "Raven's Crime"); + addCard(Zone.HAND, playerA, "Swamp"); + + // // Noncreature spells cost {1} more to cast. + addCard(Zone.BATTLEFIELD, playerB, "Thalia, Guardian of Thraben", 1); + addCard(Zone.HAND, playerB, "Silvercoat Lion", 1); + + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Raven's Crime", playerB); + + setStopAt(1, PhaseStep.BEGIN_COMBAT); + execute(); + + assertGraveyardCount(playerA,"Raven's Crime", 1); + assertGraveyardCount(playerA,"Swamp", 1); + + assertGraveyardCount(playerB,"Silvercoat Lion", 1); + } + +} diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/abilities/oneshot/damage/SatyrFiredancerTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/abilities/oneshot/damage/SatyrFiredancerTest.java new file mode 100644 index 00000000000..b97cd37240f --- /dev/null +++ b/Mage.Tests/src/test/java/org/mage/test/cards/abilities/oneshot/damage/SatyrFiredancerTest.java @@ -0,0 +1,86 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package org.mage.test.cards.abilities.oneshot.damage; + +import mage.constants.PhaseStep; +import mage.constants.Zone; +import mage.counters.CounterType; +import org.junit.Test; +import org.mage.test.serverside.base.CardTestPlayerBase; + +/** + * + * @author LevelX2 + */ + +public class SatyrFiredancerTest extends CardTestPlayerBase { + + @Test + public void testDamageFromInstantToPlayer() { + // Whenever an instant or sorcery spell you control deals damage to an opponent, Satyr Firedancer deals that much damage to target creature that player controls. + addCard(Zone.BATTLEFIELD, playerA, "Satyr Firedancer"); + addCard(Zone.BATTLEFIELD, playerA, "Mountain", 1); + addCard(Zone.HAND, playerA, "Lightning Bolt"); + + addCard(Zone.BATTLEFIELD, playerB, "Silvercoat Lion"); + + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Lightning Bolt", playerB); + addTarget(playerA, "Silvercoat Lion"); + + setStopAt(1, PhaseStep.BEGIN_COMBAT); + execute(); + + assertLife(playerA, 20); + assertLife(playerB, 17); + + assertGraveyardCount(playerA, "Lightning Bolt", 1); + assertGraveyardCount(playerB, "Silvercoat Lion", 1); + } + + @Test + public void testDamageFromAttackWontTrigger() { + // Whenever an instant or sorcery spell you control deals damage to an opponent, Satyr Firedancer deals that much damage to target creature that player controls. + addCard(Zone.BATTLEFIELD, playerA, "Satyr Firedancer"); + addCard(Zone.BATTLEFIELD, playerA, "Pillarfield Ox", 1); + + addCard(Zone.BATTLEFIELD, playerB, "Silvercoat Lion"); + + attack(1, playerA, "Pillarfield Ox"); + addTarget(playerA, "Silvercoat Lion"); + + setStopAt(1, PhaseStep.END_TURN); + execute(); + + assertLife(playerA, 20); + assertLife(playerB, 18); + + assertGraveyardCount(playerB, "Silvercoat Lion", 0); + assertPermanentCount(playerB, "Silvercoat Lion", 1); + } + +} diff --git a/Mage/src/mage/abilities/TriggeredAbilities.java b/Mage/src/mage/abilities/TriggeredAbilities.java index a712c956a02..fe0dd47fe64 100644 --- a/Mage/src/mage/abilities/TriggeredAbilities.java +++ b/Mage/src/mage/abilities/TriggeredAbilities.java @@ -47,8 +47,11 @@ import mage.game.permanent.Permanent; /** * * @author BetaSteward_at_googlemail.com + * + * This class uses ConcurrentHashMap to avoid ConcurrentModificationExceptions. + * See ticket https://github.com/magefree/mage/issues/966 and https://github.com/magefree/mage/issues/473 */ -public class TriggeredAbilities extends HashMap { +public class TriggeredAbilities extends ConcurrentHashMap { private final Map> sources = new HashMap<>(); diff --git a/Mage/src/mage/abilities/condition/common/SourceOnBattelfieldCondition.java b/Mage/src/mage/abilities/condition/common/SourceOnBattlefieldCondition.java similarity index 88% rename from Mage/src/mage/abilities/condition/common/SourceOnBattelfieldCondition.java rename to Mage/src/mage/abilities/condition/common/SourceOnBattlefieldCondition.java index c3fe73771b5..5c7acd33f0e 100644 --- a/Mage/src/mage/abilities/condition/common/SourceOnBattelfieldCondition.java +++ b/Mage/src/mage/abilities/condition/common/SourceOnBattlefieldCondition.java @@ -38,11 +38,11 @@ import mage.game.Game; * * @author LevelX2 */ -public class SourceOnBattelfieldCondition implements Condition { +public class SourceOnBattlefieldCondition implements Condition { - private static final SourceOnBattelfieldCondition fInstance = new SourceOnBattelfieldCondition(); + private static final SourceOnBattlefieldCondition fInstance = new SourceOnBattlefieldCondition(); - public static SourceOnBattelfieldCondition getInstance() { + public static SourceOnBattlefieldCondition getInstance() { return fInstance; } diff --git a/Mage/src/mage/abilities/costs/AlternativeCostImpl.java b/Mage/src/mage/abilities/costs/AlternativeCostImpl.java index d6fdb81be45..36e3d63d154 100644 --- a/Mage/src/mage/abilities/costs/AlternativeCostImpl.java +++ b/Mage/src/mage/abilities/costs/AlternativeCostImpl.java @@ -3,7 +3,7 @@ package mage.abilities.costs; import mage.abilities.Ability; import mage.game.Game; -public class AlternativeCostImpl extends CostsImpl implements AlternativeCost { +public class AlternativeCostImpl extends CostsImpl implements AlternativeCost { protected String name; @@ -13,7 +13,7 @@ public class AlternativeCostImpl extends CostsImpl implements AlternativeCost { public AlternativeCostImpl(String name, Cost cost) { this.name = name; - this.add(cost); + this.add((T)cost); } public AlternativeCostImpl(final AlternativeCostImpl cost) { diff --git a/Mage/src/mage/abilities/costs/common/PutTopCardOfYourLibraryToGraveyardCost.java b/Mage/src/mage/abilities/costs/common/PutTopCardOfYourLibraryToGraveyardCost.java index 8ae3d2d8457..8923b3079ed 100644 --- a/Mage/src/mage/abilities/costs/common/PutTopCardOfYourLibraryToGraveyardCost.java +++ b/Mage/src/mage/abilities/costs/common/PutTopCardOfYourLibraryToGraveyardCost.java @@ -33,6 +33,8 @@ import mage.constants.Zone; import mage.abilities.Ability; import mage.abilities.costs.CostImpl; import mage.cards.Card; +import mage.cards.Cards; +import mage.cards.CardsImpl; import mage.game.Game; import mage.players.Player; import mage.util.CardUtil; @@ -65,16 +67,10 @@ public class PutTopCardOfYourLibraryToGraveyardCost extends CostImpl { public boolean pay(Ability ability, Game game, UUID sourceId, UUID controllerId, boolean noMana) { Player player = game.getPlayer(controllerId); if (player != null && player.getLibrary().size() >= numberOfCards) { - int i = 0; paid = true; - while (player.isInGame() && i < numberOfCards) { - Card card = player.getLibrary().removeFromTop(game); - if (card != null) { - // all cards must reach the graveyard to pay the costs - paid &= card.moveToZone(Zone.GRAVEYARD, sourceId, game, true); - } - ++i; - } + Cards cards = new CardsImpl(); + cards.addAll(player.getLibrary().getTopCards(game, numberOfCards)); + player.moveCardsToGraveyardWithInfo(cards, ability, game, Zone.LIBRARY); } return paid; } @@ -82,10 +78,7 @@ public class PutTopCardOfYourLibraryToGraveyardCost extends CostImpl { @Override public boolean canPay(Ability ability, UUID sourceId, UUID controllerId, Game game) { Player player = game.getPlayer(controllerId); - if (player != null && player.getLibrary().size() >= numberOfCards) { - return true; - } - return false; + return player != null && player.getLibrary().size() >= numberOfCards; } @Override diff --git a/Mage/src/mage/abilities/keyword/RetraceAbility.java b/Mage/src/mage/abilities/keyword/RetraceAbility.java index 22a1fe7f538..4c26c31b6cd 100644 --- a/Mage/src/mage/abilities/keyword/RetraceAbility.java +++ b/Mage/src/mage/abilities/keyword/RetraceAbility.java @@ -27,32 +27,31 @@ */ package mage.abilities.keyword; -import mage.abilities.Ability; -import mage.abilities.ActivatedAbilityImpl; -import mage.abilities.costs.Cost; +import mage.abilities.SpellAbility; import mage.abilities.costs.common.DiscardTargetCost; -import mage.abilities.effects.OneShotEffect; import mage.cards.Card; -import mage.constants.Outcome; -import mage.constants.TimingRule; +import mage.constants.SpellAbilityType; import mage.constants.Zone; import mage.filter.common.FilterLandCard; -import mage.game.Game; -import mage.players.Player; import mage.target.common.TargetCardInHand; - /** * - * @author Plopman + * @author LevelX2 */ -public class RetraceAbility extends ActivatedAbilityImpl { - public RetraceAbility(Cost cost, TimingRule timingRule) { - super(Zone.GRAVEYARD, new RetraceEffect(), cost); - super.addCost(new DiscardTargetCost(new TargetCardInHand(new FilterLandCard()))); - this.timing = timingRule; - this.usesStack = false; +public class RetraceAbility extends SpellAbility { + + public RetraceAbility(Card card) { + super(card.getManaCost(), card.getName() + " with retrace", Zone.GRAVEYARD, SpellAbilityType.BASE_ALTERNATE); + this.getCosts().addAll(card.getSpellAbility().getCosts().copy()); + this.addCost(new DiscardTargetCost(new TargetCardInHand(new FilterLandCard()))); + this.getEffects().addAll(card.getSpellAbility().getEffects().copy()); + this.getTargets().addAll(card.getSpellAbility().getTargets().copy()); + this.getChoices().addAll(card.getSpellAbility().getChoices().copy()); + this.spellAbilityType = SpellAbilityType.BASE_ALTERNATE; + this.timing = card.getSpellAbility().getTiming(); + } public RetraceAbility(final RetraceAbility ability) { @@ -64,41 +63,13 @@ public class RetraceAbility extends ActivatedAbilityImpl { return new RetraceAbility(this); } + @Override + public String getRule(boolean all) { + return getRule(); + } + @Override public String getRule() { return "Retrace (You may cast this card from your graveyard by discarding a land card in addition to paying its other costs.)"; } } - -class RetraceEffect extends OneShotEffect { - - public RetraceEffect() { - super(Outcome.Benefit); - staticText = ""; - } - - public RetraceEffect(final RetraceEffect effect) { - super(effect); - } - - @Override - public RetraceEffect copy() { - return new RetraceEffect(this); - } - - @Override - public boolean apply(Game game, Ability source) { - Card card = (Card) game.getObject(source.getSourceId()); - if (card != null) { - Player controller = game.getPlayer(source.getControllerId()); - if (controller != null) { - card.getSpellAbility().clear(); - int amount = source.getManaCostsToPay().getX(); - card.getSpellAbility().getManaCostsToPay().setX(amount); - return controller.cast(card.getSpellAbility(), game, true); - } - } - return false; - } -} - diff --git a/Mage/src/mage/abilities/mana/ManaAbility.java b/Mage/src/mage/abilities/mana/ManaAbility.java index 15affee8efb..7155dd8ea5d 100644 --- a/Mage/src/mage/abilities/mana/ManaAbility.java +++ b/Mage/src/mage/abilities/mana/ManaAbility.java @@ -46,10 +46,12 @@ import mage.game.Game; public abstract class ManaAbility extends ActivatedAbilityImpl { protected List netMana = new ArrayList<>(); - + protected boolean undoPossible; + public ManaAbility(Zone zone, ManaEffect effect, Cost cost) { super(AbilityType.MANA, zone); this.usesStack = false; + this.undoPossible = true; if (effect != null) { this.addEffect(effect); } @@ -92,4 +94,13 @@ public abstract class ManaAbility extends ActivatedAbilityImpl { public boolean definesMana() { return netMana.size() > 0; } + + public boolean isUndoPossible() { + return undoPossible; + } + + public void setUndoPossible(boolean undoPossible) { + this.undoPossible = undoPossible; + } + } diff --git a/Mage/src/mage/filter/FilterCard.java b/Mage/src/mage/filter/FilterCard.java index 3d58f08202d..97cb529a055 100644 --- a/Mage/src/mage/filter/FilterCard.java +++ b/Mage/src/mage/filter/FilterCard.java @@ -95,7 +95,6 @@ public class FilterCard extends FilterObject { if (!this.match(card, game)) { return false; } - return Predicates.and(extraPredicates).apply(new ObjectSourcePlayer(card, sourceId, playerId), game); } diff --git a/Mage/src/mage/players/PlayerImpl.java b/Mage/src/mage/players/PlayerImpl.java index 8b883257598..2d344cc591d 100644 --- a/Mage/src/mage/players/PlayerImpl.java +++ b/Mage/src/mage/players/PlayerImpl.java @@ -1016,7 +1016,7 @@ public abstract class PlayerImpl implements Player, Serializable { int bookmark = game.bookmarkState(); if (ability.activate(game, false)) { if (ability.resolve(game)) { - if (storedBookmark == -1 || storedBookmark > bookmark) { // e.g. usefull for undo Nykthos, Shrine to Nyx + if (ability.isUndoPossible() && storedBookmark == -1 || storedBookmark > bookmark) { // e.g. usefull for undo Nykthos, Shrine to Nyx setStoredBookmark(bookmark); } return true; diff --git a/Mage/src/mage/target/common/TargetCardInOpponentsGraveyard.java b/Mage/src/mage/target/common/TargetCardInOpponentsGraveyard.java index faa1ab2d90c..202572c0b54 100644 --- a/Mage/src/mage/target/common/TargetCardInOpponentsGraveyard.java +++ b/Mage/src/mage/target/common/TargetCardInOpponentsGraveyard.java @@ -8,6 +8,8 @@ import mage.game.Game; import mage.target.TargetCard; import java.util.UUID; +import mage.game.events.GameEvent; +import mage.players.Player; public class TargetCardInOpponentsGraveyard extends TargetCard { @@ -52,9 +54,37 @@ public class TargetCardInOpponentsGraveyard extends TargetCard { @Override public boolean canChoose(UUID sourceControllerId, Game game) { - return true; + return canChoose(null, sourceControllerId, game); + } + + /** + * Checks if there are enough {@link Card} that can be chosen. + * + * @param sourceId - the target event source + * @param sourceControllerId - controller of the target event source + * @param game + * @return - true if enough valid {@link Card} exist + */ + @Override + public boolean canChoose(UUID sourceId, UUID sourceControllerId, Game game) { + int possibleTargets = 0; + for (UUID playerId: game.getPlayer(sourceControllerId).getInRange()) { + if (!playerId.equals(sourceControllerId)) { + Player player = game.getPlayer(playerId); + if (player != null) { + for (Card card : player.getGraveyard().getCards(filter, sourceId, sourceControllerId, game)) { + if (sourceId == null || isNotTarget() || !game.replaceEvent(GameEvent.getEvent(GameEvent.EventType.TARGET, card.getId(), sourceId, sourceControllerId))) { + possibleTargets++; + if (possibleTargets >= this.minNumberOfTargets) { + return true; + } + } + } + } + } + } + return false; } - @Override public TargetCardInOpponentsGraveyard copy() { return new TargetCardInOpponentsGraveyard(this);