* Some rework of play card effects.

This commit is contained in:
LevelX2 2015-11-26 17:06:50 +01:00
parent 780702be1b
commit eb6a5e7dcb
14 changed files with 201 additions and 240 deletions

View file

@ -79,8 +79,6 @@ import mage.cards.decks.Deck;
import mage.cards.repository.CardCriteria; import mage.cards.repository.CardCriteria;
import mage.cards.repository.CardInfo; import mage.cards.repository.CardInfo;
import mage.cards.repository.CardRepository; import mage.cards.repository.CardRepository;
import mage.cards.repository.ExpansionInfo;
import mage.cards.repository.ExpansionRepository;
import mage.choices.Choice; import mage.choices.Choice;
import mage.choices.ChoiceColor; import mage.choices.ChoiceColor;
import mage.constants.AsThoughEffectType; import mage.constants.AsThoughEffectType;
@ -995,7 +993,7 @@ public class ComputerPlayer extends PlayerImpl implements Player {
} }
while (lands.size() > 0 && this.canPlayLand()) { while (lands.size() > 0 && this.canPlayLand()) {
if (lands.size() == 1) { if (lands.size() == 1) {
this.playLand(lands.iterator().next(), game); this.playLand(lands.iterator().next(), game, false);
} else { } else {
playALand(lands, game); playALand(lands, game);
} }
@ -1010,7 +1008,7 @@ public class ComputerPlayer extends PlayerImpl implements Player {
for (ManaAbility ability : card.getAbilities().getManaAbilities(Zone.BATTLEFIELD)) { for (ManaAbility ability : card.getAbilities().getManaAbilities(Zone.BATTLEFIELD)) {
for (Mana netMana : ability.getNetMana(game)) { for (Mana netMana : ability.getNetMana(game)) {
if (netMana.enough(mana)) { if (netMana.enough(mana)) {
this.playLand(card, game); this.playLand(card, game, false);
lands.remove(card); lands.remove(card);
return; return;
} }
@ -1024,7 +1022,7 @@ public class ComputerPlayer extends PlayerImpl implements Player {
for (ManaAbility ability : card.getAbilities().getManaAbilities(Zone.BATTLEFIELD)) { for (ManaAbility ability : card.getAbilities().getManaAbilities(Zone.BATTLEFIELD)) {
for (Mana netMana : ability.getNetMana(game)) { for (Mana netMana : ability.getNetMana(game)) {
if (mana.contains(netMana)) { if (mana.contains(netMana)) {
this.playLand(card, game); this.playLand(card, game, false);
lands.remove(card); lands.remove(card);
return; return;
} }
@ -1033,7 +1031,7 @@ public class ComputerPlayer extends PlayerImpl implements Player {
} }
} }
//play first available land //play first available land
this.playLand(lands.iterator().next(), game); this.playLand(lands.iterator().next(), game, false);
lands.remove(lands.iterator().next()); lands.remove(lands.iterator().next());
} }

View file

@ -113,7 +113,7 @@ class EmeriaShepherdReturnToHandTargetEffect extends OneShotEffect {
&& controller.chooseUse(Outcome.PutCardInPlay, "Put the card to battlefield instead?", source, game)) { && controller.chooseUse(Outcome.PutCardInPlay, "Put the card to battlefield instead?", source, game)) {
toZone = Zone.BATTLEFIELD; toZone = Zone.BATTLEFIELD;
} }
return controller.moveCards(new CardsImpl(targetPointer.getTargets(game, source)), null, toZone, source, game); return controller.moveCards(new CardsImpl(targetPointer.getTargets(game, source)), toZone, source, game);
} }
} }

View file

@ -109,11 +109,11 @@ class GuileReplacementEffect extends ReplacementEffectImpl {
Spell spell = game.getStack().getSpell(event.getTargetId()); Spell spell = game.getStack().getSpell(event.getTargetId());
Player controller = game.getPlayer(source.getControllerId()); Player controller = game.getPlayer(source.getControllerId());
if (spell != null && controller != null) { if (spell != null && controller != null) {
controller.moveCards(spell, null, Zone.EXILED, source, game); controller.moveCards(spell, Zone.EXILED, source, game);
if (!spell.isCopy()) { if (!spell.isCopy()) {
Card spellCard = spell.getCard(); Card spellCard = spell.getCard();
if (spellCard != null && controller.chooseUse(Outcome.PlayForFree, "Cast " + spellCard.getIdName() + " for free?", source, game)) { if (spellCard != null && controller.chooseUse(Outcome.PlayForFree, "Cast " + spellCard.getIdName() + " for free?", source, game)) {
controller.cast(spellCard.getSpellAbility(), game, true); controller.playCard(spellCard, game, true, true);
} }
return true; return true;
} }

View file

@ -33,9 +33,9 @@ import mage.abilities.Ability;
import mage.abilities.common.SimpleActivatedAbility; import mage.abilities.common.SimpleActivatedAbility;
import mage.abilities.costs.mana.ManaCostsImpl; import mage.abilities.costs.mana.ManaCostsImpl;
import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.OneShotEffect;
import mage.abilities.keyword.VigilanceAbility;
import mage.abilities.keyword.TrampleAbility;
import mage.abilities.keyword.HasteAbility; import mage.abilities.keyword.HasteAbility;
import mage.abilities.keyword.TrampleAbility;
import mage.abilities.keyword.VigilanceAbility;
import mage.cards.Card; import mage.cards.Card;
import mage.cards.CardImpl; import mage.cards.CardImpl;
import mage.constants.CardType; import mage.constants.CardType;
@ -55,11 +55,11 @@ import mage.target.common.TargetCardInYourGraveyard;
public class HordeOfNotions extends CardImpl { public class HordeOfNotions extends CardImpl {
private final static FilterCard filter = new FilterCard("Elemental card from your graveyard"); private final static FilterCard filter = new FilterCard("Elemental card from your graveyard");
static { static {
filter.add(new SubtypePredicate("Elemental")); filter.add(new SubtypePredicate("Elemental"));
} }
public HordeOfNotions(UUID ownerId) { public HordeOfNotions(UUID ownerId) {
super(ownerId, 249, "Horde of Notions", Rarity.RARE, new CardType[]{CardType.CREATURE}, "{W}{U}{B}{R}{G}"); super(ownerId, 249, "Horde of Notions", Rarity.RARE, new CardType[]{CardType.CREATURE}, "{W}{U}{B}{R}{G}");
this.expansionSetCode = "LRW"; this.expansionSetCode = "LRW";
@ -74,8 +74,8 @@ public class HordeOfNotions extends CardImpl {
this.addAbility(TrampleAbility.getInstance()); this.addAbility(TrampleAbility.getInstance());
// Haste // Haste
this.addAbility(HasteAbility.getInstance()); this.addAbility(HasteAbility.getInstance());
// {W}{U}{B}{R}{G}: You may play target Elemental card from your graveyard without paying its mana cost. // {W}{U}{B}{R}{G}: You may play target Elemental card from your graveyard without paying its mana cost.
Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new HordeOfNotionsEffect(), new ManaCostsImpl<>("{W}{U}{B}{R}{G}")); Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new HordeOfNotionsEffect(), new ManaCostsImpl<>("{W}{U}{B}{R}{G}"));
ability.addTarget(new TargetCardInYourGraveyard(filter)); ability.addTarget(new TargetCardInYourGraveyard(filter));
this.addAbility(ability); this.addAbility(ability);
@ -92,37 +92,28 @@ public class HordeOfNotions extends CardImpl {
} }
class HordeOfNotionsEffect extends OneShotEffect { class HordeOfNotionsEffect extends OneShotEffect {
public HordeOfNotionsEffect() { public HordeOfNotionsEffect() {
super(Outcome.PlayForFree); super(Outcome.PlayForFree);
this.staticText = "You may play target Elemental card from your graveyard without paying its mana cost"; this.staticText = "You may play target Elemental card from your graveyard without paying its mana cost";
} }
public HordeOfNotionsEffect(final HordeOfNotionsEffect effect) { public HordeOfNotionsEffect(final HordeOfNotionsEffect effect) {
super(effect); super(effect);
} }
@Override @Override
public HordeOfNotionsEffect copy() { public HordeOfNotionsEffect copy() {
return new HordeOfNotionsEffect(this); return new HordeOfNotionsEffect(this);
} }
@Override @Override
public boolean apply(Game game, Ability source) { public boolean apply(Game game, Ability source) {
Player controller = game.getPlayer(source.getControllerId()); Player controller = game.getPlayer(source.getControllerId());
if (controller != null) { if (controller != null) {
Card card = game.getCard(getTargetPointer().getFirst(game, source)); Card card = game.getCard(getTargetPointer().getFirst(game, source));
if (card != null ) { if (card != null && controller.chooseUse(outcome, "Play " + card.getName() + " from your graveyard for free?", source, game)) {
// Probably there is no Elemental land, but who knows controller.playCard(card, game, true, true);
if (card.getCardType().contains(CardType.LAND) && controller.canPlayLand() &&
controller.chooseUse(outcome, "Play " + card.getName() + " from your graveyard for free?", source, game)) {
controller.playLand(card, game);
} else {
if (card.getSpellAbility().canChooseTarget(game) &&
controller.chooseUse(outcome, "Play " + card.getName() + " from your graveyard for free?", source, game)) {
controller.cast(card.getSpellAbility(), game, true);
}
}
} }
return true; return true;
} }

View file

@ -28,12 +28,8 @@
package mage.sets.magic2010; package mage.sets.magic2010;
import java.util.UUID; import java.util.UUID;
import mage.constants.CardType;
import mage.constants.Outcome;
import mage.constants.Rarity;
import mage.constants.Zone;
import mage.MageInt; import mage.MageInt;
import mage.MageObject;
import mage.abilities.Ability; import mage.abilities.Ability;
import mage.abilities.common.EntersBattlefieldAbility; import mage.abilities.common.EntersBattlefieldAbility;
import mage.abilities.common.SimpleActivatedAbility; import mage.abilities.common.SimpleActivatedAbility;
@ -46,6 +42,10 @@ import mage.cards.Card;
import mage.cards.CardImpl; import mage.cards.CardImpl;
import mage.cards.Cards; import mage.cards.Cards;
import mage.cards.CardsImpl; import mage.cards.CardsImpl;
import mage.constants.CardType;
import mage.constants.Outcome;
import mage.constants.Rarity;
import mage.constants.Zone;
import mage.counters.CounterType; import mage.counters.CounterType;
import mage.game.Game; import mage.game.Game;
import mage.players.Player; import mage.players.Player;
@ -100,33 +100,16 @@ class DjinnOfWishesEffect extends OneShotEffect {
@Override @Override
public boolean apply(Game game, Ability source) { public boolean apply(Game game, Ability source) {
Player player = game.getPlayer(source.getControllerId()); Player controller = game.getPlayer(source.getControllerId());
if (player != null && player.getLibrary().size() > 0) { MageObject sourceObject = game.getObject(source.getSourceId());
Card card = player.getLibrary().getFromTop(game); if (controller != null && sourceObject != null && controller.getLibrary().size() > 0) {
Cards cards = new CardsImpl(); Card card = controller.getLibrary().getFromTop(game);
cards.add(card); Cards cards = new CardsImpl(card);
player.revealCards("Djinn of Wishes", cards, game); controller.revealCards(sourceObject.getIdName(), cards, game);
if (!controller.chooseUse(Outcome.PlayForFree, "Play " + card.getName() + " without paying its mana cost?", source, game)
player.getLibrary().removeFromTop(game); || !controller.playCard(card, game, true, true)) {
boolean used = false;
if (player.chooseUse(Outcome.PlayForFree, "Play " + card.getName() + " without paying its mana cost?", source, game)) {
if (card.getCardType().contains(CardType.LAND)) {
// If the revealed card is a land, you can play it only if it's your turn and you haven't yet played a land this turn.
if (game.getActivePlayerId().equals(player.getId()) && player.canPlayLand()) {
used = true;
player.playLand(card, game);
}
} else {
used = true;
player.cast(card.getSpellAbility(), game, true);
}
}
if (!used) {
card.moveToZone(Zone.EXILED, source.getSourceId(), game, false); card.moveToZone(Zone.EXILED, source.getSourceId(), game, false);
} }
return true; return true;
} }
return false; return false;

View file

@ -55,10 +55,10 @@ public class LeafCrownedElder extends CardImpl {
this.power = new MageInt(3); this.power = new MageInt(3);
this.toughness = new MageInt(5); this.toughness = new MageInt(5);
// Kinship - At the beginning of your upkeep, you may look at the top card of your library. If it shares a creature type with Leaf-Crowned Elder, you may reveal it. // Kinship - At the beginning of your upkeep, you may look at the top card of your library. If it shares a creature type with Leaf-Crowned Elder, you may reveal it.
// If you do, you may play that card without paying its mana cost. // If you do, you may play that card without paying its mana cost.
this.addAbility(new KinshipAbility(new LeafCrownedElderPlayEffect())); this.addAbility(new KinshipAbility(new LeafCrownedElderPlayEffect()));
} }
public LeafCrownedElder(final LeafCrownedElder card) { public LeafCrownedElder(final LeafCrownedElder card) {
@ -84,18 +84,11 @@ class LeafCrownedElderPlayEffect extends OneShotEffect {
@Override @Override
public boolean apply(Game game, Ability source) { public boolean apply(Game game, Ability source) {
Player player = game.getPlayer(source.getControllerId()); Player controller = game.getPlayer(source.getControllerId());
Card card = game.getCard(getTargetPointer().getFirst(game, source)); Card card = game.getCard(getTargetPointer().getFirst(game, source));
if (player != null && card != null) { if (controller != null && card != null) {
if (player.chooseUse(Outcome.PlayForFree, "Play " + card.getName() + " without paying its mana cost?", source, game)) { if (controller.chooseUse(Outcome.PlayForFree, "Play " + card.getIdName() + " without paying its mana cost?", source, game)) {
if (card.getCardType().contains(CardType.LAND)) { controller.playCard(card, game, true, true);
// If the revealed card is a land, you can play it only if it's your turn and you haven't yet played a land this turn.
if (game.getActivePlayerId().equals(player.getId()) && player.canPlayLand()) {
player.playLand(card, game);
}
} else {
player.cast(card.getSpellAbility(), game, true);
}
} }
return true; return true;
} }

View file

@ -30,6 +30,7 @@ package mage.sets.shardsofalara;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.UUID; import java.util.UUID;
import mage.MageObject;
import mage.abilities.Ability; import mage.abilities.Ability;
import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.OneShotEffect;
import mage.cards.Card; import mage.cards.Card;
@ -56,11 +57,8 @@ public class BrilliantUltimatum extends CardImpl {
super(ownerId, 159, "Brilliant Ultimatum", Rarity.RARE, new CardType[]{CardType.SORCERY}, "{W}{W}{U}{U}{U}{B}{B}"); super(ownerId, 159, "Brilliant Ultimatum", Rarity.RARE, new CardType[]{CardType.SORCERY}, "{W}{W}{U}{U}{U}{B}{B}");
this.expansionSetCode = "ALA"; this.expansionSetCode = "ALA";
// Exile the top five cards of your library. An opponent separates those cards into two piles. You may play any number of cards from one of those piles without paying their mana costs. // Exile the top five cards of your library. An opponent separates those cards into two piles. You may play any number of cards from one of those piles without paying their mana costs.
this.getSpellAbility().addEffect(new BrilliantUltimatumEffect()); this.getSpellAbility().addEffect(new BrilliantUltimatumEffect());
this.getSpellAbility().addTarget(new TargetOpponent(true));
} }
public BrilliantUltimatum(final BrilliantUltimatum card) { public BrilliantUltimatum(final BrilliantUltimatum card) {
@ -91,22 +89,19 @@ class BrilliantUltimatumEffect extends OneShotEffect {
@Override @Override
public boolean apply(Game game, Ability source) { public boolean apply(Game game, Ability source) {
Player you = game.getPlayer(source.getControllerId()); Player controller = game.getPlayer(source.getControllerId());
if (you == null) { MageObject sourceObject = game.getObject(source.getSourceId());
if (controller == null || sourceObject == null) {
return false; return false;
} }
Cards pile2 = new CardsImpl(); Cards pile2 = new CardsImpl();
int max = Math.min(you.getLibrary().size(), 5); pile2.addAll(controller.getLibrary().getTopCards(game, 5));
for (int i = 0; i < max; i++) { controller.moveCardsToExile(pile2.getCards(game), source, game, true, source.getSourceId(), sourceObject.getIdName());
Card card = you.getLibrary().removeFromTop(game);
if (card != null) {
card.moveToExile(source.getSourceId(), "Brilliant Ultimatum", source.getSourceId(), game);
pile2.add(card);
}
}
Player opponent = game.getPlayer(source.getFirstTarget()); TargetOpponent targetOpponent = new TargetOpponent(true);
targetOpponent.choose(outcome, source.getControllerId(), source.getSourceId(), game);
Player opponent = game.getPlayer(targetOpponent.getFirstTarget());
if (opponent != null) { if (opponent != null) {
TargetCard target = new TargetCard(0, pile2.size(), Zone.EXILED, new FilterCard("cards to put in the first pile")); TargetCard target = new TargetCard(0, pile2.size(), Zone.EXILED, new FilterCard("cards to put in the first pile"));
target.setRequired(false); target.setRequired(false);
@ -123,55 +118,32 @@ class BrilliantUltimatumEffect extends OneShotEffect {
} }
} }
} }
for (UUID cardID : pile1) { pileOne.addAll(pile1.getCards(game));
Card card = pile1.get(cardID, game); pileTwo.addAll(pile2.getCards(game));
pileOne.add(card); controller.revealCards("Pile 1 - " + sourceObject.getIdName(), pile1, game);
} controller.revealCards("Pile 2 - " + sourceObject.getIdName(), pile2, game);
for (UUID cardId : pile2) {
Card card = pile2.get(cardId, game); boolean choice = controller.choosePile(Outcome.PlayForFree, "Which pile (play for free)?", pileOne, pileTwo, game);
pileTwo.add(card); String selectedPileName;
} List<Card> selectedPileCards;
Cards selectedPile;
you.revealCards("Pile 1 (Brilliant Ultimatum)", pile1, game);
you.revealCards("Pile 2 (Brilliant Ultimatum)", pile2, game);
boolean choice = you.choosePile(Outcome.PlayForFree, "Which pile (play for free)?", pileOne, pileTwo, game);
if (choice) { if (choice) {
game.informPlayer(you, you.getLogName() + " chose Pile 1."); selectedPileName = "pile 1";
while (!pileOne.isEmpty() && you.chooseUse(Outcome.PlayForFree, "Do you want to play a card from Pile 1?", source, game)) { selectedPileCards = pileOne;
TargetCard targetExiledCard = new TargetCard(Zone.EXILED, new FilterCard()); selectedPile = pile1;
if (you.chooseTarget(Outcome.PlayForFree, pile1, targetExiledCard, source, game)) {
Card card = pile1.get(targetExiledCard.getFirstTarget(), game);
if (card != null) {
if (card.getCardType().contains(CardType.LAND)) {
you.playLand(card, game);
pileOne.remove(card);
pile1.remove(card);
} else {
you.cast(card.getSpellAbility(), game, true);
pileOne.remove(card);
pile1.remove(card);
}
}
}
}
} else { } else {
game.informPlayer(you, you.getLogName() + " chose Pile 2."); selectedPileName = "pile 2";
while (!pileTwo.isEmpty() && you.chooseUse(Outcome.PlayForFree, "Do you want to play a card from Pile 2?", source, game)) { selectedPileCards = pileTwo;
TargetCard targetExiledCard = new TargetCard(Zone.EXILED, new FilterCard()); selectedPile = pile2;
if (you.chooseTarget(Outcome.PlayForFree, pile2, targetExiledCard, source, game)) { }
Card card = pile2.get(targetExiledCard.getFirstTarget(), game); game.informPlayers(controller.getLogName() + " chose " + selectedPileName + ".");
if (card != null) { while (!selectedPileCards.isEmpty() && controller.chooseUse(Outcome.PlayForFree, "Do you want to play a card for free from " + selectedPileName + "?", source, game)) {
if (card.getCardType().contains(CardType.LAND)) { TargetCard targetExiledCard = new TargetCard(Zone.EXILED, new FilterCard());
you.playLand(card, game); if (controller.chooseTarget(Outcome.PlayForFree, selectedPile, targetExiledCard, source, game)) {
pileTwo.remove(card); Card card = selectedPile.get(targetExiledCard.getFirstTarget(), game);
pile2.remove(card); if (controller.playCard(card, game, true, true)) {
} else { selectedPileCards.remove(card);
you.cast(card.getSpellAbility(), game, true); selectedPile.remove(card);
pileTwo.remove(card);
pile2.remove(card);
}
}
} }
} }
} }

View file

@ -1207,8 +1207,13 @@ public class TestPlayer implements Player {
} }
@Override @Override
public boolean playLand(Card card, Game game) { public boolean playCard(Card card, Game game, boolean noMana, boolean ignoreTiming) {
return computerPlayer.playLand(card, game); return computerPlayer.playCard(card, game, noMana, ignoreTiming);
}
@Override
public boolean playLand(Card card, Game game, boolean ignoreTiming) {
return computerPlayer.playLand(card, game, ignoreTiming);
} }
@Override @Override
@ -1786,34 +1791,23 @@ public class TestPlayer implements Player {
} }
@Override @Override
@Deprecated
public boolean moveCards(Cards cards, Zone fromZone, Zone toZone, Ability source, Game game) { public boolean moveCards(Cards cards, Zone fromZone, Zone toZone, Ability source, Game game) {
return computerPlayer.moveCards(cards, fromZone, toZone, source, game); return computerPlayer.moveCards(cards, fromZone, toZone, source, game);
} }
@Override @Override
@Deprecated
public boolean moveCards(Card card, Zone fromZone, Zone toZone, Ability source, Game game) { public boolean moveCards(Card card, Zone fromZone, Zone toZone, Ability source, Game game) {
return computerPlayer.moveCards(card, fromZone, toZone, source, game); return computerPlayer.moveCards(card, fromZone, toZone, source, game);
} }
@Override @Override
@Deprecated
public boolean moveCards(Set<Card> cards, Zone fromZone, Zone toZone, Ability source, Game game) { public boolean moveCards(Set<Card> cards, Zone fromZone, Zone toZone, Ability source, Game game) {
return computerPlayer.moveCards(cards, fromZone, toZone, source, game); return computerPlayer.moveCards(cards, fromZone, toZone, source, game);
} }
// @Override
// public boolean moveCards(Cards cards, Zone fromZone, Zone toZone, Ability source, Game game, boolean withName) {
// return computerPlayer.moveCards(cards, fromZone, toZone, source, game);
// }
//
// @Override
// public boolean moveCards(Card card, Zone fromZone, Zone toZone, Ability source, Game game, boolean withName) {
// return computerPlayer.moveCards(card, fromZone, toZone, source, game);
// }
//
// @Override
// public boolean moveCards(Set<Card> cards, Zone fromZone, Zone toZone, Ability source, Game game, boolean withName) {
// return computerPlayer.moveCards(cards, fromZone, toZone, source, game);
// }
@Override @Override
public boolean moveCardToHandWithInfo(Card card, UUID sourceId, Game game) { public boolean moveCardToHandWithInfo(Card card, UUID sourceId, Game game) {
return computerPlayer.moveCardToHandWithInfo(card, sourceId, game); return computerPlayer.moveCardToHandWithInfo(card, sourceId, game);

View file

@ -25,11 +25,23 @@
* authors and should not be interpreted as representing official policies, either expressed * authors and should not be interpreted as representing official policies, either expressed
* or implied, of BetaSteward_at_googlemail.com. * or implied, of BetaSteward_at_googlemail.com.
*/ */
package org.mage.test.stub; package org.mage.test.stub;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.UUID;
import mage.MageObject; import mage.MageObject;
import mage.abilities.*; import mage.abilities.Abilities;
import mage.abilities.Ability;
import mage.abilities.ActivatedAbility;
import mage.abilities.Mode;
import mage.abilities.Modes;
import mage.abilities.SpellAbility;
import mage.abilities.TriggeredAbility;
import mage.abilities.costs.AlternativeSourceCosts; import mage.abilities.costs.AlternativeSourceCosts;
import mage.abilities.costs.Cost; import mage.abilities.costs.Cost;
import mage.abilities.costs.Costs; import mage.abilities.costs.Costs;
@ -41,8 +53,12 @@ import mage.cards.Card;
import mage.cards.Cards; import mage.cards.Cards;
import mage.cards.decks.Deck; import mage.cards.decks.Deck;
import mage.choices.Choice; import mage.choices.Choice;
import mage.constants.*; import mage.constants.AbilityType;
import mage.constants.ManaType;
import mage.constants.Outcome;
import mage.constants.PlayerAction; import mage.constants.PlayerAction;
import mage.constants.RangeOfInfluence;
import mage.constants.Zone;
import mage.counters.Counter; import mage.counters.Counter;
import mage.counters.Counters; import mage.counters.Counters;
import mage.game.Game; import mage.game.Game;
@ -64,9 +80,6 @@ import mage.target.TargetCard;
import mage.target.common.TargetCardInLibrary; import mage.target.common.TargetCardInLibrary;
import mage.util.MessageToClient; import mage.util.MessageToClient;
import java.io.Serializable;
import java.util.*;
/** /**
* *
* @author Quercitron * @author Quercitron
@ -601,7 +614,12 @@ public class PlayerStub implements Player {
} }
@Override @Override
public boolean playLand(Card card, Game game) { public boolean playCard(Card card, Game game, boolean noMana, boolean checkTiming) {
return false;
}
@Override
public boolean playLand(Card card, Game game, boolean ignoreTiming) {
return false; return false;
} }

View file

@ -1,31 +1,30 @@
/* /*
* Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved.
* *
* Redistribution and use in source and binary forms, with or without modification, are * Redistribution and use in source and binary forms, with or without modification, are
* permitted provided that the following conditions are met: * permitted provided that the following conditions are met:
* *
* 1. Redistributions of source code must retain the above copyright notice, this list of * 1. Redistributions of source code must retain the above copyright notice, this list of
* conditions and the following disclaimer. * conditions and the following disclaimer.
* *
* 2. Redistributions in binary form must reproduce the above copyright notice, this list * 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 * of conditions and the following disclaimer in the documentation and/or other materials
* provided with the distribution. * provided with the distribution.
* *
* THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED * 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 * 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 * 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 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 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 * 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 * 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 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
* *
* The views and conclusions contained in the software and documentation are those of the * 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 * authors and should not be interpreted as representing official policies, either expressed
* or implied, of BetaSteward_at_googlemail.com. * or implied, of BetaSteward_at_googlemail.com.
*/ */
package mage.abilities; package mage.abilities;
import java.util.UUID; import java.util.UUID;
@ -52,24 +51,24 @@ public class PlayLandAbility extends ActivatedAbilityImpl {
@Override @Override
public boolean canActivate(UUID playerId, Game game) { public boolean canActivate(UUID playerId, Game game) {
if (!controlsAbility(playerId, game) && if (!controlsAbility(playerId, game)
!game.getContinuousEffects().asThough(getSourceId(), AsThoughEffectType.PLAY_FROM_NOT_OWN_HAND_ZONE, playerId, game)) { && !game.getContinuousEffects().asThough(getSourceId(), AsThoughEffectType.PLAY_FROM_NOT_OWN_HAND_ZONE, playerId, game)) {
return false; return false;
} }
//20091005 - 114.2a //20091005 - 114.2a
return game.canPlaySorcery(playerId) && game.getPlayer(playerId).canPlayLand(); return game.getPlayer(playerId).canPlayLand();
} }
@Override @Override
public String getGameLogMessage(Game game) { public String getGameLogMessage(Game game) {
return new StringBuilder(" plays ").append(getMessageText(game)).toString(); return " plays " + getMessageText(game);
} }
@Override @Override
public String toString() { public String toString() {
return this.name; return this.name;
} }
@Override @Override
public String getRule() { public String getRule() {
return this.name; return this.name;

View file

@ -1,16 +1,16 @@
/* /*
* Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved.
* *
* Redistribution and use in source and binary forms, with or without modification, are * Redistribution and use in source and binary forms, with or without modification, are
* permitted provided that the following conditions are met: * permitted provided that the following conditions are met:
* *
* 1. Redistributions of source code must retain the above copyright notice, this list of * 1. Redistributions of source code must retain the above copyright notice, this list of
* conditions and the following disclaimer. * conditions and the following disclaimer.
* *
* 2. Redistributions in binary form must reproduce the above copyright notice, this list * 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 * of conditions and the following disclaimer in the documentation and/or other materials
* provided with the distribution. * provided with the distribution.
* *
* THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED * 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 * 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 * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR
@ -20,31 +20,26 @@
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * 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 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
* *
* The views and conclusions contained in the software and documentation are those of the * 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 * authors and should not be interpreted as representing official policies, either expressed
* or implied, of BetaSteward_at_googlemail.com. * or implied, of BetaSteward_at_googlemail.com.
*/ */
package mage.abilities.effects.common; package mage.abilities.effects.common;
import java.util.UUID; import java.util.UUID;
import mage.abilities.Ability; import mage.abilities.Ability;
import mage.abilities.Mode; import mage.abilities.Mode;
import mage.abilities.SpellAbility;
import mage.abilities.effects.common.search.SearchTargetGraveyardHandLibraryForCardNameAndExileEffect; import mage.abilities.effects.common.search.SearchTargetGraveyardHandLibraryForCardNameAndExileEffect;
import mage.cards.Card;
import mage.game.Game; import mage.game.Game;
import mage.game.permanent.Permanent; import mage.game.permanent.Permanent;
import mage.target.Target; import mage.target.Target;
import mage.target.TargetPermanent; import mage.target.TargetPermanent;
import mage.target.TargetPlayer;
/** /**
* *
* @author LevelX2 * @author LevelX2
*/ */
public class ExileTargetAndSearchGraveyardHandLibraryEffect extends SearchTargetGraveyardHandLibraryForCardNameAndExileEffect { public class ExileTargetAndSearchGraveyardHandLibraryEffect extends SearchTargetGraveyardHandLibraryForCardNameAndExileEffect {
public ExileTargetAndSearchGraveyardHandLibraryEffect(Boolean graveyardExileOptional, String searchWhatText, String searchForText) { public ExileTargetAndSearchGraveyardHandLibraryEffect(Boolean graveyardExileOptional, String searchWhatText, String searchForText) {
@ -66,17 +61,16 @@ public class ExileTargetAndSearchGraveyardHandLibraryEffect extends SearchTarget
exileTarget = target; exileTarget = target;
break; break;
} }
} }
if (exileTarget != null) { if (exileTarget != null) {
Permanent permanentToExile = game.getPermanent(exileTarget.getFirstTarget()); Permanent permanentToExile = game.getPermanent(exileTarget.getFirstTarget());
if (permanentToExile != null) { if (permanentToExile != null) {
targetPlayerId = permanentToExile.getControllerId(); targetPlayerId = permanentToExile.getControllerId();
result = permanentToExile.moveToExile(null, "", source.getSourceId(), game); result = permanentToExile.moveToExile(null, "", source.getSourceId(), game);
this.applySearchAndExile(game, source, permanentToExile.getName(), targetPlayerId); this.applySearchAndExile(game, source, permanentToExile.getName(), targetPlayerId);
} }
} }
return result; return result;
} }
@ -92,4 +86,4 @@ public class ExileTargetAndSearchGraveyardHandLibraryEffect extends SearchTarget
sb.append(super.getText(mode)); sb.append(super.getText(mode));
return sb.toString(); return sb.toString();
} }
} }

View file

@ -28,17 +28,13 @@
package mage.abilities.effects.common; package mage.abilities.effects.common;
import mage.abilities.Ability; import mage.abilities.Ability;
import mage.abilities.condition.common.MyMainPhaseCondition;
import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.OneShotEffect;
import mage.cards.Card; import mage.cards.Card;
import mage.constants.CardType;
import mage.constants.Outcome; import mage.constants.Outcome;
import mage.constants.Zone;
import mage.game.ExileZone; import mage.game.ExileZone;
import mage.game.Game; import mage.game.Game;
import mage.players.Player; import mage.players.Player;
import mage.util.CardUtil; import mage.util.CardUtil;
import org.apache.log4j.Logger;
/** /**
* @author LevelX2 * @author LevelX2
@ -64,35 +60,13 @@ public class HideawayPlayEffect extends OneShotEffect {
public boolean apply(Game game, Ability source) { public boolean apply(Game game, Ability source) {
ExileZone zone = game.getExile().getExileZone(CardUtil.getCardExileZoneId(game, source)); ExileZone zone = game.getExile().getExileZone(CardUtil.getCardExileZoneId(game, source));
if (zone == null || zone.isEmpty()) { if (zone == null || zone.isEmpty()) {
return false; return true;
} }
Card card = zone.getCards(game).iterator().next(); Card card = zone.getCards(game).iterator().next();
Player controller = game.getPlayer(source.getControllerId()); Player controller = game.getPlayer(source.getControllerId());
if (card != null && controller != null) { if (card != null && controller != null) {
if (card.getCardType().contains(CardType.LAND)) { if (controller.chooseUse(Outcome.PlayForFree, "Do you want to play " + card.getIdName() + " for free now?", source, game)) {
// If the revealed card is a land, you can play it only if it's your turn and you haven't yet played a land this turn. controller.playCard(card, game, true, false);
if (game.getActivePlayerId().equals(source.getControllerId()) && controller.canPlayLand() && MyMainPhaseCondition.getInstance().apply(game, source)) {
if (controller.chooseUse(Outcome.Benefit, "Play " + card.getLogName() + " from Exile?", source, game)) {
// normal player.playLand(card, game) can't be used because this abilit is on the stack
card.setFaceDown(false, game);
return controller.moveCards(card, Zone.EXILED, Zone.BATTLEFIELD, source, game);
}
} else if (!game.isSimulation()) {
game.informPlayer(controller, "You're not able to play the land now due to regular restrictions.");
}
} else {
if (card.getSpellAbility() != null) {
// The land's last ability allows you to play the removed card as part of the resolution of that ability.
// Timing restrictions based on the card's type are ignored (for instance, if it's a creature or sorcery).
// Other play restrictions are not (such as "Play [this card] only during combat").
if (controller.chooseUse(Outcome.Benefit, "Cast " + card.getLogName() + " without paying its mana cost?", source, game)) {
card.setFaceDown(false, game);
return controller.cast(card.getSpellAbility(), game, true);
}
} else {
Logger.getLogger(HideawayPlayEffect.class).error("Non land card had no spell ability: " + card.getName());
return false;
}
} }
return true; return true;
} }

View file

@ -368,7 +368,29 @@ public interface Player extends MageItem, Copyable<Player> {
boolean canPlayLand(); boolean canPlayLand();
boolean playLand(Card card, Game game); /**
* Plays a card if possible
*
* @param card the card that can be cast
* @param game
* @param noMana if it's a spell i can be cast without paying mana
* @param ignoreTiming if it's cast during the resolution of another spell
* no sorcery or play land timing restriction are checked. For a land it has
* to be the turn of the player playing that card.
* @return
*/
boolean playCard(Card card, Game game, boolean noMana, boolean ignoreTiming);
/**
*
* @param card the land card to play
* @param game
* @param ignoreTiming false - it won't be checked if the stack is empty and
* you are able to play a Sorcery. It's still checked, if you are able to
* play a land concerning the numner of lands you already played.
* @return
*/
boolean playLand(Card card, Game game, boolean ignoreTiming);
boolean activateAbility(ActivatedAbility ability, Game game); boolean activateAbility(ActivatedAbility ability, Game game);

View file

@ -955,6 +955,23 @@ public abstract class PlayerImpl implements Player, Serializable {
return payManaMode; return payManaMode;
} }
@Override
public boolean playCard(Card card, Game game, boolean noMana, boolean ignoreTiming) {
if (card == null) {
return false;
}
boolean result;
if (card.getCardType().contains(CardType.LAND)) {
result = playLand(card, game, ignoreTiming);
} else {
result = cast(card.getSpellAbility(), game, noMana);
}
if (result == false) {
game.informPlayer(this, "You can't play " + card.getIdName() + ".");
}
return result;
}
@Override @Override
public boolean cast(SpellAbility ability, Game game, boolean noMana) { public boolean cast(SpellAbility ability, Game game, boolean noMana) {
if (!ability.getSpellAbilityType().equals(SpellAbilityType.BASE)) { if (!ability.getSpellAbilityType().equals(SpellAbilityType.BASE)) {
@ -1007,14 +1024,12 @@ public abstract class PlayerImpl implements Player, Serializable {
} }
@Override @Override
public SpellAbility chooseSpellAbilityForCast(SpellAbility ability, Game game, boolean noMana public SpellAbility chooseSpellAbilityForCast(SpellAbility ability, Game game, boolean noMana) {
) {
return ability; return ability;
} }
@Override @Override
public boolean playLand(Card card, Game game public boolean playLand(Card card, Game game, boolean ignoreTiming) {
) {
// Check for alternate casting possibilities: e.g. land with Morph // Check for alternate casting possibilities: e.g. land with Morph
ActivatedAbility playLandAbility = null; ActivatedAbility playLandAbility = null;
boolean found = false; boolean found = false;
@ -1038,9 +1053,18 @@ public abstract class PlayerImpl implements Player, Serializable {
if (playLandAbility == null) { if (playLandAbility == null) {
return false; return false;
} }
//20091005 - 114.2a
if (!playLandAbility.canActivate(this.playerId, game)) { if (!playLandAbility.canActivate(this.playerId, game)) {
return false; return false;
} }
if (ignoreTiming) {
if (!game.getActivePlayerId().equals(playerId)) {
// Also if a land can be played during the resolution of another spell, it has to be the turn of the player playing the land
return false;
}
} else if (!game.canPlaySorcery(playerId)) {
return false;
}
//20091005 - 305.1 //20091005 - 305.1
if (!game.replaceEvent(GameEvent.getEvent(GameEvent.EventType.PLAY_LAND, card.getId(), card.getId(), playerId))) { if (!game.replaceEvent(GameEvent.getEvent(GameEvent.EventType.PLAY_LAND, card.getId(), card.getId(), playerId))) {
// int bookmark = game.bookmarkState(); // int bookmark = game.bookmarkState();
@ -1147,9 +1171,8 @@ public abstract class PlayerImpl implements Player, Serializable {
return true; return true;
} }
if (ability instanceof PlayLandAbility) { if (ability instanceof PlayLandAbility) {
Card card = game.getCard(ability.getSourceId()); Card card = game.getCard(ability.getSourceId());
result = playLand(card, game); result = playLand(card, game, false);
} else { } else {
if (!ability.canActivate(this.playerId, game)) { if (!ability.canActivate(this.playerId, game)) {
return false; return false;