diff --git a/Mage.Client/src/main/java/mage/client/dialog/PreferencesDialog.java b/Mage.Client/src/main/java/mage/client/dialog/PreferencesDialog.java index 14219e5e2e..abe9cea1d3 100644 --- a/Mage.Client/src/main/java/mage/client/dialog/PreferencesDialog.java +++ b/Mage.Client/src/main/java/mage/client/dialog/PreferencesDialog.java @@ -3052,7 +3052,7 @@ public class PreferencesDialog extends javax.swing.JDialog { } public static boolean isSaveImagesToZip() { - return PreferencesDialog.getCachedValue(PreferencesDialog.KEY_CARD_IMAGES_SAVE_TO_ZIP, "false").equals("true"); + return PreferencesDialog.getCachedValue(PreferencesDialog.KEY_CARD_IMAGES_SAVE_TO_ZIP, "true").equals("true"); } private static void load(Preferences prefs, JCheckBox checkBox, String propName, String yesValue) { diff --git a/Mage.Common/src/mage/utils/MageVersion.java b/Mage.Common/src/mage/utils/MageVersion.java index 41fed76607..6dfaaf8828 100644 --- a/Mage.Common/src/mage/utils/MageVersion.java +++ b/Mage.Common/src/mage/utils/MageVersion.java @@ -41,7 +41,7 @@ public class MageVersion implements Serializable, Comparable { public final static int MAGE_VERSION_MAJOR = 1; public final static int MAGE_VERSION_MINOR = 4; public final static int MAGE_VERSION_PATCH = 9; - public final static String MAGE_VERSION_MINOR_PATCH = "v1"; + public final static String MAGE_VERSION_MINOR_PATCH = "v2"; public final static String MAGE_VERSION_INFO = ""; private final int major; diff --git a/Mage.Server.Plugins/Mage.Tournament.BoosterDraft/src/mage/tournament/cubes/AdamStyborskisPauperCube.java b/Mage.Server.Plugins/Mage.Tournament.BoosterDraft/src/mage/tournament/cubes/AdamStyborskisPauperCube.java index de91373ba2..cfb3f5e3d4 100644 --- a/Mage.Server.Plugins/Mage.Tournament.BoosterDraft/src/mage/tournament/cubes/AdamStyborskisPauperCube.java +++ b/Mage.Server.Plugins/Mage.Tournament.BoosterDraft/src/mage/tournament/cubes/AdamStyborskisPauperCube.java @@ -82,6 +82,7 @@ public AdamStyborskisPauperCube() { cubeCards.add(new CardIdentity("Boros Guildgate", "")); cubeCards.add(new CardIdentity("Branching Bolt", "")); cubeCards.add(new CardIdentity("Brute Force", "")); + cubeCards.add(new CardIdentity("Brute Strength", "")); cubeCards.add(new CardIdentity("Burst Lightning", "")); cubeCards.add(new CardIdentity("Butcher Ghoul", "")); cubeCards.add(new CardIdentity("Cadaver Imp", "")); @@ -89,7 +90,6 @@ public AdamStyborskisPauperCube() { cubeCards.add(new CardIdentity("Calcite Snapper", "")); cubeCards.add(new CardIdentity("Capsize", "")); cubeCards.add(new CardIdentity("Carnivorous Death-Parrot", "")); - cubeCards.add(new CardIdentity("Carnophage", "")); cubeCards.add(new CardIdentity("Cathodion", "")); cubeCards.add(new CardIdentity("Cavern Harpy", "")); cubeCards.add(new CardIdentity("Centaur Healer", "")); @@ -106,8 +106,10 @@ public AdamStyborskisPauperCube() { cubeCards.add(new CardIdentity("Coalition Honor Guard", "")); cubeCards.add(new CardIdentity("Cogwork Librarian", "")); cubeCards.add(new CardIdentity("Colossal Might", "")); + cubeCards.add(new CardIdentity("Comparative Analysis", "")); cubeCards.add(new CardIdentity("Compulsive Research", "")); cubeCards.add(new CardIdentity("Consume Strength", "")); + cubeCards.add(new CardIdentity("Corpse Churn", "")); cubeCards.add(new CardIdentity("Corrupted Zendikon", "")); cubeCards.add(new CardIdentity("Counterspell", "")); cubeCards.add(new CardIdentity("Crippling Fatigue", "")); @@ -144,7 +146,6 @@ public AdamStyborskisPauperCube() { cubeCards.add(new CardIdentity("Eldrazi Skyspawner", "")); cubeCards.add(new CardIdentity("Elephant Ambush", "")); cubeCards.add(new CardIdentity("Elephant Guide", "")); - cubeCards.add(new CardIdentity("Enhanced Awareness", "")); cubeCards.add(new CardIdentity("Epic Confrontation", "")); cubeCards.add(new CardIdentity("Errant Ephemeron", "")); cubeCards.add(new CardIdentity("Esper Cormorants", "")); @@ -152,15 +153,12 @@ public AdamStyborskisPauperCube() { cubeCards.add(new CardIdentity("Evincar's Justice", "")); cubeCards.add(new CardIdentity("Evolution Charm", "")); cubeCards.add(new CardIdentity("Evolving Wilds", "")); - cubeCards.add(new CardIdentity("Eye of Nowhere", "")); cubeCards.add(new CardIdentity("Faceless Butcher", "")); cubeCards.add(new CardIdentity("Faith's Fetters", "")); cubeCards.add(new CardIdentity("Fall of the Hammer", "")); - cubeCards.add(new CardIdentity("Feat of Resistance", "")); cubeCards.add(new CardIdentity("Feeling of Dread", "")); cubeCards.add(new CardIdentity("Fellwar Stone", "")); cubeCards.add(new CardIdentity("Fervent Cathar", "")); - cubeCards.add(new CardIdentity("Fireblast", "")); cubeCards.add(new CardIdentity("Firebolt", "")); cubeCards.add(new CardIdentity("Firefiend Elemental", "")); cubeCards.add(new CardIdentity("Fireslinger", "")); @@ -181,6 +179,7 @@ public AdamStyborskisPauperCube() { cubeCards.add(new CardIdentity("Giant Growth", "")); cubeCards.add(new CardIdentity("Gideon's Lawkeeper", "")); cubeCards.add(new CardIdentity("Gideon's Reproach", "")); + cubeCards.add(new CardIdentity("Goblin Freerunner", "")); cubeCards.add(new CardIdentity("Goblin Heelcutter", "")); cubeCards.add(new CardIdentity("Gods Willing", "")); cubeCards.add(new CardIdentity("Goldmeadow Harrier", "")); @@ -207,18 +206,20 @@ public AdamStyborskisPauperCube() { cubeCards.add(new CardIdentity("Incinerate", "")); cubeCards.add(new CardIdentity("Inner-Flame Acolyte", "")); cubeCards.add(new CardIdentity("Into the Roil", "")); + cubeCards.add(new CardIdentity("Isolation Zone", "")); cubeCards.add(new CardIdentity("Izzet Chronarch", "")); cubeCards.add(new CardIdentity("Izzet Guildgate", "")); cubeCards.add(new CardIdentity("Jilt", "")); cubeCards.add(new CardIdentity("Journey to Nowhere", "")); cubeCards.add(new CardIdentity("Jungle Hollow", "")); + cubeCards.add(new CardIdentity("Jwar Isle Avenger", "")); cubeCards.add(new CardIdentity("Kabuto Moth", "")); cubeCards.add(new CardIdentity("Keldon Marauders", "")); cubeCards.add(new CardIdentity("Khalni Garden", "")); cubeCards.add(new CardIdentity("Kingpin's Pet", "")); cubeCards.add(new CardIdentity("Kodama's Reach", "")); cubeCards.add(new CardIdentity("Kor Skyfisher", "")); - cubeCards.add(new CardIdentity("Kozilek's Predator", "")); + cubeCards.add(new CardIdentity("Kozilek's Channeler", "")); cubeCards.add(new CardIdentity("Krenko's Command", "")); cubeCards.add(new CardIdentity("Krosan Tusker", "")); cubeCards.add(new CardIdentity("Kruin Striker", "")); @@ -236,7 +237,6 @@ public AdamStyborskisPauperCube() { cubeCards.add(new CardIdentity("Loyal Pegasus", "")); cubeCards.add(new CardIdentity("Lurking Automaton", "")); cubeCards.add(new CardIdentity("Makeshift Mauler", "")); - cubeCards.add(new CardIdentity("Makindi Sliderunner", "")); cubeCards.add(new CardIdentity("Mana Leak", "")); cubeCards.add(new CardIdentity("Man-o'-War", "")); cubeCards.add(new CardIdentity("Mardu Hordechief", "")); @@ -247,6 +247,7 @@ public AdamStyborskisPauperCube() { cubeCards.add(new CardIdentity("Maze of Ith", "")); cubeCards.add(new CardIdentity("Mind Stone", "")); cubeCards.add(new CardIdentity("Minotaur Skullcleaver", "")); + cubeCards.add(new CardIdentity("Mire's Malice", "")); cubeCards.add(new CardIdentity("Miscalculation", "")); cubeCards.add(new CardIdentity("Mishra's Factory", "")); cubeCards.add(new CardIdentity("Mist Raven", "")); @@ -269,7 +270,6 @@ public AdamStyborskisPauperCube() { cubeCards.add(new CardIdentity("Ninja of the Deep Hours", "")); cubeCards.add(new CardIdentity("Oblivion Ring", "")); cubeCards.add(new CardIdentity("Okiba-Gang Shinobi", "")); - cubeCards.add(new CardIdentity("Omenspeaker", "")); cubeCards.add(new CardIdentity("Orzhov Guildgate", "")); cubeCards.add(new CardIdentity("Otherworldly Journey", "")); cubeCards.add(new CardIdentity("Pacifism", "")); @@ -297,6 +297,7 @@ public AdamStyborskisPauperCube() { cubeCards.add(new CardIdentity("Pristine Talisman", "")); cubeCards.add(new CardIdentity("Probe", "")); cubeCards.add(new CardIdentity("Prophetic Prism", "")); + cubeCards.add(new CardIdentity("Pulse of Murasa", "")); cubeCards.add(new CardIdentity("Putrid Leech", "")); cubeCards.add(new CardIdentity("Pyrotechnics", "")); cubeCards.add(new CardIdentity("Qasali Pridemage", "")); @@ -309,7 +310,6 @@ public AdamStyborskisPauperCube() { cubeCards.add(new CardIdentity("Ray of Command", "")); cubeCards.add(new CardIdentity("Razorfin Hunter", "")); cubeCards.add(new CardIdentity("Reckless Charge", "")); - cubeCards.add(new CardIdentity("Reclaim", "")); cubeCards.add(new CardIdentity("Recoil", "")); cubeCards.add(new CardIdentity("Remove Soul", "")); cubeCards.add(new CardIdentity("Rend Flesh", "")); @@ -320,6 +320,7 @@ public AdamStyborskisPauperCube() { cubeCards.add(new CardIdentity("Rugged Highlands", "")); cubeCards.add(new CardIdentity("Runed Servitor", "")); cubeCards.add(new CardIdentity("Rushing River", "")); + cubeCards.add(new CardIdentity("Saddleback Lagac", "")); cubeCards.add(new CardIdentity("Safehold Elite", "")); cubeCards.add(new CardIdentity("Sakura-Tribe Elder", "")); cubeCards.add(new CardIdentity("Sandsteppe Outcast", "")); @@ -329,6 +330,7 @@ public AdamStyborskisPauperCube() { cubeCards.add(new CardIdentity("Savage Surge", "")); cubeCards.add(new CardIdentity("Scatter the Seeds", "")); cubeCards.add(new CardIdentity("Scion of the Wild", "")); + cubeCards.add(new CardIdentity("Scion Summoner", "")); cubeCards.add(new CardIdentity("Scoured Barrens", "")); cubeCards.add(new CardIdentity("Scuzzback Marauders", "")); cubeCards.add(new CardIdentity("Searing Blaze", "")); @@ -350,19 +352,16 @@ public AdamStyborskisPauperCube() { cubeCards.add(new CardIdentity("Skinthinner", "")); cubeCards.add(new CardIdentity("Skirk Marauder", "")); cubeCards.add(new CardIdentity("Skyknight Legionnaire", "")); - cubeCards.add(new CardIdentity("Skywinder Drake", "")); cubeCards.add(new CardIdentity("Slash Panther", "")); cubeCards.add(new CardIdentity("Slippery Bogle", "")); cubeCards.add(new CardIdentity("Snakeform", "")); cubeCards.add(new CardIdentity("Snap", "")); cubeCards.add(new CardIdentity("Snuff Out", "")); cubeCards.add(new CardIdentity("Soul Manipulation", "")); - cubeCards.add(new CardIdentity("Sparksmith", "")); cubeCards.add(new CardIdentity("Sphere of the Suns", "")); cubeCards.add(new CardIdentity("Spined Thopter", "")); cubeCards.add(new CardIdentity("Splatter Thug", "")); cubeCards.add(new CardIdentity("Staggershock", "")); - cubeCards.add(new CardIdentity("Stampeding Elk Herd", "")); cubeCards.add(new CardIdentity("Stave Off", "")); cubeCards.add(new CardIdentity("Stitched Drake", "")); cubeCards.add(new CardIdentity("Stormfront Pegasus", "")); @@ -373,9 +372,11 @@ public AdamStyborskisPauperCube() { cubeCards.add(new CardIdentity("Sultai Scavenger", "")); cubeCards.add(new CardIdentity("Suppression Bonds", "")); cubeCards.add(new CardIdentity("Suq'Ata Lancer", "")); + cubeCards.add(new CardIdentity("Sweep Away", "")); cubeCards.add(new CardIdentity("Swiftwater Cliffs", "")); cubeCards.add(new CardIdentity("Sylvok Lifestaff", "")); cubeCards.add(new CardIdentity("Tail Slash", "")); + cubeCards.add(new CardIdentity("Tajuru Pathwarden", "")); cubeCards.add(new CardIdentity("Teetering Peaks", "")); cubeCards.add(new CardIdentity("Temporal Isolation", "")); cubeCards.add(new CardIdentity("Tenement Crasher", "")); @@ -399,15 +400,14 @@ public AdamStyborskisPauperCube() { cubeCards.add(new CardIdentity("Twin Bolt", "")); cubeCards.add(new CardIdentity("Typhoid Rats", "")); cubeCards.add(new CardIdentity("Ulamog's Crusher", "")); + cubeCards.add(new CardIdentity("Umara Entangler", "")); cubeCards.add(new CardIdentity("Undying Evil", "")); cubeCards.add(new CardIdentity("Unearth", "")); cubeCards.add(new CardIdentity("Unmake", "")); cubeCards.add(new CardIdentity("Unnatural Aggression", "")); + cubeCards.add(new CardIdentity("Vampire Envoy", "")); cubeCards.add(new CardIdentity("Vampire Interloper", "")); - cubeCards.add(new CardIdentity("Vampire Lacerator", "")); cubeCards.add(new CardIdentity("Vault Skirge", "")); - cubeCards.add(new CardIdentity("Vendetta", "")); - cubeCards.add(new CardIdentity("Veteran's Sidearm", "")); cubeCards.add(new CardIdentity("Viashino Firstblade", "")); cubeCards.add(new CardIdentity("Vines of Vastwood", "")); cubeCards.add(new CardIdentity("Voidwielder", "")); @@ -436,8 +436,8 @@ public AdamStyborskisPauperCube() { cubeCards.add(new CardIdentity("Wrecking Ball", "")); cubeCards.add(new CardIdentity("Yavimaya Elder", "")); cubeCards.add(new CardIdentity("Yotian Soldier", "")); - cubeCards.add(new CardIdentity("Young Wolf", "")); cubeCards.add(new CardIdentity("Youthful Knight", "")); + cubeCards.add(new CardIdentity("Zada's Commando", "")); cubeCards.add(new CardIdentity("Zhur-Taa Swine", "")); } } diff --git a/Mage.Sets/src/mage/sets/antiquities/GateToPhyrexia.java b/Mage.Sets/src/mage/sets/antiquities/GateToPhyrexia.java index 4d902ed4b3..889fdb890f 100644 --- a/Mage.Sets/src/mage/sets/antiquities/GateToPhyrexia.java +++ b/Mage.Sets/src/mage/sets/antiquities/GateToPhyrexia.java @@ -30,16 +30,15 @@ package mage.sets.antiquities; import java.util.UUID; import mage.abilities.Ability; import mage.abilities.common.LimitedTimesPerTurnActivatedAbility; -import mage.abilities.costs.Cost; +import mage.abilities.condition.common.IsStepCondition; import mage.abilities.costs.common.SacrificeTargetCost; -import mage.abilities.effects.Effect; import mage.abilities.effects.common.DestroyTargetEffect; import mage.cards.CardImpl; import mage.constants.CardType; import mage.constants.PhaseStep; import mage.constants.Rarity; import mage.constants.Zone; -import mage.game.Game; +import mage.filter.common.FilterControlledCreaturePermanent; import mage.target.common.TargetArtifactPermanent; import mage.target.common.TargetControlledCreaturePermanent; @@ -54,7 +53,9 @@ public class GateToPhyrexia extends CardImpl { this.expansionSetCode = "ATQ"; // Sacrifice a creature: Destroy target artifact. Activate this ability only during your upkeep and only once each turn. - Ability ability = new GateToPhyrexiaAbility(new DestroyTargetEffect(), new SacrificeTargetCost(new TargetControlledCreaturePermanent())); + Ability ability = new LimitedTimesPerTurnActivatedAbility(Zone.BATTLEFIELD, new DestroyTargetEffect(), + new SacrificeTargetCost(new TargetControlledCreaturePermanent(new FilterControlledCreaturePermanent("a creature"))), + 1, new IsStepCondition(PhaseStep.UPKEEP, true)); ability.addTarget(new TargetArtifactPermanent()); this.addAbility(ability); } @@ -68,32 +69,3 @@ public class GateToPhyrexia extends CardImpl { return new GateToPhyrexia(this); } } - -class GateToPhyrexiaAbility extends LimitedTimesPerTurnActivatedAbility { - - public GateToPhyrexiaAbility(Effect effect, Cost cost) { - super(Zone.BATTLEFIELD, effect, cost); - } - - public GateToPhyrexiaAbility(final GateToPhyrexiaAbility ability) { - super(ability); - } - - @Override - public GateToPhyrexiaAbility copy() { - return new GateToPhyrexiaAbility(this); - } - - @Override - public boolean canActivate(UUID playerId, Game game) { - if (!game.getActivePlayerId().equals(controllerId) || !PhaseStep.UPKEEP.equals(game.getStep().getType())) { - return false; - } - return super.canActivate(playerId, game); - } - - @Override - public String getRule() { - return "Sacrifice a creature: Destroy target artifact. Activate this ability only during your upkeep and only once each turn."; - } -} diff --git a/Mage.Sets/src/mage/sets/championsofkamigawa/BrutalDeceiver.java b/Mage.Sets/src/mage/sets/championsofkamigawa/BrutalDeceiver.java index 831aefa388..b767e0d80b 100644 --- a/Mage.Sets/src/mage/sets/championsofkamigawa/BrutalDeceiver.java +++ b/Mage.Sets/src/mage/sets/championsofkamigawa/BrutalDeceiver.java @@ -28,17 +28,12 @@ package mage.sets.championsofkamigawa; import java.util.UUID; - -import mage.constants.CardType; -import mage.constants.Duration; -import mage.constants.Rarity; -import mage.constants.Zone; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.LimitedTimesPerTurnActivatedAbility; -import mage.abilities.costs.mana.GenericManaCost; import mage.abilities.common.SimpleActivatedAbility; import mage.abilities.costs.Cost; +import mage.abilities.costs.mana.GenericManaCost; import mage.abilities.costs.mana.ManaCostsImpl; import mage.abilities.effects.Effect; import mage.abilities.effects.common.LookLibraryControllerEffect; @@ -49,6 +44,10 @@ import mage.cards.Card; import mage.cards.CardImpl; import mage.cards.Cards; import mage.cards.CardsImpl; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.Rarity; +import mage.constants.Zone; import mage.game.Game; import mage.players.Player; @@ -67,11 +66,11 @@ public class BrutalDeceiver extends CardImpl { this.toughness = new MageInt(2); // {1}: Look at the top card of your library. - this.addAbility(new SimpleActivatedAbility(Zone.BATTLEFIELD, new LookLibraryControllerEffect(), new GenericManaCost(1))); + this.addAbility(new SimpleActivatedAbility(Zone.BATTLEFIELD, new LookLibraryControllerEffect(), new GenericManaCost(1))); // {2}: Reveal the top card of your library. If it's a land card, {this} gets +1/+0 and gains first strike until end of turn. - Ability ability = new BrutalDeceiverAbility(Zone.BATTLEFIELD, new BoostSourceEffect(1,0,Duration.EndOfTurn), new ManaCostsImpl("{2}")); - ability.addEffect(new GainAbilitySourceEffect(FirstStrikeAbility.getInstance(),Duration.EndOfTurn)); + Ability ability = new BrutalDeceiverAbility(Zone.BATTLEFIELD, new BoostSourceEffect(1, 0, Duration.EndOfTurn), new ManaCostsImpl("{2}")); + ability.addEffect(new GainAbilitySourceEffect(FirstStrikeAbility.getInstance(), Duration.EndOfTurn)); this.addAbility(ability); } @@ -87,36 +86,36 @@ public class BrutalDeceiver extends CardImpl { class BrutalDeceiverAbility extends LimitedTimesPerTurnActivatedAbility { - public BrutalDeceiverAbility(Zone zone, Effect effect, Cost cost) { + public BrutalDeceiverAbility(Zone zone, Effect effect, Cost cost) { super(zone, effect, cost); } - public BrutalDeceiverAbility(BrutalDeceiverAbility ability) { + public BrutalDeceiverAbility(BrutalDeceiverAbility ability) { super(ability); } - @Override - public BrutalDeceiverAbility copy() { - return new BrutalDeceiverAbility(this); - } + @Override + public BrutalDeceiverAbility copy() { + return new BrutalDeceiverAbility(this); + } - @Override + @Override public boolean checkIfClause(Game game) { - Player player = game.getPlayer(this.getControllerId()); - if (player != null) { - Cards cards = new CardsImpl(); - Card card = player.getLibrary().getFromTop(game); - cards.add(card); - player.revealCards("Brutal Deceiver", cards, game); - if (card != null && card.getCardType().contains(CardType.LAND)) { - return true; - } - } - return false; + Player player = game.getPlayer(this.getControllerId()); + if (player != null) { + Cards cards = new CardsImpl(); + Card card = player.getLibrary().getFromTop(game); + cards.add(card); + player.revealCards("Brutal Deceiver", cards, game); + if (card != null && card.getCardType().contains(CardType.LAND)) { + return true; + } } + return false; + } - @Override + @Override public String getRule() { - return "{2}: Reveal the top card of your library. If it's a land card, {this} gets +1/+0 and gains first strike until end of turn. Activate this ability only once each turn."; + return "{2}: Reveal the top card of your library. If it's a land card, {this} gets +1/+0 and gains first strike until end of turn. Activate this ability only once each turn."; } } diff --git a/Mage.Sets/src/mage/sets/fifthedition/InstillEnergy.java b/Mage.Sets/src/mage/sets/fifthedition/InstillEnergy.java index 9c0b869103..835cee02a7 100644 --- a/Mage.Sets/src/mage/sets/fifthedition/InstillEnergy.java +++ b/Mage.Sets/src/mage/sets/fifthedition/InstillEnergy.java @@ -29,14 +29,11 @@ package mage.sets.fifthedition; import java.util.UUID; import mage.abilities.Ability; -import mage.abilities.common.ActivateIfConditionActivatedAbility; +import mage.abilities.common.LimitedTimesPerTurnActivatedAbility; import mage.abilities.common.SimpleStaticAbility; -import mage.abilities.condition.Condition; import mage.abilities.condition.common.MyTurnCondition; -import mage.abilities.costs.Cost; import mage.abilities.costs.mana.GenericManaCost; import mage.abilities.effects.AsThoughEffectImpl; -import mage.abilities.effects.Effect; import mage.abilities.effects.common.AttachEffect; import mage.abilities.effects.common.UntapEnchantedEffect; import mage.abilities.effects.common.continuous.GainAbilityAttachedEffect; @@ -53,7 +50,6 @@ import mage.game.Game; import mage.game.permanent.Permanent; import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; -import mage.util.CardUtil; /** * @@ -77,8 +73,7 @@ public class InstillEnergy extends CardImpl { Ability haste = new SimpleStaticAbility(Zone.BATTLEFIELD, new GainAbilityAttachedEffect(asThough, AttachmentType.AURA, Duration.WhileOnBattlefield, "Enchanted creature can attack as though it had haste.")); this.addAbility(haste); // {0}: Untap enchanted creature. Activate this ability only during your turn and only once each turn. - Ability gainedAbility = new LimitedTimesIfConditionActivatedAbility(Zone.BATTLEFIELD, new UntapEnchantedEffect(), new GenericManaCost(0), MyTurnCondition.getInstance(), 1); - this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new GainAbilityAttachedEffect(gainedAbility, AttachmentType.AURA, Duration.WhileOnBattlefield, "{0}: Untap enchanted creature. Activate this ability only during your turn and only once each turn."))); + this.addAbility(new LimitedTimesPerTurnActivatedAbility(Zone.BATTLEFIELD, new UntapEnchantedEffect(), new GenericManaCost(0), 1, MyTurnCondition.getInstance())); } public InstillEnergy(final InstillEnergy card) { @@ -118,104 +113,3 @@ class CanAttackAsThoughItHadHasteEnchantedEffect extends AsThoughEffectImpl { return enchantment != null && enchantment.getAttachedTo() != null && enchantment.getAttachedTo().equals(objectId); } } - -class LimitedTimesIfConditionActivatedAbility extends ActivateIfConditionActivatedAbility { - - class ActivationInfo { - - public int turnNum; - public int activationCounter; - - public ActivationInfo(int turnNum, int activationCounter) { - this.turnNum = turnNum; - this.activationCounter = activationCounter; - } - } - - private int maxActivationsPerTurn; - - public LimitedTimesIfConditionActivatedAbility(Zone zone, Effect effect, Cost cost, Condition condition) { - this(zone, effect, cost, condition, 1); - } - - public LimitedTimesIfConditionActivatedAbility(Zone zone, Effect effect, Cost cost, Condition condition, int maxActivationsPerTurn) { - super(zone, effect, cost, condition); - this.maxActivationsPerTurn = maxActivationsPerTurn; - } - - public LimitedTimesIfConditionActivatedAbility(LimitedTimesIfConditionActivatedAbility ability) { - super(ability); - this.maxActivationsPerTurn = ability.maxActivationsPerTurn; - } - - @Override - public boolean canActivate(UUID playerId, Game game) { - if (super.canActivate(playerId, game)) { - ActivationInfo activationInfo = getActivationInfo(game); - return activationInfo == null || activationInfo.turnNum != game.getTurnNum() || activationInfo.activationCounter < maxActivationsPerTurn; - } - return false; - } - - @Override - public boolean activate(Game game, boolean noMana) { - if (canActivate(this.controllerId, game)) { - if (super.activate(game, noMana)) { - ActivationInfo activationInfo = getActivationInfo(game); - if (activationInfo == null) { - activationInfo = new ActivationInfo(game.getTurnNum(), 1); - } else if (activationInfo.turnNum != game.getTurnNum()) { - activationInfo.turnNum = game.getTurnNum(); - activationInfo.activationCounter = 1; - } else { - activationInfo.activationCounter++; - } - setActivationInfo(activationInfo, game); - return true; - } - } - return false; - } - - @Override - public boolean resolve(Game game) { - return super.resolve(game); - } - - @Override - public String getRule() { - StringBuilder sb = new StringBuilder(super.getRule()); - sb.replace(sb.length() - 1, sb.length() - 1, " and "); //suppress super()'s final period - switch (maxActivationsPerTurn) { - case 1: - sb.append("only once"); - break; - case 2: - sb.append("no more than twice"); - break; - default: - sb.append("no more than ").append(CardUtil.numberToText(maxActivationsPerTurn)).append(" times"); - } - sb.append(" each turn."); - return sb.toString(); - } - - @Override - public LimitedTimesIfConditionActivatedAbility copy() { - return new LimitedTimesIfConditionActivatedAbility(this); - } - - private ActivationInfo getActivationInfo(Game game) { - Integer turnNum = (Integer) game.getState().getValue(CardUtil.getCardZoneString("activationsTurn", sourceId, game)); - Integer activationCount = (Integer) game.getState().getValue(CardUtil.getCardZoneString("activationsCount", sourceId, game)); - if (turnNum == null || activationCount == null) { - return null; - } - return new ActivationInfo(turnNum, activationCount); - } - - private void setActivationInfo(ActivationInfo activationInfo, Game game) { - game.getState().setValue(CardUtil.getCardZoneString("activationsTurn", sourceId, game), activationInfo.turnNum); - game.getState().setValue(CardUtil.getCardZoneString("activationsCount", sourceId, game), activationInfo.activationCounter); - } -} diff --git a/Mage.Sets/src/mage/sets/innistrad/ManorGargoyle.java b/Mage.Sets/src/mage/sets/innistrad/ManorGargoyle.java index 0d96736fe0..2290650796 100644 --- a/Mage.Sets/src/mage/sets/innistrad/ManorGargoyle.java +++ b/Mage.Sets/src/mage/sets/innistrad/ManorGargoyle.java @@ -28,10 +28,6 @@ package mage.sets.innistrad; import java.util.UUID; -import mage.constants.CardType; -import mage.constants.Duration; -import mage.constants.Rarity; -import mage.constants.Zone; import mage.MageInt; import mage.abilities.Abilities; import mage.abilities.Ability; @@ -40,13 +36,18 @@ import mage.abilities.common.SimpleStaticAbility; import mage.abilities.condition.Condition; import mage.abilities.costs.mana.ManaCostsImpl; import mage.abilities.decorator.ConditionalContinuousEffect; -import mage.abilities.effects.Effect; +import mage.abilities.effects.ContinuousEffect; import mage.abilities.effects.common.continuous.GainAbilitySourceEffect; import mage.abilities.effects.common.continuous.LoseAbilitySourceEffect; import mage.abilities.keyword.DefenderAbility; import mage.abilities.keyword.FlyingAbility; import mage.abilities.keyword.IndestructibleAbility; import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.DependencyType; +import mage.constants.Duration; +import mage.constants.Rarity; +import mage.constants.Zone; import mage.game.Game; import mage.game.permanent.Permanent; @@ -67,32 +68,33 @@ public class ManorGargoyle extends CardImpl { this.toughness = new MageInt(4); this.addAbility(DefenderAbility.getInstance()); - - - /* - TODO: Implement the dependency rule - 613.7. Within a layer or sublayer, determining which order effects are applied in is sometimes done using a dependency system. + + /* + 613.7. Within a layer or sublayer, determining which order effects are applied in is sometimes done using a dependency system. If a dependency exists, it will override the timestamp system. - 613.7a An effect is said to “depend on” another if - (a) it’s applied in the same layer (and, if applicable, sublayer) as the other effect (see rules 613.1 and 613.3); - (b) applying the other would change the text or the existence of the first effect, what it applies to, or what - it does to any of the things it applies to; and - (c) neither effect is from a characteristic-defining ability or both effects are from characteristic-defining + 613.7a An effect is said to “depend on” another if + (a) it’s applied in the same layer (and, if applicable, sublayer) as the other effect (see rules 613.1 and 613.3); + (b) applying the other would change the text or the existence of the first effect, what it applies to, or what + it does to any of the things it applies to; and + (c) neither effect is from a characteristic-defining ability or both effects are from characteristic-defining abilities. Otherwise, the effect is considered to be independent of the other effect. 613.7b An effect dependent on one or more other effects waits to apply until just after all of those effects have been applied. If multiple dependent effects would apply simultaneously in this way, they’re applied in timestamp order relative to each - other. If several dependent effects form a dependency loop, then this rule is ignored and the effects in the dependency + other. If several dependent effects form a dependency loop, then this rule is ignored and the effects in the dependency loop are applied in timestamp order. 613.7c After each effect is applied, the order of remaining effects is reevaluated and may change if an effect that has not yet been applied becomes dependent on or independent of one or more other effects that have not yet been applied. */ - // Manor Gargoyle has indestructible as long as it has defender. - ConditionalContinuousEffect effect = new ConditionalContinuousEffect(new GainAbilitySourceEffect(IndestructibleAbility.getInstance()), HasDefenderCondition.getInstance(), rule); + GainAbilitySourceEffect gainEffect = new GainAbilitySourceEffect(IndestructibleAbility.getInstance()); + gainEffect.setDependedToType(DependencyType.LooseDefenderEffect); + ConditionalContinuousEffect effect = new ConditionalContinuousEffect(gainEffect, HasDefenderCondition.getInstance(), rule); + this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, effect)); - + // {1}: Until end of turn, Manor Gargoyle loses defender and gains flying. - Effect effect2 = new LoseAbilitySourceEffect(DefenderAbility.getInstance(), Duration.EndOfTurn); + ContinuousEffect effect2 = new LoseAbilitySourceEffect(DefenderAbility.getInstance(), Duration.EndOfTurn); + effect2.addDependencyType(DependencyType.LooseDefenderEffect); effect2.setText("Until end of turn, {this} loses defender"); Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, effect2, new ManaCostsImpl("{1}")); effect2 = new GainAbilitySourceEffect(FlyingAbility.getInstance(), Duration.EndOfTurn); diff --git a/Mage.Sets/src/mage/sets/innistrad/UndeadAlchemist.java b/Mage.Sets/src/mage/sets/innistrad/UndeadAlchemist.java index 4e39289c8d..b537d0996c 100644 --- a/Mage.Sets/src/mage/sets/innistrad/UndeadAlchemist.java +++ b/Mage.Sets/src/mage/sets/innistrad/UndeadAlchemist.java @@ -85,7 +85,7 @@ public class UndeadAlchemist extends CardImpl { class UndeadAlchemistTriggeredAbility extends TriggeredAbilityImpl { public UndeadAlchemistTriggeredAbility() { - super(Zone.BATTLEFIELD, new ExileTargetEffect(), true); + super(Zone.BATTLEFIELD, new ExileTargetEffect(), false); this.addEffect(new CreateTokenEffect(new ZombieToken())); } diff --git a/Mage.Sets/src/mage/sets/masterseditionii/EbonPraetor.java b/Mage.Sets/src/mage/sets/masterseditionii/EbonPraetor.java index 9b7905996e..04ed4d15c0 100644 --- a/Mage.Sets/src/mage/sets/masterseditionii/EbonPraetor.java +++ b/Mage.Sets/src/mage/sets/masterseditionii/EbonPraetor.java @@ -32,9 +32,9 @@ import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.BeginningOfUpkeepTriggeredAbility; import mage.abilities.common.LimitedTimesPerTurnActivatedAbility; +import mage.abilities.condition.common.IsStepCondition; import mage.abilities.costs.Cost; import mage.abilities.costs.common.SacrificeTargetCost; -import mage.abilities.effects.Effect; import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.counter.AddCountersSourceEffect; import mage.abilities.effects.common.counter.RemoveCounterSourceEffect; @@ -48,6 +48,7 @@ import mage.constants.Rarity; import mage.constants.TargetController; import mage.constants.Zone; import mage.counters.CounterType; +import mage.filter.common.FilterControlledCreaturePermanent; import mage.game.Game; import mage.game.permanent.Permanent; import mage.target.common.TargetControlledCreaturePermanent; @@ -68,16 +69,16 @@ public class EbonPraetor extends CardImpl { // First strike this.addAbility(FirstStrikeAbility.getInstance()); - + // Trample this.addAbility(TrampleAbility.getInstance()); - + // At the beginning of your upkeep, put a -2/-2 counter on Ebon Praetor. this.addAbility(new BeginningOfUpkeepTriggeredAbility(new AddCountersSourceEffect(CounterType.M2M2.createInstance()), TargetController.YOU, false)); - + // Sacrifice a creature: Remove a -2/-2 counter from Ebon Praetor. If the sacrificed creature was a Thrull, put a +1/+0 counter on Ebon Praetor. Activate this ability only during your upkeep and only once each turn. - Ability ability = new EbonPraetorAbility(new RemoveCounterSourceEffect(CounterType.M2M2.createInstance()), - new SacrificeTargetCost(new TargetControlledCreaturePermanent())); + Ability ability = new LimitedTimesPerTurnActivatedAbility(Zone.BATTLEFIELD, new RemoveCounterSourceEffect(CounterType.M2M2.createInstance()), + new SacrificeTargetCost(new TargetControlledCreaturePermanent(new FilterControlledCreaturePermanent("a creature"))), 1, new IsStepCondition(PhaseStep.UPKEEP, true)); ability.addEffect(new EbonPraetorEffect()); this.addAbility(ability); } @@ -92,37 +93,6 @@ public class EbonPraetor extends CardImpl { } } -class EbonPraetorAbility extends LimitedTimesPerTurnActivatedAbility { - - public EbonPraetorAbility(Effect effect, Cost cost) { - super(Zone.BATTLEFIELD, effect, cost); - } - - public EbonPraetorAbility(final EbonPraetorAbility ability) { - super(ability); - } - - @Override - public EbonPraetorAbility copy() { - return new EbonPraetorAbility(this); - } - - @Override - public boolean canActivate(UUID playerId, Game game) { - if (!game.getActivePlayerId().equals(controllerId) || !PhaseStep.UPKEEP.equals(game.getStep().getType())) { - return false; - } - return super.canActivate(playerId, game); - } - - @Override - public String getRule() { - StringBuilder sb = new StringBuilder(""); - sb.append(super.getRule()).append(" Activate this ability only during your upkeep."); - return sb.toString(); - } -} - class EbonPraetorEffect extends OneShotEffect { public EbonPraetorEffect() { diff --git a/Mage.Sets/src/mage/sets/mirage/FetidHorror.java b/Mage.Sets/src/mage/sets/mirage/FetidHorror.java new file mode 100644 index 0000000000..40844d3dd4 --- /dev/null +++ b/Mage.Sets/src/mage/sets/mirage/FetidHorror.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.mirage; + +import java.util.UUID; +import mage.MageInt; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.costs.mana.ColoredManaCost; +import mage.abilities.effects.common.continuous.BoostSourceEffect; +import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.ColoredManaSymbol; +import mage.constants.Duration; +import mage.constants.Rarity; +import mage.constants.Zone; + +/** + * + * @author djbrez + */ +public class FetidHorror extends CardImpl { + + public FetidHorror(UUID ownerId) { + super(ownerId, 21, "Fetid Horror", Rarity.COMMON, new CardType[]{CardType.CREATURE}, "{3}{B}"); + this.expansionSetCode = "MIR"; + this.subtype.add("Shade"); + this.subtype.add("Horror"); + this.power = new MageInt(1); + this.toughness = new MageInt(2); + + // {B}: Fetid Horror gets +1/+1 until end of turn. + this.addAbility(new SimpleActivatedAbility(Zone.BATTLEFIELD, new BoostSourceEffect(1, 1, Duration.EndOfTurn), new ColoredManaCost(ColoredManaSymbol.B))); + } + + public FetidHorror(final FetidHorror card) { + super(card); + } + + @Override + public FetidHorror copy() { + return new FetidHorror(this); + } +} diff --git a/Mage.Sets/src/mage/sets/odyssey/CeaseFire.java b/Mage.Sets/src/mage/sets/odyssey/CeaseFire.java index e10245abbe..7bccbfe271 100644 --- a/Mage.Sets/src/mage/sets/odyssey/CeaseFire.java +++ b/Mage.Sets/src/mage/sets/odyssey/CeaseFire.java @@ -37,8 +37,7 @@ import mage.constants.CardType; import mage.constants.Duration; import mage.constants.Outcome; import mage.constants.Rarity; -import mage.filter.FilterSpell; -import mage.filter.predicate.mageobject.CardTypePredicate; +import mage.filter.common.FilterCreatureSpell; import mage.game.Game; import mage.game.events.GameEvent; import mage.game.stack.Spell; @@ -74,11 +73,7 @@ public class CeaseFire extends CardImpl { class CeaseFireEffect extends ContinuousRuleModifyingEffectImpl { - private static final FilterSpell filter = new FilterSpell(); - - static { - filter.add(new CardTypePredicate(CardType.CREATURE)); - } + private static final FilterCreatureSpell filter = new FilterCreatureSpell(); public CeaseFireEffect() { super(Duration.EndOfTurn, Outcome.Detriment); @@ -94,11 +89,6 @@ class CeaseFireEffect extends ContinuousRuleModifyingEffectImpl { return new CeaseFireEffect(this); } - @Override - public boolean apply(Game game, Ability source) { - return true; - } - @Override public String getInfoMessage(Ability source, GameEvent event, Game game) { MageObject mageObject = game.getObject(source.getSourceId()); @@ -115,9 +105,9 @@ class CeaseFireEffect extends ContinuousRuleModifyingEffectImpl { @Override public boolean applies(GameEvent event, Ability source, Game game) { - if (event.getPlayerId().equals(source.getFirstTarget())) { - MageObject object = game.getObject(event.getSourceId()); - if (filter.match((Spell) object, game)) { + if (event.getPlayerId().equals(getTargetPointer().getFirst(game, source))) { + Spell spell = game.getStack().getSpell(event.getSourceId()); + if (spell != null && filter.match(spell, game)) { return true; } } diff --git a/Mage.Sets/src/mage/sets/onslaught/ScreechingBuzzard.java b/Mage.Sets/src/mage/sets/onslaught/ScreechingBuzzard.java new file mode 100644 index 0000000000..23df35498d --- /dev/null +++ b/Mage.Sets/src/mage/sets/onslaught/ScreechingBuzzard.java @@ -0,0 +1,67 @@ +/* + * 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.onslaught; + +import java.util.UUID; +import mage.MageInt; +import mage.abilities.common.DiesTriggeredAbility; +import mage.abilities.effects.common.discard.DiscardEachPlayerEffect; +import mage.abilities.keyword.FlyingAbility; +import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.Rarity; +import mage.constants.TargetController; + +/** + * + * @author djbrez + */ +public class ScreechingBuzzard extends CardImpl { + + public ScreechingBuzzard(UUID ownerId) { + super(ownerId, 165, "Screeching Buzzard", Rarity.COMMON, new CardType[]{CardType.CREATURE}, "{3}{B}"); + this.expansionSetCode = "ONS"; + this.subtype.add("Bird"); + this.power = new MageInt(2); + this.toughness = new MageInt(2); + + // Flying + this.addAbility(FlyingAbility.getInstance()); + // When Screeching Buzzard dies, each opponent discards a card. + this.addAbility(new DiesTriggeredAbility(new DiscardEachPlayerEffect(TargetController.OPPONENT), false)); + } + + public ScreechingBuzzard(final ScreechingBuzzard card) { + super(card); + } + + @Override + public ScreechingBuzzard copy() { + return new ScreechingBuzzard(this); + } +} diff --git a/Mage.Sets/src/mage/sets/portalthreekingdoms/WuSpy.java b/Mage.Sets/src/mage/sets/portalthreekingdoms/WuSpy.java new file mode 100644 index 0000000000..bf9f90dccc --- /dev/null +++ b/Mage.Sets/src/mage/sets/portalthreekingdoms/WuSpy.java @@ -0,0 +1,118 @@ +/* + * 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.portalthreekingdoms; + +import java.util.UUID; +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.effects.OneShotEffect; +import mage.cards.Card; +import mage.cards.CardImpl; +import mage.cards.Cards; +import mage.cards.CardsImpl; +import mage.constants.CardType; +import mage.constants.Outcome; +import mage.constants.Rarity; +import mage.constants.Zone; +import mage.filter.FilterCard; +import mage.game.Game; +import mage.players.Player; +import mage.target.TargetCard; +import mage.target.TargetPlayer; +import mage.target.common.TargetCardInLibrary; + +/** + * + * @author djbrez + */ +public class WuSpy extends CardImpl { + + public WuSpy(UUID ownerId) { + super(ownerId, 63, "Wu Spy", Rarity.UNCOMMON, new CardType[]{CardType.CREATURE}, "{1}{U}"); + this.expansionSetCode = "PTK"; + this.subtype.add("Human"); + this.subtype.add("Soldier"); + this.subtype.add("Rogue"); + this.power = new MageInt(1); + this.toughness = new MageInt(1); + + // When Wu Spy enters the battlefield, look at the top two cards of target player's library. Put one of them into his or her graveyard. + Ability ability = new EntersBattlefieldTriggeredAbility(new WuSpyEffect(), false); + ability.addTarget(new TargetPlayer()); + this.addAbility(ability); + + } + + public WuSpy(final WuSpy card) { + super(card); + } + + @Override + public WuSpy copy() { + return new WuSpy(this); + } +} + +class WuSpyEffect extends OneShotEffect { + + WuSpyEffect() { + super(Outcome.Exile); + this.staticText = "look at the top two cards of target player's library. Put one of them into his or her graveyard"; + } + + WuSpyEffect(final WuSpyEffect effect) { + super(effect); + } + + @Override + public WuSpyEffect copy() { + return new WuSpyEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player controller = game.getPlayer(source.getControllerId()); + Player opponent = game.getPlayer(this.getTargetPointer().getFirst(game, source)); + if (controller != null && opponent != null) { + Cards cards = new CardsImpl(); + cards.addAll(opponent.getLibrary().getTopCards(game, 2)); + if (!cards.isEmpty()) { + TargetCard target = new TargetCardInLibrary(new FilterCard("card to put into graveyard")); + controller.choose(Outcome.Benefit, cards, target, game); + Card card = cards.get(target.getFirstTarget(), game); + if (card != null) { + cards.remove(card); + controller.moveCards(card, Zone.GRAVEYARD, source, game); + } + } + return true; + } + return false; + } +} diff --git a/Mage.Sets/src/mage/sets/shadowsoverinnistrad/ForsakenSanctuary.java b/Mage.Sets/src/mage/sets/shadowsoverinnistrad/ForsakenSanctuary.java new file mode 100644 index 0000000000..7faae86191 --- /dev/null +++ b/Mage.Sets/src/mage/sets/shadowsoverinnistrad/ForsakenSanctuary.java @@ -0,0 +1,64 @@ +/* + * 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.shadowsoverinnistrad; + +import java.util.UUID; +import mage.abilities.common.EntersBattlefieldTappedAbility; +import mage.abilities.mana.BlackManaAbility; +import mage.abilities.mana.WhiteManaAbility; +import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.Rarity; + +/** + * + * @author fireshoes + */ +public class ForsakenSanctuary extends CardImpl { + + public ForsakenSanctuary(UUID ownerId) { + super(ownerId, 273, "Forsaken Sanctuary", Rarity.UNCOMMON, new CardType[]{CardType.LAND}, ""); + this.expansionSetCode = "SOI"; + + // Forsaken Sanctuary enters the battlefield tapped. + this.addAbility(new EntersBattlefieldTappedAbility()); + + // {T}: Add {W} or {B} to your mana pool. + this.addAbility(new WhiteManaAbility()); + this.addAbility(new BlackManaAbility()); + } + + public ForsakenSanctuary(final ForsakenSanctuary card) { + super(card); + } + + @Override + public ForsakenSanctuary copy() { + return new ForsakenSanctuary(this); + } +} diff --git a/Mage.Sets/src/mage/sets/shadowsoverinnistrad/FoulOrchard.java b/Mage.Sets/src/mage/sets/shadowsoverinnistrad/FoulOrchard.java new file mode 100644 index 0000000000..b0480109b8 --- /dev/null +++ b/Mage.Sets/src/mage/sets/shadowsoverinnistrad/FoulOrchard.java @@ -0,0 +1,64 @@ +/* + * 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.shadowsoverinnistrad; + +import java.util.UUID; +import mage.abilities.common.EntersBattlefieldTappedAbility; +import mage.abilities.mana.BlackManaAbility; +import mage.abilities.mana.GreenManaAbility; +import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.Rarity; + +/** + * + * @author fireshoes + */ +public class FoulOrchard extends CardImpl { + + public FoulOrchard(UUID ownerId) { + super(ownerId, 275, "Foul Orchard", Rarity.UNCOMMON, new CardType[]{CardType.LAND}, ""); + this.expansionSetCode = "SOI"; + + // Foul Orchard enters the battlefield tapped. + this.addAbility(new EntersBattlefieldTappedAbility()); + + // {T}: Add {B} or {G} to your mana pool. + this.addAbility(new BlackManaAbility()); + this.addAbility(new GreenManaAbility()); + } + + public FoulOrchard(final FoulOrchard card) { + super(card); + } + + @Override + public FoulOrchard copy() { + return new FoulOrchard(this); + } +} diff --git a/Mage.Sets/src/mage/sets/shadowsoverinnistrad/HighlandLake.java b/Mage.Sets/src/mage/sets/shadowsoverinnistrad/HighlandLake.java new file mode 100644 index 0000000000..cc48de58ec --- /dev/null +++ b/Mage.Sets/src/mage/sets/shadowsoverinnistrad/HighlandLake.java @@ -0,0 +1,64 @@ +/* + * 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.shadowsoverinnistrad; + +import java.util.UUID; +import mage.abilities.common.EntersBattlefieldTappedAbility; +import mage.abilities.mana.BlueManaAbility; +import mage.abilities.mana.RedManaAbility; +import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.Rarity; + +/** + * + * @author fireshoes + */ +public class HighlandLake extends CardImpl { + + public HighlandLake(UUID ownerId) { + super(ownerId, 277, "Highland Lake", Rarity.UNCOMMON, new CardType[]{CardType.LAND}, ""); + this.expansionSetCode = "SOI"; + + // Highland Lake enters the battlefield tapped. + this.addAbility(new EntersBattlefieldTappedAbility()); + + // {T}: Add {U} or {R} to your mana pool. + this.addAbility(new BlueManaAbility()); + this.addAbility(new RedManaAbility()); + } + + public HighlandLake(final HighlandLake card) { + super(card); + } + + @Override + public HighlandLake copy() { + return new HighlandLake(this); + } +} diff --git a/Mage.Sets/src/mage/sets/shadowsoverinnistrad/PiousEvangel.java b/Mage.Sets/src/mage/sets/shadowsoverinnistrad/PiousEvangel.java new file mode 100644 index 0000000000..4501a9419f --- /dev/null +++ b/Mage.Sets/src/mage/sets/shadowsoverinnistrad/PiousEvangel.java @@ -0,0 +1,97 @@ +/* + * 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.shadowsoverinnistrad; + +import java.util.UUID; +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.EntersBattlefieldControlledTriggeredAbility; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.costs.common.SacrificeTargetCost; +import mage.abilities.costs.common.TapSourceCost; +import mage.abilities.costs.mana.GenericManaCost; +import mage.abilities.effects.common.GainLifeEffect; +import mage.abilities.effects.common.TransformSourceEffect; +import mage.abilities.keyword.TransformAbility; +import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.Rarity; +import mage.constants.TargetController; +import mage.constants.Zone; +import mage.filter.FilterPermanent; +import mage.filter.common.FilterControlledPermanent; +import mage.filter.common.FilterCreaturePermanent; +import mage.filter.predicate.permanent.AnotherPredicate; +import mage.filter.predicate.permanent.ControllerPredicate; +import mage.target.common.TargetControlledPermanent; + +/** + * + * @author fireshoes + */ +public class PiousEvangel extends CardImpl { + + private static final FilterPermanent filter = new FilterCreaturePermanent("{this} or another creature"); + private static final FilterControlledPermanent filter2 = new FilterControlledPermanent("another permanent"); + + static { + filter.add(new ControllerPredicate(TargetController.YOU)); + filter2.add(new AnotherPredicate()); + } + + public PiousEvangel(UUID ownerId) { + super(ownerId, 34, "Pious Evangel", Rarity.UNCOMMON, new CardType[]{CardType.CREATURE}, "{2}{W}"); + this.expansionSetCode = "SOI"; + this.subtype.add("Human"); + this.subtype.add("Cleric"); + this.power = new MageInt(2); + this.toughness = new MageInt(2); + + this.canTransform = true; + this.secondSideCard = new WaywardDisciple(ownerId); + + // Whenever Pious Evangel or another creature enters the battlefield under your control, you gain 1 life. + this.addAbility(new EntersBattlefieldControlledTriggeredAbility(new GainLifeEffect(1), filter)); + + // {2}, {T}, Sacrifice another permanent: Transform Pious Evangel. + this.addAbility(new TransformAbility()); + Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new TransformSourceEffect(true), new GenericManaCost(2)); + ability.addCost(new TapSourceCost()); + ability.addCost(new SacrificeTargetCost(new TargetControlledPermanent(filter2))); + this.addAbility(ability); + } + + public PiousEvangel(final PiousEvangel card) { + super(card); + } + + @Override + public PiousEvangel copy() { + return new PiousEvangel(this); + } +} diff --git a/Mage.Sets/src/mage/sets/shadowsoverinnistrad/StoneQuarry.java b/Mage.Sets/src/mage/sets/shadowsoverinnistrad/StoneQuarry.java new file mode 100644 index 0000000000..00a792c460 --- /dev/null +++ b/Mage.Sets/src/mage/sets/shadowsoverinnistrad/StoneQuarry.java @@ -0,0 +1,64 @@ +/* + * 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.shadowsoverinnistrad; + +import java.util.UUID; +import mage.abilities.common.EntersBattlefieldTappedAbility; +import mage.abilities.mana.RedManaAbility; +import mage.abilities.mana.WhiteManaAbility; +import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.Rarity; + +/** + * + * @author fireshoes + */ +public class StoneQuarry extends CardImpl { + + public StoneQuarry(UUID ownerId) { + super(ownerId, 279, "Stone Quarry", Rarity.UNCOMMON, new CardType[]{CardType.LAND}, ""); + this.expansionSetCode = "SOI"; + + // Stone Quarry enters the battlefield tapped. + this.addAbility(new EntersBattlefieldTappedAbility()); + + // {T}: Add {R} or {W} to your mana pool. + this.addAbility(new RedManaAbility()); + this.addAbility(new WhiteManaAbility()); + } + + public StoneQuarry(final StoneQuarry card) { + super(card); + } + + @Override + public StoneQuarry copy() { + return new StoneQuarry(this); + } +} diff --git a/Mage.Sets/src/mage/sets/shadowsoverinnistrad/WaywardDisciple.java b/Mage.Sets/src/mage/sets/shadowsoverinnistrad/WaywardDisciple.java new file mode 100644 index 0000000000..9ed58f01a7 --- /dev/null +++ b/Mage.Sets/src/mage/sets/shadowsoverinnistrad/WaywardDisciple.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.shadowsoverinnistrad; + +import java.util.UUID; +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.DiesThisOrAnotherCreatureTriggeredAbility; +import mage.abilities.effects.Effect; +import mage.abilities.effects.common.GainLifeEffect; +import mage.abilities.effects.common.LoseLifeTargetEffect; +import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.Rarity; +import mage.constants.TargetController; +import mage.filter.common.FilterCreaturePermanent; +import mage.filter.predicate.permanent.ControllerPredicate; +import mage.target.common.TargetOpponent; + +/** + * + * @author fireshoes + */ +public class WaywardDisciple extends CardImpl { + + private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("creature you control"); + + static { + filter.add(new ControllerPredicate(TargetController.YOU)); + } + + public WaywardDisciple(UUID ownerId) { + super(ownerId, 34, "Wayward Disciple", Rarity.UNCOMMON, new CardType[]{CardType.CREATURE}, ""); + this.expansionSetCode = "SOI"; + this.subtype.add("Human"); + this.subtype.add("Cleric"); + this.power = new MageInt(2); + this.toughness = new MageInt(4); + + // this card is the second face of double-faced card + this.nightCard = true; + + // Whenever Wayward Disciple or another creature you control dies, target opponent loses 1 life and you gain 1 life. + Ability ability = new DiesThisOrAnotherCreatureTriggeredAbility(new LoseLifeTargetEffect(1), false, filter); + ability.addTarget(new TargetOpponent()); + Effect effect = new GainLifeEffect(1); + effect.setText("and you gain 1 life"); + ability.addEffect(effect); + this.addAbility(ability); + } + + public WaywardDisciple(final WaywardDisciple card) { + super(card); + } + + @Override + public WaywardDisciple copy() { + return new WaywardDisciple(this); + } +} diff --git a/Mage.Sets/src/mage/sets/shadowsoverinnistrad/WoodlandStream.java b/Mage.Sets/src/mage/sets/shadowsoverinnistrad/WoodlandStream.java new file mode 100644 index 0000000000..c34b29b7a2 --- /dev/null +++ b/Mage.Sets/src/mage/sets/shadowsoverinnistrad/WoodlandStream.java @@ -0,0 +1,64 @@ +/* + * 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.shadowsoverinnistrad; + +import java.util.UUID; +import mage.abilities.common.EntersBattlefieldTappedAbility; +import mage.abilities.mana.BlueManaAbility; +import mage.abilities.mana.GreenManaAbility; +import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.Rarity; + +/** + * + * @author fireshoes + */ +public class WoodlandStream extends CardImpl { + + public WoodlandStream(UUID ownerId) { + super(ownerId, 282, "Woodland Stream", Rarity.UNCOMMON, new CardType[]{CardType.LAND}, ""); + this.expansionSetCode = "SOI"; + + // Woodland Stream enters the battlefield tapped. + this.addAbility(new EntersBattlefieldTappedAbility()); + + // {T}: Add {G} or {U} to your mana pool. + this.addAbility(new GreenManaAbility()); + this.addAbility(new BlueManaAbility()); + } + + public WoodlandStream(final WoodlandStream card) { + super(card); + } + + @Override + public WoodlandStream copy() { + return new WoodlandStream(this); + } +} diff --git a/Mage.Sets/src/mage/sets/tenthedition/SteelGolem.java b/Mage.Sets/src/mage/sets/tenthedition/SteelGolem.java index 184d9b5def..6c8ead5bf9 100644 --- a/Mage.Sets/src/mage/sets/tenthedition/SteelGolem.java +++ b/Mage.Sets/src/mage/sets/tenthedition/SteelGolem.java @@ -31,13 +31,14 @@ import java.util.UUID; import mage.constants.*; import mage.MageInt; -import mage.MageObject; import mage.abilities.Ability; import mage.abilities.common.SimpleStaticAbility; import mage.abilities.effects.ContinuousRuleModifyingEffectImpl; import mage.cards.CardImpl; +import mage.filter.common.FilterCreatureSpell; import mage.game.Game; import mage.game.events.GameEvent; +import mage.game.stack.Spell; /** * @@ -68,7 +69,9 @@ public class SteelGolem extends CardImpl { } class SteelGolemEffect extends ContinuousRuleModifyingEffectImpl { - + + private static final FilterCreatureSpell filter = new FilterCreatureSpell(); + public SteelGolemEffect() { super(Duration.WhileOnBattlefield, Outcome.Detriment); staticText = "You can't cast creature spells"; @@ -84,15 +87,15 @@ class SteelGolemEffect extends ContinuousRuleModifyingEffectImpl { } @Override - public boolean apply(Game game, Ability source) { - return true; + public boolean checksEventType(GameEvent event, Game game) { + return event.getType() == GameEvent.EventType.CAST_SPELL; } @Override public boolean applies(GameEvent event, Ability source, Game game) { - if (event.getType() == GameEvent.EventType.CAST_SPELL && event.getPlayerId().equals(source.getControllerId())) { - MageObject object = game.getObject(event.getSourceId()); - if (object.getCardType().contains(CardType.CREATURE)) { + if (event.getPlayerId().equals(source.getControllerId())) { + Spell spell = game.getStack().getSpell(event.getSourceId()); + if (spell != null && filter.match(spell, game)) { return true; } } @@ -100,4 +103,3 @@ class SteelGolemEffect extends ContinuousRuleModifyingEffectImpl { } } - diff --git a/Mage.Sets/src/mage/sets/timeshifted/Dragonstorm.java b/Mage.Sets/src/mage/sets/timeshifted/Dragonstorm.java index 13173c7171..8f9b653ad7 100644 --- a/Mage.Sets/src/mage/sets/timeshifted/Dragonstorm.java +++ b/Mage.Sets/src/mage/sets/timeshifted/Dragonstorm.java @@ -28,11 +28,11 @@ package mage.sets.timeshifted; import java.util.UUID; -import mage.constants.CardType; -import mage.constants.Rarity; import mage.abilities.effects.common.search.SearchLibraryPutInPlayEffect; import mage.abilities.keyword.StormAbility; import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.Rarity; import mage.filter.common.FilterPermanentCard; import mage.filter.predicate.mageobject.SubtypePredicate; import mage.target.common.TargetCardInLibrary; @@ -43,17 +43,15 @@ import mage.target.common.TargetCardInLibrary; */ public class Dragonstorm extends CardImpl { - private static final FilterPermanentCard filter = new FilterPermanentCard("Dragon permanent card"); static { filter.add(new SubtypePredicate("Dragon")); } - - public Dragonstorm(UUID ownerId) { - super(ownerId, 60, "Dragonstorm", Rarity.COMMON, new CardType[]{CardType.SORCERY}, "{8}{R}"); - this.expansionSetCode = "TSB"; + public Dragonstorm(UUID ownerId) { + super(ownerId, 60, "Dragonstorm", Rarity.SPECIAL, new CardType[]{CardType.SORCERY}, "{8}{R}"); + this.expansionSetCode = "TSB"; // Search your library for a Dragon permanent card and put it onto the battlefield. Then shuffle your library. this.getSpellAbility().addEffect(new SearchLibraryPutInPlayEffect(new TargetCardInLibrary(filter), false)); diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/conditional/ConditionalContinuousEffectTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/conditional/ConditionalContinuousEffectTest.java new file mode 100644 index 0000000000..c3603818ee --- /dev/null +++ b/Mage.Tests/src/test/java/org/mage/test/cards/conditional/ConditionalContinuousEffectTest.java @@ -0,0 +1,58 @@ +/* + * 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.conditional; + +import mage.abilities.keyword.DefenderAbility; +import mage.abilities.keyword.IndestructibleAbility; +import mage.constants.PhaseStep; +import mage.constants.Zone; +import org.junit.Test; +import org.mage.test.serverside.base.CardTestPlayerBase; + +/** + * + * @author LevelX2 + */ +public class ConditionalContinuousEffectTest extends CardTestPlayerBase { + + @Test + public void testManorGargoyle() { + addCard(Zone.BATTLEFIELD, playerA, "Mountain"); + addCard(Zone.BATTLEFIELD, playerA, "Manor Gargoyle"); + + activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "{1}: Until end of turn"); + + setStopAt(1, PhaseStep.BEGIN_COMBAT); + execute(); + + assertTapped("Mountain", true); + assertAbility(playerA, "Manor Gargoyle", DefenderAbility.getInstance(), false); + assertAbility(playerA, "Manor Gargoyle", IndestructibleAbility.getInstance(), false); + } + +} diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/copy/ProgenitorMimicTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/copy/ProgenitorMimicTest.java index 31e9e34ee2..ad064755f1 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/copy/ProgenitorMimicTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/copy/ProgenitorMimicTest.java @@ -186,4 +186,36 @@ public class ProgenitorMimicTest extends CardTestPlayerBase { } + /** + * Deadbridge Chant returns the battlefield Progenitor Mimic, but it's copy + * effect doesn't applied. It's 0/0, game put it into graveyard. + */ + @Test + public void testDeadbridgeChant() { + addCard(Zone.BATTLEFIELD, playerA, "Swamp", 3); + addCard(Zone.BATTLEFIELD, playerA, "Forest", 3); + // When Deadbridge Chant enters the battlefield, put the top ten cards of your library into your graveyard. + // At the beginning of your upkeep, choose a card at random in your graveyard. If it's a creature card, put it onto the battlefield. Otherwise, put it into your hand. + addCard(Zone.HAND, playerA, "Deadbridge Chant", 1); // {4}{B}{G} + addCard(Zone.BATTLEFIELD, playerA, "Silvercoat Lion", 1); + + // You may have Progenitor Mimic enter the battlefield as a copy of any creature on the battlefield except + // it gains "At the beginning of your upkeep, if this creature isn't a token, put a token onto the battlefield + // that's a copy of this creature." + addCard(Zone.LIBRARY, playerA, "Progenitor Mimic", 10); + skipInitShuffling(); + + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Deadbridge Chant"); + setChoice(playerA, "Silvercoat Lion"); // Copied by Progenitor Mimic returned by Deadbridge Chant on upkeep of turn 3 + + setStopAt(3, PhaseStep.PRECOMBAT_MAIN); + execute(); + + assertPermanentCount(playerA, "Deadbridge Chant", 1); + + assertPermanentCount(playerA, "Silvercoat Lion", 2); + assertPowerToughness(playerA, "Silvercoat Lion", 2, 2); + + assertGraveyardCount(playerA, "Progenitor Mimic", 9); + } } diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/requirement/AttackRequirementTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/requirement/AttackRequirementTest.java index 6fcfd8a443..98fc4af658 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/requirement/AttackRequirementTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/requirement/AttackRequirementTest.java @@ -36,56 +36,73 @@ import org.mage.test.serverside.base.CardTestPlayerBase; * * @author LevelX2 */ - public class AttackRequirementTest extends CardTestPlayerBase { - @Test public void testSimpleAttackRequirement() { // Defender // {G}: Wall of Tanglecord gains reach until end of turn. (It can block creatures with flying.) addCard(Zone.BATTLEFIELD, playerA, "Wall of Tanglecord"); // 0/6 - + // Juggernaut attacks each turn if able. // Juggernaut can't be blocked by Walls addCard(Zone.BATTLEFIELD, playerB, "Juggernaut"); // 5/3 - - // Juggernaut should be forced to ttack + + // Juggernaut should be forced to ttack block(2, playerA, "Wall of Tanglecord", "Juggernaut"); // this block should'nt work because of Juggernauts restriction setStopAt(2, PhaseStep.POSTCOMBAT_MAIN); execute(); - assertLife(playerA, 15); + assertLife(playerA, 15); assertLife(playerB, 20); } - @Test public void testAttackRequirementWithAttackRestriction() { addCard(Zone.BATTLEFIELD, playerA, "Plains", 3); // Defender // {G}: Wall of Tanglecord gains reach until end of turn. (It can block creatures with flying.) addCard(Zone.BATTLEFIELD, playerA, "Wall of Tanglecord"); // 0/6 - + // Creatures can't attack you unless their controller pays {2} for each creature he or she controls that's attacking you addCard(Zone.HAND, playerA, "Ghostly Prison"); - + // Juggernaut attacks each turn if able. // Juggernaut can't be blocked by Walls addCard(Zone.BATTLEFIELD, playerB, "Juggernaut"); // 5/3 - + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Ghostly Prison"); - + // Juggernaut is forced to attack but can't without paying the Ghostly Prison cost and don't has to pay the costs so no attack + setStopAt(2, PhaseStep.POSTCOMBAT_MAIN); + execute(); + + assertLife(playerA, 20); + assertLife(playerB, 20); + + } + + /** + * Goblin Rabblemaster isn't forcing Goblins to attack. + */ + @Test + public void testAttackRequirementGoblinRabblemaster() { + // Other Goblin creatures you control attack each turn if able. + // At the beginning of combat on your turn, put a 1/1 red Goblin creature token with haste onto the battlefield. + // When Goblin Rabblemaster attacks, it gets +1/+0 until end of turn for each other attacking Goblin. + addCard(Zone.BATTLEFIELD, playerB, "Goblin Rabblemaster"); // 2/2 + // Menace (This creature can't be blocked except by two or more creatures.) + addCard(Zone.BATTLEFIELD, playerB, "Boggart Brute"); // 3/2 + + attack(2, playerB, "Goblin Rabblemaster"); setStopAt(2, PhaseStep.POSTCOMBAT_MAIN); execute(); - assertLife(playerA, 20); + assertLife(playerA, 12); // got damage 1 from Token, 3 from Boggart Brute + 2 + 2 from Goblin Rabblemaster = 9 assertLife(playerB, 20); } - } diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/triggers/dies/BloodArtistTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/triggers/dies/BloodArtistTest.java index 996cba1c97..e975ff6629 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/triggers/dies/BloodArtistTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/triggers/dies/BloodArtistTest.java @@ -2,7 +2,6 @@ package org.mage.test.cards.triggers.dies; import mage.constants.PhaseStep; import mage.constants.Zone; -import org.junit.Ignore; import org.junit.Test; import org.mage.test.serverside.base.CardTestPlayerBase; @@ -40,12 +39,6 @@ public class BloodArtistTest extends CardTestPlayerBase { assertLife(playerB, 17); } - /** - * There is realy something wrong with sacrifice effects triggers. Had - * Zulaport Cutthroat on battlefield and tried Altar's Reap and Bone - * Splinters on it. Neither triggered ZC's abbility. Tried the same with - * Blood Artist on battlefield, same result - no trigger. - */ @Test public void testWithBoneSplinters() { addCard(Zone.BATTLEFIELD, playerA, "Swamp", 1); @@ -73,7 +66,6 @@ public class BloodArtistTest extends CardTestPlayerBase { } @Test - @Ignore // not Fixed yet public void testWithBoneSplinters2() { addCard(Zone.BATTLEFIELD, playerA, "Swamp", 1); // As an additional cost to cast Bone Splinters, sacrifice a creature. @@ -98,7 +90,6 @@ public class BloodArtistTest extends CardTestPlayerBase { } @Test - @Ignore // not Fixed yet public void testWithBoneSplinters3() { addCard(Zone.BATTLEFIELD, playerA, "Swamp", 3); // As an additional cost to cast Bone Splinters, sacrifice a creature. diff --git a/Mage.Tests/src/test/java/org/mage/test/sets/BoosterGenerationTest.java b/Mage.Tests/src/test/java/org/mage/test/sets/BoosterGenerationTest.java index 4142d713ba..7803ab3d9d 100644 --- a/Mage.Tests/src/test/java/org/mage/test/sets/BoosterGenerationTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/sets/BoosterGenerationTest.java @@ -1,21 +1,19 @@ package org.mage.test.sets; +import java.util.Arrays; +import java.util.Iterator; +import java.util.List; import mage.cards.Card; import mage.cards.repository.CardScanner; import mage.sets.FateReforged; import mage.sets.MastersEditionII; import mage.sets.MastersEditionIV; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; import org.junit.Before; import org.junit.Test; import org.mage.test.serverside.base.MageTestBase; -import java.util.Arrays; -import java.util.Iterator; -import java.util.List; - -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertTrue; - /** * * @author nigelzor @@ -38,8 +36,9 @@ public class BoosterGenerationTest extends MageTestBase { "Bloodstained Mire", "Flooded Strand", "Polluted Delta", "Windswept Heath", "Wooded Foothills"); List booster = FateReforged.getInstance().createBooster(); - assertTrue(str(booster), contains(booster, tapland, "FRF") || contains(booster, fetchland, "KTK")); - assertFalse(str(booster), contains(booster, basics, null)); + assertTrue(str(booster), contains(booster, tapland, "FRF") || contains(booster, fetchland, "KTK") + || contains(booster, basics, null)); + // assertFalse(str(booster), contains(booster, basics, null)); } @Test diff --git a/Mage/src/main/java/mage/abilities/common/LimitedTimesPerTurnActivatedAbility.java b/Mage/src/main/java/mage/abilities/common/LimitedTimesPerTurnActivatedAbility.java index a415bb19a1..1d11c10c13 100644 --- a/Mage/src/main/java/mage/abilities/common/LimitedTimesPerTurnActivatedAbility.java +++ b/Mage/src/main/java/mage/abilities/common/LimitedTimesPerTurnActivatedAbility.java @@ -24,12 +24,12 @@ * The views and conclusions contained in the software and documentation are those of the * authors and should not be interpreted as representing official policies, either expressed * or implied, of BetaSteward_at_googlemail.com. -*/ - + */ package mage.abilities.common; import java.util.UUID; import mage.abilities.ActivatedAbilityImpl; +import mage.abilities.condition.Condition; import mage.abilities.costs.Cost; import mage.abilities.effects.Effect; import mage.constants.Zone; @@ -54,24 +54,33 @@ public class LimitedTimesPerTurnActivatedAbility extends ActivatedAbilityImpl { } private int maxActivationsPerTurn; + private Condition condition; public LimitedTimesPerTurnActivatedAbility(Zone zone, Effect effect, Cost cost) { this(zone, effect, cost, 1); } public LimitedTimesPerTurnActivatedAbility(Zone zone, Effect effect, Cost cost, int maxActivationsPerTurn) { - super(zone, effect, cost); - this.maxActivationsPerTurn = maxActivationsPerTurn; + this(zone, effect, cost, maxActivationsPerTurn, null); } - public LimitedTimesPerTurnActivatedAbility(LimitedTimesPerTurnActivatedAbility ability) { + public LimitedTimesPerTurnActivatedAbility(Zone zone, Effect effect, Cost cost, int maxActivationsPerTurn, Condition condition) { + super(zone, effect, cost); + this.maxActivationsPerTurn = maxActivationsPerTurn; + this.condition = condition; + } + + public LimitedTimesPerTurnActivatedAbility(final LimitedTimesPerTurnActivatedAbility ability) { super(ability); this.maxActivationsPerTurn = ability.maxActivationsPerTurn; + this.condition = ability.condition; } @Override public boolean canActivate(UUID playerId, Game game) { - return super.canActivate(playerId, game) && hasMoreActivationsThisTurn(game); + return super.canActivate(playerId, game) + && hasMoreActivationsThisTurn(game) + && (condition == null || condition.apply(game, this)); } private boolean hasMoreActivationsThisTurn(Game game) { @@ -86,13 +95,11 @@ public class LimitedTimesPerTurnActivatedAbility extends ActivatedAbilityImpl { ActivationInfo activationInfo = getActivationInfo(game); if (activationInfo == null) { activationInfo = new ActivationInfo(game.getTurnNum(), 1); + } else if (activationInfo.turnNum != game.getTurnNum()) { + activationInfo.turnNum = game.getTurnNum(); + activationInfo.activationCounter = 1; } else { - if (activationInfo.turnNum != game.getTurnNum()) { - activationInfo.turnNum = game.getTurnNum(); - activationInfo.activationCounter = 1; - } else { - activationInfo.activationCounter++; - } + activationInfo.activationCounter++; } setActivationInfo(activationInfo, game); return true; @@ -109,7 +116,10 @@ public class LimitedTimesPerTurnActivatedAbility extends ActivatedAbilityImpl { @Override public String getRule() { StringBuilder sb = new StringBuilder(super.getRule()).append(" Activate this ability "); - switch(maxActivationsPerTurn) { + if (condition != null) { + sb.append("only ").append(condition.toString()).append(" and "); + } + switch (maxActivationsPerTurn) { case 1: sb.append("only once"); break; @@ -127,6 +137,7 @@ public class LimitedTimesPerTurnActivatedAbility extends ActivatedAbilityImpl { public LimitedTimesPerTurnActivatedAbility copy() { return new LimitedTimesPerTurnActivatedAbility(this); } + private ActivationInfo getActivationInfo(Game game) { Integer turnNum = (Integer) game.getState().getValue(CardUtil.getCardZoneString("activationsTurn", sourceId, game)); Integer activationCount = (Integer) game.getState().getValue(CardUtil.getCardZoneString("activationsCount", sourceId, game)); @@ -135,7 +146,7 @@ public class LimitedTimesPerTurnActivatedAbility extends ActivatedAbilityImpl { } return new ActivationInfo(turnNum, activationCount); } - + private void setActivationInfo(ActivationInfo activationInfo, Game game) { game.getState().setValue(CardUtil.getCardZoneString("activationsTurn", sourceId, game), activationInfo.turnNum); game.getState().setValue(CardUtil.getCardZoneString("activationsCount", sourceId, game), activationInfo.activationCounter); diff --git a/Mage/src/main/java/mage/abilities/effects/ContinuousEffect.java b/Mage/src/main/java/mage/abilities/effects/ContinuousEffect.java index 0e3635eeea..13cd406e9d 100644 --- a/Mage/src/main/java/mage/abilities/effects/ContinuousEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/ContinuousEffect.java @@ -76,6 +76,10 @@ public interface ContinuousEffect extends Effect { Set getDependencyTypes(); + void addDependencyType(DependencyType dependencyType); + + void setDependedToType(DependencyType dependencyType); + @Override void newId(); diff --git a/Mage/src/main/java/mage/abilities/effects/ContinuousEffectImpl.java b/Mage/src/main/java/mage/abilities/effects/ContinuousEffectImpl.java index 83e04a6493..5a86d98f13 100644 --- a/Mage/src/main/java/mage/abilities/effects/ContinuousEffectImpl.java +++ b/Mage/src/main/java/mage/abilities/effects/ContinuousEffectImpl.java @@ -29,6 +29,7 @@ package mage.abilities.effects; import java.util.ArrayList; import java.util.EnumSet; +import java.util.HashSet; import java.util.List; import java.util.Set; import java.util.UUID; @@ -71,7 +72,8 @@ public abstract class ContinuousEffectImpl extends EffectImpl implements Continu protected boolean affectedObjectsSet = false; protected List affectedObjectList = new ArrayList<>(); protected boolean temporary = false; - protected EnumSet dependencyTypes; + protected EnumSet dependencyTypes; // this effect has the dependencyTypes defined here + protected DependencyType dependendToType; // this effect is dependent to this type /* A Characteristic Defining Ability (CDA) is an ability that defines a characteristic of a card or token. There are 3 specific rules that distinguish a CDA from other abilities. @@ -91,6 +93,7 @@ public abstract class ContinuousEffectImpl extends EffectImpl implements Continu this.order = 0; this.effectType = EffectType.CONTINUOUS; this.dependencyTypes = EnumSet.noneOf(DependencyType.class); + this.dependendToType = null; } public ContinuousEffectImpl(Duration duration, Layer layer, SubLayer sublayer, Outcome outcome) { @@ -188,12 +191,10 @@ public abstract class ContinuousEffectImpl extends EffectImpl implements Continu case PTChangingEffects_7: this.affectedObjectsSet = true; } - } else { - if (hasLayer(Layer.CopyEffects_1) || hasLayer(Layer.ControlChangingEffects_2) || hasLayer(Layer.TextChangingEffects_3) - || hasLayer(Layer.TypeChangingEffects_4) || hasLayer(Layer.ColorChangingEffects_5) || hasLayer(Layer.AbilityAddingRemovingEffects_6) - || hasLayer(Layer.PTChangingEffects_7)) { - this.affectedObjectsSet = true; - } + } else if (hasLayer(Layer.CopyEffects_1) || hasLayer(Layer.ControlChangingEffects_2) || hasLayer(Layer.TextChangingEffects_3) + || hasLayer(Layer.TypeChangingEffects_4) || hasLayer(Layer.ColorChangingEffects_5) || hasLayer(Layer.AbilityAddingRemovingEffects_6) + || hasLayer(Layer.PTChangingEffects_7)) { + this.affectedObjectsSet = true; } } startingTurn = game.getTurnNum(); @@ -275,6 +276,19 @@ public abstract class ContinuousEffectImpl extends EffectImpl implements Continu @Override public Set isDependentTo(List allEffectsInLayer) { + if (dependendToType != null) { + // the dependent classes needs to be an enclosed class for dependent check of continuous effects + Set dependentTo = null; + for (ContinuousEffect effect : allEffectsInLayer) { + if (effect.getDependencyTypes().contains(dependendToType)) { + if (dependentTo == null) { + dependentTo = new HashSet<>(); + } + dependentTo.add(effect.getId()); + } + } + return dependentTo; + } return null; } @@ -283,4 +297,14 @@ public abstract class ContinuousEffectImpl extends EffectImpl implements Continu return dependencyTypes; } + @Override + public void addDependencyType(DependencyType dependencyType) { + dependencyTypes.add(dependencyType); + } + + @Override + public void setDependedToType(DependencyType dependencyType) { + dependendToType = dependencyType; + } + } diff --git a/Mage/src/main/java/mage/cards/repository/CardRepository.java b/Mage/src/main/java/mage/cards/repository/CardRepository.java index 527ff0faaf..595498eff2 100644 --- a/Mage/src/main/java/mage/cards/repository/CardRepository.java +++ b/Mage/src/main/java/mage/cards/repository/CardRepository.java @@ -63,7 +63,7 @@ public enum CardRepository { // raise this if db structure was changed private static final long CARD_DB_VERSION = 43; // raise this if new cards were added to the server - private static final long CARD_CONTENT_VERSION = 47; + private static final long CARD_CONTENT_VERSION = 48; private final Random random = new Random(); private Dao cardDao; diff --git a/Mage/src/main/java/mage/constants/DependencyType.java b/Mage/src/main/java/mage/constants/DependencyType.java index bae316c540..9b2eed7d15 100644 --- a/Mage/src/main/java/mage/constants/DependencyType.java +++ b/Mage/src/main/java/mage/constants/DependencyType.java @@ -46,5 +46,6 @@ public enum DependencyType { BecomeMountain, BecomePlains, BecomeSwamp, - EnchantmentAddingRemoving; + EnchantmentAddingRemoving, + LooseDefenderEffect; } diff --git a/Mage/src/main/java/mage/game/GameImpl.java b/Mage/src/main/java/mage/game/GameImpl.java index 2298f96a77..debe5347a1 100644 --- a/Mage/src/main/java/mage/game/GameImpl.java +++ b/Mage/src/main/java/mage/game/GameImpl.java @@ -1278,6 +1278,7 @@ public abstract class GameImpl implements Game, Serializable { if (executingRollback()) { return; } + getState().handleSimultaneousEvent(this); // needed here to handle triggers e.g. from paying costs like sacrificing a creatures before LKIShort is cleared applyEffects(); } if (isPaused()) { diff --git a/Utils/mtg-cards-data.txt b/Utils/mtg-cards-data.txt index 1eac9e1072..80d1826d60 100644 --- a/Utils/mtg-cards-data.txt +++ b/Utils/mtg-cards-data.txt @@ -56944,6 +56944,8 @@ Bygone Bishop|Shadows over Innistrad|8|R|{2}{W}|Creature - Spirit Cleric|2|3|Fly Declaration in Stone|Shadows over Innistrad|12|R|{1}{W}|Sorcery|||Exile target creature and all other creatures its controller controls with the same name as that creature. That player investigates for each nontoken creature exiled this way.| Eerie Interlude|Shadows over Innistrad|16|R|{2}{W}|Instant|||Exile any number of target creatures you control. Return those cards to the battlefield under their owner's control at the beginning of the next end step.| Expose Evil|Shadows over Innistrad|19|C|{1}{W}|Instant|||Tap up to two target creatures.$Investigate. (Put a colorless Clue artifact token onto the battlefield with "{2}, Sacrifice this artifact: Draw a card.")| +Pious Evangel|Shadows over Innistrad|34a|U|{2}{W}|Creature - Human Cleric|2|2|Whenever Pious Evangel or another creature enters the battlefield under your control, you gain 1 life.${2}, {T}, Sacrifice another permanent: Transform Pious Evangel.| +Wayward Disciple|Shadows over Innistrad|34b|U||Creature - Human Cleric|2|4|Whenever Wayward Disciple or another creature you control dies, target opponent loses 1 life and you gain 1 life.| Reaper of Flight Moonsilver|Shadows over Innistrad|36|U|{3}{W}{W}|Creature - Angel|3|3|Flying$Delirium — Sacrifice another creature: Reaper of Flight Moonsilver gets +2/+1 until end of turn. Activate this ability only if there are four or more card types among cards in your graveyard.| Thraben Inspector|Shadows over Innistrad|44|C|{W}|Creature - Human Soldier|1|2|When Thraben Inspector enters the battlefield, investigate. (Put a colorless Clue artifact token onto the battlefield with "{2}, Sacrifice this artifact: Draw a card.")| Topplegeist|Shadows over Innistrad|45|U|{W}|Creature - Spirit|1|1|Flying$When Topplegeist enters the battlefield, tap target creature an opponent controls.$Delirium — At the beginning of each opponent's upkeep, if there are four or more card types among cards in your graveyard, tap target creature that player controls.| @@ -57002,6 +57004,11 @@ Explosive Apparatus|Shadows over Innistrad|255|C|{1}|Artifact|||{3}, {T}, Sacrif Magnifying Glass|Shadows over Innistrad|258|U|{3}|Artifact|||{T}: Add {C} to your mana pool.${4}, {T}: Investigate. (Put a colorless Clue artifact token onto the battlefield with "{2}, Sacrifice this artifact: Draw a card.")| Shard of Broken Glass|Shadows over Innistrad|262|C|{1}|Artifact - Equipment|||Equipped creature gets +1/+0.$Whenever equipped creature attacks, you may put the top two cards of your library into your graveyard.$Equip {1} ({1}: Attach to target creature you control. Equip only as a sorcery.)| Tamiyo's Journal|Shadows over Innistrad|265|R|{5}|Legendary Artifact|||At the beginning of your upkeep, investigate. (Put a colorless Clue artifact token onto the battlefield with "{2}, Sacrifice this artifact: Draw a card.")${T}, Sacrifice three Clues: Search your library for a card and put that card into your hand. Then shuffle your library.| +Forsaken Sanctuary|Shadows over Innistrad|273|U||Land|||Forsaken Sanctuary enters the battlefield tapped.${T}: Add {W} or {B} to your mana pool.| +Foul Orchard|Shadows over Innistrad|275|U||Land|||Foul Orchard enters the battlefield tapped.${T}: Add {B} or {G} to your mana pool.| +Highland Lake|Shadows over Innistrad|277|U||Land|||Highland Lake enters the battlefield tapped.${T}: Add {U} or {R} to your mana pool.| +Stone Quarry|Shadows over Innistrad|279|U||Land|||Stone Quarry enters the battlefield tapped.${T}: Add {R} or {W} to your mana pool.| +Woodland Stream|Shadows over Innistrad|282|U||Land|||Woodland Stream enters the battlefield tapped.${T}: Add {G} or {U} to your mana pool.| Warped Landscape|Shadows over Innistrad|280|C||Land|||{T}: Add {C} to your mana pool.${2}, {T}, Sacrifice Warped Landscape: Search your library for a basic land card and put it onto the battlefield tapped. Then shuffle your library.| Force of Will|Eternal Masters|49|M|{3}{U}{U}|Instant|||You may pay 1 life and exile a blue card from your hand rather than pay Force of Will's mana cost.$Counter target spell.| Wasteland|Eternal Masters|248|R||Land|||{T}: Add {C} to your mana pool.${T}, Sacrifice Wasteland: Destroy target nonbasic land.| \ No newline at end of file diff --git a/Utils/release/getting_implemented_cards.txt b/Utils/release/getting_implemented_cards.txt index 4e0e5e41b7..1ad453a717 100644 --- a/Utils/release/getting_implemented_cards.txt +++ b/Utils/release/getting_implemented_cards.txt @@ -66,6 +66,9 @@ git log 51a0d8a4b2f53ea67d21f771acc533b610a02e0c..head --diff-filter=A --name-st since 1.4.9v1 git log 6d4a3bac288e9f3aff84d878c9816f89500a67af..head --diff-filter=A --name-status | sed -ne "s/^A[^u]Mage.Sets\/src\/mage\/sets\///p" | sort > added_cards.txt +since 1.4.9v2 +git log d818fadf52ff2e4e4df2142d0eb98a48e8cddb86..head --diff-filter=A --name-status | sed -ne "s/^A[^u]Mage.Sets\/src\/mage\/sets\///p" | sort > added_cards.txt + 3. Copy added_cards.txt to trunk\Utils folder 4. Run script: > perl extract_in_wiki_format.perl