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:
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
|
@ -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);
|
||||||
|
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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 {
|
||||||
|
|
|
@ -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();
|
||||||
|
|
Loading…
Add table
Reference in a new issue