Some changes to kicker implementation.

This commit is contained in:
LevelX2 2012-12-15 18:40:03 +01:00
parent 9f140579e5
commit 66ebfb6aa3
7 changed files with 173 additions and 20 deletions

View file

@ -30,7 +30,6 @@ package mage.abilities.condition.common;
import mage.abilities.Ability; import mage.abilities.Ability;
import mage.abilities.condition.Condition; import mage.abilities.condition.Condition;
import mage.abilities.costs.OptionalAdditionalCost;
import mage.abilities.keyword.KickerAbility; import mage.abilities.keyword.KickerAbility;
import mage.cards.Card; import mage.cards.Card;
import mage.game.Game; import mage.game.Game;

View file

@ -3,7 +3,6 @@ package mage.abilities.condition.common;
import mage.abilities.Ability; import mage.abilities.Ability;
import mage.abilities.condition.Condition; import mage.abilities.condition.Condition;
import mage.abilities.costs.OptionalAdditionalCost; import mage.abilities.costs.OptionalAdditionalCost;
import mage.abilities.costs.mana.KickerManaCost;
import mage.abilities.keyword.KickerAbility; import mage.abilities.keyword.KickerAbility;
import mage.cards.Card; import mage.cards.Card;
import mage.game.Game; import mage.game.Game;
@ -15,10 +14,10 @@ import mage.game.Game;
*/ */
public class KickedCostCondition implements Condition { public class KickedCostCondition implements Condition {
protected KickerManaCost kickerManaCost; protected String kickerCostText;
public KickedCostCondition(KickerManaCost kickerManaCost) { public KickedCostCondition(String kickerCostText) {
this.kickerManaCost = kickerManaCost; this.kickerCostText = kickerCostText;
} }
@Override @Override
@ -33,7 +32,7 @@ public class KickedCostCondition implements Condition {
} }
if (kickerAbility != null) { if (kickerAbility != null) {
for (OptionalAdditionalCost cost: kickerAbility.getKickerCosts()) { for (OptionalAdditionalCost cost: kickerAbility.getKickerCosts()) {
if (cost.equals(kickerManaCost)) { if (cost.getText(true).equals(kickerCostText)) {
return cost.isActivated(); return cost.isActivated();
} }
} }

View file

@ -74,6 +74,12 @@ public interface OptionalAdditionalCost extends Cost {
*/ */
public void reset(); public void reset();
/**
* Set if the cost be multiple times activated
*
*/
public void setRepeatable(boolean repeatable);
/** /**
* Can the cost be multiple times activated * Can the cost be multiple times activated
* *

View file

@ -28,8 +28,6 @@
package mage.abilities.costs; package mage.abilities.costs;
import mage.abilities.costs.mana.ManaCostsImpl;
/** /**
* *
* @author LevelX2 * @author LevelX2
@ -41,14 +39,21 @@ public class OptionalAdditionalCostImpl <T extends OptionalAdditionalCostImpl<T>
protected String name; protected String name;
protected String reminderText; protected String reminderText;
protected String delimiter;
protected boolean activated; protected boolean activated;
protected int activatedCounter; protected int activatedCounter;
protected boolean repeatable; protected boolean repeatable;
public OptionalAdditionalCostImpl(String name, String reminderText, Cost cost) { 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.activated = false;
this.name = name; this.name = name;
this.reminderText = reminderText; this.delimiter = delimiter;
this.reminderText = new StringBuilder("<i>").append(reminderText).append("</i>").toString();
this.activatedCounter = 0; this.activatedCounter = 0;
this.add((Cost) cost); this.add((Cost) cost);
} }
@ -59,6 +64,7 @@ public class OptionalAdditionalCostImpl <T extends OptionalAdditionalCostImpl<T>
this.reminderText = cost.reminderText; this.reminderText = cost.reminderText;
this.activated = cost.activated; this.activated = cost.activated;
this.activatedCounter = cost.activatedCounter; this.activatedCounter = cost.activatedCounter;
this.delimiter = cost.delimiter;
} }
@Override @Override
@ -67,7 +73,7 @@ public class OptionalAdditionalCostImpl <T extends OptionalAdditionalCostImpl<T>
} }
/** /**
* 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 * only the pure text fore the included native cost
* *
* @param onlyCost * @param onlyCost
@ -78,7 +84,7 @@ public class OptionalAdditionalCostImpl <T extends OptionalAdditionalCostImpl<T>
if (onlyCost) { if (onlyCost) {
return getText(); return getText();
} else { } else {
return name + " " + getText(); return new StringBuffer(name).append(delimiter).append(getText()).toString();
} }
} }
@ -105,7 +111,12 @@ public class OptionalAdditionalCostImpl <T extends OptionalAdditionalCostImpl<T>
*/ */
@Override @Override
public String getCastSuffixMessage(int position) { 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 <T extends OptionalAdditionalCostImpl<T>
activatedCounter = 0; 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 * Can the cost be multiple times activated
* *

View file

@ -28,7 +28,6 @@
package mage.abilities.dynamicvalue.common; package mage.abilities.dynamicvalue.common;
import mage.abilities.Ability; import mage.abilities.Ability;
import mage.abilities.costs.OptionalAdditionalCost;
import mage.abilities.dynamicvalue.DynamicValue; import mage.abilities.dynamicvalue.DynamicValue;
import mage.abilities.keyword.KickerAbility; import mage.abilities.keyword.KickerAbility;
import mage.cards.Card; import mage.cards.Card;

View file

@ -39,24 +39,78 @@ import mage.abilities.StaticAbility;
import mage.abilities.costs.Cost; import mage.abilities.costs.Cost;
import mage.abilities.costs.Costs; import mage.abilities.costs.Costs;
import mage.abilities.costs.OptionalAdditionalCost; import mage.abilities.costs.OptionalAdditionalCost;
import mage.abilities.costs.OptionalAdditionalCostImpl;
import mage.abilities.costs.OptionalAdditionalSourceCosts; import mage.abilities.costs.OptionalAdditionalSourceCosts;
import mage.abilities.costs.mana.ManaCostsImpl; import mage.abilities.costs.mana.ManaCostsImpl;
import mage.game.Game; import mage.game.Game;
import mage.players.Player; 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<KickerAbility> implements OptionalAdditionalSourceCosts { public class KickerAbility extends StaticAbility<KickerAbility> 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<OptionalAdditionalCost> kickerCosts = new LinkedList<OptionalAdditionalCost>(); protected List<OptionalAdditionalCost> kickerCosts = new LinkedList<OptionalAdditionalCost>();
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); super(Zone.STACK, null);
kickerCosts.add(kickerCost); name = keywordText;
this.keywordText = keywordText;
this.reminderText = reminderText;
setRuleAtTheTop(true); setRuleAtTheTop(true);
} }
public KickerAbility(final KickerAbility ability) { public KickerAbility(final KickerAbility ability) {
super(ability); super(ability);
this.kickerCosts = ability.kickerCosts; this.kickerCosts = ability.kickerCosts;
this.keywordText = ability.keywordText;
this.reminderText = ability.reminderText;
} }
@Override @Override
@ -64,6 +118,18 @@ public class KickerAbility extends StaticAbility<KickerAbility> implements Optio
return new KickerAbility(this); 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() { public void resetKicker() {
for (OptionalAdditionalCost cost: kickerCosts) { for (OptionalAdditionalCost cost: kickerCosts) {
cost.reset(); cost.reset();
@ -91,10 +157,6 @@ public class KickerAbility extends StaticAbility<KickerAbility> implements Optio
return kickerCosts; return kickerCosts;
} }
public void addKickerManaCost(OptionalAdditionalCost kickerCost) {
kickerCosts.add(kickerCost);
}
@Override @Override
public void addOptionalAdditionalCosts(Ability ability, Game game) { public void addOptionalAdditionalCosts(Ability ability, Game game) {
if (ability instanceof SpellAbility) { if (ability instanceof SpellAbility) {
@ -109,7 +171,8 @@ public class KickerAbility extends StaticAbility<KickerAbility> implements Optio
int activated = kickerCost.getActivateCount(); int activated = kickerCost.getActivateCount();
times = Integer.toString(activated + 1) + (activated == 0 ? " time ":" times "); 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(); kickerCost.activate();
for (Iterator it = ((Costs) kickerCost).iterator(); it.hasNext();) { for (Iterator it = ((Costs) kickerCost).iterator(); it.hasNext();) {
Cost cost = (Cost) it.next(); Cost cost = (Cost) it.next();

View file

@ -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);
}
}