From eb6a5e7dcbadeba0b540fb8ba9b27702949a76aa Mon Sep 17 00:00:00 2001 From: LevelX2 Date: Thu, 26 Nov 2015 17:06:50 +0100 Subject: [PATCH] * Some rework of play card effects. --- .../java/mage/player/ai/ComputerPlayer.java | 10 +- .../battleforzendikar/EmeriaShepherd.java | 2 +- Mage.Sets/src/mage/sets/lorwyn/Guile.java | 4 +- .../src/mage/sets/lorwyn/HordeOfNotions.java | 33 +++---- .../mage/sets/magic2010/DjinnOfWishes.java | 43 +++------ .../sets/morningtide/LeafCrownedElder.java | 19 ++-- .../shardsofalara/BrilliantUltimatum.java | 94 +++++++------------ .../java/org/mage/test/player/TestPlayer.java | 26 ++--- .../java/org/mage/test/stub/PlayerStub.java | 32 +++++-- Mage/src/mage/abilities/PlayLandAbility.java | 65 +++++++------ ...etAndSearchGraveyardHandLibraryEffect.java | 22 ++--- .../effects/common/HideawayPlayEffect.java | 32 +------ Mage/src/mage/players/Player.java | 24 ++++- Mage/src/mage/players/PlayerImpl.java | 35 +++++-- 14 files changed, 201 insertions(+), 240 deletions(-) diff --git a/Mage.Server.Plugins/Mage.Player.AI/src/main/java/mage/player/ai/ComputerPlayer.java b/Mage.Server.Plugins/Mage.Player.AI/src/main/java/mage/player/ai/ComputerPlayer.java index f46dcf9ee32..9f90db3a4c7 100644 --- a/Mage.Server.Plugins/Mage.Player.AI/src/main/java/mage/player/ai/ComputerPlayer.java +++ b/Mage.Server.Plugins/Mage.Player.AI/src/main/java/mage/player/ai/ComputerPlayer.java @@ -79,8 +79,6 @@ import mage.cards.decks.Deck; import mage.cards.repository.CardCriteria; import mage.cards.repository.CardInfo; import mage.cards.repository.CardRepository; -import mage.cards.repository.ExpansionInfo; -import mage.cards.repository.ExpansionRepository; import mage.choices.Choice; import mage.choices.ChoiceColor; import mage.constants.AsThoughEffectType; @@ -995,7 +993,7 @@ public class ComputerPlayer extends PlayerImpl implements Player { } while (lands.size() > 0 && this.canPlayLand()) { if (lands.size() == 1) { - this.playLand(lands.iterator().next(), game); + this.playLand(lands.iterator().next(), game, false); } else { playALand(lands, game); } @@ -1010,7 +1008,7 @@ public class ComputerPlayer extends PlayerImpl implements Player { for (ManaAbility ability : card.getAbilities().getManaAbilities(Zone.BATTLEFIELD)) { for (Mana netMana : ability.getNetMana(game)) { if (netMana.enough(mana)) { - this.playLand(card, game); + this.playLand(card, game, false); lands.remove(card); return; } @@ -1024,7 +1022,7 @@ public class ComputerPlayer extends PlayerImpl implements Player { for (ManaAbility ability : card.getAbilities().getManaAbilities(Zone.BATTLEFIELD)) { for (Mana netMana : ability.getNetMana(game)) { if (mana.contains(netMana)) { - this.playLand(card, game); + this.playLand(card, game, false); lands.remove(card); return; } @@ -1033,7 +1031,7 @@ public class ComputerPlayer extends PlayerImpl implements Player { } } //play first available land - this.playLand(lands.iterator().next(), game); + this.playLand(lands.iterator().next(), game, false); lands.remove(lands.iterator().next()); } diff --git a/Mage.Sets/src/mage/sets/battleforzendikar/EmeriaShepherd.java b/Mage.Sets/src/mage/sets/battleforzendikar/EmeriaShepherd.java index b4322ab7f47..df914e83869 100644 --- a/Mage.Sets/src/mage/sets/battleforzendikar/EmeriaShepherd.java +++ b/Mage.Sets/src/mage/sets/battleforzendikar/EmeriaShepherd.java @@ -113,7 +113,7 @@ class EmeriaShepherdReturnToHandTargetEffect extends OneShotEffect { && controller.chooseUse(Outcome.PutCardInPlay, "Put the card to battlefield instead?", source, game)) { 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); } } diff --git a/Mage.Sets/src/mage/sets/lorwyn/Guile.java b/Mage.Sets/src/mage/sets/lorwyn/Guile.java index a945a8c5c54..f420c52eefa 100644 --- a/Mage.Sets/src/mage/sets/lorwyn/Guile.java +++ b/Mage.Sets/src/mage/sets/lorwyn/Guile.java @@ -109,11 +109,11 @@ class GuileReplacementEffect extends ReplacementEffectImpl { Spell spell = game.getStack().getSpell(event.getTargetId()); Player controller = game.getPlayer(source.getControllerId()); if (spell != null && controller != null) { - controller.moveCards(spell, null, Zone.EXILED, source, game); + controller.moveCards(spell, Zone.EXILED, source, game); if (!spell.isCopy()) { Card spellCard = spell.getCard(); 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; } diff --git a/Mage.Sets/src/mage/sets/lorwyn/HordeOfNotions.java b/Mage.Sets/src/mage/sets/lorwyn/HordeOfNotions.java index ab05c32d1e8..976cff926fd 100644 --- a/Mage.Sets/src/mage/sets/lorwyn/HordeOfNotions.java +++ b/Mage.Sets/src/mage/sets/lorwyn/HordeOfNotions.java @@ -33,9 +33,9 @@ import mage.abilities.Ability; import mage.abilities.common.SimpleActivatedAbility; import mage.abilities.costs.mana.ManaCostsImpl; import mage.abilities.effects.OneShotEffect; -import mage.abilities.keyword.VigilanceAbility; -import mage.abilities.keyword.TrampleAbility; import mage.abilities.keyword.HasteAbility; +import mage.abilities.keyword.TrampleAbility; +import mage.abilities.keyword.VigilanceAbility; import mage.cards.Card; import mage.cards.CardImpl; import mage.constants.CardType; @@ -55,11 +55,11 @@ import mage.target.common.TargetCardInYourGraveyard; public class HordeOfNotions extends CardImpl { private final static FilterCard filter = new FilterCard("Elemental card from your graveyard"); - + static { filter.add(new SubtypePredicate("Elemental")); } - + public HordeOfNotions(UUID ownerId) { super(ownerId, 249, "Horde of Notions", Rarity.RARE, new CardType[]{CardType.CREATURE}, "{W}{U}{B}{R}{G}"); this.expansionSetCode = "LRW"; @@ -74,8 +74,8 @@ public class HordeOfNotions extends CardImpl { this.addAbility(TrampleAbility.getInstance()); // Haste 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.addTarget(new TargetCardInYourGraveyard(filter)); this.addAbility(ability); @@ -92,37 +92,28 @@ public class HordeOfNotions extends CardImpl { } class HordeOfNotionsEffect extends OneShotEffect { - + public HordeOfNotionsEffect() { super(Outcome.PlayForFree); this.staticText = "You may play target Elemental card from your graveyard without paying its mana cost"; } - + public HordeOfNotionsEffect(final HordeOfNotionsEffect effect) { super(effect); } - + @Override public HordeOfNotionsEffect copy() { return new HordeOfNotionsEffect(this); } - + @Override public boolean apply(Game game, Ability source) { Player controller = game.getPlayer(source.getControllerId()); if (controller != null) { Card card = game.getCard(getTargetPointer().getFirst(game, source)); - if (card != null ) { - // Probably there is no Elemental land, but who knows - 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); - } - } + if (card != null && controller.chooseUse(outcome, "Play " + card.getName() + " from your graveyard for free?", source, game)) { + controller.playCard(card, game, true, true); } return true; } diff --git a/Mage.Sets/src/mage/sets/magic2010/DjinnOfWishes.java b/Mage.Sets/src/mage/sets/magic2010/DjinnOfWishes.java index ea454dc5cdb..b42be2535a1 100644 --- a/Mage.Sets/src/mage/sets/magic2010/DjinnOfWishes.java +++ b/Mage.Sets/src/mage/sets/magic2010/DjinnOfWishes.java @@ -28,12 +28,8 @@ package mage.sets.magic2010; 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.MageObject; import mage.abilities.Ability; import mage.abilities.common.EntersBattlefieldAbility; import mage.abilities.common.SimpleActivatedAbility; @@ -46,6 +42,10 @@ import mage.cards.Card; import mage.cards.CardImpl; import mage.cards.Cards; 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.game.Game; import mage.players.Player; @@ -100,33 +100,16 @@ class DjinnOfWishesEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { - Player player = game.getPlayer(source.getControllerId()); - if (player != null && player.getLibrary().size() > 0) { - Card card = player.getLibrary().getFromTop(game); - Cards cards = new CardsImpl(); - cards.add(card); - player.revealCards("Djinn of Wishes", cards, game); - - player.getLibrary().removeFromTop(game); - - 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) { + Player controller = game.getPlayer(source.getControllerId()); + MageObject sourceObject = game.getObject(source.getSourceId()); + if (controller != null && sourceObject != null && controller.getLibrary().size() > 0) { + Card card = controller.getLibrary().getFromTop(game); + Cards cards = new CardsImpl(card); + controller.revealCards(sourceObject.getIdName(), cards, game); + if (!controller.chooseUse(Outcome.PlayForFree, "Play " + card.getName() + " without paying its mana cost?", source, game) + || !controller.playCard(card, game, true, true)) { card.moveToZone(Zone.EXILED, source.getSourceId(), game, false); } - return true; } return false; diff --git a/Mage.Sets/src/mage/sets/morningtide/LeafCrownedElder.java b/Mage.Sets/src/mage/sets/morningtide/LeafCrownedElder.java index 29bf162db7e..80824610284 100644 --- a/Mage.Sets/src/mage/sets/morningtide/LeafCrownedElder.java +++ b/Mage.Sets/src/mage/sets/morningtide/LeafCrownedElder.java @@ -55,10 +55,10 @@ public class LeafCrownedElder extends CardImpl { this.power = new MageInt(3); 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. this.addAbility(new KinshipAbility(new LeafCrownedElderPlayEffect())); - + } public LeafCrownedElder(final LeafCrownedElder card) { @@ -84,18 +84,11 @@ class LeafCrownedElderPlayEffect extends OneShotEffect { @Override 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)); - if (player != null && card != null) { - 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()) { - player.playLand(card, game); - } - } else { - player.cast(card.getSpellAbility(), game, true); - } + if (controller != null && card != null) { + if (controller.chooseUse(Outcome.PlayForFree, "Play " + card.getIdName() + " without paying its mana cost?", source, game)) { + controller.playCard(card, game, true, true); } return true; } diff --git a/Mage.Sets/src/mage/sets/shardsofalara/BrilliantUltimatum.java b/Mage.Sets/src/mage/sets/shardsofalara/BrilliantUltimatum.java index 1f7020d8412..795c79dea3e 100644 --- a/Mage.Sets/src/mage/sets/shardsofalara/BrilliantUltimatum.java +++ b/Mage.Sets/src/mage/sets/shardsofalara/BrilliantUltimatum.java @@ -30,6 +30,7 @@ package mage.sets.shardsofalara; import java.util.ArrayList; import java.util.List; import java.util.UUID; +import mage.MageObject; import mage.abilities.Ability; import mage.abilities.effects.OneShotEffect; 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}"); 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. this.getSpellAbility().addEffect(new BrilliantUltimatumEffect()); - this.getSpellAbility().addTarget(new TargetOpponent(true)); - } public BrilliantUltimatum(final BrilliantUltimatum card) { @@ -91,22 +89,19 @@ class BrilliantUltimatumEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { - Player you = game.getPlayer(source.getControllerId()); - if (you == null) { + Player controller = game.getPlayer(source.getControllerId()); + MageObject sourceObject = game.getObject(source.getSourceId()); + if (controller == null || sourceObject == null) { return false; } Cards pile2 = new CardsImpl(); - int max = Math.min(you.getLibrary().size(), 5); - for (int i = 0; i < max; i++) { - Card card = you.getLibrary().removeFromTop(game); - if (card != null) { - card.moveToExile(source.getSourceId(), "Brilliant Ultimatum", source.getSourceId(), game); - pile2.add(card); - } - } + pile2.addAll(controller.getLibrary().getTopCards(game, 5)); + controller.moveCardsToExile(pile2.getCards(game), source, game, true, source.getSourceId(), sourceObject.getIdName()); - 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) { TargetCard target = new TargetCard(0, pile2.size(), Zone.EXILED, new FilterCard("cards to put in the first pile")); target.setRequired(false); @@ -123,55 +118,32 @@ class BrilliantUltimatumEffect extends OneShotEffect { } } } - for (UUID cardID : pile1) { - Card card = pile1.get(cardID, game); - pileOne.add(card); - } - for (UUID cardId : pile2) { - Card card = pile2.get(cardId, game); - pileTwo.add(card); - } - - 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); + pileOne.addAll(pile1.getCards(game)); + pileTwo.addAll(pile2.getCards(game)); + controller.revealCards("Pile 1 - " + sourceObject.getIdName(), pile1, game); + controller.revealCards("Pile 2 - " + sourceObject.getIdName(), pile2, game); + + boolean choice = controller.choosePile(Outcome.PlayForFree, "Which pile (play for free)?", pileOne, pileTwo, game); + String selectedPileName; + List selectedPileCards; + Cards selectedPile; if (choice) { - game.informPlayer(you, you.getLogName() + " chose Pile 1."); - while (!pileOne.isEmpty() && you.chooseUse(Outcome.PlayForFree, "Do you want to play a card from Pile 1?", source, game)) { - TargetCard targetExiledCard = new TargetCard(Zone.EXILED, new FilterCard()); - 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); - } - } - } - } + selectedPileName = "pile 1"; + selectedPileCards = pileOne; + selectedPile = pile1; } else { - game.informPlayer(you, you.getLogName() + " chose Pile 2."); - while (!pileTwo.isEmpty() && you.chooseUse(Outcome.PlayForFree, "Do you want to play a card from Pile 2?", source, game)) { - TargetCard targetExiledCard = new TargetCard(Zone.EXILED, new FilterCard()); - if (you.chooseTarget(Outcome.PlayForFree, pile2, targetExiledCard, source, game)) { - Card card = pile2.get(targetExiledCard.getFirstTarget(), game); - if (card != null) { - if (card.getCardType().contains(CardType.LAND)) { - you.playLand(card, game); - pileTwo.remove(card); - pile2.remove(card); - } else { - you.cast(card.getSpellAbility(), game, true); - pileTwo.remove(card); - pile2.remove(card); - } - } + selectedPileName = "pile 2"; + selectedPileCards = pileTwo; + selectedPile = pile2; + } + game.informPlayers(controller.getLogName() + " chose " + selectedPileName + "."); + while (!selectedPileCards.isEmpty() && controller.chooseUse(Outcome.PlayForFree, "Do you want to play a card for free from " + selectedPileName + "?", source, game)) { + TargetCard targetExiledCard = new TargetCard(Zone.EXILED, new FilterCard()); + if (controller.chooseTarget(Outcome.PlayForFree, selectedPile, targetExiledCard, source, game)) { + Card card = selectedPile.get(targetExiledCard.getFirstTarget(), game); + if (controller.playCard(card, game, true, true)) { + selectedPileCards.remove(card); + selectedPile.remove(card); } } } 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 6950e3c8ddd..2d070c4fa7f 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 @@ -1207,8 +1207,13 @@ public class TestPlayer implements Player { } @Override - public boolean playLand(Card card, Game game) { - return computerPlayer.playLand(card, game); + public boolean playCard(Card card, Game game, boolean noMana, boolean ignoreTiming) { + return computerPlayer.playCard(card, game, noMana, ignoreTiming); + } + + @Override + public boolean playLand(Card card, Game game, boolean ignoreTiming) { + return computerPlayer.playLand(card, game, ignoreTiming); } @Override @@ -1786,34 +1791,23 @@ public class TestPlayer implements Player { } @Override + @Deprecated public boolean moveCards(Cards cards, Zone fromZone, Zone toZone, Ability source, Game game) { return computerPlayer.moveCards(cards, fromZone, toZone, source, game); } @Override + @Deprecated public boolean moveCards(Card card, Zone fromZone, Zone toZone, Ability source, Game game) { return computerPlayer.moveCards(card, fromZone, toZone, source, game); } @Override + @Deprecated public boolean moveCards(Set cards, Zone fromZone, Zone toZone, Ability source, Game 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 cards, Zone fromZone, Zone toZone, Ability source, Game game, boolean withName) { -// return computerPlayer.moveCards(cards, fromZone, toZone, source, game); -// } @Override public boolean moveCardToHandWithInfo(Card card, UUID sourceId, Game game) { return computerPlayer.moveCardToHandWithInfo(card, sourceId, game); diff --git a/Mage.Tests/src/test/java/org/mage/test/stub/PlayerStub.java b/Mage.Tests/src/test/java/org/mage/test/stub/PlayerStub.java index 0ae6463b2af..d076ed3265c 100644 --- a/Mage.Tests/src/test/java/org/mage/test/stub/PlayerStub.java +++ b/Mage.Tests/src/test/java/org/mage/test/stub/PlayerStub.java @@ -25,11 +25,23 @@ * authors and should not be interpreted as representing official policies, either expressed * or implied, of BetaSteward_at_googlemail.com. */ - 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.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.Cost; import mage.abilities.costs.Costs; @@ -41,8 +53,12 @@ import mage.cards.Card; import mage.cards.Cards; import mage.cards.decks.Deck; 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.RangeOfInfluence; +import mage.constants.Zone; import mage.counters.Counter; import mage.counters.Counters; import mage.game.Game; @@ -64,9 +80,6 @@ import mage.target.TargetCard; import mage.target.common.TargetCardInLibrary; import mage.util.MessageToClient; -import java.io.Serializable; -import java.util.*; - /** * * @author Quercitron @@ -601,7 +614,12 @@ public class PlayerStub implements Player { } @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; } diff --git a/Mage/src/mage/abilities/PlayLandAbility.java b/Mage/src/mage/abilities/PlayLandAbility.java index 60a60797ccf..ed7689ef717 100644 --- a/Mage/src/mage/abilities/PlayLandAbility.java +++ b/Mage/src/mage/abilities/PlayLandAbility.java @@ -1,31 +1,30 @@ /* -* 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.abilities; import java.util.UUID; @@ -52,24 +51,24 @@ public class PlayLandAbility extends ActivatedAbilityImpl { @Override public boolean canActivate(UUID playerId, Game game) { - if (!controlsAbility(playerId, game) && - !game.getContinuousEffects().asThough(getSourceId(), AsThoughEffectType.PLAY_FROM_NOT_OWN_HAND_ZONE, playerId, game)) { + if (!controlsAbility(playerId, game) + && !game.getContinuousEffects().asThough(getSourceId(), AsThoughEffectType.PLAY_FROM_NOT_OWN_HAND_ZONE, playerId, game)) { return false; } - //20091005 - 114.2a - return game.canPlaySorcery(playerId) && game.getPlayer(playerId).canPlayLand(); + //20091005 - 114.2a + return game.getPlayer(playerId).canPlayLand(); } @Override public String getGameLogMessage(Game game) { - return new StringBuilder(" plays ").append(getMessageText(game)).toString(); + return " plays " + getMessageText(game); } @Override public String toString() { return this.name; } - + @Override public String getRule() { return this.name; diff --git a/Mage/src/mage/abilities/effects/common/ExileTargetAndSearchGraveyardHandLibraryEffect.java b/Mage/src/mage/abilities/effects/common/ExileTargetAndSearchGraveyardHandLibraryEffect.java index 5c7d93bdaf6..58c9e3c03ae 100644 --- a/Mage/src/mage/abilities/effects/common/ExileTargetAndSearchGraveyardHandLibraryEffect.java +++ b/Mage/src/mage/abilities/effects/common/ExileTargetAndSearchGraveyardHandLibraryEffect.java @@ -1,16 +1,16 @@ /* * 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 @@ -20,31 +20,26 @@ * 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.abilities.effects.common; import java.util.UUID; import mage.abilities.Ability; import mage.abilities.Mode; -import mage.abilities.SpellAbility; import mage.abilities.effects.common.search.SearchTargetGraveyardHandLibraryForCardNameAndExileEffect; -import mage.cards.Card; import mage.game.Game; import mage.game.permanent.Permanent; import mage.target.Target; import mage.target.TargetPermanent; -import mage.target.TargetPlayer; /** * * @author LevelX2 */ - public class ExileTargetAndSearchGraveyardHandLibraryEffect extends SearchTargetGraveyardHandLibraryForCardNameAndExileEffect { public ExileTargetAndSearchGraveyardHandLibraryEffect(Boolean graveyardExileOptional, String searchWhatText, String searchForText) { @@ -66,17 +61,16 @@ public class ExileTargetAndSearchGraveyardHandLibraryEffect extends SearchTarget exileTarget = target; break; } - } + } if (exileTarget != null) { Permanent permanentToExile = game.getPermanent(exileTarget.getFirstTarget()); if (permanentToExile != null) { targetPlayerId = permanentToExile.getControllerId(); result = permanentToExile.moveToExile(null, "", source.getSourceId(), game); - this.applySearchAndExile(game, source, permanentToExile.getName(), targetPlayerId); + this.applySearchAndExile(game, source, permanentToExile.getName(), targetPlayerId); } } - return result; } @@ -92,4 +86,4 @@ public class ExileTargetAndSearchGraveyardHandLibraryEffect extends SearchTarget sb.append(super.getText(mode)); return sb.toString(); } -} \ No newline at end of file +} diff --git a/Mage/src/mage/abilities/effects/common/HideawayPlayEffect.java b/Mage/src/mage/abilities/effects/common/HideawayPlayEffect.java index 749f5214e5e..6c757284942 100644 --- a/Mage/src/mage/abilities/effects/common/HideawayPlayEffect.java +++ b/Mage/src/mage/abilities/effects/common/HideawayPlayEffect.java @@ -28,17 +28,13 @@ package mage.abilities.effects.common; import mage.abilities.Ability; -import mage.abilities.condition.common.MyMainPhaseCondition; import mage.abilities.effects.OneShotEffect; import mage.cards.Card; -import mage.constants.CardType; import mage.constants.Outcome; -import mage.constants.Zone; import mage.game.ExileZone; import mage.game.Game; import mage.players.Player; import mage.util.CardUtil; -import org.apache.log4j.Logger; /** * @author LevelX2 @@ -64,35 +60,13 @@ public class HideawayPlayEffect extends OneShotEffect { public boolean apply(Game game, Ability source) { ExileZone zone = game.getExile().getExileZone(CardUtil.getCardExileZoneId(game, source)); if (zone == null || zone.isEmpty()) { - return false; + return true; } Card card = zone.getCards(game).iterator().next(); Player controller = game.getPlayer(source.getControllerId()); if (card != null && controller != null) { - 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(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; - } + if (controller.chooseUse(Outcome.PlayForFree, "Do you want to play " + card.getIdName() + " for free now?", source, game)) { + controller.playCard(card, game, true, false); } return true; } diff --git a/Mage/src/mage/players/Player.java b/Mage/src/mage/players/Player.java index 8ff08946832..d2565bd84a1 100644 --- a/Mage/src/mage/players/Player.java +++ b/Mage/src/mage/players/Player.java @@ -368,7 +368,29 @@ public interface Player extends MageItem, Copyable { 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); diff --git a/Mage/src/mage/players/PlayerImpl.java b/Mage/src/mage/players/PlayerImpl.java index 4a6d6c81f28..8d2553044b3 100644 --- a/Mage/src/mage/players/PlayerImpl.java +++ b/Mage/src/mage/players/PlayerImpl.java @@ -955,6 +955,23 @@ public abstract class PlayerImpl implements Player, Serializable { 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 public boolean cast(SpellAbility ability, Game game, boolean noMana) { if (!ability.getSpellAbilityType().equals(SpellAbilityType.BASE)) { @@ -1007,14 +1024,12 @@ public abstract class PlayerImpl implements Player, Serializable { } @Override - public SpellAbility chooseSpellAbilityForCast(SpellAbility ability, Game game, boolean noMana - ) { + public SpellAbility chooseSpellAbilityForCast(SpellAbility ability, Game game, boolean noMana) { return ability; } @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 ActivatedAbility playLandAbility = null; boolean found = false; @@ -1038,9 +1053,18 @@ public abstract class PlayerImpl implements Player, Serializable { if (playLandAbility == null) { return false; } + //20091005 - 114.2a if (!playLandAbility.canActivate(this.playerId, game)) { 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 if (!game.replaceEvent(GameEvent.getEvent(GameEvent.EventType.PLAY_LAND, card.getId(), card.getId(), playerId))) { // int bookmark = game.bookmarkState(); @@ -1147,9 +1171,8 @@ public abstract class PlayerImpl implements Player, Serializable { return true; } if (ability instanceof PlayLandAbility) { - Card card = game.getCard(ability.getSourceId()); - result = playLand(card, game); + result = playLand(card, game, false); } else { if (!ability.canActivate(this.playerId, game)) { return false;