mirror of
https://github.com/magefree/mage.git
synced 2025-12-20 10:40:06 -08:00
fix that Manamorphose can't be used to cast Imperiosaur (#11620)
This commit is contained in:
parent
5376e81d90
commit
98a3d8b947
2 changed files with 230 additions and 7 deletions
|
|
@ -0,0 +1,216 @@
|
|||
package org.mage.test.cards.abilities.mana;
|
||||
|
||||
import mage.constants.PhaseStep;
|
||||
import mage.constants.Zone;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
import org.mage.test.serverside.base.CardTestPlayerBase;
|
||||
|
||||
/**
|
||||
* Note: game engine does not currently support checkPlayable for mana source filter, hence try/catch for tests
|
||||
*
|
||||
* @author xenohedron
|
||||
*/
|
||||
public class SpendOnlyManaProducedByTest extends CardTestPlayerBase {
|
||||
|
||||
private static final String imperiosaur = "Imperiosaur"; // 2GG
|
||||
// Spend only mana produced by basic lands to cast this spell.
|
||||
|
||||
private static final String myrSuperion = "Myr Superion"; // 2
|
||||
// Spend only mana produced by creatures to cast this spell.
|
||||
|
||||
private static final String securityRhox = "Security Rhox"; // 2RG
|
||||
// You may pay {R}{G} rather than pay this spell’s mana cost. Spend only mana produced by Treasures to cast it this way.
|
||||
|
||||
private static final String rapaciousDragon = "Rapacious Dragon"; // 4R
|
||||
// When Rapacious Dragon enters the battlefield, create two Treasure tokens.
|
||||
|
||||
@Test
|
||||
public void testImperiosaurPlayable() {
|
||||
addCard(Zone.HAND, playerA, imperiosaur);
|
||||
addCard(Zone.BATTLEFIELD, playerA, "Forest", 4);
|
||||
|
||||
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, imperiosaur);
|
||||
|
||||
setStrictChooseMode(true);
|
||||
setStopAt(1, PhaseStep.POSTCOMBAT_MAIN);
|
||||
execute();
|
||||
|
||||
assertPermanentCount(playerA, imperiosaur, 1);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void tryToCastImperiosaur() {
|
||||
addCard(Zone.HAND, playerA, imperiosaur);
|
||||
addCard(Zone.BATTLEFIELD, playerA, "Tree of Tales", 4);
|
||||
|
||||
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, imperiosaur);
|
||||
|
||||
setStrictChooseMode(true);
|
||||
setStopAt(1, PhaseStep.POSTCOMBAT_MAIN);
|
||||
String expectedError = "Can't find ability to activate command: Cast Imperiosaur";
|
||||
String foundError = "";
|
||||
try {
|
||||
execute();
|
||||
} catch (AssertionError e) {
|
||||
foundError = e.getMessage();
|
||||
}
|
||||
Assert.assertEquals(expectedError, foundError);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void tryToCastImperiosaurAgain() {
|
||||
addCard(Zone.HAND, playerA, imperiosaur);
|
||||
addCard(Zone.BATTLEFIELD, playerA, "Elvish Mystic", 1);
|
||||
addCard(Zone.BATTLEFIELD, playerA, "Forest", 3);
|
||||
|
||||
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, imperiosaur);
|
||||
|
||||
setStrictChooseMode(true);
|
||||
setStopAt(1, PhaseStep.POSTCOMBAT_MAIN);
|
||||
String expectedError = "Can't find ability to activate command: Cast Imperiosaur";
|
||||
String foundError = "";
|
||||
try {
|
||||
execute();
|
||||
} catch (AssertionError e) {
|
||||
foundError = e.getMessage();
|
||||
}
|
||||
Assert.assertEquals(expectedError, foundError);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void imperiosaurManamorphose() {
|
||||
String manamorphose = "Manamorphose"; // add two mana in any combination of colors
|
||||
|
||||
addCard(Zone.HAND, playerA, imperiosaur);
|
||||
addCard(Zone.HAND, playerA, manamorphose);
|
||||
addCard(Zone.BATTLEFIELD, playerA, "Forest", 4);
|
||||
|
||||
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, manamorphose);
|
||||
setChoiceAmount(playerA, 0, 0, 0, 0, 2);
|
||||
waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN);
|
||||
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, imperiosaur);
|
||||
|
||||
setStrictChooseMode(true);
|
||||
setStopAt(1, PhaseStep.POSTCOMBAT_MAIN);
|
||||
String expectedError = "Can't find ability to activate command: Cast Imperiosaur";
|
||||
String foundError = "";
|
||||
try {
|
||||
execute();
|
||||
} catch (AssertionError e) {
|
||||
foundError = e.getMessage();
|
||||
}
|
||||
Assert.assertEquals(expectedError, foundError);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void tryToCastMyrSuperion() {
|
||||
addCard(Zone.HAND, playerA, myrSuperion);
|
||||
addCard(Zone.BATTLEFIELD, playerA, "Wastes", 2);
|
||||
|
||||
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, myrSuperion);
|
||||
|
||||
setStrictChooseMode(true);
|
||||
setStopAt(1, PhaseStep.POSTCOMBAT_MAIN);
|
||||
String expectedError = "Can't find ability to activate command: Cast Myr Superion";
|
||||
String foundError = "";
|
||||
try {
|
||||
execute();
|
||||
} catch (AssertionError e) {
|
||||
foundError = e.getMessage();
|
||||
}
|
||||
Assert.assertEquals(expectedError, foundError);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void castMyrSuperion() {
|
||||
addCard(Zone.HAND, playerA, myrSuperion);
|
||||
addCard(Zone.BATTLEFIELD, playerA, "Palladium Myr");
|
||||
|
||||
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, myrSuperion);
|
||||
|
||||
setStrictChooseMode(true);
|
||||
setStopAt(1, PhaseStep.POSTCOMBAT_MAIN);
|
||||
execute();
|
||||
|
||||
assertPermanentCount(playerA, myrSuperion, 1);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void castMyrSuperionWithConvoke() {
|
||||
addCard(Zone.HAND, playerA, myrSuperion);
|
||||
addCard(Zone.BATTLEFIELD, playerA, "Silver Myr");
|
||||
addCard(Zone.BATTLEFIELD, playerA, "Chief Engineer"); // artifact creature spells you cast have convoke
|
||||
|
||||
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, myrSuperion);
|
||||
addTarget(playerA, "Chief Engineer"); // tap for convoke
|
||||
|
||||
setStrictChooseMode(true);
|
||||
setStopAt(1, PhaseStep.POSTCOMBAT_MAIN);
|
||||
execute();
|
||||
|
||||
assertPermanentCount(playerA, myrSuperion, 1);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void tryToCastMyrSuperionWithConvoke() {
|
||||
addCard(Zone.HAND, playerA, myrSuperion);
|
||||
addCard(Zone.BATTLEFIELD, playerA, "Island");
|
||||
addCard(Zone.BATTLEFIELD, playerA, "Chief Engineer"); // artifact creature spells you cast have convoke
|
||||
|
||||
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, myrSuperion);
|
||||
addTarget(playerA, "Chief Engineer"); // tap for convoke
|
||||
|
||||
setStrictChooseMode(true);
|
||||
setStopAt(1, PhaseStep.POSTCOMBAT_MAIN);
|
||||
String expectedError = "Can't find ability to activate command: Cast Myr Superion";
|
||||
String foundError = "";
|
||||
try {
|
||||
execute();
|
||||
} catch (AssertionError e) {
|
||||
foundError = e.getMessage();
|
||||
}
|
||||
Assert.assertEquals(expectedError, foundError);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void castSecurityRhox() {
|
||||
addCard(Zone.HAND, playerA, rapaciousDragon);
|
||||
addCard(Zone.HAND, playerA, securityRhox);
|
||||
addCard(Zone.BATTLEFIELD, playerA, "Mountain", 5);
|
||||
|
||||
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, rapaciousDragon);
|
||||
castSpell(1, PhaseStep.POSTCOMBAT_MAIN, playerA, securityRhox);
|
||||
setChoice(playerA, true); // pay alternative cost
|
||||
setChoice(playerA, "Red");
|
||||
setChoice(playerA, "Green");
|
||||
|
||||
setStrictChooseMode(true);
|
||||
setStopAt(1, PhaseStep.END_TURN);
|
||||
execute();
|
||||
|
||||
assertPermanentCount(playerA, rapaciousDragon, 1);
|
||||
assertPermanentCount(playerA, securityRhox, 1);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void cantCastSecurityRhox() {
|
||||
addCard(Zone.HAND, playerA, securityRhox);
|
||||
addCard(Zone.BATTLEFIELD, playerA, "Taiga", 2);
|
||||
|
||||
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, securityRhox);
|
||||
setChoice(playerA, true); // pay alternative cost
|
||||
|
||||
setStrictChooseMode(true);
|
||||
setStopAt(1, PhaseStep.POSTCOMBAT_MAIN);
|
||||
String expectedError = "Can't find ability to activate command: Cast Security Rhox";
|
||||
String foundError = "";
|
||||
try {
|
||||
execute();
|
||||
} catch (AssertionError e) {
|
||||
foundError = e.getMessage();
|
||||
}
|
||||
Assert.assertEquals(expectedError, foundError);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -6,6 +6,7 @@ import mage.MageObject;
|
|||
import mage.Mana;
|
||||
import mage.abilities.Ability;
|
||||
import mage.abilities.costs.Cost;
|
||||
import mage.abilities.effects.mana.ManaEffect;
|
||||
import mage.constants.Duration;
|
||||
import mage.constants.ManaType;
|
||||
import mage.constants.TurnPhase;
|
||||
|
|
@ -138,13 +139,19 @@ public class ManaPool implements Serializable {
|
|||
}
|
||||
|
||||
for (ManaPoolItem mana : manaItems) {
|
||||
if (filter != null) {
|
||||
if (!filter.match(mana.getSourceObject(), game)) {
|
||||
// Prevent that cost reduction by convoke is filtered out
|
||||
if (!(mana.getSourceObject() instanceof Spell)
|
||||
|| ability.getSourceId().equals(mana.getSourceId())) {
|
||||
continue;
|
||||
}
|
||||
if (filter != null && !filter.match(mana.getSourceObject(), game)) {
|
||||
// If here, then mana source does not match the filter
|
||||
// However, alternate mana payment abilities such as convoke won't match the filter but are valid
|
||||
// So we need to do some ugly checks to allow them
|
||||
// For convoke, mana apparently comes from a spell without a mana effect, that doesn't match the ability source
|
||||
if (ability.getSourceId().equals(mana.getSourceId())
|
||||
|| !(mana.getSourceObject() instanceof Spell)
|
||||
|| ((Spell) mana.getSourceObject())
|
||||
.getAbilities(game)
|
||||
.stream()
|
||||
.flatMap(a -> a.getAllEffects().stream())
|
||||
.anyMatch(ManaEffect.class::isInstance)) {
|
||||
continue; // if any of the above cases, not an alt mana payment ability, thus excluded by filter
|
||||
}
|
||||
}
|
||||
if (possibleAsThoughPoolManaType == null
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue