mirror of
https://github.com/magefree/mage.git
synced 2025-12-29 23:12:10 -08:00
implement [MH3] Nethergoyf, refactor targets usages by game param (#12267)
This commit is contained in:
parent
88b6f4036f
commit
754b382e78
62 changed files with 592 additions and 285 deletions
|
|
@ -0,0 +1,193 @@
|
|||
package org.mage.test.cards.single.mh3;
|
||||
|
||||
import mage.constants.PhaseStep;
|
||||
import mage.constants.Zone;
|
||||
import org.junit.Test;
|
||||
import org.mage.test.serverside.base.CardTestPlayerBaseWithAIHelps;
|
||||
|
||||
/**
|
||||
* @author Susucr
|
||||
*/
|
||||
public class NethergoyfTest extends CardTestPlayerBaseWithAIHelps {
|
||||
|
||||
/**
|
||||
* {@link mage.cards.n.Nethergoyf Nethergoyf} {B}
|
||||
* Creature — Lhurgoyf
|
||||
* Nethergoyf’s power is equal to the number of card types among cards in your graveyard and its toughness is equal to that number plus 1.
|
||||
* Escape—{2}{B}, Exile any number of other cards from your graveyard with four or more card types among them. (You may cast this card from your graveyard for its escape cost.)
|
||||
* * / 1+*
|
||||
*/
|
||||
private static final String nethergoyf = "Nethergoyf";
|
||||
|
||||
@Test
|
||||
public void test_Escape_Two_DualTypes() {
|
||||
setStrictChooseMode(true);
|
||||
|
||||
addCard(Zone.GRAVEYARD, playerA, nethergoyf);
|
||||
addCard(Zone.BATTLEFIELD, playerA, "Swamp", 3);
|
||||
addCard(Zone.GRAVEYARD, playerA, "Memnite"); // Creature Artifact
|
||||
addCard(Zone.GRAVEYARD, playerA, "Bitterblossom"); // Tribal Enchantment
|
||||
|
||||
checkPlayableAbility("can escape", 1, PhaseStep.PRECOMBAT_MAIN, playerA, "Cast " + nethergoyf + " with Escape", true);
|
||||
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, nethergoyf + " with Escape");
|
||||
setChoice(playerA, "Memnite^Bitterblossom"); // cards exiled for escape cost
|
||||
|
||||
setStopAt(1, PhaseStep.BEGIN_COMBAT);
|
||||
execute();
|
||||
|
||||
assertPermanentCount(playerA, nethergoyf, 1);
|
||||
assertPowerToughness(playerA, nethergoyf, 0, 1);
|
||||
assertExileCount(playerA, 2);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test_AI_Escape_Two_DualTypes() {
|
||||
setStrictChooseMode(true);
|
||||
|
||||
addCard(Zone.GRAVEYARD, playerA, nethergoyf);
|
||||
addCard(Zone.BATTLEFIELD, playerA, "Swamp", 3);
|
||||
addCard(Zone.GRAVEYARD, playerA, "Memnite"); // Creature Artifact
|
||||
addCard(Zone.GRAVEYARD, playerA, "Bitterblossom"); // Tribal Enchantment
|
||||
|
||||
checkPlayableAbility("can escape", 1, PhaseStep.PRECOMBAT_MAIN, playerA, "Cast " + nethergoyf + " with Escape", true);
|
||||
aiPlayStep(1, PhaseStep.PRECOMBAT_MAIN, playerA);
|
||||
|
||||
setStopAt(1, PhaseStep.BEGIN_COMBAT);
|
||||
execute();
|
||||
|
||||
assertPermanentCount(playerA, nethergoyf, 1);
|
||||
assertPowerToughness(playerA, nethergoyf, 0, 1);
|
||||
assertExileCount(playerA, 2);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test_Escape_MoreCardsThanNeeded() {
|
||||
setStrictChooseMode(true);
|
||||
|
||||
addCard(Zone.GRAVEYARD, playerA, nethergoyf);
|
||||
addCard(Zone.BATTLEFIELD, playerA, "Swamp", 3);
|
||||
addCard(Zone.GRAVEYARD, playerA, "Memnite", 5); // Creature Artifact
|
||||
addCard(Zone.GRAVEYARD, playerA, "Bitterblossom"); // Tribal Enchantment
|
||||
|
||||
checkPlayableAbility("can escape", 1, PhaseStep.PRECOMBAT_MAIN, playerA, "Cast " + nethergoyf + " with Escape", true);
|
||||
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, nethergoyf + " with Escape");
|
||||
setChoice(playerA, "Memnite^Memnite^Memnite^Memnite^Bitterblossom"); // cards exiled for escape cost: Exile all the Memnite but one.
|
||||
|
||||
setStopAt(1, PhaseStep.BEGIN_COMBAT);
|
||||
execute();
|
||||
|
||||
assertPermanentCount(playerA, nethergoyf, 1);
|
||||
assertPowerToughness(playerA, nethergoyf, 2, 3); // 1 Memnite in graveyard
|
||||
assertExileCount(playerA, 5);
|
||||
assertGraveyardCount(playerA, 1);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test_AI_Escape_MoreCardsThanNeeded() {
|
||||
setStrictChooseMode(true);
|
||||
|
||||
addCard(Zone.GRAVEYARD, playerA, nethergoyf);
|
||||
addCard(Zone.BATTLEFIELD, playerA, "Swamp", 3);
|
||||
addCard(Zone.GRAVEYARD, playerA, "Bitterblossom"); // Tribal Enchantment
|
||||
addCard(Zone.GRAVEYARD, playerA, "Memnite", 5); // Creature Artifact
|
||||
|
||||
aiPlayStep(1, PhaseStep.PRECOMBAT_MAIN, playerA);
|
||||
|
||||
setStopAt(1, PhaseStep.BEGIN_COMBAT);
|
||||
execute();
|
||||
|
||||
assertPermanentCount(playerA, nethergoyf, 1);
|
||||
assertPowerToughness(playerA, nethergoyf, 0, 1);
|
||||
assertExileCount(playerA, 6); // It is weird, but AI likes to choose all to be exiled, even though the Outcome is Exile (so detriment)
|
||||
assertGraveyardCount(playerA, 0);
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void test_CantEscape_Without4TypesInGraveyard() {
|
||||
setStrictChooseMode(true);
|
||||
|
||||
addCard(Zone.GRAVEYARD, playerA, nethergoyf);
|
||||
addCard(Zone.BATTLEFIELD, playerA, "Swamp", 3);
|
||||
addCard(Zone.GRAVEYARD, playerA, "Taiga"); // Land
|
||||
addCard(Zone.GRAVEYARD, playerA, "Bitterblossom"); // Tribal Enchantment
|
||||
|
||||
checkPlayableAbility("can't escape", 1, PhaseStep.PRECOMBAT_MAIN, playerA, "Cast " + nethergoyf + " with Escape", false);
|
||||
// 3 types from other cards in graveyard, Nethergoyf can't escape
|
||||
|
||||
setStopAt(1, PhaseStep.BEGIN_COMBAT);
|
||||
execute();
|
||||
|
||||
assertGraveyardCount(playerA, 3);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test_AI_CantEscape_Without4TypesInGraveyard() {
|
||||
setStrictChooseMode(true);
|
||||
|
||||
addCard(Zone.GRAVEYARD, playerA, nethergoyf);
|
||||
addCard(Zone.BATTLEFIELD, playerA, "Swamp", 3);
|
||||
addCard(Zone.GRAVEYARD, playerA, "Taiga"); // Land
|
||||
addCard(Zone.GRAVEYARD, playerA, "Bitterblossom"); // Tribal Enchantment
|
||||
|
||||
checkPlayableAbility("can't escape", 1, PhaseStep.PRECOMBAT_MAIN, playerA, "Cast " + nethergoyf + " with Escape", false);
|
||||
// 3 types from other cards in graveyard, Nethergoyf can't escape
|
||||
aiPlayStep(1, PhaseStep.PRECOMBAT_MAIN, playerA);
|
||||
|
||||
setStopAt(1, PhaseStep.BEGIN_COMBAT);
|
||||
execute();
|
||||
|
||||
assertGraveyardCount(playerA, 3);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test_DynamicGameType() {
|
||||
setStrictChooseMode(true);
|
||||
|
||||
addCard(Zone.GRAVEYARD, playerA, nethergoyf);
|
||||
addCard(Zone.BATTLEFIELD, playerA, "Underground Sea", 7);
|
||||
addCard(Zone.GRAVEYARD, playerA, "Taiga"); // Land
|
||||
addCard(Zone.GRAVEYARD, playerA, "Grist, the Hunger Tide"); // Planeswalker, is a Creature if not in play
|
||||
// Nonland permanents you control are artifacts in addition to their other types.
|
||||
// The same is true for permanent spells you control and nonland permanent cards you own that aren’t on the battlefield.
|
||||
addCard(Zone.HAND, playerA, "Encroaching Mycosynth");
|
||||
|
||||
checkPlayableAbility("1: can't escape", 1, PhaseStep.PRECOMBAT_MAIN, playerA, "Cast " + nethergoyf + " with Escape", false);
|
||||
// 3 types from other cards in graveyard, Nethergoyf can't escape
|
||||
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Encroaching Mycosynth", true);
|
||||
// After Mycosynth in play, Grist is now an Artifact in addition to its other types
|
||||
checkPlayableAbility("2: can", 1, PhaseStep.PRECOMBAT_MAIN, playerA, "Cast " + nethergoyf + " with Escape", true);
|
||||
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, nethergoyf + " with Escape");
|
||||
setChoice(playerA, "Taiga^Grist, the Hunger Tide"); // cards exiled for escape cost
|
||||
|
||||
setStopAt(1, PhaseStep.BEGIN_COMBAT);
|
||||
execute();
|
||||
|
||||
assertPermanentCount(playerA, nethergoyf, 1);
|
||||
assertPowerToughness(playerA, nethergoyf, 0, 1);
|
||||
assertExileCount(playerA, 2);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test_AI_DynamicGameType() {
|
||||
setStrictChooseMode(true);
|
||||
|
||||
addCard(Zone.GRAVEYARD, playerA, nethergoyf);
|
||||
addCard(Zone.BATTLEFIELD, playerA, "Underground Sea", 7);
|
||||
addCard(Zone.GRAVEYARD, playerA, "Taiga"); // Land
|
||||
addCard(Zone.GRAVEYARD, playerA, "Grist, the Hunger Tide"); // Planeswalker, is a Creature if not in play
|
||||
|
||||
// Nonland permanents you control are artifacts in addition to their other types.
|
||||
// The same is true for permanent spells you control and nonland permanent cards you own that aren’t on the battlefield.
|
||||
addCard(Zone.HAND, playerA, "Encroaching Mycosynth");
|
||||
|
||||
aiPlayStep(1, PhaseStep.PRECOMBAT_MAIN, playerA);
|
||||
|
||||
setStopAt(1, PhaseStep.BEGIN_COMBAT);
|
||||
execute();
|
||||
|
||||
assertPermanentCount(playerA, nethergoyf, 1);
|
||||
assertPowerToughness(playerA, nethergoyf, 0, 1);
|
||||
assertExileCount(playerA, 2);
|
||||
}
|
||||
}
|
||||
|
|
@ -2001,8 +2001,8 @@ public class TestPlayer implements Player {
|
|||
return "Ability: null";
|
||||
}
|
||||
|
||||
private String getInfo(Target o) {
|
||||
return "Target: " + (o != null ? o.getClass().getSimpleName() + ": " + o.getMessage() : "null");
|
||||
private String getInfo(Target o, Game game) {
|
||||
return "Target: " + (o != null ? o.getClass().getSimpleName() + ": " + o.getMessage(game) : "null");
|
||||
}
|
||||
|
||||
private void assertAliasSupportInChoices(boolean methodSupportAliases) {
|
||||
|
|
@ -2167,7 +2167,7 @@ public class TestPlayer implements Player {
|
|||
}
|
||||
|
||||
// ignore player select
|
||||
if (target.getMessage().equals("Select a starting player")) {
|
||||
if (target.getMessage(game).equals("Select a starting player")) {
|
||||
return computerPlayer.choose(outcome, target, source, game, options);
|
||||
}
|
||||
|
||||
|
|
@ -2317,7 +2317,7 @@ public class TestPlayer implements Player {
|
|||
|
||||
// apply only on ALL targets or revert
|
||||
if (usedChoices.size() > 0) {
|
||||
if (target.isChosen()) {
|
||||
if (target.isChosen(game)) {
|
||||
// remove all used choices
|
||||
for (int i = choices.size(); i >= 0; i--) {
|
||||
if (usedChoices.contains(i)) {
|
||||
|
|
@ -2369,7 +2369,7 @@ public class TestPlayer implements Player {
|
|||
}
|
||||
}
|
||||
|
||||
this.chooseStrictModeFailed("choice", game, getInfo(source, game) + "\n" + getInfo(target));
|
||||
this.chooseStrictModeFailed("choice", game, getInfo(source, game) + "\n" + getInfo(target, game));
|
||||
return computerPlayer.choose(outcome, target, source, game, options);
|
||||
}
|
||||
|
||||
|
|
@ -2690,19 +2690,19 @@ public class TestPlayer implements Player {
|
|||
message = this.getName() + " - Targets list was setup by addTarget with " + targets + ", but not used"
|
||||
+ "\nCard: " + source.getSourceObject(game)
|
||||
+ "\nAbility: " + source.getClass().getSimpleName() + " (" + source.getRule() + ")"
|
||||
+ "\nTarget: " + target.getClass().getSimpleName() + " (" + target.getMessage() + ")"
|
||||
+ "\nTarget: " + target.getClass().getSimpleName() + " (" + target.getMessage(game) + ")"
|
||||
+ "\nYou must implement target class support in TestPlayer, \"filter instanceof\", or setup good targets";
|
||||
} else {
|
||||
message = this.getName() + " - Targets list was setup by addTarget with " + targets + ", but not used"
|
||||
+ "\nCard: unknown source"
|
||||
+ "\nAbility: unknown source"
|
||||
+ "\nTarget: " + target.getClass().getSimpleName() + " (" + target.getMessage() + ")"
|
||||
+ "\nTarget: " + target.getClass().getSimpleName() + " (" + target.getMessage(game) + ")"
|
||||
+ "\nYou must implement target class support in TestPlayer, \"filter instanceof\", or setup good targets";
|
||||
}
|
||||
Assert.fail(message);
|
||||
}
|
||||
|
||||
this.chooseStrictModeFailed("target", game, getInfo(source, game) + "\n" + getInfo(target));
|
||||
this.chooseStrictModeFailed("target", game, getInfo(source, game) + "\n" + getInfo(target, game));
|
||||
return computerPlayer.chooseTarget(outcome, target, source, game);
|
||||
}
|
||||
|
||||
|
|
@ -2748,7 +2748,7 @@ public class TestPlayer implements Player {
|
|||
LOGGER.warn("Wrong target");
|
||||
}
|
||||
|
||||
this.chooseStrictModeFailed("target", game, getInfo(source, game) + "\n" + getInfo(target));
|
||||
this.chooseStrictModeFailed("target", game, getInfo(source, game) + "\n" + getInfo(target, game));
|
||||
return computerPlayer.chooseTarget(outcome, cards, target, source, game);
|
||||
}
|
||||
|
||||
|
|
@ -4134,7 +4134,7 @@ public class TestPlayer implements Player {
|
|||
assertWrongChoiceUsage(choices.size() > 0 ? choices.get(0) : "empty list");
|
||||
}
|
||||
|
||||
this.chooseStrictModeFailed("choice", game, getInfo(source, game) + "\n" + getInfo(target));
|
||||
this.chooseStrictModeFailed("choice", game, getInfo(source, game) + "\n" + getInfo(target, game));
|
||||
return computerPlayer.choose(outcome, cards, target, source, game);
|
||||
}
|
||||
|
||||
|
|
@ -4207,7 +4207,7 @@ public class TestPlayer implements Player {
|
|||
}
|
||||
}
|
||||
|
||||
this.chooseStrictModeFailed("target", game, getInfo(source, game) + "\n" + getInfo(target));
|
||||
this.chooseStrictModeFailed("target", game, getInfo(source, game) + "\n" + getInfo(target, game));
|
||||
return computerPlayer.chooseTargetAmount(outcome, target, source, game);
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue