diff --git a/Mage.Tests/CommanderDuel_Karador_BGW.dck b/Mage.Tests/CommanderDuel_Karador_BGW.dck new file mode 100644 index 0000000000..e0ea3d96a1 --- /dev/null +++ b/Mage.Tests/CommanderDuel_Karador_BGW.dck @@ -0,0 +1,100 @@ +1 [M15:108] Necromancer's Stockpile +1 [FRF:76] Merciless Executioner +1 [9ED:283] Wood Elves +1 [M11:172] Fauna Shaman +1 [CMD:140] Acidic Slime +1 [PLS:42] Diabolic Intent +1 [AVR:226] Cavern of Souls +1 [TOR:77] Putrid Imp +1 [M15:194] Reclamation Sage +1 [RAV:230] Shambling Shell +1 [ISD:105] Liliana of the Veil +1 [M15:198] Satyr Wayfinder +1 [UDS:115] Pattern of Rebirth +1 [JOU:163] Mana Confluence +1 [ARB:75] Qasali Pridemage +1 [BFZ:250] Plains +1 [ZEN:172] Oracle of Mul Daya +1 [M13:229] Sunpetal Grove +1 [WWK:20] Stoneforge Mystic +1 [8ED:322] City of Brass +1 [ZEN:83] Bloodghast +1 [TSP:104] Dread Return +1 [ICE:278] Swords to Plowshares +1 [USG:230] Acridian +1 [RAV:107] Stinkweed Imp +1 [CON:113] Knight of the Reliquary +1 [AVR:106] Griselbrand +1 [10E:137] Doomed Necromancer +1 [M12:39] Sun Titan +1 [NPH:104] Birthing Pod +1 [M12:165] Birds of Paradise +1 [ORI:245] Caves of Koilos +1 [ZEN:211] Arid Mesa +1 [SOM:72] Necrotic Ooze +1 [M13:83] Bloodthrone Vampire +1 [ZEN:219] Marsh Flats +1 [TMP:340] Wasteland +1 [RAV:81] Dark Confidant +1 [TOR:69] Mesmeric Fiend +1 [RAV:87] Golgari Thug +1 [ISD:15] Fiend Hunter +1 [M15:248] Urborg, Tomb of Yawgmoth +1 [ORI:248] Llanowar Wastes +1 [KTK:248] Windswept Heath +1 [KTK:249] Wooded Foothills +1 [WWK:132] Bojuka Bog +1 [ALL:167] Phyrexian Devourer +1 [EVE:180] Twilight Mire +1 [5DN:86] Eternal Witness +1 [ZEN:220] Misty Rainforest +1 [MOR:22] Reveillark +1 [RAV:167] Golgari Grave-Troll +1 [ZEN:229] Verdant Catacombs +1 [KTK:239] Polluted Delta +1 [10E:349] Brushland +1 [RTR:243] Overgrown Tomb +1 [WWK:144] Stirring Wildwood +1 [C15:281] Command Tower +1 [SCG:59] Carrion Feeder +1 [ISD:249] Woodland Cemetery +1 [RTR:248] Temple Garden +1 [KTK:233] Flooded Strand +1 [ROE:33] Linvala, Keeper of Silence +1 [NPH:9] Elesh Norn, Grand Cenobite +1 [ISD:242] Isolated Chapel +1 [FUT:169] Dakmor Salvage +1 [M15:5] Boonweaver Giant +1 [LRW:248] Gaddock Teeg +1 [KTK:230] Bloodstained Mire +1 [RAV:172] Life from the Loam +1 [M12:188] Primeval Titan +1 [CHK:239] Sakura-Tribe Elder +1 [USG:321] Gaea's Cradle +1 [RTR:213] Deathrite Shaman +1 [USG:322] Phyrexian Tower +1 [BFZ:270] Forest +1 [FUT:174] Dryad Arbor +1 [3ED:297] Savannah +1 [ULG:11] Karmic Guide +1 [3ED:298] Scrubland +1 [UDS:1] Academy Rector +1 [5ED:191] Sylvan Library +1 [M11:218] Triskelion +1 [9ED:54] Weathered Wayfarer +1 [5ED:2] Animate Dead +1 [3ED:13] Demonic Tutor +1 [ARN:84] Bazaar of Baghdad +1 [ISD:122] Unburial Rites +1 [GTC:242] Godless Shrine +1 [ME3:69] Grim Tutor +1 [SHM:110] Devoted Druid +1 [EXO:129] Survival of the Fittest +1 [BFZ:260] Swamp +1 [DST:140] Skullclamp +1 [ALA:202] Tidehollow Sculler +1 [3ED:283] Bayou +1 [10E:361] Treetop Village +1 [TSP:245] Saffi Eriksdotter +1 [M11:120] Viscera Seer +SB: 1 [CMD:207] Karador, Ghost Chieftain diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/cost/modification/KaradorGhostChieftainTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/cost/modification/KaradorGhostChieftainTest.java new file mode 100644 index 0000000000..9149006006 --- /dev/null +++ b/Mage.Tests/src/test/java/org/mage/test/cards/cost/modification/KaradorGhostChieftainTest.java @@ -0,0 +1,86 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package org.mage.test.cards.cost.modification; + +import mage.constants.PhaseStep; +import mage.constants.Zone; +import org.junit.Test; +import org.mage.test.serverside.base.CardTestPlayerBase; + +/** + * + * @author LevelX2 + */ +public class KaradorGhostChieftainTest extends CardTestPlayerBase { + + @Test + public void castReducedTwo() { + addCard(Zone.BATTLEFIELD, playerA, "Swamp", 1); + addCard(Zone.BATTLEFIELD, playerA, "Forest", 1); + addCard(Zone.BATTLEFIELD, playerA, "Plains", 1); + addCard(Zone.BATTLEFIELD, playerA, "Island", 5); + addCard(Zone.GRAVEYARD, playerA, "Silvercoat Lion", 2); + // Karador, Ghost Chieftain costs {1} less to cast for each creature card in your graveyard. + // During each of your turns, you may cast one creature card from your graveyard. + addCard(Zone.HAND, playerA, "Karador, Ghost Chieftain");// {5}{B}{G}{W} + + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Karador, Ghost Chieftain"); + setStopAt(1, PhaseStep.BEGIN_COMBAT); + execute(); + assertTappedCount("Island", false, 2); + assertPermanentCount(playerA, "Karador, Ghost Chieftain", 1); + } + + /** + * I had a couple problems in a commander game last night. Using Karador, + * Ghost Chieftain as my commander. Most of the match, his casting cost was + * correctly calculated, reducing the extra commander tax and generic mana + * costs by the number of creature cards in my graveyard. On the 4th cast + * though, the cost was 12 mana total. I tried casting a few times over a + * couple turns, but it was still an incorrect cost (I had probably 15 + * creatures in my graveyard). + */ + @Test + public void castReducedSeven() { + addCard(Zone.BATTLEFIELD, playerA, "Swamp", 1); + addCard(Zone.BATTLEFIELD, playerA, "Forest", 1); + addCard(Zone.BATTLEFIELD, playerA, "Plains", 1); + addCard(Zone.BATTLEFIELD, playerA, "Island", 5); + addCard(Zone.GRAVEYARD, playerA, "Silvercoat Lion", 7); + // Karador, Ghost Chieftain costs {1} less to cast for each creature card in your graveyard. + // During each of your turns, you may cast one creature card from your graveyard. + addCard(Zone.HAND, playerA, "Karador, Ghost Chieftain");// {5}{B}{G}{W} + + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Karador, Ghost Chieftain"); + setStopAt(1, PhaseStep.BEGIN_COMBAT); + execute(); + assertTappedCount("Island", false, 5); + assertPermanentCount(playerA, "Karador, Ghost Chieftain", 1); + } + +} diff --git a/Mage.Tests/src/test/java/org/mage/test/commander/duel/KaradorGhostChieftainTest.java b/Mage.Tests/src/test/java/org/mage/test/commander/duel/KaradorGhostChieftainTest.java new file mode 100644 index 0000000000..b2901ee77d --- /dev/null +++ b/Mage.Tests/src/test/java/org/mage/test/commander/duel/KaradorGhostChieftainTest.java @@ -0,0 +1,155 @@ +/* + * 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 KaradorGhostChieftainTest extends CardTestCommanderDuelBase { + + @Override + protected Game createNewGameAndPlayers() throws GameException, FileNotFoundException { + // Karador, Ghost Chieftain costs {1} less to cast for each creature card in your graveyard. + // During each of your turns, you may cast one creature card from your graveyard. + setDecknamePlayerA("CommanderDuel_Karador_BGW.dck"); // Commander = Karador, Ghost Chieftain {5}{B}{G}{W} + setDecknamePlayerB("CMDNorinTheWary.dck"); // Need red + + return super.createNewGameAndPlayers(); + } + + @Test + public void castKarador() { + addCard(Zone.BATTLEFIELD, playerA, "Swamp", 1); + addCard(Zone.BATTLEFIELD, playerA, "Forest", 1); + addCard(Zone.BATTLEFIELD, playerA, "Plains", 1); + addCard(Zone.BATTLEFIELD, playerA, "Island", 5); + addCard(Zone.GRAVEYARD, playerA, "Silvercoat Lion", 2); + + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Karador, Ghost Chieftain"); + setStopAt(1, PhaseStep.BEGIN_COMBAT); + execute(); + assertTappedCount("Island", false, 2); + assertPermanentCount(playerA, "Karador, Ghost Chieftain", 1); + } + + @Test + public void castKaradorTwice() { + addCard(Zone.BATTLEFIELD, playerA, "Swamp", 1); + addCard(Zone.BATTLEFIELD, playerA, "Forest", 1); + addCard(Zone.BATTLEFIELD, playerA, "Plains", 1); + addCard(Zone.BATTLEFIELD, playerA, "Island", 7); + addCard(Zone.GRAVEYARD, playerA, "Silvercoat Lion", 2); + + addCard(Zone.BATTLEFIELD, playerB, "Mountain", 4); + // Lightning Blast deals 4 damage to target creature or player. + addCard(Zone.HAND, playerB, "Lightning Blast", 1); + + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Karador, Ghost Chieftain"); + castSpell(2, PhaseStep.PRECOMBAT_MAIN, playerB, "Lightning Blast", "Karador, Ghost Chieftain"); + + castSpell(3, PhaseStep.PRECOMBAT_MAIN, playerA, "Karador, Ghost Chieftain"); + + setStopAt(3, PhaseStep.BEGIN_COMBAT); + execute(); + assertGraveyardCount(playerB, "Lightning Blast", 1); + assertPermanentCount(playerA, "Karador, Ghost Chieftain", 1); + + assertTappedCount("Island", true, 5); + } + + @Test + public void castKaradorFourTimes() { + addCard(Zone.BATTLEFIELD, playerA, "Swamp", 1); + addCard(Zone.BATTLEFIELD, playerA, "Forest", 1); + addCard(Zone.BATTLEFIELD, playerA, "Plains", 1); + addCard(Zone.BATTLEFIELD, playerA, "Island", 11); + addCard(Zone.GRAVEYARD, playerA, "Silvercoat Lion", 2); + + addCard(Zone.BATTLEFIELD, playerB, "Mountain", 4); + // Lightning Blast deals 4 damage to target creature or player. + addCard(Zone.HAND, playerB, "Lightning Blast", 3); + + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Karador, Ghost Chieftain"); + castSpell(2, PhaseStep.PRECOMBAT_MAIN, playerB, "Lightning Blast", "Karador, Ghost Chieftain"); + + castSpell(3, PhaseStep.PRECOMBAT_MAIN, playerA, "Karador, Ghost Chieftain"); + castSpell(4, PhaseStep.PRECOMBAT_MAIN, playerB, "Lightning Blast", "Karador, Ghost Chieftain"); + + castSpell(5, PhaseStep.PRECOMBAT_MAIN, playerA, "Karador, Ghost Chieftain"); + castSpell(6, PhaseStep.PRECOMBAT_MAIN, playerB, "Lightning Blast", "Karador, Ghost Chieftain"); + + castSpell(7, PhaseStep.PRECOMBAT_MAIN, playerA, "Karador, Ghost Chieftain"); + + setStopAt(7, PhaseStep.BEGIN_COMBAT); + execute(); + assertGraveyardCount(playerB, "Lightning Blast", 3); + assertPermanentCount(playerA, "Karador, Ghost Chieftain", 1); + + assertTappedCount("Island", true, 9); + } + + @Test + public void castKaradorFourTimes15Reduction() { + addCard(Zone.BATTLEFIELD, playerA, "Swamp", 1); + addCard(Zone.BATTLEFIELD, playerA, "Forest", 1); + addCard(Zone.BATTLEFIELD, playerA, "Plains", 1); + addCard(Zone.BATTLEFIELD, playerA, "Island", 11); + addCard(Zone.GRAVEYARD, playerA, "Silvercoat Lion", 15); + + addCard(Zone.BATTLEFIELD, playerB, "Mountain", 4); + // Lightning Blast deals 4 damage to target creature or player. + addCard(Zone.HAND, playerB, "Lightning Blast", 3); + + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Karador, Ghost Chieftain"); + castSpell(2, PhaseStep.PRECOMBAT_MAIN, playerB, "Lightning Blast", "Karador, Ghost Chieftain"); + + castSpell(3, PhaseStep.PRECOMBAT_MAIN, playerA, "Karador, Ghost Chieftain"); + castSpell(4, PhaseStep.PRECOMBAT_MAIN, playerB, "Lightning Blast", "Karador, Ghost Chieftain"); + + castSpell(5, PhaseStep.PRECOMBAT_MAIN, playerA, "Karador, Ghost Chieftain"); + castSpell(6, PhaseStep.PRECOMBAT_MAIN, playerB, "Lightning Blast", "Karador, Ghost Chieftain"); + + castSpell(7, PhaseStep.PRECOMBAT_MAIN, playerA, "Karador, Ghost Chieftain"); + + setStopAt(7, PhaseStep.BEGIN_COMBAT); + execute(); + assertGraveyardCount(playerB, "Lightning Blast", 3); + assertPermanentCount(playerA, "Karador, Ghost Chieftain", 1); + + assertTappedCount("Island", true, 0); + } +} diff --git a/Mage/src/main/java/mage/abilities/common/CastCommanderAbility.java b/Mage/src/main/java/mage/abilities/common/CastCommanderAbility.java index faaf804a0e..b980bd45ca 100644 --- a/Mage/src/main/java/mage/abilities/common/CastCommanderAbility.java +++ b/Mage/src/main/java/mage/abilities/common/CastCommanderAbility.java @@ -27,7 +27,6 @@ */ package mage.abilities.common; - import mage.abilities.SpellAbility; import mage.cards.Card; import mage.constants.SpellAbilityType; @@ -57,22 +56,14 @@ public class CastCommanderAbility extends SpellAbility { public boolean activate(Game game, boolean noMana) { if (super.activate(game, noMana)) { // save amount of times commander was cast - Integer castCount = (Integer)game.getState().getValue(sourceId + "_castCount"); - if(castCount != null){ - castCount++; - game.getState().setValue(sourceId + "_castCount", castCount); - } - else { - castCount = 1; - game.getState().setValue(sourceId + "_castCount", castCount); - } + Integer castCount = (Integer) game.getState().getValue(sourceId + "_castCount"); + castCount++; + game.getState().setValue(sourceId + "_castCount", castCount); return true; } return false; } - - @Override public CastCommanderAbility copy() { return new CastCommanderAbility(this); diff --git a/Mage/src/main/java/mage/abilities/effects/common/cost/CommanderCostModification.java b/Mage/src/main/java/mage/abilities/effects/common/cost/CommanderCostModification.java index 73cb10d770..dc503ffccd 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/cost/CommanderCostModification.java +++ b/Mage/src/main/java/mage/abilities/effects/common/cost/CommanderCostModification.java @@ -1,16 +1,16 @@ /* * 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 @@ -20,7 +20,7 @@ * 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. @@ -40,15 +40,14 @@ import mage.game.Game; * * @author Plopman */ - //20130711 /*903.10. A player may cast a commander he or she owns from the command zone. * Doing so costs that player an additional {2} for each previous time he or she cast that commander from the command zone that game. * */ public class CommanderCostModification extends CostModificationEffectImpl { - private UUID commanderId; - + private final UUID commanderId; + public CommanderCostModification(UUID commanderId) { super(Duration.Custom, Outcome.Neutral, CostModificationType.INCREASE_COST); this.commanderId = commanderId; @@ -61,22 +60,17 @@ public class CommanderCostModification extends CostModificationEffectImpl { @Override public boolean apply(Game game, Ability source, Ability abilityToModify) { - Integer castCount = (Integer)game.getState().getValue(commanderId + "_castCount"); - if(castCount == null){ - castCount = 0; - game.getState().setValue(commanderId + "_castCount", castCount); - } - abilityToModify.getManaCostsToPay().add(new GenericManaCost(2*castCount)); + Integer castCount = (Integer) game.getState().getValue(commanderId + "_castCount"); + if (castCount > 0) { + abilityToModify.getManaCostsToPay().add(new GenericManaCost(2 * castCount)); + } return true; - + } @Override public boolean applies(Ability abilityToModify, Ability source, Game game) { - if (abilityToModify instanceof CastCommanderAbility && abilityToModify.getSourceId().equals(commanderId)) { - return true; - } - return false; + return abilityToModify instanceof CastCommanderAbility && abilityToModify.getSourceId().equals(commanderId); } @Override