GUI: fixed that user can target/click on second side of mdf card instead the main side (related to #7297);

This commit is contained in:
Oleg Agafonov 2020-12-27 01:36:01 +04:00
parent 5731360f1d
commit 767644f1c8
2 changed files with 157 additions and 102 deletions

View file

@ -1,18 +1,5 @@
package mage.player.human; package mage.player.human;
import java.awt.*;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.LinkedList;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.UUID;
import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.stream.Collectors;
import mage.MageObject; import mage.MageObject;
import mage.abilities.*; import mage.abilities.*;
import mage.abilities.costs.VariableCost; import mage.abilities.costs.VariableCost;
@ -26,12 +13,11 @@ import mage.abilities.mana.ActivatedManaAbilityImpl;
import mage.abilities.mana.ManaAbility; import mage.abilities.mana.ManaAbility;
import mage.cards.Card; import mage.cards.Card;
import mage.cards.Cards; import mage.cards.Cards;
import mage.cards.ModalDoubleFacesCardHalf;
import mage.cards.decks.Deck; import mage.cards.decks.Deck;
import mage.choices.Choice; import mage.choices.Choice;
import mage.choices.ChoiceImpl; import mage.choices.ChoiceImpl;
import mage.constants.*; import mage.constants.*;
import static mage.constants.PlayerAction.REQUEST_AUTO_ANSWER_RESET_ALL;
import static mage.constants.PlayerAction.TRIGGER_AUTO_ORDER_RESET_ALL;
import mage.filter.StaticFilters; import mage.filter.StaticFilters;
import mage.filter.common.FilterAttackingCreature; import mage.filter.common.FilterAttackingCreature;
import mage.filter.common.FilterBlockingCreature; import mage.filter.common.FilterBlockingCreature;
@ -62,6 +48,15 @@ import mage.util.ManaUtil;
import mage.util.MessageToClient; import mage.util.MessageToClient;
import org.apache.log4j.Logger; import org.apache.log4j.Logger;
import java.awt.*;
import java.io.Serializable;
import java.util.*;
import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.stream.Collectors;
import static mage.constants.PlayerAction.REQUEST_AUTO_ANSWER_RESET_ALL;
import static mage.constants.PlayerAction.TRIGGER_AUTO_ORDER_RESET_ALL;
/** /**
* @author BetaSteward_at_googlemail.com * @author BetaSteward_at_googlemail.com
*/ */
@ -504,22 +499,23 @@ public class HumanPlayer extends PlayerImpl {
} }
waitForResponse(game); waitForResponse(game);
if (response.getUUID() != null) { UUID responseId = getFixedResponseUUID(game);
if (responseId != null) {
// selected some target // selected some target
// remove selected // remove selected
if (target.getTargets().contains(response.getUUID())) { if (target.getTargets().contains(responseId)) {
target.remove(response.getUUID()); target.remove(responseId);
continue; continue;
} }
if (!targetIds.contains(response.getUUID())) { if (!targetIds.contains(responseId)) {
continue; continue;
} }
if (target instanceof TargetPermanent) { if (target instanceof TargetPermanent) {
if (((TargetPermanent) target).canTarget(abilityControllerId, response.getUUID(), sourceId, game, false)) { if (((TargetPermanent) target).canTarget(abilityControllerId, responseId, sourceId, game, false)) {
target.add(response.getUUID(), game); target.add(responseId, game);
if (target.doneChosing()) { if (target.doneChosing()) {
return true; return true;
} }
@ -527,21 +523,21 @@ public class HumanPlayer extends PlayerImpl {
} else { } else {
MageObject object = game.getObject(sourceId); MageObject object = game.getObject(sourceId);
if (object instanceof Ability) { if (object instanceof Ability) {
if (target.canTarget(response.getUUID(), (Ability) object, game)) { if (target.canTarget(responseId, (Ability) object, game)) {
if (target.getTargets().contains(response.getUUID())) { // if already included remove it with if (target.getTargets().contains(responseId)) { // if already included remove it with
target.remove(response.getUUID()); target.remove(responseId);
} else { } else {
target.addTarget(response.getUUID(), (Ability) object, game); target.addTarget(responseId, (Ability) object, game);
if (target.doneChosing()) { if (target.doneChosing()) {
return true; return true;
} }
} }
} }
} else if (target.canTarget(response.getUUID(), game)) { } else if (target.canTarget(responseId, game)) {
if (target.getTargets().contains(response.getUUID())) { // if already included remove it with if (target.getTargets().contains(responseId)) { // if already included remove it with
target.remove(response.getUUID()); target.remove(responseId);
} else { } else {
target.addTarget(response.getUUID(), null, game); target.addTarget(responseId, null, game);
if (target.doneChosing()) { if (target.doneChosing()) {
return true; return true;
} }
@ -594,16 +590,17 @@ public class HumanPlayer extends PlayerImpl {
} }
waitForResponse(game); waitForResponse(game);
if (response.getUUID() != null) { UUID responseId = getFixedResponseUUID(game);
if (responseId != null) {
// remove selected // remove selected
if (target.getTargets().contains(response.getUUID())) { if (target.getTargets().contains(responseId)) {
target.remove(response.getUUID()); target.remove(responseId);
continue; continue;
} }
if (possibleTargets.contains(response.getUUID())) { if (possibleTargets.contains(responseId)) {
if (target.canTarget(abilityControllerId, response.getUUID(), source, game)) { if (target.canTarget(abilityControllerId, responseId, source, game)) {
target.addTarget(response.getUUID(), source, game); target.addTarget(responseId, source, game);
if (target.doneChosing()) { if (target.doneChosing()) {
return true; return true;
} }
@ -684,12 +681,13 @@ public class HumanPlayer extends PlayerImpl {
} }
waitForResponse(game); waitForResponse(game);
if (response.getUUID() != null) { UUID responseId = getFixedResponseUUID(game);
if (target.getTargets().contains(response.getUUID())) { // if already included remove it with if (responseId != null) {
target.remove(response.getUUID()); if (target.getTargets().contains(responseId)) { // if already included remove it with
target.remove(responseId);
} else { } else {
if (target.canTarget(abilityControllerId, response.getUUID(), null, cards, game)) { if (target.canTarget(abilityControllerId, responseId, null, cards, game)) {
target.add(response.getUUID(), game); target.add(responseId, game);
if (target.doneChosing()) { if (target.doneChosing()) {
return true; return true;
} }
@ -758,11 +756,12 @@ public class HumanPlayer extends PlayerImpl {
} }
waitForResponse(game); waitForResponse(game);
if (response.getUUID() != null) { UUID responseId = getFixedResponseUUID(game);
if (target.getTargets().contains(response.getUUID())) { // if already included remove it if (responseId != null) {
target.remove(response.getUUID()); if (target.getTargets().contains(responseId)) { // if already included remove it
} else if (target.canTarget(abilityControllerId, response.getUUID(), source, cards, game)) { target.remove(responseId);
target.addTarget(response.getUUID(), source, game); } else if (target.canTarget(abilityControllerId, responseId, source, cards, game)) {
target.addTarget(responseId, source, game);
if (target.doneChosing()) { if (target.doneChosing()) {
return true; return true;
} }
@ -805,23 +804,24 @@ public class HumanPlayer extends PlayerImpl {
if (!isExecutingMacro()) { if (!isExecutingMacro()) {
String selectedNames = target.getTargetedName(game); String selectedNames = target.getTargetedName(game);
game.fireSelectTargetEvent(playerId, new MessageToClient(target.getMessage() game.fireSelectTargetEvent(playerId, new MessageToClient(target.getMessage()
+ "<br> Amount remaining: " + target.getAmountRemaining() + "<br> Amount remaining: " + target.getAmountRemaining()
+ (selectedNames.isEmpty() ? "" : ", selected: " + selectedNames), + (selectedNames.isEmpty() ? "" : ", selected: " + selectedNames),
getRelatedObjectName(source, game)), getRelatedObjectName(source, game)),
possibleTargets, possibleTargets,
required, required,
getOptions(target, null)); getOptions(target, null));
} }
waitForResponse(game); waitForResponse(game);
if (response.getUUID() != null) { UUID responseId = getFixedResponseUUID(game);
if (target.canTarget(abilityControllerId, response.getUUID(), source, game)) { if (responseId != null) {
UUID targetId = response.getUUID(); if (target.canTarget(abilityControllerId, responseId, source, game)) {
UUID targetId = responseId;
MageObject targetObject = game.getObject(targetId); MageObject targetObject = game.getObject(targetId);
boolean removeMode = target.getTargets().contains(targetId) boolean removeMode = target.getTargets().contains(targetId)
&& chooseUse(outcome, "What do you want to do with " + (targetObject != null ? targetObject.getLogName() : " target") + "?", "", && chooseUse(outcome, "What do you want to do with " + (targetObject != null ? targetObject.getLogName() : " target") + "?", "",
"Remove from selected", "Add extra amount (remaining " + target.getAmountRemaining() + ")", source, game); "Remove from selected", "Add extra amount (remaining " + target.getAmountRemaining() + ")", source, game);
if (removeMode) { if (removeMode) {
target.remove(targetId); target.remove(targetId);
@ -963,9 +963,9 @@ public class HumanPlayer extends PlayerImpl {
if (!skippedAtLeastOnce if (!skippedAtLeastOnce
|| (playerId.equals(game.getActivePlayerId()) || (playerId.equals(game.getActivePlayerId())
&& !controllingPlayer && !controllingPlayer
.getUserData() .getUserData()
.getUserSkipPrioritySteps() .getUserSkipPrioritySteps()
.isStopOnAllEndPhases())) { .isStopOnAllEndPhases())) {
skippedAtLeastOnce = true; skippedAtLeastOnce = true;
if (passWithManaPoolCheck(game)) { if (passWithManaPoolCheck(game)) {
return false; return false;
@ -997,9 +997,9 @@ public class HumanPlayer extends PlayerImpl {
if (haveNewObjectsOnStack if (haveNewObjectsOnStack
&& (playerId.equals(game.getActivePlayerId()) && (playerId.equals(game.getActivePlayerId())
&& controllingPlayer && controllingPlayer
.getUserData() .getUserData()
.getUserSkipPrioritySteps() .getUserSkipPrioritySteps()
.isStopOnStackNewObjects())) { .isStopOnStackNewObjects())) {
// new objects on stack -- disable "pass until stack resolved" // new objects on stack -- disable "pass until stack resolved"
passedUntilStackResolved = false; passedUntilStackResolved = false;
} else { } else {
@ -1044,12 +1044,13 @@ public class HumanPlayer extends PlayerImpl {
break; break;
} }
UUID responseId = getFixedResponseUUID(game);
if (response.getString() != null if (response.getString() != null
&& response.getString().equals("special")) { && response.getString().equals("special")) {
activateSpecialAction(game, null); activateSpecialAction(game, null);
} else if (response.getUUID() != null) { } else if (responseId != null) {
boolean result = false; boolean result = false;
MageObject object = game.getObject(response.getUUID()); MageObject object = game.getObject(responseId);
if (object != null) { if (object != null) {
Zone zone = game.getState().getZone(object.getId()); Zone zone = game.getState().getZone(object.getId());
if (zone != null) { if (zone != null) {
@ -1106,6 +1107,21 @@ public class HumanPlayer extends PlayerImpl {
return false; return false;
} }
private UUID getFixedResponseUUID(Game game) {
// user can clicks on any side of multi/double faces card, but game must process click to main card all the time
MageObject object = game.getObject(response.getUUID());
// mdf cards
if (object instanceof ModalDoubleFacesCardHalf) {
if (!Zone.BATTLEFIELD.equals(game.getState().getZone(object.getId()))
&& !Zone.STACK.equals(game.getState().getZone(object.getId()))) {
return ((ModalDoubleFacesCardHalf) object).getMainCard().getId();
}
}
return response.getUUID();
}
private boolean checkPassStep(Game game, HumanPlayer controllingPlayer) { private boolean checkPassStep(Game game, HumanPlayer controllingPlayer) {
try { try {
@ -1191,11 +1207,12 @@ public class HumanPlayer extends PlayerImpl {
} }
waitForResponse(game); waitForResponse(game);
if (response.getUUID() != null) { UUID responseId = getFixedResponseUUID(game);
if (responseId != null) {
for (TriggeredAbility ability : abilitiesWithNoOrderSet) { for (TriggeredAbility ability : abilitiesWithNoOrderSet) {
if (ability.getId().equals(response.getUUID()) if (ability.getId().equals(responseId)
|| (!macroTriggeredSelectionFlag || (!macroTriggeredSelectionFlag
&& ability.getSourceId().equals(response.getUUID()))) { && ability.getSourceId().equals(responseId))) {
if (recordingMacro) { if (recordingMacro) {
PlayerResponse tResponse = new PlayerResponse(); PlayerResponse tResponse = new PlayerResponse();
tResponse.setUUID(ability.getSourceId()); tResponse.setUUID(ability.getSourceId());
@ -1239,10 +1256,11 @@ public class HumanPlayer extends PlayerImpl {
} }
waitForResponse(game); waitForResponse(game);
UUID responseId = getFixedResponseUUID(game);
if (response.getBoolean() != null) { if (response.getBoolean() != null) {
return false; return false;
} else if (response.getUUID() != null) { } else if (responseId != null) {
playManaAbilities(abilityToCast, unpaid, game); playManaAbilities(responseId, abilityToCast, unpaid, game);
} else if (response.getString() != null } else if (response.getString() != null
&& response.getString().equals("special")) { && response.getString().equals("special")) {
if (unpaid instanceof ManaCostsImpl) { if (unpaid instanceof ManaCostsImpl) {
@ -1355,9 +1373,9 @@ public class HumanPlayer extends PlayerImpl {
return xValue; return xValue;
} }
protected void playManaAbilities(Ability abilityToCast, ManaCost unpaid, Game game) { protected void playManaAbilities(UUID objectId, Ability abilityToCast, ManaCost unpaid, Game game) {
updateGameStatePriority("playManaAbilities", game); updateGameStatePriority("playManaAbilities", game);
MageObject object = game.getObject(response.getUUID()); MageObject object = game.getObject(objectId);
if (object == null) { if (object == null) {
return; return;
} }
@ -1417,8 +1435,8 @@ public class HumanPlayer extends PlayerImpl {
if (passedAllTurns if (passedAllTurns
|| passedUntilEndStepBeforeMyTurn || passedUntilEndStepBeforeMyTurn
|| (!getControllingPlayersUserData(game) || (!getControllingPlayersUserData(game)
.getUserSkipPrioritySteps() .getUserSkipPrioritySteps()
.isStopOnDeclareAttackers() .isStopOnDeclareAttackers()
&& (passedTurn && (passedTurn
|| passedTurnSkipStack || passedTurnSkipStack
|| passedUntilEndOfTurn || passedUntilEndOfTurn
@ -1453,6 +1471,7 @@ public class HumanPlayer extends PlayerImpl {
} }
waitForResponse(game); waitForResponse(game);
UUID responseId = getFixedResponseUUID(game);
if (response.getString() != null if (response.getString() != null
&& response.getString().equals("special")) { // All attack && response.getString().equals("special")) { // All attack
setStoredBookmark(game.bookmarkState()); setStoredBookmark(game.bookmarkState());
@ -1486,8 +1505,8 @@ public class HumanPlayer extends PlayerImpl {
if (checkIfAttackersValid(game)) { if (checkIfAttackersValid(game)) {
return; return;
} }
} else if (response.getUUID() != null) { } else if (responseId != null) {
Permanent attacker = game.getPermanent(response.getUUID()); Permanent attacker = game.getPermanent(responseId);
if (attacker != null) { if (attacker != null) {
if (filterCreatureForCombat.match(attacker, null, playerId, game)) { if (filterCreatureForCombat.match(attacker, null, playerId, game)) {
selectDefender(game.getCombat().getDefenders(), attacker.getId(), game); selectDefender(game.getCombat().getDefenders(), attacker.getId(), game);
@ -1631,13 +1650,7 @@ public class HumanPlayer extends PlayerImpl {
} }
} }
if (chooseTarget(Outcome.Damage, target, null, game)) { if (chooseTarget(Outcome.Damage, target, null, game)) {
UUID defenderId = response.getUUID(); UUID defenderId = getFixedResponseUUID(game);
for (Player player : game.getPlayers().values()) {
if (player.getId().equals(response.getUUID())) {
defenderId = player.getId(); // get the correct player object
break;
}
}
declareAttacker(attackerId, defenderId, game, true); declareAttacker(attackerId, defenderId, game, true);
return true; return true;
} }
@ -1649,7 +1662,7 @@ public class HumanPlayer extends PlayerImpl {
TargetDefender target = new TargetDefender(defenders, null); TargetDefender target = new TargetDefender(defenders, null);
target.setNotTarget(true); // player or planswalker hexproof does not prevent attacking a player target.setNotTarget(true); // player or planswalker hexproof does not prevent attacking a player
if (chooseTarget(Outcome.Damage, target, null, game)) { if (chooseTarget(Outcome.Damage, target, null, game)) {
return response.getUUID(); return getFixedResponseUUID(game);
} }
return null; return null;
} }
@ -1692,12 +1705,13 @@ public class HumanPlayer extends PlayerImpl {
} }
waitForResponse(game); waitForResponse(game);
UUID responseId = getFixedResponseUUID(game);
if (response.getBoolean() != null) { if (response.getBoolean() != null) {
return; return;
} else if (response.getInteger() != null) { } else if (response.getInteger() != null) {
return; return;
} else if (response.getUUID() != null) { } else if (responseId != null) {
Permanent blocker = game.getPermanent(response.getUUID()); Permanent blocker = game.getPermanent(responseId);
if (blocker != null) { if (blocker != null) {
boolean removeBlocker = false; boolean removeBlocker = false;
// does not block yet and can block or can block more attackers // does not block yet and can block or can block more attackers
@ -1730,9 +1744,10 @@ public class HumanPlayer extends PlayerImpl {
} }
waitForResponse(game); waitForResponse(game);
if (response.getUUID() != null) { UUID responseId = getFixedResponseUUID(game);
if (responseId != null) {
for (Permanent perm : attackers) { for (Permanent perm : attackers) {
if (perm.getId().equals(response.getUUID())) { if (perm.getId().equals(responseId)) {
return perm.getId(); return perm.getId();
} }
} }
@ -1755,9 +1770,10 @@ public class HumanPlayer extends PlayerImpl {
} }
waitForResponse(game); waitForResponse(game);
if (response.getUUID() != null) { UUID responseId = getFixedResponseUUID(game);
if (responseId != null) {
for (Permanent perm : blockers) { for (Permanent perm : blockers) {
if (perm.getId().equals(response.getUUID())) { if (perm.getId().equals(responseId)) {
return perm.getId(); return perm.getId();
} }
} }
@ -1795,14 +1811,15 @@ public class HumanPlayer extends PlayerImpl {
} }
waitForResponse(game); waitForResponse(game);
UUID responseId = getFixedResponseUUID(game);
if (response.getBoolean() != null) { if (response.getBoolean() != null) {
// do nothing // do nothing
} else if (response.getUUID() != null) { } else if (responseId != null) {
CombatGroup group = game.getCombat().findGroup(response.getUUID()); CombatGroup group = game.getCombat().findGroup(responseId);
if (group != null) { if (group != null) {
// check if already blocked, if not add // check if already blocked, if not add
if (!group.getBlockers().contains(blockerId)) { if (!group.getBlockers().contains(blockerId)) {
declareBlocker(defenderId, blockerId, response.getUUID(), game); declareBlocker(defenderId, blockerId, responseId, game);
} else { // else remove from block } else { // else remove from block
game.getCombat().removeBlockerGromGroup(blockerId, group, game); game.getCombat().removeBlockerGromGroup(blockerId, group, game);
} }
@ -1904,9 +1921,10 @@ public class HumanPlayer extends PlayerImpl {
} }
waitForResponse(game); waitForResponse(game);
if (response.getUUID() != null) { UUID responseId = getFixedResponseUUID(game);
if (specialActions.containsKey(response.getUUID())) { if (responseId != null) {
SpecialAction specialAction = specialActions.get(response.getUUID()); if (specialActions.containsKey(responseId)) {
SpecialAction specialAction = specialActions.get(responseId);
if (unpaidForManaAction != null) { if (unpaidForManaAction != null) {
specialAction.setUnpaidMana(unpaidForManaAction); specialAction.setUnpaidMana(unpaidForManaAction);
} }
@ -1966,9 +1984,10 @@ public class HumanPlayer extends PlayerImpl {
} }
waitForResponse(game); waitForResponse(game);
if (response.getUUID() != null) { UUID responseId = getFixedResponseUUID(game);
if (abilities.containsKey(response.getUUID())) { if (responseId != null) {
activateAbility(abilities.get(response.getUUID()), game); if (abilities.containsKey(responseId)) {
activateAbility(abilities.get(responseId), game);
} }
} }
} }
@ -2015,9 +2034,10 @@ public class HumanPlayer extends PlayerImpl {
} }
waitForResponse(game); waitForResponse(game);
if (response.getUUID() != null) { UUID responseId = getFixedResponseUUID(game);
if (useableAbilities.containsKey(response.getUUID())) { if (responseId != null) {
return (SpellAbility) useableAbilities.get(response.getUUID()); if (useableAbilities.containsKey(responseId)) {
return (SpellAbility) useableAbilities.get(responseId);
} }
} }
} }
@ -2096,9 +2116,10 @@ public class HumanPlayer extends PlayerImpl {
} }
waitForResponse(game); waitForResponse(game);
if (response.getUUID() != null) { UUID responseId = getFixedResponseUUID(game);
if (responseId != null) {
for (Mode mode : modes.getAvailableModes(source, game)) { for (Mode mode : modes.getAvailableModes(source, game)) {
if (mode.getId().equals(response.getUUID())) { if (mode.getId().equals(responseId)) {
// TODO: add checks on 2x selects (cheaters can rewrite client side code and select same mode multiple times) // TODO: add checks on 2x selects (cheaters can rewrite client side code and select same mode multiple times)
// reason: wrong setup eachModeMoreThanOnce and eachModeOnlyOnce in many cards // reason: wrong setup eachModeMoreThanOnce and eachModeOnlyOnce in many cards
return mode; return mode;
@ -2106,12 +2127,12 @@ public class HumanPlayer extends PlayerImpl {
} }
// end choice by done option in ability pickup dialog // end choice by done option in ability pickup dialog
if (canEndChoice && Modes.CHOOSE_OPTION_DONE_ID.equals(response.getUUID())) { if (canEndChoice && Modes.CHOOSE_OPTION_DONE_ID.equals(responseId)) {
done = true; done = true;
} }
// cancel choice (remove all selections) // cancel choice (remove all selections)
if (Modes.CHOOSE_OPTION_CANCEL_ID.equals(response.getUUID())) { if (Modes.CHOOSE_OPTION_CANCEL_ID.equals(responseId)) {
modes.clearSelectedModes(); modes.clearSelectedModes();
} }
} else if (canEndChoice) { } else if (canEndChoice) {

View file

@ -314,7 +314,7 @@ public class ModalDoubleFacesCardsTest extends CardTestPlayerBase {
} }
@Test @Test
public void test_Zones_AfterCast() { public void test_Zones_AfterCast_1() {
// Akoum Warrior {5}{R} - creature // Akoum Warrior {5}{R} - creature
// Akoum Teeth - land // Akoum Teeth - land
addCard(Zone.HAND, playerA, "Akoum Warrior"); addCard(Zone.HAND, playerA, "Akoum Warrior");
@ -342,6 +342,40 @@ public class ModalDoubleFacesCardsTest extends CardTestPlayerBase {
Assert.assertEquals("main card must be on battlefield", Zone.BATTLEFIELD, currentGame.getState().getZone(((PermanentCard) card).getCard().getMainCard().getId())); Assert.assertEquals("main card must be on battlefield", Zone.BATTLEFIELD, currentGame.getState().getZone(((PermanentCard) card).getCard().getMainCard().getId()));
} }
@Test
public void test_Zones_AfterCast_2() {
removeAllCardsFromHand(playerA);
// possible bug: if you click on mdf card second side then keep in hand after cast (sorcery + land)
// P.S. it works in GUI only, reason: user can sends UUID from wrong card side
// Ondu Inversion {6}{W}{W} - sorcery
// Ondu Skyruins - land
addCard(Zone.HAND, playerA, "Ondu Inversion");
addCard(Zone.BATTLEFIELD, playerA, "Plains", 8);
// prepare mdf permanent
playLand(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Ondu Skyruins");
waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN);
checkPermanentCount("prepare", 1, PhaseStep.PRECOMBAT_MAIN, playerA, "Ondu Skyruins", 1);
setStrictChooseMode(true);
setStopAt(1, PhaseStep.END_TURN);
execute();
assertAllCommandsUsed();
assertHandCount(playerA, 0);
Card card = currentGame.getState().getBattlefield().getAllPermanents()
.stream()
.filter(p -> CardUtil.haveSameNames(p, "Ondu Skyruins", currentGame))
.findFirst()
.orElse(null);
Assert.assertNotNull(card);
Assert.assertEquals("permanent card must be on battlefield", Zone.BATTLEFIELD, currentGame.getState().getZone(card.getId()));
Assert.assertEquals("main permanent card must be on battlefield", Zone.BATTLEFIELD, currentGame.getState().getZone(card.getMainCard().getId()));
Assert.assertEquals("half card must be on battlefield", Zone.BATTLEFIELD, currentGame.getState().getZone(((PermanentCard) card).getCard().getId()));
Assert.assertEquals("main card must be on battlefield", Zone.BATTLEFIELD, currentGame.getState().getZone(((PermanentCard) card).getCard().getMainCard().getId()));
}
@Test @Test
public void test_Zones_AfterExile() { public void test_Zones_AfterExile() {
// {2}, {tap}: Exile target permanent you control. // {2}, {tap}: Exile target permanent you control.