diff --git a/Mage.Sets/src/mage/cards/a/AvengerEnDal.java b/Mage.Sets/src/mage/cards/a/AvengerEnDal.java index c32ebb9dbe1..78d78ccd1e9 100644 --- a/Mage.Sets/src/mage/cards/a/AvengerEnDal.java +++ b/Mage.Sets/src/mage/cards/a/AvengerEnDal.java @@ -70,7 +70,7 @@ class AvengerEnDalEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { - Permanent permanent = game.getPermanent(getTargetPointer().getFirst(game, source)); + Permanent permanent = game.getPermanentOrLKIBattlefield(getTargetPointer().getFirst(game, source)); if (permanent != null) { Player player = game.getPlayer(permanent.getControllerId()); if (player != null) { diff --git a/Mage.Sets/src/mage/cards/b/BeastWithin.java b/Mage.Sets/src/mage/cards/b/BeastWithin.java index 0aa0262f0bb..ed66eab7de8 100644 --- a/Mage.Sets/src/mage/cards/b/BeastWithin.java +++ b/Mage.Sets/src/mage/cards/b/BeastWithin.java @@ -59,7 +59,7 @@ class BeastWithinEffect extends OneShotEffect { // If the permanent is an illegal target when Beast Within tries to resolve, the spell won’t resolve and none // of its effects will happen. The permanent’s controller won’t get a Beast token. // (2011-06-01) - Permanent permanent = game.getPermanent(getTargetPointer().getFirst(game, source)); + Permanent permanent = game.getPermanentOrLKIBattlefield(getTargetPointer().getFirst(game, source)); // must use LKI if (permanent != null) { new BeastToken().putOntoBattlefield(1, game, source.getSourceId(), permanent.getControllerId()); } diff --git a/Mage.Sets/src/mage/cards/c/Crumble.java b/Mage.Sets/src/mage/cards/c/Crumble.java index 474db44b4e3..90ead36ee18 100644 --- a/Mage.Sets/src/mage/cards/c/Crumble.java +++ b/Mage.Sets/src/mage/cards/c/Crumble.java @@ -58,8 +58,9 @@ class CrumbleEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { - // If the target artifact becomes illegal before resolution, the player does not gain any life. (2004-10-04) - Permanent permanent = game.getPermanent(getTargetPointer().getFirst(game, source)); + // If the target artifact becomes illegal before resolution, the player does not gain any life. + // (2004-10-04) + Permanent permanent = game.getPermanentOrLKIBattlefield(getTargetPointer().getFirst(game, source)); // must use LKI if (permanent != null) { int cost = permanent.getConvertedManaCost(); Player player = game.getPlayer(permanent.getControllerId()); diff --git a/Mage.Sets/src/mage/cards/f/FaerieArtisans.java b/Mage.Sets/src/mage/cards/f/FaerieArtisans.java index b751bffa324..8eb37e5af9e 100644 --- a/Mage.Sets/src/mage/cards/f/FaerieArtisans.java +++ b/Mage.Sets/src/mage/cards/f/FaerieArtisans.java @@ -44,6 +44,7 @@ public final class FaerieArtisans extends CardImpl { // Flying this.addAbility(FlyingAbility.getInstance()); + // Whenever a nontoken creature enters the battlefield under an opponent's control, create a token that's a copy of that creature except it's an artifact in addition to its other types. Then exile all other tokens created with Faerie Artisans. Ability ability = new EntersBattlefieldAllTriggeredAbility(Zone.BATTLEFIELD, new FaerieArtisansEffect(), filterNontoken, false, SetTargetPointer.PERMANENT, "Whenever a nontoken creature enters the battlefield under an opponent's control, create a token that's a copy of that creature except it's an artifact in addition to its other types. Then exile all other tokens created with {this}."); diff --git a/Mage.Sets/src/mage/cards/i/IncubationIncongruity.java b/Mage.Sets/src/mage/cards/i/IncubationIncongruity.java index bae310cd8fe..17fa9b08509 100644 --- a/Mage.Sets/src/mage/cards/i/IncubationIncongruity.java +++ b/Mage.Sets/src/mage/cards/i/IncubationIncongruity.java @@ -74,7 +74,7 @@ class IncongruityEffect extends OneShotEffect { // If the target creature is an illegal target by the time Incongruity tries to resolve, the spell doesn’t resolve. // No player creates a Frog Lizard token. // (2019-01-25) - Permanent permanent = game.getPermanent(targetPointer.getFirst(game, source)); + Permanent permanent = game.getPermanentOrLKIBattlefield(targetPointer.getFirst(game, source)); // must use LKI if (permanent != null) { FrogLizardToken token = new FrogLizardToken(); token.putOntoBattlefield(1, game, source.getSourceId(), permanent.getControllerId()); diff --git a/Mage.Tests/src/test/java/org/mage/test/player/TestPlayer.java b/Mage.Tests/src/test/java/org/mage/test/player/TestPlayer.java index de3381f1ef4..4920288a9e5 100644 --- a/Mage.Tests/src/test/java/org/mage/test/player/TestPlayer.java +++ b/Mage.Tests/src/test/java/org/mage/test/player/TestPlayer.java @@ -1,10 +1,5 @@ package org.mage.test.player; -import java.io.Serializable; -import java.util.*; -import java.util.regex.Matcher; -import java.util.regex.Pattern; -import java.util.stream.Collectors; import mage.MageItem; import mage.MageObject; import mage.MageObjectReference; @@ -61,6 +56,14 @@ import mage.util.CardUtil; import org.apache.log4j.Logger; import org.junit.Assert; import org.junit.Ignore; + +import java.io.Serializable; +import java.util.*; +import java.util.regex.Matcher; +import java.util.regex.Pattern; +import java.util.stream.Collectors; +import java.util.stream.IntStream; + import static org.mage.test.serverside.base.impl.CardTestPlayerAPIImpl.*; /** @@ -177,7 +180,7 @@ public class TestPlayer implements Player { /** * @param maxCallsWithoutAction max number of priority passes a player may - * have for this test (default = 100) + * have for this test (default = 100) */ public void setMaxCallsWithoutAction(int maxCallsWithoutAction) { this.maxCallsWithoutAction = maxCallsWithoutAction; @@ -901,12 +904,12 @@ public class TestPlayer implements Player { List data = cards.stream() .map(c -> (((c instanceof PermanentToken) ? "[T] " : "[C] ") - + c.getIdName() - + (c.isCopy() ? " [copy of " + c.getCopyFrom().getId().toString().substring(0, 3) + "]" : "") - + " - " + c.getPower().getValue() + "/" + c.getToughness().getValue() - + (c.isPlaneswalker() ? " - L" + c.getCounters(game).getCount(CounterType.LOYALTY) : "") - + ", " + (c.isTapped() ? "Tapped" : "Untapped") - + (c.getAttachedTo() == null ? "" : ", attached to " + game.getPermanent(c.getAttachedTo()).getIdName()))) + + c.getIdName() + + (c.isCopy() ? " [copy of " + c.getCopyFrom().getId().toString().substring(0, 3) + "]" : "") + + " - " + c.getPower().getValue() + "/" + c.getToughness().getValue() + + (c.isPlaneswalker() ? " - L" + c.getCounters(game).getCount(CounterType.LOYALTY) : "") + + ", " + (c.isTapped() ? "Tapped" : "Untapped") + + (c.getAttachedTo() == null ? "" : ", attached to " + game.getPermanent(c.getAttachedTo()).getIdName()))) .sorted() .collect(Collectors.toList()); @@ -930,11 +933,11 @@ public class TestPlayer implements Player { List data = abilities.stream() .map(a -> (a.getZone() + " -> " - + a.getSourceObject(game).getIdName() + " -> " - + (a.toString().length() > 0 - ? a.toString().substring(0, Math.min(20, a.toString().length()) - 1) - : a.getClass().getSimpleName()) - + "...")) + + a.getSourceObject(game).getIdName() + " -> " + + (a.toString().length() > 0 + ? a.toString().substring(0, Math.min(20, a.toString().length()) - 1) + : a.getClass().getSimpleName()) + + "...")) .sorted() .collect(Collectors.toList()); @@ -1288,7 +1291,7 @@ public class TestPlayer implements Player { UUID defenderId = null; boolean mustAttackByAction = false; boolean madeAttackByAction = false; - for (Iterator it = actions.iterator(); it.hasNext();) { + for (Iterator it = actions.iterator(); it.hasNext(); ) { PlayerAction action = it.next(); if (action.getTurnNum() == game.getTurnNum() && action.getAction().startsWith("attack:")) { mustAttackByAction = true; @@ -1453,21 +1456,28 @@ public class TestPlayer implements Player { } private String getInfo(MageObject o) { - return o != null ? o.getClass().getSimpleName() + ": " + o.getName() : "null"; + return "Object: " + (o != null ? o.getClass().getSimpleName() + ": " + o.getName() : "null"); } - private String getInfo(Ability o) { - return o != null ? o.getClass().getSimpleName() + ": " + o.getRule() : "null"; + private String getInfo(Ability o, Game game) { + if (o != null) { + MageObject object = o.getSourceObject(game); + return "Ability: " + (object == null ? "" : object.getName() + " - " + o.getClass().getSimpleName() + ": " + o.getRule()); + } + return "Ability: null"; } private String getInfo(Target o) { - return o != null ? o.getClass().getSimpleName() + ": " + o.getMessage() : "null"; + return "Target: " + (o != null ? o.getClass().getSimpleName() + ": " + o.getMessage() : "null"); } private void chooseStrictModeFailed(String choiceType, Game game, String reason) { if (strictChooseMode) { - Assert.fail("Missing " + choiceType + " def for turn " + game.getTurnNum() + ", " + this.getName() + ", " - + game.getStep().getType().name() + ": " + reason); + Assert.fail("Missing " + choiceType + " def for" + + " turn " + game.getTurnNum() + + ", step " + game.getStep().getType().name() + + ", " + this.getName() + + "\n" + reason); } } @@ -1493,7 +1503,7 @@ public class TestPlayer implements Player { return null; } - this.chooseStrictModeFailed("mode", game, getInfo(source)); + this.chooseStrictModeFailed("mode", game, getInfo(source, game)); return computerPlayer.chooseMode(modes, source, game); } @@ -1770,7 +1780,7 @@ public class TestPlayer implements Player { // skip targets if (targets.get(0).equals(TARGET_SKIP)) { Assert.assertTrue("found skip target, but it require more targets, needs " - + (target.getMinNumberOfTargets() - target.getTargets().size()) + " more", + + (target.getMinNumberOfTargets() - target.getTargets().size()) + " more", target.getTargets().size() >= target.getMinNumberOfTargets()); targets.remove(0); return true; @@ -2025,7 +2035,7 @@ public class TestPlayer implements Player { Assert.fail(message); } - this.chooseStrictModeFailed("target", game, getInfo(source) + "; " + getInfo(target)); + this.chooseStrictModeFailed("target", game,getInfo(source, game) + "\n" + getInfo(target)); return computerPlayer.chooseTarget(outcome, target, source, game); } @@ -2054,7 +2064,7 @@ public class TestPlayer implements Player { //Assert.fail("Wrong target"); } - this.chooseStrictModeFailed("target", game, getInfo(source) + "; " + getInfo(target)); + this.chooseStrictModeFailed("target", game, getInfo(source, game) + "; " + getInfo(target)); return computerPlayer.chooseTarget(outcome, cards, target, source, game); } @@ -2071,7 +2081,9 @@ public class TestPlayer implements Player { //Assert.fail("Wrong choice"); } - this.chooseStrictModeFailed("choice", game, abilities.stream().map(this::getInfo).collect(Collectors.joining("; "))); + this.chooseStrictModeFailed("choice", game, + "Triggered list (total " + abilities.size() + "):\n" + + abilities.stream().map(a -> getInfo(a, game)).collect(Collectors.joining("\n"))); return computerPlayer.chooseTriggeredAbility(abilities, game); } @@ -2098,8 +2110,9 @@ public class TestPlayer implements Player { //Assert.fail("Wrong choice"); } - this.chooseStrictModeFailed("choice", game, getInfo(source) + "; " + message + ": " - + (trueText != null ? trueText : "Yes") + " - " + (falseText != null ? falseText : "No")); + this.chooseStrictModeFailed("choice", game, getInfo(source, game) + + "\nMessage: " + message + + "\nChoices: " + (trueText != null ? trueText : "Yes") + " - " + (falseText != null ? falseText : "No")); return computerPlayer.chooseUse(outcome, message, secondMessage, trueText, falseText, source, game); } @@ -2115,7 +2128,7 @@ public class TestPlayer implements Player { } } - this.chooseStrictModeFailed("choice", game, getInfo(ability) + "; " + message); + this.chooseStrictModeFailed("choice", game, getInfo(ability, game) + "; " + message); return computerPlayer.announceXMana(min, max, multiplier, message, game, ability); } @@ -2129,7 +2142,7 @@ public class TestPlayer implements Player { } } - this.chooseStrictModeFailed("choice", game, getInfo(ability) + "; " + message); + this.chooseStrictModeFailed("choice", game, getInfo(ability, game) + "; " + message); return computerPlayer.announceXCost(min, max, message, game, ability, null); } @@ -3244,7 +3257,7 @@ public class TestPlayer implements Player { @Override public boolean choose(Outcome outcome, Target target, - UUID sourceId, Game game + UUID sourceId, Game game ) { // needed to call here the TestPlayer because it's overwitten return choose(outcome, target, sourceId, game, null); @@ -3252,7 +3265,7 @@ public class TestPlayer implements Player { @Override public boolean choose(Outcome outcome, Cards cards, - TargetCard target, Game game + TargetCard target, Game game ) { if (!choices.isEmpty()) { for (String choose2 : choices) { @@ -3288,7 +3301,7 @@ public class TestPlayer implements Player { @Override public boolean chooseTargetAmount(Outcome outcome, TargetAmount target, - Ability source, Game game + Ability source, Game game ) { // chooseTargetAmount calls for EACH target cycle (e.g. one target per click, see TargetAmount) // if use want to stop choosing then chooseTargetAmount must return false (example: up to xxx) @@ -3300,7 +3313,7 @@ public class TestPlayer implements Player { // skip targets if (targets.get(0).equals(TARGET_SKIP)) { Assert.assertTrue("found skip target, but it require more targets, needs " - + (target.getMinNumberOfTargets() - target.getTargets().size()) + " more", + + (target.getMinNumberOfTargets() - target.getTargets().size()) + " more", target.getTargets().size() >= target.getMinNumberOfTargets()); targets.remove(0); return false; // false in chooseTargetAmount = stop to choose @@ -3341,7 +3354,7 @@ public class TestPlayer implements Player { } } - this.chooseStrictModeFailed("target", game, getInfo(source) + "; " + getInfo(target)); + this.chooseStrictModeFailed("target", game, getInfo(source, game) + "; " + getInfo(target)); return computerPlayer.chooseTargetAmount(outcome, target, source, game); } @@ -3353,15 +3366,15 @@ public class TestPlayer implements Player { @Override public boolean choosePile(Outcome outcome, String message, - List pile1, List pile2, - Game game + List pile1, List pile2, + Game game ) { return computerPlayer.choosePile(outcome, message, pile1, pile2, game); } @Override public boolean playMana(Ability ability, ManaCost unpaid, - String promptText, Game game + String promptText, Game game ) { groupsForTargetHandling = null; return computerPlayer.playMana(ability, unpaid, promptText, game); @@ -3375,15 +3388,15 @@ public class TestPlayer implements Player { @Override public UUID chooseBlockerOrder(List blockers, CombatGroup combatGroup, - List blockerOrder, Game game + List blockerOrder, Game game ) { return computerPlayer.chooseBlockerOrder(blockers, combatGroup, blockerOrder, game); } @Override public void assignDamage(int damage, List targets, - String singleTargetName, UUID sourceId, - Game game + String singleTargetName, UUID sourceId, + Game game ) { computerPlayer.assignDamage(damage, targets, singleTargetName, sourceId, game); } @@ -3402,14 +3415,14 @@ public class TestPlayer implements Player { @Override public void pickCard(List cards, Deck deck, - Draft draft + Draft draft ) { computerPlayer.pickCard(cards, deck, draft); } @Override public boolean scry(int value, Ability source, - Game game + Game game ) { // Don't scry at the start of the game. if (game.getTurnNum() == 1 && game.getStep() == null) { @@ -3420,44 +3433,44 @@ public class TestPlayer implements Player { @Override public boolean surveil(int value, Ability source, - Game game + Game game ) { return computerPlayer.surveil(value, source, game); } @Override public boolean moveCards(Card card, Zone toZone, - Ability source, Game game + Ability source, Game game ) { return computerPlayer.moveCards(card, toZone, source, game); } @Override public boolean moveCards(Card card, Zone toZone, - Ability source, Game game, - boolean tapped, boolean faceDown, boolean byOwner, List appliedEffects + Ability source, Game game, + boolean tapped, boolean faceDown, boolean byOwner, List appliedEffects ) { return computerPlayer.moveCards(card, toZone, source, game, tapped, faceDown, byOwner, appliedEffects); } @Override public boolean moveCards(Cards cards, Zone toZone, - Ability source, Game game + Ability source, Game game ) { return computerPlayer.moveCards(cards, toZone, source, game); } @Override public boolean moveCards(Set cards, Zone toZone, - Ability source, Game game + Ability source, Game game ) { return computerPlayer.moveCards(cards, toZone, source, game); } @Override public boolean moveCards(Set cards, Zone toZone, - Ability source, Game game, - boolean tapped, boolean faceDown, boolean byOwner, List appliedEffects + Ability source, Game game, + boolean tapped, boolean faceDown, boolean byOwner, List appliedEffects ) { return computerPlayer.moveCards(cards, toZone, source, game, tapped, faceDown, byOwner, appliedEffects); }