mirror of
https://github.com/correl/mage.git
synced 2024-11-13 03:00:11 +00:00
* Savage Summoning - Fixed that it did not work to cast a commander from command zone.
This commit is contained in:
parent
1a458a0837
commit
4aebcd2399
3 changed files with 199 additions and 33 deletions
|
@ -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());
|
||||
|
|
84
Mage.Tests/Power Hungry.dck
Normal file
84
Mage.Tests/Power Hungry.dck
Normal 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
|
|
@ -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);
|
||||
|
||||
}
|
||||
|
||||
}
|
Loading…
Reference in a new issue