diff --git a/Mage/src/mage/abilities/Abilities.java b/Mage/src/mage/abilities/Abilities.java index e5ca34ee702..5ab6425b062 100644 --- a/Mage/src/mage/abilities/Abilities.java +++ b/Mage/src/mage/abilities/Abilities.java @@ -32,7 +32,6 @@ import java.io.Serializable; import java.util.List; import java.util.UUID; import mage.Constants.Zone; -import mage.abilities.keyword.KickerAbility; import mage.abilities.keyword.ProtectionAbility; import mage.abilities.mana.ManaAbility; import mage.game.Game; @@ -142,16 +141,6 @@ public interface Abilities extends List, Serializable { */ public Abilities getProtectionAbilities(); - /** - * Retrieves all {@link KickerAbility kicker abilities}. - * - * @return All found {@link KickerAbility kicker abilities}. - * - * @see mage.players.PlayerImpl#cast(mage.abilities.SpellAbility, mage.game.Game, boolean) - * @see mage.game.stack.Spell#resolveKicker(mage.game.Game) - */ - public Abilities getKickerAbilities(); - /** * TODO Method is unused, keep it around? * diff --git a/Mage/src/mage/abilities/AbilitiesImpl.java b/Mage/src/mage/abilities/AbilitiesImpl.java index b6c23575d3a..76b3bd0c8bc 100644 --- a/Mage/src/mage/abilities/AbilitiesImpl.java +++ b/Mage/src/mage/abilities/AbilitiesImpl.java @@ -28,20 +28,18 @@ package mage.abilities; -import mage.Constants.Zone; -import mage.abilities.common.ZoneChangeTriggeredAbility; -import mage.abilities.costs.AlternativeCost; -import mage.abilities.costs.Cost; -import mage.abilities.keyword.KickerAbility; -import mage.abilities.keyword.ProtectionAbility; -import mage.abilities.mana.ManaAbility; -import mage.game.Game; - import java.util.ArrayList; import java.util.Collections; import java.util.List; import java.util.UUID; -import mage.abilities.costs.mana.KickerManaCost; +import mage.Constants.Zone; +import mage.abilities.common.ZoneChangeTriggeredAbility; +import mage.abilities.costs.AlternativeCost; +import mage.abilities.costs.Cost; +import mage.abilities.keyword.ProtectionAbility; +import mage.abilities.mana.ManaAbility; +import mage.game.Game; + /** * @@ -81,10 +79,6 @@ public class AbilitiesImpl extends ArrayList implements Ab } } if (ability instanceof SpellAbility) { - String kickerRule = getKickerRule(ability); - if (!kickerRule.isEmpty()) { - rules.add(kickerRule); - } if (ability.getAlternativeCosts().size() > 0) { StringBuilder sbRule = new StringBuilder(); for (AlternativeCost cost: ability.getAlternativeCosts()) { @@ -122,25 +116,6 @@ public class AbilitiesImpl extends ArrayList implements Ab return rules; } - private String getKickerRule(Ability ability) { - StringBuilder sb = new StringBuilder(); - int numberKicker = 0; - for (Object cost : ability.getOptionalCosts()) { - if (cost instanceof KickerManaCost) { - if (numberKicker == 0) { - sb.append(((KickerManaCost)cost).getText(true)); - } else { - sb.append(" and/or ").append(((KickerManaCost)cost).getText(true)); - } - ++numberKicker; - } - } - if (numberKicker > 0) { - return "Kicker " + sb.toString() + " (You may pay an additional " + sb.toString() + " as you cast this spell.)"; - } - return sb.toString(); - } - @Override public Abilities getActivatedAbilities(Zone zone) { Abilities zonedAbilities = new AbilitiesImpl(); @@ -168,8 +143,9 @@ public class AbilitiesImpl extends ArrayList implements Ab Abilities abilities = new AbilitiesImpl(); for (T ability: this) { if (ability instanceof ManaAbility && ability.getZone().match(zone)) { - if ((((ManaAbility)ability).canActivate(ability.getControllerId(), game))) + if ((((ManaAbility)ability).canActivate(ability.getControllerId(), game))) { abilities.add((ManaAbility)ability); + } } } return abilities; @@ -225,17 +201,6 @@ public class AbilitiesImpl extends ArrayList implements Ab return abilities; } - @Override - public Abilities getKickerAbilities() { - Abilities abilities = new AbilitiesImpl(); - for (T ability: this) { - if (ability instanceof KickerAbility) { - abilities.add((KickerAbility)ability); - } - } - return abilities; - } - @Override public void setControllerId(UUID controllerId) { for (Ability ability: this) { @@ -276,11 +241,13 @@ public class AbilitiesImpl extends ArrayList implements Ab @Override public boolean containsAll(Abilities abilities) { - if (this.size() < abilities.size()) + if (this.size() < abilities.size()) { return false; + } for (T ability: abilities) { - if (!contains(ability)) + if (!contains(ability)) { return false; + } } return true; } @@ -288,8 +255,9 @@ public class AbilitiesImpl extends ArrayList implements Ab @Override public boolean containsKey(UUID abilityId) { for (T ability: this) { - if (ability.getId().equals(abilityId)) + if (ability.getId().equals(abilityId)) { return true; + } } return false; } @@ -297,8 +265,9 @@ public class AbilitiesImpl extends ArrayList implements Ab @Override public T get(UUID abilityId) { for (T ability: this) { - if (ability.getId().equals(abilityId)) + if (ability.getId().equals(abilityId)) { return ability; + } } return null; } diff --git a/Mage/src/mage/abilities/AbilityImpl.java b/Mage/src/mage/abilities/AbilityImpl.java index d5ee254eb0f..7e360687994 100644 --- a/Mage/src/mage/abilities/AbilityImpl.java +++ b/Mage/src/mage/abilities/AbilityImpl.java @@ -28,17 +28,28 @@ package mage.abilities; +import java.util.ArrayList; +import java.util.List; +import java.util.UUID; import mage.Constants.AbilityType; import mage.Constants.EffectType; import mage.Constants.Outcome; import mage.Constants.Zone; import mage.MageObject; -import mage.abilities.costs.*; -import mage.abilities.costs.mana.KickerManaCost; +import mage.abilities.costs.AdjustingSourceCosts; +import mage.abilities.costs.AlternativeCost; +import mage.abilities.costs.Cost; +import mage.abilities.costs.Costs; +import mage.abilities.costs.CostsImpl; +import mage.abilities.costs.OptionalAdditionalSourceCosts; import mage.abilities.costs.mana.ManaCost; import mage.abilities.costs.mana.ManaCosts; import mage.abilities.costs.mana.ManaCostsImpl; -import mage.abilities.effects.*; +import mage.abilities.effects.ContinuousEffect; +import mage.abilities.effects.Effect; +import mage.abilities.effects.Effects; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.PostResolveEffect; import mage.abilities.mana.ManaAbility; import mage.cards.Card; import mage.choices.Choice; @@ -49,9 +60,6 @@ import mage.target.Target; import mage.target.Targets; import org.apache.log4j.Logger; -import java.util.ArrayList; -import java.util.List; -import java.util.UUID; /** * @@ -144,8 +152,9 @@ public abstract class AbilityImpl> implements Ability { if (checkIfClause(game)) { for (Effect effect: getEffects()) { if (effect instanceof OneShotEffect) { - if (!(effect instanceof PostResolveEffect)) + if (!(effect instanceof PostResolveEffect)) { result &= effect.apply(game, this); + } } else { game.addEffect((ContinuousEffect) effect, this); @@ -158,8 +167,9 @@ public abstract class AbilityImpl> implements Ability { @Override public boolean activate(Game game, boolean noMana) { // 20110204 - 700.2 - if (!modes.choose(game, this)) + if (!modes.choose(game, this)) { return false; + } //20100716 - 601.2b Card card = game.getCard(sourceId); if (card != null) { @@ -170,22 +180,29 @@ public abstract class AbilityImpl> implements Ability { return false; } + // 20121001 - 601.2b + // If the spell has alternative or additional costs that will be paid as it's being cast such + // 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). + if (card != null) { + for (Ability ability : card.getAbilities()) { + if (ability instanceof OptionalAdditionalSourceCosts) { + ((OptionalAdditionalSourceCosts)ability).addOptionalAdditionalCosts(this, game); + } + } + } + + //20121001 - 601.2c if (card != null) { card.adjustTargets(this, game); } - //20100716 - 601.2b if (getTargets().size() > 0 && getTargets().chooseTargets(getEffects().get(0).getOutcome(), this.controllerId, this, game) == false) { logger.debug("activate failed - target"); return false; } for (Cost cost : optionalCosts) { - if (cost instanceof KickerManaCost) { - cost.clearPaid(); - if (game.getPlayer(this.controllerId).chooseUse(Outcome.Benefit, "Pay " + cost.getText() + "?", game)) { - manaCostsToPay.add((ManaCost) cost); - } - } else if (cost instanceof ManaCost) { + if (cost instanceof ManaCost) { cost.clearPaid(); if (game.getPlayer(this.controllerId).chooseUse(Outcome.Benefit, "Pay optional cost " + cost.getText() + "?", game)) { manaCostsToPay.add((ManaCost) cost); @@ -454,8 +471,9 @@ public abstract class AbilityImpl> implements Ability { @Override public boolean canChooseTarget(Game game) { for (Mode mode: modes.values()) { - if (mode.getTargets().canChoose(sourceId, controllerId, game)) + if (mode.getTargets().canChoose(sourceId, controllerId, game)) { return true; + } } return false; } @@ -477,15 +495,15 @@ public abstract class AbilityImpl> implements Ability { } MageObject object; - UUID sourceId; + UUID parameterSourceId; // for singleton abilities like Flying we can't rely on abilities' source // so will use the one that came as a parameter if it is not null if (this instanceof MageSingleton && source != null) { object = source; - sourceId = source.getId(); + parameterSourceId = source.getId(); } else { object = game.getObject(getSourceId()); - sourceId = getSourceId(); + parameterSourceId = getSourceId(); } if (object != null && !object.getAbilities().contains(this)) { @@ -501,7 +519,7 @@ public abstract class AbilityImpl> implements Ability { } // check against current state - Zone test = game.getState().getZone(sourceId); + Zone test = game.getState().getZone(parameterSourceId); return test != null && zone.match(test); } diff --git a/Mage/src/mage/abilities/ActivatedAbilityImpl.java b/Mage/src/mage/abilities/ActivatedAbilityImpl.java index cd2854a2653..018da30aa41 100644 --- a/Mage/src/mage/abilities/ActivatedAbilityImpl.java +++ b/Mage/src/mage/abilities/ActivatedAbilityImpl.java @@ -28,26 +28,24 @@ package mage.abilities; +import java.util.UUID; import mage.Constants.AbilityType; import mage.Constants.TimingRule; import mage.Constants.Zone; import mage.MageObject; import mage.abilities.costs.Cost; import mage.abilities.costs.Costs; +import mage.abilities.costs.OptionalAdditionalSourceCosts; import mage.abilities.costs.mana.ManaCosts; import mage.abilities.costs.mana.PhyrexianManaCost; import mage.abilities.effects.Effect; import mage.abilities.effects.Effects; import mage.cards.Card; import mage.game.Game; +import mage.game.stack.Spell; import mage.game.stack.StackAbility; import mage.target.Target; -import java.util.UUID; -import mage.abilities.costs.mana.KickerManaCost; -import mage.abilities.keyword.MultikickerAbility; -import mage.game.permanent.Permanent; -import mage.game.stack.Spell; /** * @@ -82,8 +80,9 @@ public abstract class ActivatedAbilityImpl> ex if (effect != null) { this.addEffect(effect); } - if (cost != null) + if (cost != null) { this.addManaCost(cost); + } } public ActivatedAbilityImpl(Zone zone, Effects effects, ManaCosts cost) { @@ -93,8 +92,9 @@ public abstract class ActivatedAbilityImpl> ex this.addEffect(effect); } } - if (cost != null) + if (cost != null) { this.addManaCost(cost); + } } public ActivatedAbilityImpl(Zone zone, Effect effect, Cost cost) { @@ -130,8 +130,9 @@ public abstract class ActivatedAbilityImpl> ex this.addEffect(effect); } } - if (cost != null) + if (cost != null) { this.addCost(cost); + } } public ActivatedAbilityImpl(Zone zone, Effects effects, Costs costs) { @@ -151,8 +152,9 @@ public abstract class ActivatedAbilityImpl> ex @Override public boolean canActivate(UUID playerId, Game game) { //20091005 - 602.2 - if (!controlsAbility(playerId, game)) + if (!controlsAbility(playerId, game)) { return false; + } //20091005 - 602.5d/602.5e if (timing == TimingRule.INSTANT || game.canPlaySorcery(playerId)) { if (costs.canPay(sourceId, controllerId, game) && canChooseTarget(game)) { @@ -163,12 +165,14 @@ public abstract class ActivatedAbilityImpl> ex } protected boolean controlsAbility(UUID playerId, Game game) { - if (this.controllerId != null && this.controllerId.equals(playerId)) + if (this.controllerId != null && this.controllerId.equals(playerId)) { return true; + } else { Card card = (Card)game.getObject(this.sourceId); - if (card != null && game.getState().getZone(this.sourceId) != Zone.BATTLEFIELD) + if (card != null && game.getState().getZone(this.sourceId) != Zone.BATTLEFIELD) { return card.getOwnerId().equals(playerId); + } } return false; } @@ -200,7 +204,7 @@ public abstract class ActivatedAbilityImpl> ex if (spell.getFromZone() == Zone.GRAVEYARD) { sb.append(" from graveyard"); } - sb.append(getKickerText(game, spell)); + sb.append(getOptionalTextSuffix(game, spell)); } else { sb.append(object.getName()); } @@ -217,37 +221,13 @@ public abstract class ActivatedAbilityImpl> ex return sb.toString(); } - String getKickerText(Game game, Spell spell) { + String getOptionalTextSuffix(Game game, Spell spell) { StringBuilder sb = new StringBuilder(); - int numberPaid = 0; - for (Object cost : spell.getSpellAbility().getOptionalCosts()) { - if (cost instanceof KickerManaCost) { - if (((KickerManaCost) cost).isPaid()) { - if (numberPaid == 0) { - sb.append(" with ").append(((KickerManaCost)cost).getText(true)); - } else { - sb.append(" and ").append(((KickerManaCost)cost).getText(true)); - } - ++numberPaid; - } + for (Ability ability : (Abilities) spell.getAbilities()) { + if (ability instanceof OptionalAdditionalSourceCosts) { + sb.append(((OptionalAdditionalSourceCosts) ability).getCastMessageSuffix()); } } - if (numberPaid > 0) { - sb.append(" kicker"); - } - // Multikicker - int multikickerCount = 0; - Card card = game.getCard(this.getSourceId()); - if (card != null) { - for (Ability ability : card.getAbilities()) { - if (ability instanceof MultikickerAbility) { - multikickerCount = ((MultikickerAbility)ability).getActivateCount(); - } - } - } - if (multikickerCount > 0) { - sb.append(" with ").append(multikickerCount).append(multikickerCount > 1? " times":" time").append(" multikicker"); - } return sb.toString(); } } diff --git a/Mage/src/mage/abilities/condition/common/KickedCondition.java b/Mage/src/mage/abilities/condition/common/KickedCondition.java index d9252711e37..033744610a3 100644 --- a/Mage/src/mage/abilities/condition/common/KickedCondition.java +++ b/Mage/src/mage/abilities/condition/common/KickedCondition.java @@ -1,15 +1,45 @@ +/* +* 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 mage.abilities.Ability; import mage.abilities.condition.Condition; -import mage.abilities.costs.mana.KickerManaCost; +import mage.abilities.costs.OptionalAdditionalCost; +import mage.abilities.keyword.KickerAbility; import mage.cards.Card; import mage.game.Game; + /** * Describes condition when spell was kicked. * - * @author nantuko + * @author LevelX2 */ public class KickedCondition implements Condition { @@ -26,19 +56,23 @@ public class KickedCondition implements Condition { @Override public boolean apply(Game game, Ability source) { - Card p = game.getCard(source.getSourceId()); - - boolean kicked = false; - if (p != null) { - for (Object cost : p.getSpellAbility().getOptionalCosts()) { - if (cost instanceof KickerManaCost) { - if (((KickerManaCost) cost).isPaid()) { - kicked = true; - } + Card card = game.getCard(source.getSourceId()); + if (card != null) { + KickerAbility kickerAbility = null; + for (Ability ability: card.getAbilities()) { + if (ability instanceof KickerAbility) { + kickerAbility = (KickerAbility) ability; } } + boolean kicked = false; + if (kickerAbility != null) { + for (OptionalAdditionalCost cost: kickerAbility.getKickerCosts()) { + kicked = cost.isActivated(); + break; + } + } + return kicked; } - - return kicked; + return false; } } diff --git a/Mage/src/mage/abilities/condition/common/KickedCostCondition.java b/Mage/src/mage/abilities/condition/common/KickedCostCondition.java index 04b382a434c..e52b56b0613 100644 --- a/Mage/src/mage/abilities/condition/common/KickedCostCondition.java +++ b/Mage/src/mage/abilities/condition/common/KickedCostCondition.java @@ -2,7 +2,9 @@ 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; @@ -21,18 +23,22 @@ public class KickedCostCondition implements Condition { @Override public boolean apply(Game game, Ability source) { - Card p = game.getCard(source.getSourceId()); - - boolean kicked = false; - if (p != null) { - for (Object cost : p.getSpellAbility().getOptionalCosts()) { - if (cost.equals(kickerManaCost)) { - if (((KickerManaCost) cost).isPaid()) { - kicked = true; + Card card = game.getCard(source.getSourceId()); + if (card != null) { + KickerAbility kickerAbility = null; + for (Ability ability: card.getAbilities()) { + if (ability instanceof KickerAbility) { + kickerAbility = (KickerAbility) ability; + } + } + if (kickerAbility != null) { + for (OptionalAdditionalCost cost: kickerAbility.getKickerCosts()) { + if (cost.equals(kickerManaCost)) { + return cost.isActivated(); } } } } - return kicked; + return false; } } diff --git a/Mage/src/mage/abilities/costs/OptionalAdditionalCost.java b/Mage/src/mage/abilities/costs/OptionalAdditionalCost.java new file mode 100644 index 00000000000..15b0679bf45 --- /dev/null +++ b/Mage/src/mage/abilities/costs/OptionalAdditionalCost.java @@ -0,0 +1,97 @@ +/* + * 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; + +/** + * @author LevelX2 + */ +public interface OptionalAdditionalCost extends Cost { + + public String getName(); + + /** + * Returns the complete text for the addional coast or if onlyCost is true + * only the pure text fore the included native cost + * + * @param onlyCost + * @return + */ + public String getText(boolean onlyCost); + + /** + * Returns a reminder text, if the cost has one + * + * @return + */ + public String getReminderText(); + + /** + * Returns a text suffix for the game log, that can be added to + * the cast message. + * + * @param position - if there are multiple costs, it's the postion the cost is set (starting with 0) + * @return + */ + public String getCastSuffixMessage(int position); + + + /** + * If the player intends to pay the cost, the cost will be activated + * + * @param activated + */ + public void activate(); + + /** + * Reset the activate and count information + * + */ + public void reset(); + + /** + * Can the cost be multiple times activated + * + * @return + */ + public boolean isRepeatable(); + + /** + * Returns if the cost was activated + * + * @return + */ + public boolean isActivated(); + + /** + * Returns the number of times the cost was activated + * @return + */ + public int getActivateCount(); + +} diff --git a/Mage/src/mage/abilities/costs/OptionalAdditionalCostImpl.java b/Mage/src/mage/abilities/costs/OptionalAdditionalCostImpl.java new file mode 100644 index 00000000000..2573509c94f --- /dev/null +++ b/Mage/src/mage/abilities/costs/OptionalAdditionalCostImpl.java @@ -0,0 +1,165 @@ +/* + * 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; + +/** + * + * @author LevelX2 + */ + + +public class OptionalAdditionalCostImpl > extends CostsImpl implements OptionalAdditionalCost{ + + + protected String name; + protected String reminderText; + protected boolean activated; + protected int activatedCounter; + protected boolean repeatable; + + public OptionalAdditionalCostImpl(String name, String reminderText, Cost cost) { + this.activated = false; + this.name = name; + this.reminderText = reminderText; + this.activatedCounter = 0; + this.add((Cost) cost); + } + + public OptionalAdditionalCostImpl(final OptionalAdditionalCostImpl cost) { + super(cost); + this.name = cost.name; + this.reminderText = cost.reminderText; + this.activated = cost.activated; + this.activatedCounter = cost.activatedCounter; + } + + @Override + public String getName() { + return this.name; + } + + /** + * Returns the complete text for the addional coast or if onlyCost is true + * only the pure text fore the included native cost + * + * @param onlyCost + * @return + */ + @Override + public String getText(boolean onlyCost) { + if (onlyCost) { + return getText(); + } else { + return name + " " + getText(); + } + } + + /** + * Returns a reminder text, if the cost has one + * + * @return + */ + @Override + public String getReminderText() { + String replace = ""; + if (reminderText != null && !reminderText.isEmpty()) { + replace = reminderText.replace("{cost}", this.getText(true)); + } + return replace; + } + + /** + * Returns a text suffix for the game log, that can be added to + * the cast message. + * + * @param position - if there are multiple costs, it's the postion the cost is set (starting with 0) + * @return + */ + @Override + public String getCastSuffixMessage(int position) { + return ""; + } + + + /** + * If the player intends to pay the cost, the cost will be activated + * + * @param activated + */ + @Override + public void activate() { + activated = true; + ++activatedCounter; + }; + + /** + * Reset the activate and count information + * + */ + @Override + public void reset() { + activated = false; + activatedCounter = 0; + } + + /** + * Can the cost be multiple times activated + * + * @return + */ + @Override + public boolean isRepeatable() { + return repeatable; + }; + + /** + * Returns if the cost was activated + * + * @return + */ + @Override + public boolean isActivated(){ + return activated; + }; + + /** + * Returns the number of times the cost was activated + * @return + */ + @Override + public int getActivateCount(){ + return activatedCounter; + }; + + + @Override + public OptionalAdditionalCostImpl copy() { + return new OptionalAdditionalCostImpl(this); + } +} \ No newline at end of file diff --git a/Mage/src/mage/abilities/costs/OptionalAdditionalSourceCosts.java b/Mage/src/mage/abilities/costs/OptionalAdditionalSourceCosts.java new file mode 100644 index 00000000000..72f59f98b1b --- /dev/null +++ b/Mage/src/mage/abilities/costs/OptionalAdditionalSourceCosts.java @@ -0,0 +1,43 @@ +/* + * 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 mage.abilities.Ability; +import mage.game.Game; + +/** + * Interface for abilities that add addional costs to the source. + * + * Example of such additional source costs: {@link mage.abilities.keyword.KickerAbility} + * + * @author LevelX2 + */ +public interface OptionalAdditionalSourceCosts { + void addOptionalAdditionalCosts(Ability ability, Game game); + String getCastMessageSuffix(); +} \ No newline at end of file diff --git a/Mage/src/mage/abilities/costs/mana/KickerManaCost.java b/Mage/src/mage/abilities/costs/mana/KickerManaCost.java index fdd1921c135..689911e5b39 100644 --- a/Mage/src/mage/abilities/costs/mana/KickerManaCost.java +++ b/Mage/src/mage/abilities/costs/mana/KickerManaCost.java @@ -1,12 +1,44 @@ +/* + * 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.mana; +import mage.abilities.costs.OptionalAdditionalCostImpl; + /** - * This cost must be used only as optional mana cost in cards with Kicker - * @author Loki - */ -public class KickerManaCost extends ManaCostsImpl { +* This cost defines the Kicker cost +* +* @author LevelX2 +*/ +public class KickerManaCost extends OptionalAdditionalCostImpl { + public KickerManaCost(String manaString) { - super(manaString); + super("Kicker","(You may pay an additional {cost} as you cast this spell.)",new ManaCostsImpl(manaString)); } public KickerManaCost(final KickerManaCost cost) { @@ -18,17 +50,12 @@ public class KickerManaCost extends ManaCostsImpl { return new KickerManaCost(this); } - - public String getText(boolean onlyMana) { - if (onlyMana) { - return super.getText(); + @Override + public String getCastSuffixMessage(int position) { + if (position == 0) { + return " with " + getText(false); } else { - return this.getText(); + return " and " + getText(true); } } - - @Override - public String getText() { - return "Kicker - " + super.getText(); - } -} +} \ No newline at end of file diff --git a/Mage/src/mage/abilities/costs/mana/MultikickerManaCost.java b/Mage/src/mage/abilities/costs/mana/MultikickerManaCost.java new file mode 100644 index 00000000000..3fafce9c7ef --- /dev/null +++ b/Mage/src/mage/abilities/costs/mana/MultikickerManaCost.java @@ -0,0 +1,58 @@ +/* + * 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.mana; + +import mage.abilities.costs.OptionalAdditionalCostImpl; + +/** + * + * @author LevelX2 + */ + + +public class MultikickerManaCost extends OptionalAdditionalCostImpl{ + + public MultikickerManaCost(String manaString) { + super("Multikicker","(You may pay an additional {cost} any number of times as you cast this spell.)",new ManaCostsImpl(manaString)); + repeatable = true; + } + + public MultikickerManaCost(final MultikickerManaCost cost) { + super(cost); + } + + @Override + public MultikickerManaCost copy() { + return new MultikickerManaCost(this); + } + + @Override + public String getCastSuffixMessage(int position) { + return (position > 0 ? " and ":"") + " with " + getActivateCount() + (getActivateCount() > 1? " times":" time") + " multikicker"; + } +} diff --git a/Mage/src/mage/abilities/dynamicvalue/common/MultikickerCount.java b/Mage/src/mage/abilities/dynamicvalue/common/MultikickerCount.java index 3738963d6ef..8e75e9c5e45 100644 --- a/Mage/src/mage/abilities/dynamicvalue/common/MultikickerCount.java +++ b/Mage/src/mage/abilities/dynamicvalue/common/MultikickerCount.java @@ -28,10 +28,13 @@ package mage.abilities.dynamicvalue.common; import mage.abilities.Ability; +import mage.abilities.costs.OptionalAdditionalCost; +import mage.abilities.costs.mana.KickerManaCost; +import mage.abilities.costs.mana.MultikickerManaCost; import mage.abilities.dynamicvalue.DynamicValue; -import mage.abilities.keyword.MultikickerAbility; +import mage.abilities.keyword.KickerAbility; +import mage.cards.Card; import mage.game.Game; -import mage.game.permanent.Permanent; /** * @@ -44,14 +47,23 @@ public class MultikickerCount implements DynamicValue { @Override public int calculate(Game game, Ability source) { - Permanent permanent = game.getPermanent(source.getSourceId()); - if (permanent != null) { - for (Ability ability : permanent.getAbilities()) { - if (ability instanceof MultikickerAbility) { - return ((MultikickerAbility)ability).getActivateCount(); - } + int count = 0; + Card card = game.getCard(source.getSourceId()); + if (card != null) { + KickerAbility kickerAbility = null; + for (Ability ability: card.getAbilities()) { + if (ability instanceof KickerAbility) { + kickerAbility = (KickerAbility) ability; } } + if (kickerAbility != null) { + for (OptionalAdditionalCost cost: kickerAbility.getKickerCosts()) { + count = cost.getActivateCount(); + break; + } + } + return count; + } return 0; } diff --git a/Mage/src/mage/abilities/keyword/AffinityForArtifactsAbility.java b/Mage/src/mage/abilities/keyword/AffinityForArtifactsAbility.java index 572b74bbda1..99b8fdb6ff9 100644 --- a/Mage/src/mage/abilities/keyword/AffinityForArtifactsAbility.java +++ b/Mage/src/mage/abilities/keyword/AffinityForArtifactsAbility.java @@ -50,6 +50,7 @@ public class AffinityForArtifactsAbility extends SimpleStaticAbility implements public AffinityForArtifactsAbility() { super(Constants.Zone.OUTSIDE, new AffinityEffect(filter)); + setRuleAtTheTop(true); } public AffinityForArtifactsAbility(final AffinityForArtifactsAbility ability) { diff --git a/Mage/src/mage/abilities/keyword/KickerAbility.java b/Mage/src/mage/abilities/keyword/KickerAbility.java index 7f6b9bc4167..7ce60cc8cfc 100644 --- a/Mage/src/mage/abilities/keyword/KickerAbility.java +++ b/Mage/src/mage/abilities/keyword/KickerAbility.java @@ -28,89 +28,123 @@ package mage.abilities.keyword; +import java.util.Iterator; +import java.util.LinkedList; +import java.util.List; +import mage.Constants; import mage.Constants.Zone; +import mage.abilities.Ability; +import mage.abilities.SpellAbility; import mage.abilities.StaticAbility; -import mage.abilities.effects.Effect; -import mage.cards.Card; +import mage.abilities.costs.Cost; +import mage.abilities.costs.Costs; +import mage.abilities.costs.OptionalAdditionalCost; +import mage.abilities.costs.OptionalAdditionalSourceCosts; +import mage.abilities.costs.mana.ManaCostsImpl; import mage.game.Game; import mage.players.Player; -/** - * - * @author BetaSteward_at_googlemail.com - */ -public class KickerAbility extends StaticAbility { +public class KickerAbility extends StaticAbility implements OptionalAdditionalSourceCosts { - protected boolean kicked = false; - protected boolean replaces = false; + protected List kickerCosts = new LinkedList(); - public KickerAbility(Effect effect, boolean replaces) { - super(Zone.STACK, effect); - this.replaces = replaces; + public KickerAbility(OptionalAdditionalCost kickerCost) { + super(Zone.STACK, null); + kickerCosts.add(kickerCost); + setRuleAtTheTop(true); } public KickerAbility(final KickerAbility ability) { - super(ability); - this.kicked = ability.kicked; - this.replaces = ability.replaces; + super(ability); + this.kickerCosts = ability.kickerCosts; } @Override public KickerAbility copy() { - return new KickerAbility(this); + return new KickerAbility(this); } - @Override - public boolean activate(Game game, boolean noMana) { - Player player = game.getPlayer(this.getControllerId()); - - String message = getKickerText(false) + "?"; - Card card = game.getCard(sourceId); - // replace by card name or just plain "this" - String text = card == null ? "this" : card.getName(); - message = message.replace("{this}", text).replace("{source}", text); - if (player.chooseUse(getEffects().get(0).getOutcome(), message, game)) { - int bookmark = game.bookmarkState(); - if (super.activate(game, noMana)) { - game.removeBookmark(bookmark); - kicked = true; - } - else { - game.restoreState(bookmark); - kicked = false; - } - return kicked; + public void resetKicker() { + for (OptionalAdditionalCost cost: kickerCosts) { + cost.reset(); } - return false; } - public boolean isKicked() { - return kicked; + public List getKickerCosts () { + return kickerCosts; } - public boolean isReplaces() { - return replaces; + public void addKickerManaCost(OptionalAdditionalCost kickerCost) { + kickerCosts.add(kickerCost); } + + @Override + public void addOptionalAdditionalCosts(Ability ability, Game game) { + if (ability instanceof SpellAbility) { + Player player = game.getPlayer(controllerId); + if (player != null) { + this.resetKicker(); + for (OptionalAdditionalCost kickerCost: kickerCosts) { + boolean again = true; + while (again) { + String times = ""; + if (kickerCost.isRepeatable()) { + 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)) { + kickerCost.activate(); + for (Iterator it = ((Costs) kickerCost).iterator(); it.hasNext();) { + Cost cost = (Cost) it.next(); + if (cost instanceof ManaCostsImpl) { + ability.getManaCostsToPay().add((ManaCostsImpl) cost.copy()); + } else { + ability.getCosts().add(cost.copy()); + } + } + + again = kickerCost.isRepeatable(); + } else { + again = false; + } + } + } + } + } + } + @Override public String getRule() { - return getKickerText(true); + StringBuilder sb = new StringBuilder(); + int numberKicker = 0; + String remarkText = ""; + for (OptionalAdditionalCost kickerCost: kickerCosts) { + if (numberKicker == 0) { + sb.append(kickerCost.getText(false)); + remarkText = kickerCost.getReminderText(); + } else { + sb.append(" and/or ").append(kickerCost.getText(true)); + } + ++numberKicker; + } + if (numberKicker == 1) { + sb.append(" ").append(remarkText); + } + + return sb.toString(); } - public String getKickerText(boolean withRemainder) { + @Override + public String getCastMessageSuffix() { StringBuilder sb = new StringBuilder(); - sb.append("Kicker - "); - if (manaCosts.size() > 0) { - sb.append(manaCosts.getText()); - if (costs.size() > 0) - sb.append(","); + int position = 0; + for (OptionalAdditionalCost cost : kickerCosts) { + if (cost.isActivated()) { + sb.append(cost.getCastSuffixMessage(position)); + ++position; + } } - if (costs.size() > 0) - sb.append(costs.getText()); - sb.append(":").append(modes.getText()); - if (replaces) - sb.append(" instead"); return sb.toString(); } - } diff --git a/Mage/src/mage/abilities/keyword/MultikickerAbility.java b/Mage/src/mage/abilities/keyword/MultikickerAbility.java index 7a8ff2b1fd1..c3bfc664414 100644 --- a/Mage/src/mage/abilities/keyword/MultikickerAbility.java +++ b/Mage/src/mage/abilities/keyword/MultikickerAbility.java @@ -28,7 +28,7 @@ package mage.abilities.keyword; -import mage.abilities.common.EmptyEffect; +import mage.abilities.costs.mana.KickerManaCost; import mage.abilities.costs.mana.ManaCosts; import mage.abilities.effects.Effect; import mage.game.Game; @@ -42,11 +42,14 @@ public class MultikickerAbility extends KickerAbility { int activateCount; public MultikickerAbility(Effect effect, boolean replaces) { - super(effect, replaces); + super(new KickerManaCost("{1}")); + // super(effect, replaces); + } public MultikickerAbility(ManaCosts manaCosts) { - super(new EmptyEffect(""), false); + super((KickerManaCost) manaCosts); + //super(new EmptyEffect(""), false); this.addManaCost(manaCosts); } @@ -70,8 +73,9 @@ public class MultikickerAbility extends KickerAbility { break; activateCount++; } - kicked = activateCount > 0; - return kicked; +// kicked = activateCount > 0; +// return kicked; + return false; } @Override @@ -83,24 +87,24 @@ public class MultikickerAbility extends KickerAbility { return result; } - @Override - public String getKickerText(boolean withRemainder) { - StringBuilder sb = new StringBuilder(); - sb.append("Multikicker "); - if (manaCosts.size() > 0) { - sb.append(manaCosts.getText()); - if (costs.size() > 0) { - sb.append(","); - } - } - if (costs.size() > 0) { - sb.append(costs.getText()); - } - if (withRemainder) { - sb.append(" (You may pay an additional ").append(manaCosts.getText()).append(" any number of times as you cast this spell.)"); - } - return sb.toString(); - } +// @Override +// public String getKickerText(boolean withRemainder) { +// StringBuilder sb = new StringBuilder(); +// sb.append("Multikicker "); +// if (manaCosts.size() > 0) { +// sb.append(manaCosts.getText()); +// if (costs.size() > 0) { +// sb.append(","); +// } +// } +// if (costs.size() > 0) { +// sb.append(costs.getText()); +// } +// if (withRemainder) { +// sb.append(" (You may pay an additional ").append(manaCosts.getText()).append(" any number of times as you cast this spell.)"); +// } +// return sb.toString(); +// } public int getActivateCount() { return activateCount; diff --git a/Mage/src/mage/game/GameState.java b/Mage/src/mage/game/GameState.java index 7067617d40d..6fbc0d67bbc 100644 --- a/Mage/src/mage/game/GameState.java +++ b/Mage/src/mage/game/GameState.java @@ -447,9 +447,6 @@ public class GameState implements Serializable, Copyable { @Deprecated public void addAbility(Ability ability, MageObject attachedTo) { if (ability instanceof StaticAbility) { - if (ability instanceof KickerAbility) { - return; - } for (Mode mode: ability.getModes().values()) { for (Effect effect: mode.getEffects()) { if (effect instanceof ContinuousEffect) { @@ -465,9 +462,6 @@ public class GameState implements Serializable, Copyable { public void addAbility(Ability ability, UUID sourceId, MageObject attachedTo) { if (ability instanceof StaticAbility) { - if (ability instanceof KickerAbility) { - return; - } for (Mode mode: ability.getModes().values()) { for (Effect effect: mode.getEffects()) { if (effect instanceof ContinuousEffect) { diff --git a/Mage/src/mage/game/stack/Spell.java b/Mage/src/mage/game/stack/Spell.java index 916bcba7c4f..5eb74003eeb 100644 --- a/Mage/src/mage/game/stack/Spell.java +++ b/Mage/src/mage/game/stack/Spell.java @@ -43,7 +43,6 @@ import mage.abilities.costs.mana.ManaCost; import mage.abilities.costs.mana.ManaCosts; import mage.abilities.effects.Effect; import mage.abilities.effects.PostResolveEffect; -import mage.abilities.keyword.KickerAbility; import mage.cards.Card; import mage.game.Game; import mage.game.events.ZoneChangeEvent; @@ -88,12 +87,7 @@ public class Spell> implements StackObject, Card { if (card.getCardType().contains(CardType.INSTANT) || card.getCardType().contains(CardType.SORCERY)) { if (ability.getTargets().stillLegal(ability, game)) { updateOptionalCosts(); - boolean replaced = resolveKicker(game); - if (!replaced) - result = ability.resolve(game); - else - result = true; - + result = ability.resolve(game); if (!copiedSpell) { for (Effect effect : ability.getEffects()) { if (effect instanceof PostResolveEffect) { @@ -126,8 +120,6 @@ public class Spell> implements StackObject, Card { return false; } else { updateOptionalCosts(); - - resolveKicker(game); result = card.putOntoBattlefield(game, Zone.HAND, ability.getId(), controllerId); return result; } @@ -157,18 +149,6 @@ public class Spell> implements StackObject, Card { } } - protected boolean resolveKicker(Game game) { - boolean replaced = false; - for (KickerAbility kicker: card.getAbilities().getKickerAbilities()) { - if (kicker.isKicked()) { - if (kicker.isReplaces()) { - replaced = true; - } - kicker.resolve(game); - } - } - return replaced; - } /** * Choose new targets for the spell diff --git a/Mage/src/mage/players/PlayerImpl.java b/Mage/src/mage/players/PlayerImpl.java index b427b1aa9df..649bb2cee50 100644 --- a/Mage/src/mage/players/PlayerImpl.java +++ b/Mage/src/mage/players/PlayerImpl.java @@ -507,11 +507,6 @@ public abstract class PlayerImpl> implements Player, Ser SpellAbility spellAbility = game.getStack().getSpell(ability.getId()).getSpellAbility(); if (spellAbility.activate(game, noMana)) { - for (KickerAbility kicker: card.getAbilities().getKickerAbilities()) { - if (kicker.getCosts().canPay(ability.getSourceId(), playerId, game) && kicker.canChooseTarget(game)) { - kicker.activate(game, false); - } - } GameEvent event = GameEvent.getEvent(GameEvent.EventType.SPELL_CAST, spellAbility.getId(), spellAbility.getSourceId(), playerId); event.setZone(fromZone); game.fireEvent(event);