* Savage Summoning - Fixed that it did not work to cast a commander from command zone.

This commit is contained in:
LevelX2 2015-07-02 23:38:37 +02:00
parent 1a458a0837
commit 4aebcd2399
3 changed files with 199 additions and 33 deletions

View file

@ -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<String> savageSummoningSpells = new HashSet<>();;
private Set<String> savageSummoningSpells = new HashSet<>();
;
private Map<UUID, Set<String>> spellsCastWithSavageSummoning = new LinkedHashMap<>();
private Map<String, Set<String>> 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<UUID, Set<String>> entry :watcher.spellsCastWithSavageSummoning.entrySet()) {
for (Entry<UUID, Set<String>> entry : watcher.spellsCastWithSavageSummoning.entrySet()) {
this.spellsCastWithSavageSummoning.put(entry.getKey(), entry.getValue());
}
for (Entry<String, Set<String>> entry :watcher.cardsCastWithSavageSummoning.entrySet()) {
for (Entry<String, Set<String>> 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<String> savageSpells = (HashSet<String>) 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());

View file

@ -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

View file

@ -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);
}
}