Added possibility to use Morph with a land. Minor changes to some cards.

This commit is contained in:
LevelX2 2014-12-03 20:20:23 +01:00
parent 40febbe086
commit 4b66cd8367
15 changed files with 323 additions and 111 deletions

View file

@ -56,7 +56,7 @@ public class ForceOfWill extends CardImpl {
this.color.setBlue(true);
// You may pay 1 life and exile a blue card from your hand rather than pay Force of Will's mana cost.
FilterOwnedCard filter = new FilterOwnedCard("blue card from your hand");
FilterOwnedCard filter = new FilterOwnedCard("a blue card from your hand");
filter.add(new ColorPredicate(ObjectColor.BLUE));
filter.add(Predicates.not(new CardIdPredicate(this.getId()))); // the exile cost can never be paid with the card itself

View file

@ -30,6 +30,7 @@ package mage.sets.fifthdawn;
import java.util.UUID;
import mage.abilities.Ability;
import mage.abilities.common.SimpleStaticAbility;
import mage.abilities.condition.common.SourceIsSpellCondition;
import mage.abilities.costs.AlternativeCostSourceAbility;
import mage.abilities.costs.mana.ManaCostsImpl;
import mage.abilities.effects.ContinuousEffectImpl;
@ -71,7 +72,7 @@ public class FistOfSuns extends CardImpl {
class FistOfSunsRuleEffect extends ContinuousEffectImpl {
static AlternativeCostSourceAbility alternativeCastingCostAbility = new AlternativeCostSourceAbility(new ManaCostsImpl("{W}{U}{B}{R}{G}"));
static AlternativeCostSourceAbility alternativeCastingCostAbility = new AlternativeCostSourceAbility(new ManaCostsImpl("{W}{U}{B}{R}{G}"), SourceIsSpellCondition.getInstance());
public FistOfSunsRuleEffect() {
super(Duration.WhileOnBattlefield, Outcome.Detriment);

View file

@ -30,6 +30,7 @@ package mage.sets.magic2013;
import java.util.UUID;
import mage.abilities.Ability;
import mage.abilities.common.SimpleStaticAbility;
import mage.abilities.condition.common.SourceIsSpellCondition;
import mage.abilities.costs.AlternativeCostSourceAbility;
import mage.abilities.effects.ContinuousEffectImpl;
import mage.cards.CardImpl;
@ -73,7 +74,7 @@ public class Omniscience extends CardImpl {
class OmniscienceCastingEffect extends ContinuousEffectImpl {
static AlternativeCostSourceAbility alternativeCastingCostAbility = new AlternativeCostSourceAbility(
null, null, null, new FilterNonlandCard(), true);
null, SourceIsSpellCondition.getInstance(), null, new FilterNonlandCard(), true);
public OmniscienceCastingEffect() {
super(Duration.WhileOnBattlefield, Outcome.Detriment);

View file

@ -30,6 +30,7 @@ package mage.sets.stronghold;
import java.util.UUID;
import mage.abilities.Ability;
import mage.abilities.common.SimpleStaticAbility;
import mage.abilities.condition.common.SourceIsSpellCondition;
import mage.abilities.costs.AlternativeCostSourceAbility;
import mage.abilities.costs.common.DiscardCardCost;
import mage.abilities.effects.ContinuousEffectImpl;
@ -82,7 +83,7 @@ class DreamHallsEffect extends ContinuousEffectImpl {
filter.add(new SharesColorWithSourcePredicate());
}
static AlternativeCostSourceAbility alternativeCastingCostAbility = new AlternativeCostSourceAbility(new DiscardCardCost(filter));
static AlternativeCostSourceAbility alternativeCastingCostAbility = new AlternativeCostSourceAbility(new DiscardCardCost(filter), SourceIsSpellCondition.getInstance());
public DreamHallsEffect() {
super(Duration.WhileOnBattlefield, Outcome.Detriment);

View file

@ -30,6 +30,7 @@ package mage.sets.tempest;
import java.util.UUID;
import mage.abilities.Ability;
import mage.abilities.common.SimpleStaticAbility;
import mage.abilities.condition.common.SourceIsSpellCondition;
import mage.abilities.costs.AlternativeCostSourceAbility;
import mage.abilities.effects.ContinuousEffectImpl;
import mage.abilities.effects.Effect;
@ -103,7 +104,7 @@ class AlurenRuleEffect extends ContinuousEffectImpl {
filter.add(new ConvertedManaCostPredicate(ComparisonType.LessThan, 4));
}
static AlternativeCostSourceAbility alternativeCastingCostAbility = new AlternativeCostSourceAbility(null, null, null, filter, true);
static AlternativeCostSourceAbility alternativeCastingCostAbility = new AlternativeCostSourceAbility(null, SourceIsSpellCondition.getInstance(), null, filter, true);
public AlurenRuleEffect() {
super(Duration.WhileOnBattlefield, Outcome.Detriment);

View file

@ -49,6 +49,8 @@ public class LlanowarElves extends CardImpl {
this.color.setGreen(true);
this.power = new MageInt(1);
this.toughness = new MageInt(1);
// {T}: Add {G} to your mana pool.
this.addAbility(new GreenManaAbility());
}

View file

@ -35,6 +35,7 @@ import java.util.List;
import java.util.UUID;
import mage.abilities.common.ZoneChangeTriggeredAbility;
import mage.abilities.costs.AlternativeCost;
import mage.abilities.costs.AlternativeSourceCosts;
import mage.abilities.costs.Cost;
import mage.abilities.keyword.ProtectionAbility;
import mage.abilities.mana.ManaAbility;

View file

@ -47,6 +47,7 @@ import mage.constants.EffectType;
import mage.constants.Zone;
import mage.game.Controllable;
import mage.game.Game;
import mage.players.Player;
import mage.target.Target;
import mage.target.Targets;
@ -473,4 +474,7 @@ public interface Ability extends Controllable, Serializable {
* @param active execute no cost modification
*/
void setCostModificationActive(boolean active);
boolean activateAlternateOrAdditionalCosts(MageObject sourceObject, boolean noMana, Player controller, Game game);
}

View file

@ -56,6 +56,7 @@ import java.util.List;
import java.util.UUID;
import mage.abilities.costs.common.TapSourceCost;
import mage.game.events.GameEvent;
import mage.game.permanent.Permanent;
/**
*
@ -238,36 +239,10 @@ public abstract class AbilityImpl implements Ability {
// as buyback, kicker, or convoke costs (see rules 117.8 and 117.9), the player announces his
// or her intentions to pay any or all of those costs (see rule 601.2e).
// A player can't apply two alternative methods of casting or two alternative costs to a single spell.
if (sourceObject != null && !(this instanceof FlashbackAbility)) {
boolean alternativeCostisUsed = false;
for (Ability ability : sourceObject.getAbilities()) {
// if cast for noMana no Alternative costs are allowed
if (!noMana && ability instanceof AlternativeSourceCosts) {
AlternativeSourceCosts alternativeSpellCosts = (AlternativeSourceCosts) ability;
if (alternativeSpellCosts.isAvailable(this, game)) {
if (alternativeSpellCosts.askToActivateAlternativeCosts(this, game)) {
// only one alternative costs may be activated
alternativeCostisUsed = true;
break;
}
}
}
if (ability instanceof OptionalAdditionalSourceCosts) {
((OptionalAdditionalSourceCosts)ability).addOptionalAdditionalCosts(this, game);
}
}
// controller specific alternate spell costs
if (!noMana && !alternativeCostisUsed) {
if (this.getAbilityType().equals(AbilityType.SPELL)) {
for (AlternativeSourceCosts alternativeSourceCosts: controller.getAlternativeSourceCosts()) {
if (alternativeSourceCosts.isAvailable(this, game)) {
if (alternativeSourceCosts.askToActivateAlternativeCosts(this, game)) {
// only one alternative costs may be activated
break;
}
}
}
}
if (!activateAlternateOrAdditionalCosts(sourceObject, noMana, controller, game)){
if (getAbilityType().equals(AbilityType.SPELL)
&& ((SpellAbility) this).getSpellAbilityType().equals(SpellAbilityType.LAND_ALTERNATE)) {
return false;
}
}
@ -367,7 +342,7 @@ public abstract class AbilityImpl implements Ability {
game.informPlayers(new StringBuilder(controller.getName()).append(" announces a value of ").append(xValue).append(" for ").append(variableManaCost.getText()).toString());
}
activated = true;
// fire if tapped for mana (may only fires now because else costs of ability itself can be payed with mana of abilities that trigger for that event
// fire if tapped for mana (may only fire now because else costs of ability itself can be payed with mana of abilities that trigger for that event
if (this.getAbilityType().equals(AbilityType.MANA)) {
for (Cost cost: costs) {
if (cost instanceof TapSourceCost) {
@ -384,6 +359,44 @@ public abstract class AbilityImpl implements Ability {
return activated;
}
@Override
public boolean activateAlternateOrAdditionalCosts(MageObject sourceObject, boolean noMana, Player controller, Game game) {
boolean alternativeCostisUsed = false;
if (sourceObject != null && !(sourceObject instanceof Permanent) && !(this instanceof FlashbackAbility)) {
for (Ability ability : sourceObject.getAbilities()) {
// if cast for noMana no Alternative costs are allowed
if (!noMana && ability instanceof AlternativeSourceCosts) {
AlternativeSourceCosts alternativeSpellCosts = (AlternativeSourceCosts) ability;
if (alternativeSpellCosts.isAvailable(this, game)) {
if (alternativeSpellCosts.askToActivateAlternativeCosts(this, game)) {
// only one alternative costs may be activated
alternativeCostisUsed = true;
break;
}
}
}
if (ability instanceof OptionalAdditionalSourceCosts) {
((OptionalAdditionalSourceCosts)ability).addOptionalAdditionalCosts(this, game);
}
}
// controller specific alternate spell costs
if (!noMana && !alternativeCostisUsed) {
if (this.getAbilityType().equals(AbilityType.SPELL)) {
for (AlternativeSourceCosts alternativeSourceCosts: controller.getAlternativeSourceCosts()) {
if (alternativeSourceCosts.isAvailable(this, game)) {
if (alternativeSourceCosts.askToActivateAlternativeCosts(this, game)) {
// only one alternative costs may be activated
alternativeCostisUsed = true;
break;
}
}
}
}
}
}
return alternativeCostisUsed;
}
/**
* Handles the setting of non mana X costs
* @param controller *

View file

@ -0,0 +1,55 @@
/*
* 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.condition.common;
import java.util.UUID;
import mage.MageObject;
import mage.abilities.Ability;
import mage.abilities.condition.Condition;
import mage.constants.CardType;
import mage.game.Game;
/**
*
* @author LevelX2
*/
public class SourceIsSpellCondition implements Condition {
private static final SourceIsSpellCondition fInstance = new SourceIsSpellCondition();
public static Condition getInstance() {
return fInstance;
}
@Override
public boolean apply(Game game, Ability source) {
MageObject object = game.getObject(source.getSourceId());
return object != null && !object.getCardType().contains(CardType.LAND);
}
}

View file

@ -50,7 +50,7 @@ public class ExileFromHandCost extends CostImpl {
public ExileFromHandCost(TargetCardInHand target) {
this.addTarget(target);
this.text = "Exile " + target.getTargetName();
this.text = "exile " + target.getTargetName();
}
public ExileFromHandCost(ExileFromHandCost cost) {

View file

@ -33,7 +33,6 @@ import java.util.Iterator;
import java.util.List;
import mage.ObjectColor;
import mage.abilities.Ability;
import mage.abilities.SpellAbility;
import mage.abilities.StaticAbility;
import mage.abilities.common.SimpleStaticAbility;
import mage.abilities.common.TurnFaceUpAbility;
@ -48,6 +47,7 @@ import mage.abilities.costs.mana.ManaCosts;
import mage.abilities.effects.ContinuousEffectImpl;
import mage.abilities.effects.common.continious.SourceEffect;
import mage.cards.Card;
import mage.constants.AbilityType;
import mage.constants.CardType;
import mage.constants.Duration;
import mage.constants.Layer;
@ -181,7 +181,7 @@ public class MorphAbility extends StaticAbility implements AlternativeSourceCost
@Override
public boolean askToActivateAlternativeCosts(Ability ability, Game game) {
if (ability instanceof SpellAbility) {
if (ability.getAbilityType().equals(AbilityType.SPELL)) {
Player player = game.getPlayer(controllerId);
Spell spell = game.getStack().getSpell(ability.getId());
if (player != null && spell != null) {
@ -214,6 +214,28 @@ public class MorphAbility extends StaticAbility implements AlternativeSourceCost
}
}
}
if (ability.getAbilityType().equals(AbilityType.PLAY_LAND)) {
Player player = game.getPlayer(controllerId);
if (player != null) {
this.resetMorph();
if (alternateCosts.canPay(ability, sourceId, controllerId, game)) {
if (player.chooseUse(Outcome.Benefit, new StringBuilder("Cast this card as a 2/2 face-down creature for ").append(getCosts().getText()).append(" ?").toString(), game)) {
activateMorph(game);
// change mana costs
ability.getManaCostsToPay().clear();
ability.getCosts().clear();
for (Iterator it = this.alternateCosts.iterator(); it.hasNext();) {
Cost cost = (Cost) it.next();
if (cost instanceof ManaCost) {
ability.getManaCostsToPay().add((ManaCost)cost.copy());
} else {
ability.getCosts().add(cost.copy());
}
}
}
}
}
}
return isActivated(ability, game);
}

View file

@ -7,6 +7,7 @@ package mage.constants;
public enum SpellAbilityType {
BASE("Basic SpellAbility"),
BASE_ALTERNATE("Basic SpellAbility Alternate"), // used for Overload, Flashback to know they must be handled as Alternate casting costs
LAND_ALTERNATE("Basic SpellAbility Alternate Land"), // used for Lands with Morph to cast as Face Down creature
SPLIT("Split SpellAbility"),
SPLIT_FUSED("Split SpellAbility"),
SPLIT_LEFT("LeftSplit SpellAbility"),

View file

@ -56,6 +56,7 @@ import java.util.List;
import java.util.UUID;
import mage.cards.Card;
import mage.constants.AbilityWord;
import mage.players.Player;
/**
*
@ -450,6 +451,11 @@ public class StackAbility implements StackObject, Ability {
throw new UnsupportedOperationException("Not supported.");
}
@Override
public boolean activateAlternateOrAdditionalCosts(MageObject sourceObject, boolean noMana, Player controller, Game game) {
throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
}
@Override
public String getGameLogMessage(Game game) {
throw new UnsupportedOperationException("Not supported."); //To change body of generated methods, choose Tools | Templates.

View file

@ -61,6 +61,7 @@ import mage.abilities.costs.AlternativeCost;
import mage.abilities.costs.AlternativeCostSourceAbility;
import mage.abilities.costs.AlternativeSourceCosts;
import mage.abilities.costs.Cost;
import mage.abilities.costs.OptionalAdditionalSourceCosts;
import mage.abilities.costs.mana.ManaCost;
import mage.abilities.costs.mana.ManaCostsImpl;
import mage.abilities.effects.RestrictionEffect;
@ -88,6 +89,14 @@ import mage.constants.ManaType;
import mage.constants.Outcome;
import mage.constants.PhaseStep;
import mage.constants.PlayerAction;
import static mage.constants.PlayerAction.PASS_PRIORITY_CANCEL_ALL_ACTIONS;
import static mage.constants.PlayerAction.PASS_PRIORITY_UNTIL_MY_NEXT_TURN;
import static mage.constants.PlayerAction.PASS_PRIORITY_UNTIL_NEXT_MAIN_PHASE;
import static mage.constants.PlayerAction.PASS_PRIORITY_UNTIL_NEXT_TURN;
import static mage.constants.PlayerAction.PASS_PRIORITY_UNTIL_STACK_RESOLVED;
import static mage.constants.PlayerAction.PASS_PRIORITY_UNTIL_TURN_END_STEP;
import static mage.constants.PlayerAction.PERMISSION_REQUESTS_ALLOWED_OFF;
import static mage.constants.PlayerAction.PERMISSION_REQUESTS_ALLOWED_ON;
import mage.constants.RangeOfInfluence;
import mage.constants.SpellAbilityType;
import mage.constants.TimingRule;
@ -940,6 +949,32 @@ public abstract class PlayerImpl implements Player, Serializable {
@Override
public boolean playLand(Card card, Game game) {
// Check for alternate casting possibilities: e.g. land with Morph
ActivatedAbility playLandAbility = null;
boolean found = false;
for (Ability ability : card.getAbilities()) {
// if cast for noMana no Alternative costs are allowed
if ((ability instanceof AlternativeSourceCosts) ||(ability instanceof OptionalAdditionalSourceCosts)) {
found = true;
}
if (ability instanceof PlayLandAbility) {
playLandAbility = (ActivatedAbility) ability;
}
}
if (found) {
SpellAbility spellAbility = new SpellAbility(null, "", game.getState().getZone(card.getId()), SpellAbilityType.LAND_ALTERNATE);
spellAbility.setControllerId(this.getId());
spellAbility.setSourceId(card.getId());
if (cast(spellAbility, game, false)) {
return true;
}
}
if (playLandAbility == null) {
return false;
}
if (!playLandAbility.canActivate(this.playerId, game)) {
return false;
}
//20091005 - 305.1
if (!game.replaceEvent(GameEvent.getEvent(GameEvent.EventType.PLAY_LAND, card.getId(), card.getId(), playerId))) {
// int bookmark = game.bookmarkState();
@ -1026,35 +1061,35 @@ public abstract class PlayerImpl implements Player, Serializable {
@Override
public boolean activateAbility(ActivatedAbility ability, Game game) {
boolean result;
if (!ability.canActivate(this.playerId, game)) {
return false;
}
if (ability instanceof PassAbility) {
pass(game);
return true;
}
else if (ability instanceof PlayLandAbility) {
if (ability instanceof PlayLandAbility) {
Card card = hand.get(ability.getSourceId(), game);
if (card == null) {
card = game.getCard(ability.getSourceId());
}
result = playLand(card, game);
}
else if (ability instanceof SpecialAction) {
result = specialAction((SpecialAction)ability.copy(), game);
}
else if (ability instanceof ManaAbility) {
result = playManaAbility((ManaAbility)ability.copy(), game);
}
else if (ability instanceof FlashbackAbility){
result = playAbility(ability.copy(), game);
}
else if (ability instanceof SpellAbility) {
result = cast((SpellAbility)ability, game, false);
}
else {
result = playAbility(ability.copy(), game);
} else {
if (!ability.canActivate(this.playerId, game)) {
return false;
}
if (ability instanceof SpecialAction) {
result = specialAction((SpecialAction)ability.copy(), game);
}
else if (ability instanceof ManaAbility) {
result = playManaAbility((ManaAbility)ability.copy(), game);
}
else if (ability instanceof FlashbackAbility){
result = playAbility(ability.copy(), game);
}
else if (ability instanceof SpellAbility) {
result = cast((SpellAbility)ability, game, false);
}
else {
result = playAbility(ability.copy(), game);
}
}
//if player has taken an action then reset all player passed flags
@ -1120,9 +1155,21 @@ public abstract class PlayerImpl implements Player, Serializable {
protected LinkedHashMap<UUID, ActivatedAbility> getUseableActivatedAbilities(MageObject object, Zone zone, Game game) {
LinkedHashMap<UUID, ActivatedAbility> useable = new LinkedHashMap<>();
if (!(object instanceof Permanent) || ((Permanent)object).canUseActivatedAbilities(game)) {
for (ActivatedAbility ability: object.getAbilities().getActivatedAbilities(zone)) {
if (ability.canActivate(playerId, game)) {
useable.put(ability.getId(), ability);
for (Ability ability: object.getAbilities()) {
if (ability.getZone().match(zone)) {
if (ability instanceof ActivatedAbility) {
if (((ActivatedAbility)ability).canActivate(playerId, game)) {
useable.put(ability.getId(), (ActivatedAbility)ability);
}
} else if (ability instanceof AlternativeSourceCosts){
if (object.getCardType().contains(CardType.LAND)) {
for (Ability ability2: object.getAbilities().copy()) {
if (ability2 instanceof PlayLandAbility) {
useable.put(ability2.getId(), (ActivatedAbility)ability2);
}
}
}
}
}
}
if (zone != Zone.HAND) {
@ -2094,9 +2141,8 @@ public abstract class PlayerImpl implements Player, Serializable {
}
}
}
MageObject object = game.getObject(ability.getSourceId());
for (Ability objectAbility :object.getAbilities()) {
// old alternate costs
for (Ability objectAbility :sourceObject.getAbilities()) {
if (objectAbility instanceof AlternativeCostSourceAbility) {
if (objectAbility.getCosts().canPay(ability, ability.getSourceId(), playerId, game)) {
return true;
@ -2109,38 +2155,79 @@ public abstract class PlayerImpl implements Player, Serializable {
return true;
}
}
if (!(sourceObject instanceof Permanent)) {
for (Ability alternateSourceCostsAbility : sourceObject.getAbilities()) {
// if cast for noMana no Alternative costs are allowed
if (alternateSourceCostsAbility instanceof AlternativeSourceCosts) {
if (((AlternativeSourceCosts)alternateSourceCostsAbility).isAvailable(ability, game)) {
if (alternateSourceCostsAbility.getCosts().canPay(ability, playerId, playerId, game)) {
ManaCostsImpl manaCosts = new ManaCostsImpl();
for(Cost cost:alternateSourceCostsAbility.getCosts()) {
if (cost instanceof ManaCost) {
manaCosts.add(cost);
}
}
// new alternate costs
if(canPlayCardByAlternateCost(card, available, ability, game)) {
return true;
}
}
return false;
}
if (manaCosts.size() == 0) {
return true;
protected boolean canPlayCardByAlternateCost(Card sourceObject, ManaOptions available, Ability ability, Game game) {
if (!(sourceObject instanceof Permanent)) {
for (Ability alternateSourceCostsAbility : sourceObject.getAbilities()) {
// if cast for noMana no Alternative costs are allowed
if (alternateSourceCostsAbility instanceof AlternativeSourceCosts) {
if (((AlternativeSourceCosts)alternateSourceCostsAbility).isAvailable(ability, game)) {
if (alternateSourceCostsAbility.getCosts().canPay(ability, playerId, playerId, game)) {
ManaCostsImpl manaCosts = new ManaCostsImpl();
for(Cost cost:alternateSourceCostsAbility.getCosts()) {
if (cost instanceof ManaCost) {
manaCosts.add(cost);
}
else {
for (Mana mana: manaCosts.getOptions()) {
for (Mana avail: available) {
if (mana.enough(avail)) {
return true;
}
}
if (manaCosts.size() == 0) {
return true;
}
else {
for (Mana mana: manaCosts.getOptions()) {
for (Mana avail: available) {
if (mana.enough(avail)) {
return true;
}
}
}
}
}
}
}
}
}
}
}
return false;
}
protected boolean canLandPlayAlternateSourceCostsAbility(Card sourceObject, ManaOptions available, Ability ability, Game game) {
if (!(sourceObject instanceof Permanent)) {
Ability sourceAbility = null;
for(Ability landAbility : sourceObject.getAbilities()) {
if (landAbility.getAbilityType().equals(AbilityType.PLAY_LAND)) {
sourceAbility = landAbility;
break;
}
}
if (sourceAbility != null && ((AlternativeSourceCosts)ability).isAvailable(sourceAbility, game)) {
if (ability.getCosts().canPay(ability, sourceObject.getId(), this.getId(), game)) {
ManaCostsImpl manaCosts = new ManaCostsImpl();
for(Cost cost:ability.getCosts()) {
if (cost instanceof ManaCost) {
manaCosts.add(cost);
}
}
if (manaCosts.size() == 0) {
return true;
}
else {
for (Mana mana: manaCosts.getOptions()) {
for (Mana avail: available) {
if (mana.enough(avail)) {
return true;
}
}
}
}
}
}
}
return false;
}
@ -2156,15 +2243,19 @@ public abstract class PlayerImpl implements Player, Serializable {
if (hidden) {
for (Card card : hand.getUniqueCards(game)) {
for (Ability ability : card.getAbilities().getPlayableAbilities(Zone.HAND)) { // gets this activated ability from hand? (Morph?)
if (ability instanceof ActivatedAbility) {
if (ability instanceof PlayLandAbility) {
if (game.getContinuousEffects().preventedByRuleModification(GameEvent.getEvent(GameEvent.EventType.PLAY_LAND, ability.getSourceId(), ability.getSourceId(), playerId), ability, game, true)) {
break;
for (Ability ability : card.getAbilities()) { // gets this activated ability from hand? (Morph?)
if (ability.getZone().match(Zone.HAND)) {
if (ability instanceof ActivatedAbility) {
if (!(ability instanceof PlayLandAbility) ||
!game.getContinuousEffects().preventedByRuleModification(GameEvent.getEvent(GameEvent.EventType.PLAY_LAND, ability.getSourceId(), ability.getSourceId(), playerId), ability, game, true)) {
if (canPlay((ActivatedAbility) ability, availableMana, card, game)) {
playable.add(ability);
}
}
} else if (card.getCardType().contains(CardType.LAND) && ability instanceof AlternativeSourceCosts) {
if (canLandPlayAlternateSourceCostsAbility(card, availableMana, ability, game)) { // e.g. Land with Morph
playable.add(ability);
}
}
if (canPlay((ActivatedAbility) ability, availableMana, card, game)) {
playable.add(ability);
}
}
}
@ -2265,23 +2356,36 @@ public abstract class PlayerImpl implements Player, Serializable {
available.addMana(manaPool.getMana());
for (Card card : hand.getCards(game)) {
for (ActivatedAbility ability : card.getAbilities().getPlayableAbilities(Zone.HAND)) {
if (ability instanceof PlayLandAbility) {
if (game.getContinuousEffects().preventedByRuleModification(GameEvent.getEvent(GameEvent.EventType.PLAY_LAND, ability.getSourceId(), ability.getSourceId(), playerId), ability, game, true)) {
break;
Abilities:
for (Ability ability : card.getAbilities()) {
if (ability.getZone().match(Zone.HAND)) {
switch (ability.getAbilityType()) {
case PLAY_LAND:
if (game.getContinuousEffects().preventedByRuleModification(GameEvent.getEvent(GameEvent.EventType.PLAY_LAND, ability.getSourceId(), ability.getSourceId(), playerId), ability, game, true)) {
break;
}
if (canPlay((ActivatedAbility) ability, available, card, game)) {
playable.add(card.getId());
break Abilities;
}
break;
case ACTIVATED:
case SPELL:
if (canPlay((ActivatedAbility) ability, available, card, game)) {
playable.add(card.getId());
break Abilities;
}
break;
case STATIC:
if (card.getCardType().contains(CardType.LAND) && ability instanceof AlternativeSourceCosts) {
if (canLandPlayAlternateSourceCostsAbility(card, available, ability, game)) { // e.g. Land with Morph
playable.add(card.getId());
break Abilities;
}
}
}
}
if (canPlay(ability, available, card, game)) {
playable.add(card.getId());
break;
}
}
// for (ActivatedAbility ability : card.getAbilities().getActivatedAbilities(Zone.HAND)) {
// if (!playable.contains(ability.getSourceId()) && canPlay(ability, available, card, game)) {
// playable.add(card.getId());
// break;
// }
// }
}
}