* 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, "Blinking Spirit"); // 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");
// A cast Fiery Justice
// Cast Fiery Justice
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Fiery Justice");
addTarget(playerA, playerB); // 5 life to B
addTarget(playerA, "Scute Mob^X=1"); // target 1
addTarget(playerA, "Spellskite^X=4"); // target 2
addTargetAmount(playerA, "Scute Mob" , 1); // target 1
addTargetAmount(playerA, "Spellskite", 4); // target 2
// 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");
setChoice(playerB, "Yes"); // pay 2 life
@ -288,7 +288,7 @@ public class SpellskiteTest extends CardTestPlayerBase {
addCard(Zone.HAND, playerA, "Fiery Justice");
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");
setChoice(playerB, "Yes"); // pay 2 life
@ -319,9 +319,9 @@ public class SpellskiteTest extends CardTestPlayerBase {
addCard(Zone.HAND, playerA, "Fiery Justice");
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Fiery Justice"); // 5 damage distributed to any number of targets
addTarget(playerA, "Royal Assassin^X=1");
addTarget(playerA, "Blinking Spirit^X=2");
addTarget(playerA, "Pearled Unicorn^X=2");
addTargetAmount(playerA, "Royal Assassin",1);
addTargetAmount(playerA, "Blinking Spirit",2);
addTargetAmount(playerA, "Pearled Unicorn",2);
activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerB, "{U/P}: Change a target", "Fiery Justice", "Fiery Justice");
setChoice(playerB, "Yes"); // pay 2 life

View file

@ -2,6 +2,7 @@ package org.mage.test.player;
import java.io.Serializable;
import java.util.*;
import java.util.Map.Entry;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
@ -16,6 +17,7 @@ import mage.abilities.costs.Costs;
import mage.abilities.costs.VariableCost;
import mage.abilities.costs.mana.ManaCost;
import mage.abilities.costs.mana.ManaCosts;
import mage.abilities.dynamicvalue.common.StaticValue;
import mage.abilities.mana.ActivatedManaAbilityImpl;
import mage.abilities.mana.ManaOptions;
import mage.cards.Card;
@ -70,7 +72,7 @@ import static org.mage.test.serverside.base.impl.CardTestPlayerAPIImpl.*;
@Ignore
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 BLOCK_SKIP = "[block_skip]";
@ -82,6 +84,7 @@ public class TestPlayer implements Player {
private final List<PlayerAction> actions = new ArrayList<>();
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 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 List<String> modesSet = new ArrayList<>();
@ -153,6 +156,16 @@ public class TestPlayer implements Player {
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) {
aliases.put(name, Id);
}
@ -3277,59 +3290,40 @@ public class TestPlayer implements Player {
return computerPlayer.choose(outcome, cards, target, game);
}
@Override
@Override
public boolean chooseTargetAmount(Outcome outcome, TargetAmount target,
Ability source, Game game
Ability source, Game game
) {
// command format: targetName^X=3
// chooseTargetAmount calls by TargetAmount for EACH target cycle
Assert.assertTrue("chooseTargetAmount supports only one target, but found " + target.getMaxNumberOfTargets(), target.getMaxNumberOfTargets() <= 1);
Assert.assertNotEquals("chooseTargetAmount need remaining > 0", 0, target.getAmountRemaining());
if (!targets.isEmpty()) {
boolean founded = false;
String foundedRecord = "";
CheckTargets:
for (String targetRecord : targets) {
String[] choiceSettings = targetRecord.split("\\^");
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 (!targetsAmount.isEmpty()) {
for (Iterator<Entry<String, Integer>> iterator = targetsAmount.entrySet().iterator(); iterator.hasNext();) {
Entry<String, Integer> targetRecord = iterator.next();
if (target.getAmountRemaining() > 0) {
target.possibleTargets(source.getSourceId(), source.getControllerId(), game).forEach((possibleTarget) -> {
MageObject objectPermanent = game.getObject(possibleTarget);
Player objectPlayer = game.getPlayer(possibleTarget);
String objectName = objectPermanent != null ? objectPermanent.getName() : objectPlayer.getName();
if (objectName.equals(targetRecord.getKey())) {
if (!target.getTargets().contains(possibleTarget) && target.canTarget(possibleTarget, source, game)) {
// can select
target.addTarget(possibleTarget, targetRecord.getValue(), source, game);
iterator.remove();
}
}
}
}
});
}
}
if (founded) {
// all done
targets.remove(foundedRecord);
}
}
if (!target.isRequired() && target.getAmountRemaining() > 0) {
if (strictChooseMode) {
target.setAmountDefinition(StaticValue.get(0));
target.setAmount(source, game);
return true;
}
}
this.chooseStrictModeFailed(game, getInfo(source) + "; " + getInfo(target));
this.chooseStrictModeFailed(game, getInfo(source) + "; " + getInfo(target));
return computerPlayer.chooseTargetAmount(outcome, target, source, game);
}
@Override
public boolean chooseMulligan(Game game
) {

View file

@ -43,7 +43,7 @@ public abstract class MageTestBase {
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\\})?");
@ -88,7 +88,7 @@ public abstract class MageTestBase {
/**
* Expected results of the test. Read from test case in {@link String} based
* format:
* <p/>
* <p></p>
* Example: turn:1 result:won:ComputerA life:ComputerA:20 life:ComputerB:0
* battlefield:ComputerB:Tine Shrike:0 graveyard:ComputerB:Tine Shrike:1
*/
@ -103,24 +103,25 @@ public abstract class MageTestBase {
logger.info("Logging level: " + logger.getLevel());
deleteSavedGames();
ConfigSettings config = ConfigSettings.instance;
for (GamePlugin plugin : config.getGameTypes()) {
GameFactory.instance.addGameType(plugin.getName(), loadGameType(plugin), loadPlugin(plugin));
}
for (GamePlugin plugin : config.getTournamentTypes()) {
TournamentFactory.instance.addTournamentType(plugin.getName(), loadTournamentType(plugin), loadPlugin(plugin));
}
for (Plugin plugin : config.getPlayerTypes()) {
PlayerFactory.instance.addPlayerType(plugin.getName(), loadPlugin(plugin));
}
config.getGameTypes().forEach((gameType) -> {
GameFactory.instance.addGameType(gameType.getName(), loadGameType(gameType), loadPlugin(gameType));
});
config.getTournamentTypes().forEach((tournamentType) -> {
TournamentFactory.instance.addTournamentType(tournamentType.getName(), loadTournamentType(tournamentType), loadPlugin(tournamentType));
});
config.getPlayerTypes().forEach((playerType) -> {
PlayerFactory.instance.addPlayerType(playerType.getName(), loadPlugin(playerType));
});
// for (Plugin plugin : config.getDeckTypes()) {
// DeckValidatorFactory.getInstance().addDeckType(plugin.getName(), loadPlugin(plugin));
// }
Copier.setLoader(classLoader);
}
@SuppressWarnings("UseSpecificCatch")
private static Class<?> loadPlugin(Plugin plugin) {
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());
return Class.forName(plugin.getClassName(), true, classLoader);
} catch (ClassNotFoundException ex) {
@ -133,11 +134,11 @@ public abstract class MageTestBase {
private static MatchType loadGameType(GamePlugin plugin) {
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());
return (MatchType) Class.forName(plugin.getTypeName(), true, classLoader).getConstructor().newInstance();
} 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) {
logger.fatal("Error loading game type " + plugin.getJar(), ex);
}
@ -146,7 +147,7 @@ public abstract class MageTestBase {
private static TournamentType loadTournamentType(GamePlugin plugin) {
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());
return (TournamentType) Class.forName(plugin.getTypeName(), true, classLoader).getConstructor().newInstance();
} catch (ClassNotFoundException ex) {

View file

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