diff --git a/Mage/src/mage/abilities/condition/common/KickedCondition.java b/Mage/src/mage/abilities/condition/common/KickedCondition.java index 002173882d..964bb67cc4 100644 --- a/Mage/src/mage/abilities/condition/common/KickedCondition.java +++ b/Mage/src/mage/abilities/condition/common/KickedCondition.java @@ -30,7 +30,6 @@ package mage.abilities.condition.common; import mage.abilities.Ability; import mage.abilities.condition.Condition; -import mage.abilities.costs.OptionalAdditionalCost; import mage.abilities.keyword.KickerAbility; import mage.cards.Card; import mage.game.Game; diff --git a/Mage/src/mage/abilities/condition/common/KickedCostCondition.java b/Mage/src/mage/abilities/condition/common/KickedCostCondition.java index e52b56b061..0add305c72 100644 --- a/Mage/src/mage/abilities/condition/common/KickedCostCondition.java +++ b/Mage/src/mage/abilities/condition/common/KickedCostCondition.java @@ -3,7 +3,6 @@ package mage.abilities.condition.common; import mage.abilities.Ability; import mage.abilities.condition.Condition; import mage.abilities.costs.OptionalAdditionalCost; -import mage.abilities.costs.mana.KickerManaCost; import mage.abilities.keyword.KickerAbility; import mage.cards.Card; import mage.game.Game; @@ -15,10 +14,10 @@ import mage.game.Game; */ public class KickedCostCondition implements Condition { - protected KickerManaCost kickerManaCost; + protected String kickerCostText; - public KickedCostCondition(KickerManaCost kickerManaCost) { - this.kickerManaCost = kickerManaCost; + public KickedCostCondition(String kickerCostText) { + this.kickerCostText = kickerCostText; } @Override @@ -33,7 +32,7 @@ public class KickedCostCondition implements Condition { } if (kickerAbility != null) { for (OptionalAdditionalCost cost: kickerAbility.getKickerCosts()) { - if (cost.equals(kickerManaCost)) { + if (cost.getText(true).equals(kickerCostText)) { return cost.isActivated(); } } diff --git a/Mage/src/mage/abilities/costs/OptionalAdditionalCost.java b/Mage/src/mage/abilities/costs/OptionalAdditionalCost.java index 15b0679bf4..f868debd79 100644 --- a/Mage/src/mage/abilities/costs/OptionalAdditionalCost.java +++ b/Mage/src/mage/abilities/costs/OptionalAdditionalCost.java @@ -74,6 +74,12 @@ public interface OptionalAdditionalCost extends Cost { */ public void reset(); + /** + * Set if the cost be multiple times activated + * + */ + public void setRepeatable(boolean repeatable); + /** * Can the cost be multiple times activated * diff --git a/Mage/src/mage/abilities/costs/OptionalAdditionalCostImpl.java b/Mage/src/mage/abilities/costs/OptionalAdditionalCostImpl.java index 8d41b9cf3c..cb8b349f35 100644 --- a/Mage/src/mage/abilities/costs/OptionalAdditionalCostImpl.java +++ b/Mage/src/mage/abilities/costs/OptionalAdditionalCostImpl.java @@ -28,8 +28,6 @@ package mage.abilities.costs; -import mage.abilities.costs.mana.ManaCostsImpl; - /** * * @author LevelX2 @@ -41,14 +39,21 @@ public class OptionalAdditionalCostImpl protected String name; protected String reminderText; + protected String delimiter; + protected boolean activated; protected int activatedCounter; protected boolean repeatable; public OptionalAdditionalCostImpl(String name, String reminderText, Cost cost) { + this(name, " ", reminderText, cost); + } + + public OptionalAdditionalCostImpl(String name, String delimiter, String reminderText, Cost cost) { this.activated = false; this.name = name; - this.reminderText = reminderText; + this.delimiter = delimiter; + this.reminderText = new StringBuilder("").append(reminderText).append("").toString(); this.activatedCounter = 0; this.add((Cost) cost); } @@ -59,6 +64,7 @@ public class OptionalAdditionalCostImpl this.reminderText = cost.reminderText; this.activated = cost.activated; this.activatedCounter = cost.activatedCounter; + this.delimiter = cost.delimiter; } @Override @@ -67,7 +73,7 @@ public class OptionalAdditionalCostImpl } /** - * Returns the complete text for the addional coast or if onlyCost is true + * Returns the complete text for the addional cost or if onlyCost is true * only the pure text fore the included native cost * * @param onlyCost @@ -78,7 +84,7 @@ public class OptionalAdditionalCostImpl if (onlyCost) { return getText(); } else { - return name + " " + getText(); + return new StringBuffer(name).append(delimiter).append(getText()).toString(); } } @@ -105,7 +111,12 @@ public class OptionalAdditionalCostImpl */ @Override public String getCastSuffixMessage(int position) { - return " with " + name; + StringBuilder sb = new StringBuilder(position > 0 ? " and ":"").append(" with "); + if (isRepeatable()) { + sb.append(getActivateCount()).append(getActivateCount() > 1? " times ":" time "); + } + sb.append(name); + return sb.toString(); } @@ -130,6 +141,14 @@ public class OptionalAdditionalCostImpl activatedCounter = 0; } + /** + * Set if the cost be multiple times activated + * + */ + public void setRepeatable(boolean repeatable) { + this.repeatable = repeatable; + } + /** * Can the cost be multiple times activated * diff --git a/Mage/src/mage/abilities/dynamicvalue/common/MultikickerCount.java b/Mage/src/mage/abilities/dynamicvalue/common/MultikickerCount.java index d81493266b..a7f887f8f0 100644 --- a/Mage/src/mage/abilities/dynamicvalue/common/MultikickerCount.java +++ b/Mage/src/mage/abilities/dynamicvalue/common/MultikickerCount.java @@ -28,7 +28,6 @@ package mage.abilities.dynamicvalue.common; import mage.abilities.Ability; -import mage.abilities.costs.OptionalAdditionalCost; import mage.abilities.dynamicvalue.DynamicValue; import mage.abilities.keyword.KickerAbility; import mage.cards.Card; diff --git a/Mage/src/mage/abilities/keyword/KickerAbility.java b/Mage/src/mage/abilities/keyword/KickerAbility.java index 057955c75d..2eb231078f 100644 --- a/Mage/src/mage/abilities/keyword/KickerAbility.java +++ b/Mage/src/mage/abilities/keyword/KickerAbility.java @@ -39,24 +39,78 @@ import mage.abilities.StaticAbility; import mage.abilities.costs.Cost; import mage.abilities.costs.Costs; import mage.abilities.costs.OptionalAdditionalCost; +import mage.abilities.costs.OptionalAdditionalCostImpl; import mage.abilities.costs.OptionalAdditionalSourceCosts; import mage.abilities.costs.mana.ManaCostsImpl; import mage.game.Game; import mage.players.Player; +/** + * + * 20121001 702.31. Kicker + * 702.31a Kicker is a static ability that functions while the spell with kicker + * is on the stack. "Kicker [cost]" means "You may pay an additional [cost] + * as you cast this spell." Paying a spell's kicker cost(s) follows the + * rules for paying additional costs in rules 601.2b and 601.2e-g. + * 702.31b The phrase "Kicker [cost 1] and/or [cost 2]" means the same thing as + * "Kicker [cost 1], kicker [cost 2]." + * 702.31c Multikicker is a variant of the kicker ability. "Multikicker [cost]" + * means "You may pay an additional [cost] any number of times as you cast + * this spell." A multikicker cost is a kicker cost. + * 702.31d If a spell's controller declares the intention to pay any of that spell's + * kicker costs, that spell has been "kicked." If a spell has two kicker + * costs or has multikicker, it may be kicked multiple times. See rule 601.2b. + * 702.31e Objects with kicker or multikicker have additional abilities that specify + * what happens if they are kicked. These abilities are linked to the kicker + * or multikicker abilities printed on that object: they can refer only to + * those specific kicker or multikicker abilities. See rule 607, + * "Linked Abilities." + * 702.31f Objects with more than one kicker cost have abilities that each correspond + * to a specific kicker cost. They contain the phrases "if it was kicked with + * its [A] kicker" and "if it was kicked with its [B] kicker," where A and B + * are the first and second kicker costs listed on the card, respectively. Each + * of those abilities is linked to the appropriate kicker ability. + * 702.31g If part of a spell's ability has its effect only if that spell was kicked, + * and that part of the ability includes any targets, the spell's controller + * chooses those targets only if that spell was kicked. Otherwise, the spell is + * cast as if it did not have those targets. See rule 601.2c. + * + * @author LevelX2 + * + */ public class KickerAbility extends StaticAbility implements OptionalAdditionalSourceCosts { + protected static final String KickerKeyword = "Kicker"; + protected static final String KickerReminderMana = "(You may pay an additional {cost} as you cast this spell.)"; + protected static final String KickerReminderCost = "(You may {cost} in addition to any other costs as you cast this spell.)"; + + protected String keywordText; + protected String reminderText; protected List kickerCosts = new LinkedList(); - public KickerAbility(OptionalAdditionalCost kickerCost) { + public KickerAbility(String manaString) { + this(KickerKeyword, KickerReminderMana); + this.addKickerCost(manaString); + } + + public KickerAbility(Cost cost) { + this(KickerKeyword, KickerReminderCost); + this.addKickerCost(cost); + } + + public KickerAbility(String keywordText, String reminderText) { super(Zone.STACK, null); - kickerCosts.add(kickerCost); + name = keywordText; + this.keywordText = keywordText; + this.reminderText = reminderText; setRuleAtTheTop(true); } public KickerAbility(final KickerAbility ability) { super(ability); this.kickerCosts = ability.kickerCosts; + this.keywordText = ability.keywordText; + this.reminderText = ability.reminderText; } @Override @@ -64,6 +118,18 @@ public class KickerAbility extends StaticAbility implements Optio return new KickerAbility(this); } + public final OptionalAdditionalCost addKickerCost(String manaString) { + OptionalAdditionalCost kickerCost = new OptionalAdditionalCostImpl(keywordText, reminderText, new ManaCostsImpl(manaString)); + kickerCosts.add(kickerCost); + return kickerCost; + } + + public final OptionalAdditionalCost addKickerCost(Cost cost) { + OptionalAdditionalCost kickerCost = new OptionalAdditionalCostImpl(keywordText, "-", reminderText, cost); + kickerCosts.add(kickerCost); + return kickerCost; + } + public void resetKicker() { for (OptionalAdditionalCost cost: kickerCosts) { cost.reset(); @@ -91,10 +157,6 @@ public class KickerAbility extends StaticAbility implements Optio return kickerCosts; } - public void addKickerManaCost(OptionalAdditionalCost kickerCost) { - kickerCosts.add(kickerCost); - } - @Override public void addOptionalAdditionalCosts(Ability ability, Game game) { if (ability instanceof SpellAbility) { @@ -109,7 +171,8 @@ public class KickerAbility extends StaticAbility implements Optio int activated = kickerCost.getActivateCount(); times = Integer.toString(activated + 1) + (activated == 0 ? " time ":" times "); } - if (player.chooseUse(Constants.Outcome.Benefit, "Pay " + times + kickerCost.getText(false) + " ?", game)) { + if (kickerCost.canPay(sourceId, controllerId, game) && + player.chooseUse(Constants.Outcome.Benefit, new StringBuilder("Pay ").append(times).append(kickerCost.getText(false)).append(" ?").toString(), game)) { kickerCost.activate(); for (Iterator it = ((Costs) kickerCost).iterator(); it.hasNext();) { Cost cost = (Cost) it.next(); diff --git a/Mage/src/mage/abilities/keyword/MultikickerAbility.java b/Mage/src/mage/abilities/keyword/MultikickerAbility.java new file mode 100644 index 0000000000..b7bbe62336 --- /dev/null +++ b/Mage/src/mage/abilities/keyword/MultikickerAbility.java @@ -0,0 +1,68 @@ +/* +* 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.keyword; + +import mage.abilities.costs.Cost; +import mage.abilities.costs.OptionalAdditionalCost; + +/** + * + * 20121001 702.31c Multikicker is a variant of the kicker ability. "Multikicker [cost]" means + * "You may pay an additional [cost] any number of times as you cast this spell." + * A multikicker cost is a kicker cost. + * + * @author LevelX2 + */ + +public class MultikickerAbility extends KickerAbility { + + protected static final String MultikickerKeyword = "Multikicker"; + protected static final String MultikickerReminder = "(You may pay an additional {cost} any number of times as you cast this spell.)"; + + public MultikickerAbility(String manaString) { + super(MultikickerKeyword, MultikickerReminder); + OptionalAdditionalCost multikickerCost = this.addKickerCost(manaString); + multikickerCost.setRepeatable(true); + } + + public MultikickerAbility(Cost cost) { + super(MultikickerKeyword, MultikickerReminder); + OptionalAdditionalCost multikickerCost =this.addKickerCost(cost); + multikickerCost.setRepeatable(true); + } + + public MultikickerAbility(final MultikickerAbility ability) { + super(ability); + } + + @Override + public MultikickerAbility copy() { + return new MultikickerAbility(this); + } +} \ No newline at end of file