* Added better handling of TargetAmount for tests.

This commit is contained in:
LevelX2 2020-01-10 15:48:21 +01:00
parent 13b522989a
commit ac2a59fdc2
4 changed files with 68 additions and 68 deletions

View file

@ -246,14 +246,14 @@ public class SpellskiteTest extends CardTestPlayerBase {
addCard(Zone.BATTLEFIELD, playerB, "Royal Assassin"); // 1/1 addCard(Zone.BATTLEFIELD, playerB, "Royal Assassin"); // 1/1
addCard(Zone.BATTLEFIELD, playerB, "Blinking Spirit"); // 2/2 addCard(Zone.BATTLEFIELD, playerB, "Blinking Spirit"); // 2/2
addCard(Zone.BATTLEFIELD, playerB, "Pearled Unicorn"); // 2/2 addCard(Zone.BATTLEFIELD, playerB, "Pearled Unicorn"); // 2/2
// Fiery Justice deals 5 damage divided as you choose among any number of target creatures and/or players. Target opponent gains 5 life.
addCard(Zone.HAND, playerA, "Fiery Justice"); addCard(Zone.HAND, playerA, "Fiery Justice");
// A cast Fiery Justice // Cast Fiery Justice
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Fiery Justice"); castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Fiery Justice");
addTarget(playerA, playerB); // 5 life to B addTarget(playerA, playerB); // 5 life to B
addTarget(playerA, "Scute Mob^X=1"); // target 1 addTargetAmount(playerA, "Scute Mob" , 1); // target 1
addTarget(playerA, "Spellskite^X=4"); // target 2 addTargetAmount(playerA, "Spellskite", 4); // target 2
// B activate Spellskite, but can't change any targets cause it's already targeted // B activate Spellskite, but can't change any targets cause it's already targeted
activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerB, "{U/P}: Change a target", "Fiery Justice", "Fiery Justice"); activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerB, "{U/P}: Change a target", "Fiery Justice", "Fiery Justice");
setChoice(playerB, "Yes"); // pay 2 life setChoice(playerB, "Yes"); // pay 2 life
@ -288,7 +288,7 @@ public class SpellskiteTest extends CardTestPlayerBase {
addCard(Zone.HAND, playerA, "Fiery Justice"); addCard(Zone.HAND, playerA, "Fiery Justice");
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Fiery Justice"); // 5 damage distributed to any number of targets castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Fiery Justice"); // 5 damage distributed to any number of targets
addTarget(playerA, "Scute Mob^X=5"); addTargetAmount(playerA, "Scute Mob", 5);
activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerB, "{U/P}: Change a target", "Fiery Justice", "Fiery Justice"); activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerB, "{U/P}: Change a target", "Fiery Justice", "Fiery Justice");
setChoice(playerB, "Yes"); // pay 2 life setChoice(playerB, "Yes"); // pay 2 life
@ -319,9 +319,9 @@ public class SpellskiteTest extends CardTestPlayerBase {
addCard(Zone.HAND, playerA, "Fiery Justice"); addCard(Zone.HAND, playerA, "Fiery Justice");
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Fiery Justice"); // 5 damage distributed to any number of targets castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Fiery Justice"); // 5 damage distributed to any number of targets
addTarget(playerA, "Royal Assassin^X=1"); addTargetAmount(playerA, "Royal Assassin",1);
addTarget(playerA, "Blinking Spirit^X=2"); addTargetAmount(playerA, "Blinking Spirit",2);
addTarget(playerA, "Pearled Unicorn^X=2"); addTargetAmount(playerA, "Pearled Unicorn",2);
activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerB, "{U/P}: Change a target", "Fiery Justice", "Fiery Justice"); activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerB, "{U/P}: Change a target", "Fiery Justice", "Fiery Justice");
setChoice(playerB, "Yes"); // pay 2 life setChoice(playerB, "Yes"); // pay 2 life

View file

@ -2,6 +2,7 @@ package org.mage.test.player;
import java.io.Serializable; import java.io.Serializable;
import java.util.*; import java.util.*;
import java.util.Map.Entry;
import java.util.regex.Matcher; import java.util.regex.Matcher;
import java.util.regex.Pattern; import java.util.regex.Pattern;
import java.util.stream.Collectors; import java.util.stream.Collectors;
@ -16,6 +17,7 @@ import mage.abilities.costs.Costs;
import mage.abilities.costs.VariableCost; import mage.abilities.costs.VariableCost;
import mage.abilities.costs.mana.ManaCost; import mage.abilities.costs.mana.ManaCost;
import mage.abilities.costs.mana.ManaCosts; import mage.abilities.costs.mana.ManaCosts;
import mage.abilities.dynamicvalue.common.StaticValue;
import mage.abilities.mana.ActivatedManaAbilityImpl; import mage.abilities.mana.ActivatedManaAbilityImpl;
import mage.abilities.mana.ManaOptions; import mage.abilities.mana.ManaOptions;
import mage.cards.Card; import mage.cards.Card;
@ -70,7 +72,7 @@ import static org.mage.test.serverside.base.impl.CardTestPlayerAPIImpl.*;
@Ignore @Ignore
public class TestPlayer implements Player { public class TestPlayer implements Player {
private static final Logger logger = Logger.getLogger(TestPlayer.class); private static final Logger LOGGER = Logger.getLogger(TestPlayer.class);
public static final String TARGET_SKIP = "[target_skip]"; public static final String TARGET_SKIP = "[target_skip]";
public static final String BLOCK_SKIP = "[block_skip]"; public static final String BLOCK_SKIP = "[block_skip]";
@ -82,6 +84,7 @@ public class TestPlayer implements Player {
private final List<PlayerAction> actions = new ArrayList<>(); private final List<PlayerAction> actions = new ArrayList<>();
private final List<String> choices = new ArrayList<>(); // choices stack for choice private final List<String> choices = new ArrayList<>(); // choices stack for choice
private final List<String> targets = new ArrayList<>(); // targets stack for choose (it's uses on empty direct target by cast command) private final List<String> targets = new ArrayList<>(); // targets stack for choose (it's uses on empty direct target by cast command)
private final LinkedHashMap<String, Integer> targetsAmount = new LinkedHashMap<>(); // targets and amounts for targets that also need to set an amount
private final Map<String, UUID> aliases = new HashMap<>(); // aliases for game objects/players (use it for cards with same name to save and use) private final Map<String, UUID> aliases = new HashMap<>(); // aliases for game objects/players (use it for cards with same name to save and use)
private final List<String> modesSet = new ArrayList<>(); private final List<String> modesSet = new ArrayList<>();
@ -153,6 +156,16 @@ public class TestPlayer implements Player {
targets.add(target); targets.add(target);
} }
/**
* Sets the data for TargetAmount classes that include also an amount beside the target like TargetPermanentAmount
*
* @param targetName
* @param amount
*/
public void addTargetAmount(String targetName, Integer amount) {
targetsAmount.put(targetName, amount);
}
public void addAlias(String name, UUID Id) { public void addAlias(String name, UUID Id) {
aliases.put(name, Id); aliases.put(name, Id);
} }
@ -3277,59 +3290,40 @@ public class TestPlayer implements Player {
return computerPlayer.choose(outcome, cards, target, game); return computerPlayer.choose(outcome, cards, target, game);
} }
@Override @Override
public boolean chooseTargetAmount(Outcome outcome, TargetAmount target, public boolean chooseTargetAmount(Outcome outcome, TargetAmount target,
Ability source, Game game Ability source, Game game
) { ) {
// command format: targetName^X=3 if (!targetsAmount.isEmpty()) {
for (Iterator<Entry<String, Integer>> iterator = targetsAmount.entrySet().iterator(); iterator.hasNext();) {
// chooseTargetAmount calls by TargetAmount for EACH target cycle Entry<String, Integer> targetRecord = iterator.next();
Assert.assertTrue("chooseTargetAmount supports only one target, but found " + target.getMaxNumberOfTargets(), target.getMaxNumberOfTargets() <= 1); if (target.getAmountRemaining() > 0) {
Assert.assertNotEquals("chooseTargetAmount need remaining > 0", 0, target.getAmountRemaining()); target.possibleTargets(source.getSourceId(), source.getControllerId(), game).forEach((possibleTarget) -> {
MageObject objectPermanent = game.getObject(possibleTarget);
if (!targets.isEmpty()) { Player objectPlayer = game.getPlayer(possibleTarget);
String objectName = objectPermanent != null ? objectPermanent.getName() : objectPlayer.getName();
boolean founded = false; if (objectName.equals(targetRecord.getKey())) {
String foundedRecord = ""; if (!target.getTargets().contains(possibleTarget) && target.canTarget(possibleTarget, source, game)) {
CheckTargets: // can select
for (String targetRecord : targets) { target.addTarget(possibleTarget, targetRecord.getValue(), source, game);
String[] choiceSettings = targetRecord.split("\\^"); iterator.remove();
if (choiceSettings.length == 2 && choiceSettings[1].startsWith("X=")) { }
// can choice
String choiceName = choiceSettings[0];
int choiceAmount = Integer.parseInt(choiceSettings[1].substring(2));
Assert.assertNotEquals("choice amount must be not zero", 0, choiceAmount);
Assert.assertTrue("choice amount " + choiceAmount + "must be <= remaining " + target.getAmountRemaining(), choiceAmount <= target.getAmountRemaining());
for (UUID possibleTarget : target.possibleTargets(source.getSourceId(), source.getControllerId(), game)) {
MageObject objectPermanent = game.getObject(possibleTarget);
Player objectPlayer = game.getPlayer(possibleTarget);
String objectName = objectPermanent != null ? objectPermanent.getName() : objectPlayer.getName();
if (objectName.equals(choiceName)) {
if (!target.getTargets().contains(possibleTarget) && target.canTarget(possibleTarget, source, game)) {
// can select
target.addTarget(possibleTarget, choiceAmount, source, game);
founded = true;
foundedRecord = targetRecord;
break CheckTargets;
} }
} });
}
} }
} }
}
if (founded) { if (!target.isRequired() && target.getAmountRemaining() > 0) {
// all done if (strictChooseMode) {
targets.remove(foundedRecord); target.setAmountDefinition(StaticValue.get(0));
target.setAmount(source, game);
return true; return true;
} }
} }
this.chooseStrictModeFailed(game, getInfo(source) + "; " + getInfo(target));
this.chooseStrictModeFailed(game, getInfo(source) + "; " + getInfo(target));
return computerPlayer.chooseTargetAmount(outcome, target, source, game); return computerPlayer.chooseTargetAmount(outcome, target, source, game);
} }
@Override @Override
public boolean chooseMulligan(Game game public boolean chooseMulligan(Game game
) { ) {

View file

@ -43,7 +43,7 @@ public abstract class MageTestBase {
public static PluginClassLoader classLoader = new PluginClassLoader(); public static PluginClassLoader classLoader = new PluginClassLoader();
private static final String pluginFolder = "plugins"; private static final String PLUGIN_FOLDER = "plugins";
protected Pattern pattern = Pattern.compile("([a-zA-Z]*):([\\w]*):([a-zA-Z ,\\-.!'\\d]*):([\\d]*)(:\\{tapped\\})?"); protected Pattern pattern = Pattern.compile("([a-zA-Z]*):([\\w]*):([a-zA-Z ,\\-.!'\\d]*):([\\d]*)(:\\{tapped\\})?");
@ -88,7 +88,7 @@ public abstract class MageTestBase {
/** /**
* Expected results of the test. Read from test case in {@link String} based * Expected results of the test. Read from test case in {@link String} based
* format: * format:
* <p/> * <p></p>
* Example: turn:1 result:won:ComputerA life:ComputerA:20 life:ComputerB:0 * Example: turn:1 result:won:ComputerA life:ComputerA:20 life:ComputerB:0
* battlefield:ComputerB:Tine Shrike:0 graveyard:ComputerB:Tine Shrike:1 * battlefield:ComputerB:Tine Shrike:0 graveyard:ComputerB:Tine Shrike:1
*/ */
@ -103,24 +103,25 @@ public abstract class MageTestBase {
logger.info("Logging level: " + logger.getLevel()); logger.info("Logging level: " + logger.getLevel());
deleteSavedGames(); deleteSavedGames();
ConfigSettings config = ConfigSettings.instance; ConfigSettings config = ConfigSettings.instance;
for (GamePlugin plugin : config.getGameTypes()) { config.getGameTypes().forEach((gameType) -> {
GameFactory.instance.addGameType(plugin.getName(), loadGameType(plugin), loadPlugin(plugin)); GameFactory.instance.addGameType(gameType.getName(), loadGameType(gameType), loadPlugin(gameType));
} });
for (GamePlugin plugin : config.getTournamentTypes()) { config.getTournamentTypes().forEach((tournamentType) -> {
TournamentFactory.instance.addTournamentType(plugin.getName(), loadTournamentType(plugin), loadPlugin(plugin)); TournamentFactory.instance.addTournamentType(tournamentType.getName(), loadTournamentType(tournamentType), loadPlugin(tournamentType));
} });
for (Plugin plugin : config.getPlayerTypes()) { config.getPlayerTypes().forEach((playerType) -> {
PlayerFactory.instance.addPlayerType(plugin.getName(), loadPlugin(plugin)); PlayerFactory.instance.addPlayerType(playerType.getName(), loadPlugin(playerType));
} });
// for (Plugin plugin : config.getDeckTypes()) { // for (Plugin plugin : config.getDeckTypes()) {
// DeckValidatorFactory.getInstance().addDeckType(plugin.getName(), loadPlugin(plugin)); // DeckValidatorFactory.getInstance().addDeckType(plugin.getName(), loadPlugin(plugin));
// } // }
Copier.setLoader(classLoader); Copier.setLoader(classLoader);
} }
@SuppressWarnings("UseSpecificCatch")
private static Class<?> loadPlugin(Plugin plugin) { private static Class<?> loadPlugin(Plugin plugin) {
try { try {
classLoader.addURL(new File(pluginFolder + '/' + plugin.getJar()).toURI().toURL()); classLoader.addURL(new File(PLUGIN_FOLDER + '/' + plugin.getJar()).toURI().toURL());
logger.debug("Loading plugin: " + plugin.getClassName()); logger.debug("Loading plugin: " + plugin.getClassName());
return Class.forName(plugin.getClassName(), true, classLoader); return Class.forName(plugin.getClassName(), true, classLoader);
} catch (ClassNotFoundException ex) { } catch (ClassNotFoundException ex) {
@ -133,11 +134,11 @@ public abstract class MageTestBase {
private static MatchType loadGameType(GamePlugin plugin) { private static MatchType loadGameType(GamePlugin plugin) {
try { try {
classLoader.addURL(new File(pluginFolder + '/' + plugin.getJar()).toURI().toURL()); classLoader.addURL(new File(PLUGIN_FOLDER + '/' + plugin.getJar()).toURI().toURL());
logger.debug("Loading game type: " + plugin.getClassName()); logger.debug("Loading game type: " + plugin.getClassName());
return (MatchType) Class.forName(plugin.getTypeName(), true, classLoader).getConstructor().newInstance(); return (MatchType) Class.forName(plugin.getTypeName(), true, classLoader).getConstructor().newInstance();
} catch (ClassNotFoundException ex) { } catch (ClassNotFoundException ex) {
logger.warn("Game type not found:" + plugin.getJar() + " - check plugin folder"); logger.warn("Game type not found:" + plugin.getJar() + " - check plugin folder", ex);
} catch (Exception ex) { } catch (Exception ex) {
logger.fatal("Error loading game type " + plugin.getJar(), ex); logger.fatal("Error loading game type " + plugin.getJar(), ex);
} }
@ -146,7 +147,7 @@ public abstract class MageTestBase {
private static TournamentType loadTournamentType(GamePlugin plugin) { private static TournamentType loadTournamentType(GamePlugin plugin) {
try { try {
classLoader.addURL(new File(pluginFolder + '/' + plugin.getJar()).toURI().toURL()); classLoader.addURL(new File(PLUGIN_FOLDER + '/' + plugin.getJar()).toURI().toURL());
logger.info("Loading tournament type: " + plugin.getClassName()); logger.info("Loading tournament type: " + plugin.getClassName());
return (TournamentType) Class.forName(plugin.getTypeName(), true, classLoader).getConstructor().newInstance(); return (TournamentType) Class.forName(plugin.getTypeName(), true, classLoader).getConstructor().newInstance();
} catch (ClassNotFoundException ex) { } catch (ClassNotFoundException ex) {

View file

@ -1604,6 +1604,11 @@ public abstract class CardTestPlayerAPIImpl extends MageTestPlayerBase implement
player.addTarget("targetPlayer=" + targetPlayer.getName()); player.addTarget("targetPlayer=" + targetPlayer.getName());
} }
public void addTargetAmount(TestPlayer player, String target, int amount) {
player.addTargetAmount(target, amount);
}
public void setDecknamePlayerA(String deckname) { public void setDecknamePlayerA(String deckname) {
deckNameA = deckname; deckNameA = deckname;
} }