From 6049a69348ab5e34b3d1e1d4bc19cbd728a269c6 Mon Sep 17 00:00:00 2001 From: LevelX2 Date: Tue, 18 Feb 2014 14:39:33 +0100 Subject: [PATCH] Added generic AlternateCostSourceAbility. Some adjustments to alternate cost handling. --- Mage/src/mage/abilities/AbilityImpl.java | 10 +- .../abilities/costs/AlternativeCost2.java | 1 - .../abilities/costs/AlternativeCost2Impl.java | 16 +- .../costs/AlternativeCostSourceAbility.java | 168 ++++++++++++++++++ .../costs/AlternativeSourceCosts.java | 12 +- .../mage/abilities/keyword/EvokeAbility.java | 7 +- .../mage/abilities/keyword/ProwlAbility.java | 9 +- 7 files changed, 209 insertions(+), 14 deletions(-) create mode 100644 Mage/src/mage/abilities/costs/AlternativeCostSourceAbility.java diff --git a/Mage/src/mage/abilities/AbilityImpl.java b/Mage/src/mage/abilities/AbilityImpl.java index 2b0a4b25fd..6e970016cd 100644 --- a/Mage/src/mage/abilities/AbilityImpl.java +++ b/Mage/src/mage/abilities/AbilityImpl.java @@ -58,6 +58,7 @@ import mage.game.command.Emblem; /** * * @author BetaSteward_at_googlemail.com + * @param */ public abstract class AbilityImpl> implements Ability { @@ -204,9 +205,12 @@ public abstract class AbilityImpl> implements Ability { if (card != null) { for (Ability ability : card.getAbilities()) { if (ability instanceof AlternativeSourceCosts) { - if (((AlternativeSourceCosts)ability).askToActivateAlternativeCosts(this, game)) { - // only one alternative costs may be activated - break; + AlternativeSourceCosts alternativeSpellCosts = (AlternativeSourceCosts) ability; + if (alternativeSpellCosts.isAvailable(this, game)) { + if (alternativeSpellCosts.askToActivateAlternativeCosts(this, game)) { + // only one alternative costs may be activated + break; + } } } if (ability instanceof OptionalAdditionalSourceCosts) { diff --git a/Mage/src/mage/abilities/costs/AlternativeCost2.java b/Mage/src/mage/abilities/costs/AlternativeCost2.java index abae796f55..b603d724ef 100644 --- a/Mage/src/mage/abilities/costs/AlternativeCost2.java +++ b/Mage/src/mage/abilities/costs/AlternativeCost2.java @@ -66,7 +66,6 @@ public interface AlternativeCost2 extends Cost { /** * If the player intends to pay the alternate cost, the cost will be activated * - * @param activated */ void activate(); diff --git a/Mage/src/mage/abilities/costs/AlternativeCost2Impl.java b/Mage/src/mage/abilities/costs/AlternativeCost2Impl.java index dccd67ba18..aacd871c23 100644 --- a/Mage/src/mage/abilities/costs/AlternativeCost2Impl.java +++ b/Mage/src/mage/abilities/costs/AlternativeCost2Impl.java @@ -29,8 +29,11 @@ package mage.abilities.costs; /** - * - * @author Ludwig + * Alternative costs + * + * @author LevelX2 + * + * @param */ public class AlternativeCost2Impl > extends CostsImpl implements AlternativeCost2 { @@ -49,7 +52,9 @@ public class AlternativeCost2Impl > extends Co this.activated = false; this.name = name; this.delimiter = delimiter; - this.reminderText = new StringBuilder("").append(reminderText).append("").toString(); + if (reminderText != null) { + this.reminderText = new StringBuilder("").append(reminderText).append("").toString(); + } this.add((Cost) cost); } @@ -67,7 +72,7 @@ public class AlternativeCost2Impl > extends Co } /** * Returns the complete text for the addional cost or if onlyCost is true - * only the pure text fore the included native cost + * only the pure text for the included native cost * * @param onlyCost * @return @@ -77,7 +82,7 @@ public class AlternativeCost2Impl > extends Co if (onlyCost) { return getText(); } else { - return new StringBuffer(name).append(delimiter).append(getText()).toString(); + return new StringBuffer(name != null ? name: "").append(delimiter != null ? delimiter: "").append(getText()).toString(); } } @@ -113,7 +118,6 @@ public class AlternativeCost2Impl > extends Co /** * If the player intends to pay the cost, the cost will be activated * - * @param activated */ @Override public void activate() { diff --git a/Mage/src/mage/abilities/costs/AlternativeCostSourceAbility.java b/Mage/src/mage/abilities/costs/AlternativeCostSourceAbility.java new file mode 100644 index 0000000000..5fa747878b --- /dev/null +++ b/Mage/src/mage/abilities/costs/AlternativeCostSourceAbility.java @@ -0,0 +1,168 @@ +/* + * 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.costs; + +import java.util.Iterator; +import java.util.LinkedList; +import java.util.List; +import mage.abilities.Ability; +import mage.abilities.SpellAbility; +import mage.abilities.StaticAbility; +import mage.abilities.condition.Condition; +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.constants.Outcome; +import mage.constants.Zone; +import mage.game.Game; +import mage.players.Player; + +/** + * + * @author LevelX2 + */ +public class AlternativeCostSourceAbility extends StaticAbility implements AlternativeSourceCosts { + + protected List alternateCosts = new LinkedList(); + protected Condition condition; + protected String rule; + + public AlternativeCostSourceAbility(Cost cost) { + this(cost, null); + } + + public AlternativeCostSourceAbility(Cost cost, Condition conditon) { + this(cost, conditon, null); + } + + public AlternativeCostSourceAbility(Cost cost, Condition condition, String rule) { + super(Zone.ALL, null); + this.convertToAlternativeCostAndAdd(cost); + this.setRuleAtTheTop(true); + this.condition = condition; + this.rule = rule; + } + + private void convertToAlternativeCostAndAdd(Cost cost) { + AlternativeCost2 alternativeCost = new AlternativeCost2Impl(null, null, cost); + this.alternateCosts.add(alternativeCost); + } + + public AlternativeCostSourceAbility(final AlternativeCostSourceAbility ability) { + super(ability); + this.alternateCosts = ability.alternateCosts; + this.condition = ability.condition; + this.rule = ability.rule; + } + + @Override + public AlternativeCostSourceAbility copy() { + return new AlternativeCostSourceAbility(this); + } + + @Override + public boolean isAvailable(Ability source, Game game) { + if (condition != null) { + return condition.apply(game, source); + } + return true; + } + + @Override + public boolean askToActivateAlternativeCosts(Ability ability, Game game) { + if (ability instanceof SpellAbility) { + Player player = game.getPlayer(controllerId); + if (player != null) { + for (AlternativeCost2 alternateCost: alternateCosts) { + if (alternateCost.canPay(sourceId, controllerId, game) && + player.chooseUse(Outcome.Benefit, new StringBuilder("Pay alternative costs: ").append(alternateCost.getText()).append(" ?").toString(), game)) { + alternateCost.activate(); + ability.getManaCostsToPay().clear(); + ability.getCosts().clear(); + for (Iterator it = ((Costs) alternateCost).iterator(); it.hasNext();) { + Cost cost = (Cost) it.next(); + if (cost instanceof ManaCostsImpl) { + ability.getManaCostsToPay().add((ManaCostsImpl) cost.copy()); + } else { + ability.getCosts().add(cost.copy()); + } + } + } + } + } + } + return isActivated(); + } + + @Override + public boolean isActivated() { + for (AlternativeCost2 cost: alternateCosts) { + if(cost.isActivated()) { + return true; + } + } + return false; + } + + @Override + public String getCastMessageSuffix() { + return " using alternative casting costs"; + } + + @Override + public String getRule() { + if (rule != null) { + return rule; + } +// You may exile a black card from your hand rather than pay Unmask's mana cost. + + StringBuilder sb = new StringBuilder(); + if (condition != null) { + sb.append(condition.toString()); + sb.append(", rather than pay {source}'s mana cost, "); + } + int numberCosts = 0; + String remarkText = ""; + for (AlternativeCost2 alternativeCost: alternateCosts) { + if (numberCosts == 0) { + sb.append(alternativeCost.getText(false)); + remarkText = alternativeCost.getReminderText(); + } else { + sb.append(" and/or ").append(alternativeCost.getText(true)); + } + ++numberCosts; + } + if (condition == null) { + sb.append(" rather than pay {source}'s mana cost"); + } + sb.append("."); + if (numberCosts == 1 && remarkText != null) { + sb.append(" ").append(remarkText); + } + return sb.toString(); + } +} diff --git a/Mage/src/mage/abilities/costs/AlternativeSourceCosts.java b/Mage/src/mage/abilities/costs/AlternativeSourceCosts.java index f724a0c02e..0791c6b766 100644 --- a/Mage/src/mage/abilities/costs/AlternativeSourceCosts.java +++ b/Mage/src/mage/abilities/costs/AlternativeSourceCosts.java @@ -44,9 +44,19 @@ public interface AlternativeSourceCosts { * * @param ability ability the alternative cost is activated for * @param game + * @return */ boolean askToActivateAlternativeCosts(Ability ability, Game game); - + + /** + * Is the alternative spell cost currently available + * + * @param source spell ability the alternative costs can be paid for + * @param game + * @return + */ + boolean isAvailable(Ability source, Game game); + /** * Was the alternative cost activated * @return diff --git a/Mage/src/mage/abilities/keyword/EvokeAbility.java b/Mage/src/mage/abilities/keyword/EvokeAbility.java index 0d08d4e937..c9dcc8f010 100644 --- a/Mage/src/mage/abilities/keyword/EvokeAbility.java +++ b/Mage/src/mage/abilities/keyword/EvokeAbility.java @@ -103,7 +103,12 @@ public class EvokeAbility extends StaticAbility implements Alterna } return false; } - + + @Override + public boolean isAvailable(Ability source, Game game) { + return true; + } + @Override public boolean askToActivateAlternativeCosts(Ability ability, Game game) { if (ability instanceof SpellAbility) { diff --git a/Mage/src/mage/abilities/keyword/ProwlAbility.java b/Mage/src/mage/abilities/keyword/ProwlAbility.java index 7630fa3f8f..4707b77246 100644 --- a/Mage/src/mage/abilities/keyword/ProwlAbility.java +++ b/Mage/src/mage/abilities/keyword/ProwlAbility.java @@ -62,7 +62,7 @@ import mage.watchers.common.ProwlWatcher; public class ProwlAbility extends StaticAbility implements AlternativeSourceCosts { private static final String PROWL_KEYWORD = "Prowl"; - private List prowlCosts = new LinkedList(); + private final List prowlCosts = new LinkedList(); private String reminderText; public ProwlAbility(Card card, String manaString) { @@ -106,7 +106,12 @@ public class ProwlAbility extends StaticAbility implements Alterna } return false; } - + + @Override + public boolean isAvailable(Ability source, Game game) { + return true; + } + @Override public boolean askToActivateAlternativeCosts(Ability ability, Game game) { if (ability instanceof SpellAbility) {