1
0
Fork 0
mirror of https://github.com/correl/mage.git synced 2025-04-12 09:11:05 -09:00

* Fixed that a player doing a library search with a stated quality (701.15b) couldn't fail to find a card if cards with the stated quality did exist in the searched library.

This commit is contained in:
LevelX2 2015-09-14 23:36:32 +02:00
parent dbc9113d52
commit 8f64a2ab54
6 changed files with 183 additions and 45 deletions
Mage.Server.Plugins/Mage.Player.Human/src/mage/player/human
Mage.Sets/src/mage/sets/morningtide
Mage.Tests/src/test/java/org/mage/test/cards/enchantments
Mage/src/mage/target

View file

@ -485,7 +485,12 @@ public class HumanPlayer extends PlayerImpl {
public boolean chooseTarget(Outcome outcome, Cards cards, TargetCard target, Ability source, Game game) {
updateGameStatePriority("chooseTarget(5)", game);
while (!abort) {
boolean required = target.isRequired(source);
boolean required;
if (target.isRequiredExplicitlySet()) {
required = target.isRequired();
} else {
required = target.isRequired(source);
}
// if there is no cards to select from, then add possibility to cancel choosing action
if (cards == null) {
required = false;

View file

@ -28,11 +28,10 @@
package mage.sets.morningtide;
import java.util.UUID;
import mage.constants.CardType;
import mage.constants.Rarity;
import mage.abilities.effects.common.search.SearchLibraryPutInHandEffect;
import mage.cards.CardImpl;
import mage.constants.CardType;
import mage.constants.Rarity;
import mage.filter.FilterCard;
import mage.filter.predicate.mageobject.CardTypePredicate;
import mage.target.common.TargetCardInLibrary;
@ -42,7 +41,7 @@ import mage.target.common.TargetCardInLibrary;
*/
public class IdyllicTutor extends CardImpl {
private static final FilterCard filter = new FilterCard("enchantment");
private static final FilterCard filter = new FilterCard("an enchantment");
static {
filter.add(new CardTypePredicate(CardType.ENCHANTMENT));
@ -52,7 +51,6 @@ public class IdyllicTutor extends CardImpl {
super(ownerId, 12, "Idyllic Tutor", Rarity.RARE, new CardType[]{CardType.SORCERY}, "{2}{W}");
this.expansionSetCode = "MOR";
// Search your library for an enchantment card, reveal it, and put it into your hand. Then shuffle your library.
this.getSpellAbility().addEffect(new SearchLibraryPutInHandEffect(new TargetCardInLibrary(filter), true));
}

View file

@ -0,0 +1,88 @@
/*
* Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are
* permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this list of
* conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice, this list
* of conditions and the following disclaimer in the documentation and/or other materials
* provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* The views and conclusions contained in the software and documentation are those of the
* authors and should not be interpreted as representing official policies, either expressed
* or implied, of BetaSteward_at_googlemail.com.
*/
package org.mage.test.cards.enchantments;
import mage.constants.PhaseStep;
import mage.constants.Zone;
import org.junit.Test;
import org.mage.test.serverside.base.CardTestPlayerBase;
/**
*
* @author LevelX2
*/
public class SagesReverieTest extends CardTestPlayerBase {
/*
21:11: MarioPineda casts Sage's Reverie [26d] targeting face down creature
21:11: Ability triggers: Sage's Reverie [26d] - When Sage's Reverie [26d] enters the battlefield, draw a card for each aura you control that's attached to a creature.
21:11: mbvash casts Crackling Doom [b78]
21:11: MarioPineda loses 2 life
21:11: MarioPineda sacrificed face down creature
21:11: mbvash puts Crackling Doom [b78] from stack into his or her graveyard
21:11: Cloudform [9cd] is put into graveyard from battlefield
21:11: Sage's Reverie [26d] is put into graveyard from battlefield
21:11: MarioPineda draws two cards
There were two other Auras on the battlefield, and Sage's Reverie made me draw two cards even though the creature it was going to enchant left the battlefield.
http://www.mtgsalvation.com/forums/magic-fundamentals/magic-rulings/604851-sages-reverie-question
*/
@Test
public void testNoCardDrawIfTargetIllegal() {
addCard(Zone.BATTLEFIELD, playerA, "Plains", 5);
// Enchant creature
// When Sage's Reverie enters the battlefield, draw a card for each aura you control that's attached to a creature.
addCard(Zone.BATTLEFIELD, playerA, "Sage's Reverie", 1); // {3}{W}
// Enchant creature
// Enchanted creature has lifelink
addCard(Zone.HAND, playerA, "Lifelink", 1); // {W}
addCard(Zone.BATTLEFIELD, playerA, "Silvercoat Lion", 1);
addCard(Zone.BATTLEFIELD, playerA, "Pillarfield Ox", 1);
addCard(Zone.BATTLEFIELD, playerB, "Swamp", 3);
// Destroy target creature or planeswalker.
addCard(Zone.HAND, playerB, "Hero's Downfall"); // {1}{B}{B}
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Lifelink", "Silvercoat Lion");
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Sage's Reverie", "Pillarfield Ox");
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerB, "Hero's Downfall", "Pillarfield Ox");
setStopAt(1, PhaseStep.BEGIN_COMBAT);
execute();
assertPermanentCount(playerA, "Lifelink", 1);
assertGraveyardCount(playerB, "Hero's Downfall", 1);
assertGraveyardCount(playerA, "Pillarfield Ox", 1);
assertGraveyardCount(playerA, "Sage's Reverie", 1);
assertHandCount(playerA, 0);
}
}

View file

@ -1,43 +1,41 @@
/*
* Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are
* permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this list of
* conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice, this list
* of conditions and the following disclaimer in the documentation and/or other materials
* provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* The views and conclusions contained in the software and documentation are those of the
* authors and should not be interpreted as representing official policies, either expressed
* or implied, of BetaSteward_at_googlemail.com.
*/
* Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are
* permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this list of
* conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice, this list
* of conditions and the following disclaimer in the documentation and/or other materials
* provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* The views and conclusions contained in the software and documentation are those of the
* authors and should not be interpreted as representing official policies, either expressed
* or implied, of BetaSteward_at_googlemail.com.
*/
package mage.target;
import mage.constants.Outcome;
import mage.constants.Zone;
import mage.abilities.Ability;
import mage.filter.Filter;
import mage.game.Game;
import java.io.Serializable;
import java.util.List;
import java.util.Set;
import java.util.UUID;
import mage.abilities.Ability;
import mage.constants.Outcome;
import mage.constants.Zone;
import mage.filter.Filter;
import mage.game.Game;
import mage.players.Player;
/**
@ -47,69 +45,110 @@ import mage.players.Player;
public interface Target extends Serializable {
boolean isChosen();
boolean doneChosing();
void clearChosen();
boolean isNotTarget();
/**
* controlls if it will be checked, if the target can be targeted from source
* @param notTarget true = do not check for protection, false = check for protection
* controlls if it will be checked, if the target can be targeted from
* source
*
* @param notTarget true = do not check for protection, false = check for
* protection
*/
void setNotTarget(boolean notTarget);
// methods for targets
boolean canChoose(UUID sourceId, UUID sourceControllerId, Game game);
Set<UUID> possibleTargets(UUID sourceId, UUID sourceControllerId, Game game);
boolean chooseTarget(Outcome outcome, UUID playerId, Ability source, Game game);
void addTarget(UUID id, Ability source, Game game);
void addTarget(UUID id, int amount, Ability source, Game game);
void addTarget(UUID id, Ability source, Game game, boolean skipEvent);
void addTarget(UUID id, int amount, Ability source, Game game, boolean skipEvent);
boolean canTarget(UUID id, Game game);
boolean canTarget(UUID id, Ability source, Game game);
boolean canTarget(UUID playerId, UUID id, Ability source, Game game);
boolean canTarget(UUID playerId, UUID id, Ability source, Game game);
boolean isLegal(Ability source, Game game);
List<? extends Target> getTargetOptions(Ability source, Game game);
//methods for non-targets
boolean canChoose(UUID sourceControllerId, Game game);
Set<UUID> possibleTargets(UUID sourceControllerId, Game game);
boolean choose(Outcome outcome, UUID playerId, UUID sourceId, Game game);
void add(UUID id, Game game);
void remove(UUID targetId);
void updateTarget(UUID targetId, Game game);
String getMessage();
String getTargetName();
void setTargetName(String name);
String getTargetedName(Game game);
Zone getZone();
int getTargetAmount(UUID targetId);
int getNumberOfTargets();
int getMaxNumberOfTargets();
void setMinNumberOfTargets(int minNumberofTargets);
void setMaxNumberOfTargets(int maxNumberofTargets);
List<UUID> getTargets();
Filter getFilter();
boolean isRequired();
boolean isRequired(UUID sourceId, Game game);
boolean isRequired(Ability ability);
void setRequired(boolean required);
boolean isRequiredExplicitlySet();
boolean isRandom();
void setRandom(boolean atRandom);
UUID getFirstTarget();
Target copy();
// some targets are choosen from players that are not the controller of the ability (e.g. Pandemonium)
void setTargetController(UUID playerId);
UUID getTargetController();
void setAbilityController(UUID playerId);
UUID getAbilityController();
Player getTargetController(Game game, UUID playerId);
}
}

View file

@ -536,4 +536,9 @@ public abstract class TargetImpl implements Target {
}
}
@Override
public boolean isRequiredExplicitlySet() {
return requiredExplicitlySet;
}
}

View file

@ -64,6 +64,9 @@ public class TargetCardInLibrary extends TargetCard {
public TargetCardInLibrary(int minNumTargets, int maxNumTargets, FilterCard filter) {
super(minNumTargets, maxNumTargets, Zone.LIBRARY, filter);
// 701.15b If a player is searching a hidden zone for cards with a stated quality, such as a card
// with a certain card type or color, that player isnt required to find some or all of those cards
// even if theyre present in that zone.
this.setRequired(!filter.hasPredicates());
this.librarySearchLimit = Integer.MAX_VALUE;
}