mirror of
https://github.com/magefree/mage.git
synced 2026-01-25 12:49:39 -08:00
Merge branch 'master' into refactor/multiple-names
This commit is contained in:
commit
f4c55dfc45
67 changed files with 1228 additions and 169 deletions
|
|
@ -22,7 +22,7 @@ import java.util.Set;
|
|||
import java.util.UUID;
|
||||
|
||||
/**
|
||||
* @author LevelX2
|
||||
* @author LevelX2, JayDi85
|
||||
*/
|
||||
public class CopySpellTest extends CardTestPlayerBase {
|
||||
|
||||
|
|
@ -905,4 +905,56 @@ public class CopySpellTest extends CardTestPlayerBase {
|
|||
Assert.fail(infoPrefix + " - " + "cards must have same zone and zcc: " + zcc1 + " - " + zone1 + " != " + zcc2 + " - " + zone2);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Bug: If Swan Song is used to counter a copied spell, no tokens are created #12883
|
||||
*/
|
||||
@Test
|
||||
public void test_LKI() {
|
||||
// Counter target enchantment, instant, or sorcery spell.
|
||||
// Its controller creates a 2/2 blue Bird creature token with flying.
|
||||
addCard(Zone.HAND, playerA, "Swan Song", 1); // {U}
|
||||
addCard(Zone.BATTLEFIELD, playerA, "Island", 1);
|
||||
//
|
||||
// Until end of turn, whenever a player casts an instant or sorcery spell, that player copies it and
|
||||
// may choose new targets for the copy.
|
||||
addCard(Zone.HAND, playerA, "Bonus Round", 1); // {1}{R}{R}
|
||||
addCard(Zone.BATTLEFIELD, playerA, "Mountain", 3);
|
||||
//
|
||||
addCard(Zone.HAND, playerA, "Lightning Bolt", 1); // {R}
|
||||
addCard(Zone.BATTLEFIELD, playerA, "Mountain", 1);
|
||||
addCard(Zone.BATTLEFIELD, playerB, "Grizzly Bears", 1);
|
||||
addCard(Zone.BATTLEFIELD, playerB, "Augmenting Automaton", 1);
|
||||
|
||||
checkPermanentCount("before", 1, PhaseStep.PRECOMBAT_MAIN, playerA, playerA, "Bird Token", 0);
|
||||
checkPermanentCount("before", 1, PhaseStep.PRECOMBAT_MAIN, playerA, playerB, "Grizzly Bears", 1);
|
||||
checkPermanentCount("before", 1, PhaseStep.PRECOMBAT_MAIN, playerA, playerB, "Augmenting Automaton", 1);
|
||||
|
||||
// prepare copy effect
|
||||
activateManaAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "{T}: Add {R}", 3);
|
||||
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Bonus Round");
|
||||
waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN);
|
||||
|
||||
// cast and duplicate bolt
|
||||
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Lightning Bolt");
|
||||
addTarget(playerA, "Grizzly Bears"); // original target
|
||||
setChoice(playerA, true); // use new target
|
||||
addTarget(playerA, "Augmenting Automaton"); // copy target
|
||||
waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN, true); // resolve copy trigger
|
||||
checkStackObject("on copy", 1, PhaseStep.PRECOMBAT_MAIN, playerA, "Cast Lightning Bolt", 2);
|
||||
|
||||
// counter copy and save Augmenting Automaton
|
||||
activateManaAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "{T}: Add {U}", 1);
|
||||
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Swan Song", "Lightning Bolt[only copy]", "Lightning Bolt", StackClause.WHILE_COPY_ON_STACK);
|
||||
setChoice(playerA, false); // no change target for duplicated counter spell (non-relevant here)
|
||||
waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN);
|
||||
|
||||
checkPermanentCount("after", 1, PhaseStep.PRECOMBAT_MAIN, playerA, playerA, "Bird Token", 1);
|
||||
checkPermanentCount("after", 1, PhaseStep.PRECOMBAT_MAIN, playerA, playerB, "Grizzly Bears", 0);
|
||||
checkPermanentCount("after", 1, PhaseStep.PRECOMBAT_MAIN, playerA, playerB, "Augmenting Automaton", 1);
|
||||
|
||||
setStrictChooseMode(true);
|
||||
setStopAt(1, PhaseStep.END_COMBAT);
|
||||
execute();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,39 @@
|
|||
package org.mage.test.cards.replacement.prevent;
|
||||
|
||||
import mage.constants.PhaseStep;
|
||||
import mage.constants.Zone;
|
||||
import org.junit.Test;
|
||||
import org.mage.test.serverside.base.CardTestPlayerBase;
|
||||
|
||||
public class TheMindskinnerTest extends CardTestPlayerBase {
|
||||
|
||||
private static final String mindskinner = "The Mindskinner"; // 10/1 can't be blocked
|
||||
// If a source you control would deal damage to an opponent, prevent that damage and each opponent mills that many cards.
|
||||
|
||||
private static final String piker = "Goblin Piker"; // 2/1
|
||||
|
||||
private static final String bolt = "Lightning Bolt";
|
||||
|
||||
@Test
|
||||
public void testPreventionAndMill() {
|
||||
addCard(Zone.BATTLEFIELD, playerA, mindskinner);
|
||||
addCard(Zone.BATTLEFIELD, playerA, piker);
|
||||
addCard(Zone.HAND, playerA, bolt);
|
||||
addCard(Zone.BATTLEFIELD, playerA, "Mountain");
|
||||
|
||||
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, bolt, playerB);
|
||||
|
||||
attack(1, playerA, piker, playerB);
|
||||
|
||||
setStrictChooseMode(true);
|
||||
setStopAt(1, PhaseStep.POSTCOMBAT_MAIN);
|
||||
execute();
|
||||
|
||||
assertLife(playerA, 20);
|
||||
assertLife(playerB, 20);
|
||||
|
||||
assertGraveyardCount(playerA, 1); // bolt
|
||||
assertGraveyardCount(playerB, 5);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1291,7 +1291,7 @@ public class TestPlayer implements Player {
|
|||
private void printStack(Game game) {
|
||||
System.out.println("Stack objects: " + game.getStack().size());
|
||||
game.getStack().forEach(stack -> {
|
||||
System.out.println(stack.getStackAbility().toString());
|
||||
System.out.println(stack.getStackAbility().toString() + (stack.isCopy() ? " [copy]" : ""));
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -514,8 +514,9 @@ public class BoosterGenerationTest extends MageTestPlayerBase {
|
|||
@Ignore // debug only: collect info about cards in boosters, see https://github.com/magefree/mage/issues/8081
|
||||
@Test
|
||||
public void test_CollectBoosterStats() {
|
||||
ExpansionSet setToAnalyse = ModernHorizons3.getInstance();
|
||||
int openBoosters = 10000;
|
||||
ExpansionSet setToAnalyse = NewPhyrexia.getInstance();
|
||||
// Takes about a minute for 100,000 boosters
|
||||
int openBoosters = 100000;
|
||||
|
||||
Map<String, Integer> resRatio = new HashMap<>();
|
||||
int totalCards = 0;
|
||||
|
|
@ -523,11 +524,23 @@ public class BoosterGenerationTest extends MageTestPlayerBase {
|
|||
List<Card> booster = setToAnalyse.createBooster();
|
||||
totalCards += booster.size();
|
||||
booster.forEach(card -> {
|
||||
String code = String.format("%s %s %s", card.getExpansionSetCode(), card.getRarity().getCode(), card.getName());
|
||||
String code = String.format("%s %s %s", card.getExpansionSetCode(), card.getRarity().toString().charAt(0), card.getName());
|
||||
resRatio.putIfAbsent(code, 0);
|
||||
resRatio.computeIfPresent(code, (u, count) -> count + 1);
|
||||
});
|
||||
}
|
||||
System.out.println(setToAnalyse.getName() + " - boosters opened: " + openBoosters + ". Found cards: " + totalCards + "\n");
|
||||
for (char rarity : Arrays.asList('C', 'U', 'R', 'M', 'S', 'L', 'B')) {
|
||||
List<Integer> rarityCounts = resRatio.entrySet().stream()
|
||||
.filter(e -> e.getKey().charAt(4) == rarity)
|
||||
.map(Map.Entry::getValue)
|
||||
.collect(Collectors.toList());
|
||||
if (!rarityCounts.isEmpty()) {
|
||||
System.out.println(rarity + String.format(": %s unique, min %s, max %s, total %s",
|
||||
rarityCounts.size(), Collections.min(rarityCounts), Collections.max(rarityCounts),
|
||||
rarityCounts.stream().mapToInt(x -> x).sum()));
|
||||
}
|
||||
}
|
||||
List<String> info = resRatio.entrySet().stream()
|
||||
.sorted((o1, o2) -> Integer.compare(o2.getValue(), o1.getValue()))
|
||||
.map(e -> String.format("%s: %d",
|
||||
|
|
@ -535,8 +548,7 @@ public class BoosterGenerationTest extends MageTestPlayerBase {
|
|||
e.getValue()
|
||||
))
|
||||
.collect(Collectors.toList());
|
||||
System.out.println(setToAnalyse.getName() + " - boosters opened: " + openBoosters + ". Found cards: " + totalCards + "\n"
|
||||
+ String.join("\n", info));
|
||||
System.out.println("\n" + String.join("\n", info));
|
||||
}
|
||||
|
||||
@Ignore // debug only
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue