diff --git a/Mage.Sets/src/mage/sets/magic2014/SavageSummoning.java b/Mage.Sets/src/mage/sets/magic2014/SavageSummoning.java index 6e1407ba2d..fc7db630f2 100644 --- a/Mage.Sets/src/mage/sets/magic2014/SavageSummoning.java +++ b/Mage.Sets/src/mage/sets/magic2014/SavageSummoning.java @@ -49,6 +49,7 @@ import mage.constants.Rarity; import mage.constants.WatcherScope; import mage.counters.CounterType; import mage.game.Game; +import mage.game.command.Commander; import mage.game.events.GameEvent; import mage.game.events.GameEvent.EventType; import mage.game.permanent.Permanent; @@ -65,13 +66,12 @@ public class SavageSummoning extends CardImpl { super(ownerId, 194, "Savage Summoning", Rarity.RARE, new CardType[]{CardType.INSTANT}, "{G}"); this.expansionSetCode = "M14"; - // Savage Summoning can't be countered. Ability ability = new CantBeCounteredAbility(); ability.setRuleAtTheTop(true); this.addAbility(ability); - // The next creature card you cast this turn can be cast as though it had flash. + // The next creature card you cast this turn can be cast as though it had flash. // That spell can't be countered. That creature enters the battlefield with an additional +1/+1 counter on it. this.getSpellAbility().addEffect(new SavageSummoningAsThoughEffect()); this.getSpellAbility().addEffect(new SavageSummoningCantCounterEffect()); @@ -91,6 +91,7 @@ public class SavageSummoning extends CardImpl { } class SavageSummoningAsThoughEffect extends AsThoughEffectImpl { + private SavageSummoningWatcher watcher; private int zoneChangeCounter; @@ -107,13 +108,13 @@ class SavageSummoningAsThoughEffect extends AsThoughEffectImpl { @Override public void init(Ability source, Game game) { - watcher = (SavageSummoningWatcher) game.getState().getWatchers().get("consumeSavageSummoningWatcher", source.getControllerId()); - Card card = game.getCard(source.getSourceId()); - if (watcher != null && card != null) { - watcher.setSavageSummoningSpellActive(card, game); - } else { - throw new IllegalArgumentException("Consume Savage watcher could not be found"); - } + watcher = (SavageSummoningWatcher) game.getState().getWatchers().get("consumeSavageSummoningWatcher", source.getControllerId()); + Card card = game.getCard(source.getSourceId()); + if (watcher != null && card != null) { + watcher.setSavageSummoningSpellActive(card, game); + } else { + throw new IllegalArgumentException("Consume Savage watcher could not be found"); + } } @Override @@ -126,13 +127,20 @@ class SavageSummoningAsThoughEffect extends AsThoughEffectImpl { return new SavageSummoningAsThoughEffect(this); } - @Override - public boolean applies(UUID sourceId, Ability source, UUID affectedControllerId, Game game) { + public boolean applies(UUID objectId, Ability source, UUID affectedControllerId, Game game) { if (watcher.isSavageSummoningSpellActive()) { - Card card = game.getCard(sourceId); - if (card != null && card.getCardType().contains(CardType.CREATURE) && card.getOwnerId().equals(source.getControllerId())) { - return card.getSpellAbility().isInUseableZone(game, card, null); + MageObject mageObject = game.getBaseObject(objectId); + if (mageObject instanceof Commander) { + Commander commander = (Commander) mageObject; + if (commander.getCardType().contains(CardType.CREATURE) && commander.getControllerId().equals(source.getControllerId())) { + return true; + } + } else if (mageObject != null && mageObject instanceof Card) { + Card card = (Card) mageObject; + if (card.getCardType().contains(CardType.CREATURE) && card.getOwnerId().equals(source.getControllerId())) { + return true; + } } } return false; @@ -140,10 +148,10 @@ class SavageSummoningAsThoughEffect extends AsThoughEffectImpl { } - class SavageSummoningWatcher extends Watcher { - private Set savageSummoningSpells = new HashSet<>();; + private Set savageSummoningSpells = new HashSet<>(); + ; private Map> spellsCastWithSavageSummoning = new LinkedHashMap<>(); private Map> cardsCastWithSavageSummoning = new LinkedHashMap<>(); @@ -154,10 +162,10 @@ class SavageSummoningWatcher extends Watcher { public SavageSummoningWatcher(final SavageSummoningWatcher watcher) { super(watcher); this.savageSummoningSpells.addAll(watcher.savageSummoningSpells); - for (Entry> entry :watcher.spellsCastWithSavageSummoning.entrySet()) { + for (Entry> entry : watcher.spellsCastWithSavageSummoning.entrySet()) { this.spellsCastWithSavageSummoning.put(entry.getKey(), entry.getValue()); } - for (Entry> entry :watcher.cardsCastWithSavageSummoning.entrySet()) { + for (Entry> entry : watcher.cardsCastWithSavageSummoning.entrySet()) { this.cardsCastWithSavageSummoning.put(entry.getKey(), entry.getValue()); } } @@ -172,7 +180,7 @@ class SavageSummoningWatcher extends Watcher { if (event.getType() == GameEvent.EventType.SPELL_CAST) { if (isSavageSummoningSpellActive() && event.getPlayerId().equals(getControllerId())) { Spell spell = game.getStack().getSpell(event.getTargetId()); - if (spell != null && spell.getCardType().contains(CardType.CREATURE)) { + if (spell != null && spell.getCardType().contains(CardType.CREATURE)) { spellsCastWithSavageSummoning.put(spell.getId(), new HashSet<>(savageSummoningSpells)); String cardKey = new StringBuilder(spell.getCard().getId().toString()).append("_").append(spell.getCard().getZoneChangeCounter(game)).toString(); cardsCastWithSavageSummoning.put(cardKey, new HashSet<>(savageSummoningSpells)); @@ -198,7 +206,7 @@ class SavageSummoningWatcher extends Watcher { } public boolean isCardCastWithThisSavageSummoning(Card card, UUID cardId, int zoneChangeCounter, Game game) { - String creatureCardKey = new StringBuilder(card.getId().toString()).append("_").append(card.getZoneChangeCounter(game)-1).toString(); + String creatureCardKey = new StringBuilder(card.getId().toString()).append("_").append(card.getZoneChangeCounter(game) - 1).toString(); // add one because card is now gone to battlefield as creature String cardKey = new StringBuilder(cardId.toString()).append("_").append(zoneChangeCounter).toString(); HashSet savageSpells = (HashSet) cardsCastWithSavageSummoning.get(creatureCardKey); @@ -216,6 +224,7 @@ class SavageSummoningWatcher extends Watcher { } class SavageSummoningCantCounterEffect extends ContinuousRuleModifyingEffectImpl { + private SavageSummoningWatcher watcher; private int zoneChangeCounter; @@ -232,12 +241,12 @@ class SavageSummoningCantCounterEffect extends ContinuousRuleModifyingEffectImpl @Override public void init(Ability source, Game game) { - watcher = (SavageSummoningWatcher) game.getState().getWatchers().get("consumeSavageSummoningWatcher", source.getControllerId()); - Card card = game.getCard(source.getSourceId()); - if (watcher == null || card == null) { - throw new IllegalArgumentException("Consume Savage watcher or card could not be found"); - } - this.zoneChangeCounter = card.getZoneChangeCounter(game); + watcher = (SavageSummoningWatcher) game.getState().getWatchers().get("consumeSavageSummoningWatcher", source.getControllerId()); + Card card = game.getCard(source.getSourceId()); + if (watcher == null || card == null) { + throw new IllegalArgumentException("Consume Savage watcher or card could not be found"); + } + this.zoneChangeCounter = card.getZoneChangeCounter(game); } @Override @@ -273,6 +282,7 @@ class SavageSummoningCantCounterEffect extends ContinuousRuleModifyingEffectImpl } class SavageSummoningEntersBattlefieldEffect extends ReplacementEffectImpl { + private SavageSummoningWatcher watcher; private int zoneChangeCounter; @@ -289,12 +299,12 @@ class SavageSummoningEntersBattlefieldEffect extends ReplacementEffectImpl { @Override public void init(Ability source, Game game) { - watcher = (SavageSummoningWatcher) game.getState().getWatchers().get("consumeSavageSummoningWatcher", source.getControllerId()); - Card card = game.getCard(source.getSourceId()); - if (watcher == null || card == null) { - throw new IllegalArgumentException("Consume Savage watcher or card could not be found"); - } - this.zoneChangeCounter = card.getZoneChangeCounter(game); + watcher = (SavageSummoningWatcher) game.getState().getWatchers().get("consumeSavageSummoningWatcher", source.getControllerId()); + Card card = game.getCard(source.getSourceId()); + if (watcher == null || card == null) { + throw new IllegalArgumentException("Consume Savage watcher or card could not be found"); + } + this.zoneChangeCounter = card.getZoneChangeCounter(game); } @Override @@ -316,7 +326,7 @@ class SavageSummoningEntersBattlefieldEffect extends ReplacementEffectImpl { public boolean checksEventType(GameEvent event, Game game) { return event.getType() == EventType.ENTERS_THE_BATTLEFIELD; } - + @Override public boolean applies(GameEvent event, Ability source, Game game) { Card card = game.getCard(event.getTargetId()); diff --git a/Mage.Tests/Power Hungry.dck b/Mage.Tests/Power Hungry.dck new file mode 100644 index 0000000000..ddabd22311 --- /dev/null +++ b/Mage.Tests/Power Hungry.dck @@ -0,0 +1,84 @@ +NAME:Power Hungry +7 [THS:246] Forest +1 [C13:78] Fell Shepherd +1 [C13:76] Endrek Sahr, Master Breeder +1 [C13:75] Endless Cockroaches +7 [THS:242] Mountain +1 [C13:73] Dirge of Dread +1 [C13:219] Sprouting Thrinax +1 [C13:259] Sol Ring +1 [C13:138] Brooding Saurian +1 [C13:335] Vivid Grove +1 [C13:213] Shattergang Brothers +1 [C13:254] Plague Boiler +1 [C13:210] Sek'Kuar, Deathkeeper +1 [C13:298] Jund Panorama +1 [C13:252] Obelisk of Jund +1 [C13:175] Walker of the Grove +1 [C13:131] Widespread Panic +1 [C13:294] Gruul Guildgate +1 [C13:172] Spoils of Victory +1 [C13:292] Grim Backwoods +1 [C13:291] Golgari Rot Farm +1 [C13:80] Hooded Horror +1 [C13:290] Golgari Guildgate +1 [C13:84] Ophiomancer +1 [C13:109] Furnace Celebration +1 [C13:229] Golgari Guildmage +6 [THS:238] Swamp +1 [C13:304] Llanowar Reborn +1 [C13:149] Hua Tuo, Honored Physician +1 [C13:105] Curse of Chaos +1 [C13:303] Kher Keep +1 [C13:302] Khalni Garden +1 [C13:301] Kazandu Refuge +1 [C13:102] Capricious Efreet +1 [C13:146] Foster +1 [C13:101] Blood Rites +1 [C13:145] Fecundity +1 [C13:100] Wight of Precinct Six +1 [C13:143] Elvish Skysweeper +1 [C13:263] Swiftfoot Boots +1 [C13:185] Deepfire Elemental +1 [C13:184] Deathbringer Thoctar +1 [C13:140] Curse of Predation +1 [C13:260] Spine of Ish Sah +1 [C13:93] Stronghold Assassin +1 [C13:180] Charnelhoard Wurm +1 [C13:90] Quagmire Druid +1 [C13:99] Viscera Seer +1 [C13:98] Vile Requiem +1 [C13:317] Savage Lands +1 [C13:118] Rough // Tumble +1 [C13:315] Rupture Spire +1 [C13:238] Carnage Altar +1 [C13:314] Rakdos Guildgate +1 [C13:116] Mass Mutiny +1 [C13:235] Armillary Sphere +1 [C13:114] Inferno Titan +1 [C13:158] Night Soil +1 [C13:310] Opal Palace +1 [C13:111] Goblin Sharpshooter +1 [C13:110] Goblin Bombardment +1 [C13:272] Akoum Refuge +1 [C13:195] Jund Charm +1 [C13:151] Jade Mage +1 [C13:150] Hunted Troll +1 [C13:209] Scarland Thrinax +1 [C13:328] Terramorphic Expanse +1 [C13:327] Temple of the False God +1 [C13:127] Tooth and Claw +1 [C13:126] Terra Ravager +1 [C13:125] Tempt with Vengeance +1 [C13:169] Silklash Spider +1 [C13:124] Sudden Demise +1 [C13:168] Sakura-Tribe Elder +1 [C13:167] Restore +1 [C13:244] Jar of Eyeballs +1 [C13:166] Reincarnation +1 [C13:287] Evolving Wilds +1 [C13:121] Stalking Vengeance +1 [C13:162] Primal Vigor +1 [C13:71] Curse of Shallow Graves +1 [C13:281] Command Tower +SB: 1 [C13:204] Prossh, Skyraider of Kher diff --git a/Mage.Tests/src/test/java/org/mage/test/commander/duel/CastBRGCommanderTest.java b/Mage.Tests/src/test/java/org/mage/test/commander/duel/CastBRGCommanderTest.java new file mode 100644 index 0000000000..b7732e593b --- /dev/null +++ b/Mage.Tests/src/test/java/org/mage/test/commander/duel/CastBRGCommanderTest.java @@ -0,0 +1,72 @@ +/* + * 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.commander.duel; + +import java.io.FileNotFoundException; +import mage.constants.PhaseStep; +import mage.constants.Zone; +import mage.game.Game; +import mage.game.GameException; +import org.junit.Test; +import org.mage.test.serverside.base.CardTestCommanderDuelBase; + +/** + * + * @author LevelX2 + */ +public class CastBRGCommanderTest extends CardTestCommanderDuelBase { + + @Override + protected Game createNewGameAndPlayers() throws GameException, FileNotFoundException { + // Flying + // When you cast Prossh, Skyraider of Kher, put X 0/1 red Kobold creature tokens named Kobolds of Kher Keep onto the battlefield, where X is the amount of mana spent to cast Prossh. + // Sacrifice another creature: Prossh gets +1/+0 until end of turn. + setDecknamePlayerA("Power Hungry.dck"); // Commander = Prosssh, Skyrider of Kher {3}{B}{R}{G} + return super.createNewGameAndPlayers(); + } + + @Test + public void castCommanderWithFlash() { + addCard(Zone.BATTLEFIELD, playerA, "Swamp", 1); + addCard(Zone.BATTLEFIELD, playerA, "Mountain", 1); + addCard(Zone.BATTLEFIELD, playerA, "Forest", 5); + + addCard(Zone.HAND, playerA, "Savage Summoning"); + + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Savage Summoning"); + castSpell(1, PhaseStep.BEGIN_COMBAT, playerA, "Prossh, Skyraider of Kher"); + setStopAt(1, PhaseStep.END_COMBAT); + execute(); + + assertGraveyardCount(playerA, "Savage Summoning", 1); + assertPermanentCount(playerA, "Prossh, Skyraider of Kher", 1); + assertPermanentCount(playerA, "Kobolds of Kher Keep", 6); + + } + +}