fix that Manamorphose can't be used to cast Imperiosaur (#11620)

This commit is contained in:
xenohedron 2024-01-07 14:22:20 -05:00 committed by GitHub
parent 5376e81d90
commit 98a3d8b947
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 230 additions and 7 deletions

View file

@ -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 spells 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);
}
}

View file

@ -6,6 +6,7 @@ import mage.MageObject;
import mage.Mana; import mage.Mana;
import mage.abilities.Ability; import mage.abilities.Ability;
import mage.abilities.costs.Cost; import mage.abilities.costs.Cost;
import mage.abilities.effects.mana.ManaEffect;
import mage.constants.Duration; import mage.constants.Duration;
import mage.constants.ManaType; import mage.constants.ManaType;
import mage.constants.TurnPhase; import mage.constants.TurnPhase;
@ -138,13 +139,19 @@ public class ManaPool implements Serializable {
} }
for (ManaPoolItem mana : manaItems) { for (ManaPoolItem mana : manaItems) {
if (filter != null) { if (filter != null && !filter.match(mana.getSourceObject(), game)) {
if (!filter.match(mana.getSourceObject(), game)) { // If here, then mana source does not match the filter
// Prevent that cost reduction by convoke is filtered out // However, alternate mana payment abilities such as convoke won't match the filter but are valid
if (!(mana.getSourceObject() instanceof Spell) // So we need to do some ugly checks to allow them
|| ability.getSourceId().equals(mana.getSourceId())) { // For convoke, mana apparently comes from a spell without a mana effect, that doesn't match the ability source
continue; 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 if (possibleAsThoughPoolManaType == null