1
0
Fork 0
mirror of https://github.com/correl/mage.git synced 2025-04-08 01:01:04 -09:00

* Flashback - Fixed handling of combined flashback costs (e.g. Deep Analysis).

This commit is contained in:
LevelX2 2016-09-15 17:34:25 +02:00
parent 0042dc1ad9
commit 0a5a073637
3 changed files with 98 additions and 48 deletions
Mage.Tests/src/test/java/org/mage/test/cards/abilities/keywords
Mage/src/main/java/mage
abilities/keyword
game/stack

View file

@ -73,70 +73,68 @@ public class FlashbackTest extends CardTestPlayerBase {
assertExileCount("Fracturing Gust", 1); assertExileCount("Fracturing Gust", 1);
} }
/** /**
* *
* Test Granting Flashback to spells with X in manacost which have targeting requirements depending on the choice of X * Test Granting Flashback to spells with X in manacost which have targeting
* * requirements depending on the choice of X
*
* Specific instance: Snapcaster Mage granting Flashback to Repeal * Specific instance: Snapcaster Mage granting Flashback to Repeal
*/ */
@Test @Test
public void testSnapcasterMageWithRepeal(){ public void testSnapcasterMageWithRepeal() {
addCard(Zone.BATTLEFIELD, playerA, "Island", 5); addCard(Zone.BATTLEFIELD, playerA, "Island", 5);
addCard(Zone.HAND, playerA, "Snapcaster Mage",1); addCard(Zone.HAND, playerA, "Snapcaster Mage", 1);
addCard(Zone.GRAVEYARD, playerA, "Repeal",1); addCard(Zone.GRAVEYARD, playerA, "Repeal", 1);
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Snapcaster Mage"); castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Snapcaster Mage");
setChoice(playerA, "Repeal"); setChoice(playerA, "Repeal");
activateAbility(1, PhaseStep.POSTCOMBAT_MAIN, playerA, "Flashback"); activateAbility(1, PhaseStep.POSTCOMBAT_MAIN, playerA, "Flashback");
setChoice(playerA, "X=2"); setChoice(playerA, "X=2");
addTarget(playerA, "Snapcaster Mage"); addTarget(playerA, "Snapcaster Mage");
setStopAt(1, PhaseStep.END_TURN); setStopAt(1, PhaseStep.END_TURN);
execute(); execute();
assertPermanentCount(playerA, "Snapcaster Mage", 0); assertPermanentCount(playerA, "Snapcaster Mage", 0);
assertGraveyardCount(playerA, "Repeal", 0); assertGraveyardCount(playerA, "Repeal", 0);
assertExileCount("Repeal", 1); assertExileCount("Repeal", 1);
} }
/** /**
* *
* Test Granting Flashback to spells with X in mana cost, where X has no influence on targeting requirements * Test Granting Flashback to spells with X in mana cost, where X has no
* * influence on targeting requirements
* Specific instance: *
* Snapcaser Mage granting Flashback to Blaze * Specific instance: Snapcaser Mage granting Flashback to Blaze
*/ */
@Test @Test
public void testSnapcasterMageWithBlaze(){ public void testSnapcasterMageWithBlaze() {
addCard(Zone.BATTLEFIELD, playerA, "Island", 5); addCard(Zone.BATTLEFIELD, playerA, "Island", 5);
addCard(Zone.BATTLEFIELD, playerA, "Mountain", 1); addCard(Zone.BATTLEFIELD, playerA, "Mountain", 1);
addCard(Zone.HAND, playerA, "Snapcaster Mage",1);
addCard(Zone.GRAVEYARD, playerA, "Blaze",1);
addCard(Zone.HAND, playerA, "Snapcaster Mage", 1);
addCard(Zone.GRAVEYARD, playerA, "Blaze", 1);
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Snapcaster Mage"); castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Snapcaster Mage");
setChoice(playerA, "B laze"); setChoice(playerA, "B laze");
activateAbility(1, PhaseStep.POSTCOMBAT_MAIN, playerA, "Flashback"); activateAbility(1, PhaseStep.POSTCOMBAT_MAIN, playerA, "Flashback");
setChoice(playerA, "X=1"); setChoice(playerA, "X=1");
addTarget(playerA, "Snapcaster Mage"); addTarget(playerA, "Snapcaster Mage");
setStopAt(1, PhaseStep.END_TURN); setStopAt(1, PhaseStep.END_TURN);
execute(); execute();
assertPermanentCount(playerA, "Snapcaster Mage", 0); assertPermanentCount(playerA, "Snapcaster Mage", 0);
assertGraveyardCount(playerA, "Blaze", 0); assertGraveyardCount(playerA, "Blaze", 0);
assertExileCount("Blaze", 1); assertExileCount("Blaze", 1);
} }
/** /**
* My opponent put Iona on the battlefield using Unburial Rites, but my game * My opponent put Iona on the battlefield using Unburial Rites, but my game
* log didn't show me the color he has chosen. * log didn't show me the color he has chosen.
@ -369,4 +367,26 @@ public class FlashbackTest extends CardTestPlayerBase {
} }
/**
* Deep Analysis doesn't cost mana when flashbacked.
*/
@Test
public void testCombinedFlashbackCosts() {
addCard(Zone.BATTLEFIELD, playerA, "Island", 2);
// Target player draws two cards.
// Flashback-{1}{U}, Pay 3 life.
addCard(Zone.GRAVEYARD, playerA, "Deep Analysis", 1); // Sorcery {3}{U}
activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Flashback"); // Flashback Deep Analysis
addTarget(playerA, playerA);
setStopAt(1, PhaseStep.BEGIN_COMBAT);
execute();
assertGraveyardCount(playerA, "Deep Analysis", 0);
assertLife(playerA, 17);
assertLife(playerB, 20);
assertHandCount(playerA, 2);
assertTappedCount("Island", true, 2);
}
} }

View file

@ -27,11 +27,14 @@
*/ */
package mage.abilities.keyword; package mage.abilities.keyword;
import java.util.Iterator;
import java.util.UUID; import java.util.UUID;
import mage.abilities.Ability; import mage.abilities.Ability;
import mage.abilities.SpellAbility; import mage.abilities.SpellAbility;
import mage.abilities.costs.Cost; import mage.abilities.costs.Cost;
import mage.abilities.costs.Costs;
import mage.abilities.costs.VariableCost; import mage.abilities.costs.VariableCost;
import mage.abilities.costs.mana.ManaCost;
import mage.abilities.effects.ContinuousEffect; import mage.abilities.effects.ContinuousEffect;
import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.OneShotEffect;
import mage.abilities.effects.ReplacementEffectImpl; import mage.abilities.effects.ReplacementEffectImpl;
@ -200,9 +203,30 @@ class FlashbackEffect extends OneShotEffect {
spellAbility.getManaCosts().clear(); spellAbility.getManaCosts().clear();
spellAbility.getManaCosts().addAll(source.getManaCosts()); spellAbility.getManaCosts().addAll(source.getManaCosts());
// needed to get e.g. paid costs from Conflagrate // needed to get e.g. paid costs from Conflagrate
for (Cost cost : source.getCosts()) { for (Cost cost : source.getCosts()) {
if (!(cost instanceof VariableCost)) { if (cost instanceof Costs) {
spellAbility.getCosts().add(cost); Costs listOfcosts = (Costs) cost;
for (Iterator itListOfcosts = listOfcosts.iterator(); itListOfcosts.hasNext();) {
Object singleCost = itListOfcosts.next();
if (singleCost instanceof ManaCost) {
((ManaCost) singleCost).clearPaid();
spellAbility.getManaCosts().add((ManaCost) singleCost);
spellAbility.getManaCostsToPay().add((ManaCost) singleCost);
} else {
spellAbility.getCosts().add((Cost) singleCost);
}
}
}
if (!(cost instanceof VariableCost) && !(cost instanceof Costs)) {
if (cost instanceof ManaCost) {
spellAbility.getManaCosts().add((ManaCost) cost);
spellAbility.getManaCostsToPay().add((ManaCost) cost);
} else {
spellAbility.getCosts().add(cost);
}
} }
} }
if (!game.isSimulation()) { if (!game.isSimulation()) {
@ -217,8 +241,10 @@ class FlashbackEffect extends OneShotEffect {
return false; return false;
} }
} }
return false; return false;
} }
} }
class FlashbackReplacementEffect extends ReplacementEffectImpl { class FlashbackReplacementEffect extends ReplacementEffectImpl {

View file

@ -141,16 +141,20 @@ public class Spell extends StackObjImpl implements Card {
if (!spellAbilities.get(0).activate(game, noMana)) { if (!spellAbilities.get(0).activate(game, noMana)) {
return false; return false;
} }
// if there are more abilities (fused split spell) or first ability added new abilities (splice), activate the additional abilities if (spellAbilities.size() > 1) {
boolean ignoreAbility = true; // if there are more abilities (fused split spell) or first ability added new abilities (splice), activate the additional abilities
boolean payNoMana = noMana; boolean ignoreAbility = true;
for (SpellAbility spellAbility : spellAbilities) { boolean payNoMana = noMana;
// costs for spliced abilities were added to main spellAbility, so pay no mana for spliced abilities for (SpellAbility spellAbility : spellAbilities) {
payNoMana |= spellAbility.getSpellAbilityType().equals(SpellAbilityType.SPLICE); if (ignoreAbility) {
if (ignoreAbility) { ignoreAbility = false;
ignoreAbility = false; } else {
} else if (!spellAbility.activate(game, payNoMana)) { // costs for spliced abilities were added to main spellAbility, so pay no mana for spliced abilities
return false; payNoMana |= spellAbility.getSpellAbilityType().equals(SpellAbilityType.SPLICE);
if (!spellAbility.activate(game, payNoMana)) {
return false;
}
}
} }
} }
return true; return true;
@ -490,7 +494,7 @@ public class Spell extends StackObjImpl implements Card {
public ObjectColor getColor(Game game) { public ObjectColor getColor(Game game) {
return color; return color;
} }
@Override @Override
public ObjectColor getFrameColor(Game game) { public ObjectColor getFrameColor(Game game) {
return frameColor; return frameColor;
@ -536,7 +540,7 @@ public class Spell extends StackObjImpl implements Card {
public MageInt getToughness() { public MageInt getToughness() {
return card.getToughness(); return card.getToughness();
} }
@Override @Override
public int getStartingLoyalty() { public int getStartingLoyalty() {
return card.getStartingLoyalty(); return card.getStartingLoyalty();
@ -595,7 +599,7 @@ public class Spell extends StackObjImpl implements Card {
public String getTokenSetCode() { public String getTokenSetCode() {
return card.getTokenSetCode(); return card.getTokenSetCode();
} }
@Override @Override
public String getTokenDescriptor() { public String getTokenDescriptor() {
return card.getTokenDescriptor(); return card.getTokenDescriptor();