Added Evoke ability.

This commit is contained in:
LevelX2 2013-05-25 15:42:52 +02:00
parent 3da35269af
commit 9f277547de
8 changed files with 540 additions and 1 deletions

View file

@ -182,6 +182,12 @@ public abstract class AbilityImpl<T extends AbilityImpl<T>> implements Ability {
// A player can't apply two alternative methods of casting or two alternative costs to a single spell.
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;
}
}
if (ability instanceof OptionalAdditionalSourceCosts) {
((OptionalAdditionalSourceCosts)ability).addOptionalAdditionalCosts(this, game);
}

View file

@ -34,7 +34,7 @@ import mage.Constants.AbilityType;
import mage.Constants.TimingRule;
import mage.Constants.Zone;
import mage.MageObject;
import mage.abilities.common.SpellCastTriggeredAbility;
import mage.abilities.costs.AlternativeSourceCosts;
import mage.abilities.costs.Cost;
import mage.abilities.costs.Costs;
import mage.abilities.costs.OptionalAdditionalSourceCosts;
@ -276,6 +276,9 @@ public abstract class ActivatedAbilityImpl<T extends ActivatedAbilityImpl<T>> ex
if (ability instanceof OptionalAdditionalSourceCosts) {
sb.append(((OptionalAdditionalSourceCosts) ability).getCastMessageSuffix());
}
if (ability instanceof AlternativeSourceCosts) {
sb.append(((AlternativeSourceCosts) ability).getCastMessageSuffix());
}
}
return sb.toString();
}

View file

@ -0,0 +1,70 @@
/*
* 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.keyword.EvokeAbility;
import mage.cards.Card;
import mage.game.Game;
/**
* Checks if a the spell was cast with the alternate evoke costs
*
* @author LevelX2
*/
public class EvokedCondition implements Condition {
private static EvokedCondition fInstance = null;
private EvokedCondition() {}
public static Condition getInstance() {
if (fInstance == null) {
fInstance = new EvokedCondition();
}
return fInstance;
}
@Override
public boolean apply(Game game, Ability source) {
Card card = game.getCard(source.getSourceId());
if (card != null) {
for (Ability ability: card.getAbilities()) {
if (ability instanceof EvokeAbility) {
if(((EvokeAbility) ability).isActivated()) {
return true;
}
}
}
}
return false;
}
}

View file

@ -0,0 +1,86 @@
/*
* 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 AlternativeCost2 extends Cost {
String getName();
/**
* Returns the complete text for the alternate cost or if onlyCost is true
* only the pure text fore the included native cost
*
* @param onlyCost
* @return
*/
String getText(boolean onlyCost);
/**
* Returns a reminder text, if the cost has one
*
* @return
*/
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
*/
String getCastSuffixMessage(int position);
/**
* If the player intends to pay the alternate cost, the cost will be activated
*
* @param activated
*/
void activate();
/**
* Reset the activate
*
*/
void reset();
/**
* Returns if the cost was activated
*
* @return
*/
boolean isActivated();
}

View file

@ -0,0 +1,146 @@
/*
* 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 Ludwig
*/
public class AlternativeCost2Impl <T extends AlternativeCost2Impl<T>> extends CostsImpl<Cost> implements AlternativeCost2 {
protected String name;
protected String reminderText;
protected String delimiter;
protected boolean activated;
public AlternativeCost2Impl(String name, String reminderText, Cost cost) {
this(name, " ", reminderText, cost);
}
public AlternativeCost2Impl(String name, String delimiter, String reminderText, Cost cost) {
this.activated = false;
this.name = name;
this.delimiter = delimiter;
this.reminderText = new StringBuilder("<i>").append(reminderText).append("</i>").toString();
this.add((Cost) cost);
}
public AlternativeCost2Impl(final AlternativeCost2Impl cost) {
super(cost);
this.name = cost.name;
this.reminderText = cost.reminderText;
this.activated = cost.activated;
this.delimiter = cost.delimiter;
}
@Override
public String getName() {
return this.name;
}
/**
* Returns the complete text for the addional cost 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 new StringBuffer(name).append(delimiter).append(getText()).toString();
}
}
/**
* 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) {
StringBuilder sb = new StringBuilder(position > 0 ? " and ":"").append(" with ");
sb.append(name);
return sb.toString();
}
/**
* If the player intends to pay the cost, the cost will be activated
*
* @param activated
*/
@Override
public void activate() {
activated = true;
};
/**
* Reset the activate and count information
*
*/
@Override
public void reset() {
activated = false;
}
/**
* Returns if the cost was activated
*
* @return
*/
@Override
public boolean isActivated(){
return activated;
};
@Override
public AlternativeCost2Impl copy() {
return new AlternativeCost2Impl(this);
}
}

View file

@ -0,0 +1,61 @@
/*
* 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 alternative costs to the source.
*
* Example of such additional source costs: {@link mage.abilities.keyword.KickerAbility}
*
* @author LevelX2
*/
public interface AlternativeSourceCosts {
/**
* Ask the player if he wants to use the alternative costs
*
* @param ability ability the alternative cost is activated for
* @param game
*/
boolean askToActivateAlternativeCosts(Ability ability, Game game);
/**
* Was the alternative cost activated
* @return
*/
boolean isActivated();
/**
* Suffix string to use for game log
* @return
*/
String getCastMessageSuffix();
}

View file

@ -0,0 +1,166 @@
/*
* 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 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.common.EntersBattlefieldTriggeredAbility;
import mage.abilities.condition.common.EvokedCondition;
import mage.abilities.costs.AlternativeCost2;
import mage.abilities.costs.AlternativeCost2Impl;
import mage.abilities.costs.AlternativeSourceCosts;
import mage.abilities.costs.Cost;
import mage.abilities.costs.Costs;
import mage.abilities.costs.mana.ManaCostsImpl;
import mage.abilities.decorator.ConditionalTriggeredAbility;
import mage.abilities.effects.common.SacrificeSourceEffect;
import mage.cards.Card;
import mage.game.Game;
import mage.players.Player;
/**
*
* @author LevelX2
*/
public class EvokeAbility extends StaticAbility<EvokeAbility> implements AlternativeSourceCosts {
protected static final String EVOKE_KEYWORD = "Evoke";
protected static final String REMINDER_TEXT = "(You may cast this spell for its evoke cost. If you do, it's sacrificed when it enters the battlefield.)";
protected List<AlternativeCost2> evokeCosts = new LinkedList<AlternativeCost2>();
public EvokeAbility(Card card, String manaString) {
super(Zone.ALL, null);
name = EVOKE_KEYWORD;
this.addEvokeCost(manaString);
Ability ability = new ConditionalTriggeredAbility(new EntersBattlefieldTriggeredAbility(new SacrificeSourceEffect()), EvokedCondition.getInstance(), "Sacrifice {this} when it enters the battlefield and was evoked.");
ability.setRuleVisible(false);
ability.setRuleVisible(false);
card.addAbility(ability);
}
public EvokeAbility(final EvokeAbility ability) {
super(ability);
}
@Override
public EvokeAbility copy() {
return new EvokeAbility(this);
}
public final AlternativeCost2 addEvokeCost(String manaString) {
AlternativeCost2 evokeCost = new AlternativeCost2Impl(EVOKE_KEYWORD, REMINDER_TEXT, new ManaCostsImpl(manaString));
evokeCosts.add(evokeCost);
return evokeCost;
}
public void resetEvoke() {
for (AlternativeCost2 cost: evokeCosts) {
cost.reset();
}
}
@Override
public boolean isActivated() {
for (AlternativeCost2 cost: evokeCosts) {
if(cost.isActivated()) {
return true;
}
}
return false;
}
@Override
public boolean askToActivateAlternativeCosts(Ability ability, Game game) {
if (ability instanceof SpellAbility) {
Player player = game.getPlayer(controllerId);
if (player != null) {
this.resetEvoke();
for (AlternativeCost2 evokeCost: evokeCosts) {
if (evokeCost.canPay(sourceId, controllerId, game) &&
player.chooseUse(Constants.Outcome.Benefit, new StringBuilder(EVOKE_KEYWORD).append(" the creature for ").append(evokeCost.getText(true)).append(" ?").toString(), game)) {
evokeCost.activate();
ability.getManaCostsToPay().clear();
ability.getCosts().clear();
for (Iterator it = ((Costs) evokeCost).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 String getRule() {
StringBuilder sb = new StringBuilder();
int numberCosts = 0;
String remarkText = "";
for (AlternativeCost2 evokeCost: evokeCosts) {
if (numberCosts == 0) {
sb.append(evokeCost.getText(false));
remarkText = evokeCost.getReminderText();
} else {
sb.append(" and/or ").append(evokeCost.getText(true));
}
++numberCosts;
}
if (numberCosts == 1) {
sb.append(" ").append(remarkText);
}
return sb.toString();
}
@Override
public String getCastMessageSuffix() {
StringBuilder sb = new StringBuilder();
int position = 0;
for (AlternativeCost2 cost : evokeCosts) {
if (cost.isActivated()) {
sb.append(cost.getCastSuffixMessage(position));
++position;
}
}
return sb.toString();
}
}

View file

@ -2,6 +2,7 @@ Annihilator|number|
Bloodthirst|number|
Bushido|number|
Dredge|number|
Evoke|card, manaString|
Soulshift|number|
Basic landcycling|cost|
Forestcycling|cost|