mirror of
https://github.com/Card-Forge/forge.git
synced 2025-11-19 20:28:00 +00:00
SpellAbility cost adjustment moved to ManaCostBeingPaid
the adjustment modifies the instance of ManaCostBeingPaid it was called on (all callers do create a new instance anyway and call this first)
This commit is contained in:
@@ -23,7 +23,6 @@ import java.util.regex.Pattern;
|
||||
|
||||
import forge.Card;
|
||||
import forge.CounterType;
|
||||
import forge.Singletons;
|
||||
import forge.card.mana.ManaCost;
|
||||
import forge.card.mana.ManaCostBeingPaid;
|
||||
import forge.card.mana.ManaCostParser;
|
||||
@@ -366,7 +365,8 @@ public class Cost {
|
||||
for (final CostPart part : this.costParts) {
|
||||
if (part instanceof CostPartMana) {
|
||||
final ManaCost mana = new ManaCost(new ManaCostParser(part.toString()));
|
||||
final ManaCostBeingPaid changedCost = Singletons.getModel().getGame().getActionPlay().getSpellCostChange(sa, new ManaCostBeingPaid(mana));
|
||||
final ManaCostBeingPaid changedCost = new ManaCostBeingPaid(mana);
|
||||
changedCost.applySpellCostChange(sa);
|
||||
|
||||
((CostPartMana)part).setAdjustedMana(changedCost.toString(false));
|
||||
costChanged = true;
|
||||
@@ -374,7 +374,8 @@ public class Cost {
|
||||
}
|
||||
if (!costChanged) {
|
||||
// Spells with a cost of 0 should be affected too
|
||||
final ManaCostBeingPaid changedCost = Singletons.getModel().getGame().getActionPlay().getSpellCostChange(sa, new ManaCostBeingPaid("0"));
|
||||
final ManaCostBeingPaid changedCost = new ManaCostBeingPaid("0");
|
||||
changedCost.applySpellCostChange(sa);
|
||||
this.costParts.add(new CostPartMana(changedCost.toString(), 0, false));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -22,8 +22,21 @@ import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map.Entry;
|
||||
|
||||
import com.google.common.collect.Lists;
|
||||
|
||||
import forge.Card;
|
||||
import forge.CardColor;
|
||||
import forge.CardLists;
|
||||
import forge.CardPredicates;
|
||||
import forge.Constant;
|
||||
import forge.card.MagicColor;
|
||||
import forge.card.spellability.SpellAbility;
|
||||
import forge.card.staticability.StaticAbility;
|
||||
import forge.game.GameState;
|
||||
import forge.game.player.Player;
|
||||
import forge.game.zone.ZoneType;
|
||||
import forge.gui.GuiChoose;
|
||||
import forge.util.MyRandom;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
@@ -652,4 +665,165 @@ public class ManaCostBeingPaid {
|
||||
public ManaCost getStartingCost() {
|
||||
return originalCost;
|
||||
}
|
||||
|
||||
public final void applySpellCostChange(final SpellAbility sa) {
|
||||
final GameState game = sa.getActivatingPlayer().getGame();
|
||||
// Beached
|
||||
final Card originalCard = sa.getSourceCard();
|
||||
final SpellAbility spell = sa;
|
||||
|
||||
|
||||
if (sa.isXCost() && !originalCard.isCopiedSpell()) {
|
||||
originalCard.setXManaCostPaid(0);
|
||||
}
|
||||
|
||||
if (sa.isTrigger()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (spell.isSpell()) {
|
||||
if (spell.isDelve()) {
|
||||
final Player pc = originalCard.getController();
|
||||
final List<Card> mutableGrave = Lists.newArrayList(pc.getZone(ZoneType.Graveyard).getCards());
|
||||
final List<Card> toExile = pc.getController().chooseCardsToDelve(this.getColorlessManaAmount(), mutableGrave);
|
||||
for (final Card c : toExile) {
|
||||
pc.getGame().getAction().exile(c);
|
||||
decreaseColorlessMana(1);
|
||||
}
|
||||
} else if (spell.getSourceCard().hasKeyword("Convoke")) {
|
||||
adjustCostByConvoke(sa, spell);
|
||||
}
|
||||
} // isSpell
|
||||
|
||||
List<Card> cardsOnBattlefield = Lists.newArrayList(game.getCardsIn(ZoneType.Battlefield));
|
||||
cardsOnBattlefield.addAll(game.getCardsIn(ZoneType.Stack));
|
||||
cardsOnBattlefield.addAll(game.getCardsIn(ZoneType.Command));
|
||||
if (!cardsOnBattlefield.contains(originalCard)) {
|
||||
cardsOnBattlefield.add(originalCard);
|
||||
}
|
||||
final ArrayList<StaticAbility> raiseAbilities = new ArrayList<StaticAbility>();
|
||||
final ArrayList<StaticAbility> reduceAbilities = new ArrayList<StaticAbility>();
|
||||
final ArrayList<StaticAbility> setAbilities = new ArrayList<StaticAbility>();
|
||||
|
||||
// Sort abilities to apply them in proper order
|
||||
for (Card c : cardsOnBattlefield) {
|
||||
final ArrayList<StaticAbility> staticAbilities = c.getStaticAbilities();
|
||||
for (final StaticAbility stAb : staticAbilities) {
|
||||
if (stAb.getMapParams().get("Mode").equals("RaiseCost")) {
|
||||
raiseAbilities.add(stAb);
|
||||
} else if (stAb.getMapParams().get("Mode").equals("ReduceCost")) {
|
||||
reduceAbilities.add(stAb);
|
||||
} else if (stAb.getMapParams().get("Mode").equals("SetCost")) {
|
||||
setAbilities.add(stAb);
|
||||
}
|
||||
}
|
||||
}
|
||||
// Raise cost
|
||||
for (final StaticAbility stAb : raiseAbilities) {
|
||||
stAb.applyAbility("RaiseCost", spell, this);
|
||||
}
|
||||
|
||||
// Reduce cost
|
||||
for (final StaticAbility stAb : reduceAbilities) {
|
||||
stAb.applyAbility("ReduceCost", spell, this);
|
||||
}
|
||||
|
||||
// Set cost (only used by Trinisphere) is applied last
|
||||
for (final StaticAbility stAb : setAbilities) {
|
||||
stAb.applyAbility("SetCost", spell, this);
|
||||
}
|
||||
} // GetSpellCostChange
|
||||
|
||||
private void adjustCostByConvoke(final SpellAbility sa, final SpellAbility spell) {
|
||||
|
||||
List<Card> untappedCreats = CardLists.filter(spell.getActivatingPlayer().getCardsIn(ZoneType.Battlefield), CardPredicates.Presets.CREATURES);
|
||||
untappedCreats = CardLists.filter(untappedCreats, CardPredicates.Presets.UNTAPPED);
|
||||
|
||||
while (!untappedCreats.isEmpty() && getConvertedManaCost() > 0) {
|
||||
Card workingCard = null;
|
||||
String chosenColor = null;
|
||||
if (sa.getActivatingPlayer().isHuman()) {
|
||||
workingCard = GuiChoose.oneOrNone("Tap for Convoke? " + toString(), untappedCreats);
|
||||
if( null == workingCard )
|
||||
break; // that means "I'm done"
|
||||
|
||||
List<String> usableColors = getConvokableColors(workingCard);
|
||||
if ( !usableColors.isEmpty() ) {
|
||||
chosenColor = usableColors.size() == 1 ? usableColors.get(0) : GuiChoose.one("Convoke for which color?", usableColors);
|
||||
}
|
||||
} else {
|
||||
// TODO: AI to choose a creature to tap would go here
|
||||
// Probably along with deciding how many creatures to
|
||||
// tap
|
||||
|
||||
if ( MyRandom.getRandom().nextInt(3) == 0 ) // 66% chance to chose first creature, 33% to cancel
|
||||
workingCard = untappedCreats.get(0);
|
||||
|
||||
if( null == workingCard )
|
||||
break; // that means "I'm done"
|
||||
|
||||
List<String> usableColors = getConvokableColors(workingCard);
|
||||
if ( !usableColors.isEmpty() ) {
|
||||
// TODO: AI for choosing which color to convoke goes here.
|
||||
chosenColor = usableColors.get(0);
|
||||
}
|
||||
|
||||
}
|
||||
untappedCreats.remove(workingCard);
|
||||
|
||||
|
||||
if ( null == chosenColor )
|
||||
continue;
|
||||
else if (chosenColor.equals("colorless")) {
|
||||
decreaseColorlessMana(1);
|
||||
} else {
|
||||
decreaseShard(ManaCostShard.valueOf(MagicColor.fromName(chosenColor)), 1);
|
||||
}
|
||||
|
||||
sa.addTappedForConvoke(workingCard);
|
||||
}
|
||||
|
||||
// Convoked creats are tapped here with triggers
|
||||
// suppressed,
|
||||
// Then again when payment is done(In
|
||||
// InputPayManaCost.done()) with suppression cleared.
|
||||
// This is to make sure that triggers go off at the
|
||||
// right time
|
||||
// AND that you can't use mana tapabilities of convoked
|
||||
// creatures
|
||||
// to pay the convoked cost.
|
||||
for (final Card c : sa.getTappedForConvoke()) {
|
||||
c.setTapped(true);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the convokable colors.
|
||||
*
|
||||
* @param cardToConvoke
|
||||
* the card to convoke
|
||||
* @param cost
|
||||
* the cost
|
||||
* @return the convokable colors
|
||||
*/
|
||||
private List<String> getConvokableColors(final Card cardToConvoke) {
|
||||
final ArrayList<String> usableColors = new ArrayList<String>();
|
||||
|
||||
if (getColorlessManaAmount() > 0) {
|
||||
usableColors.add("colorless");
|
||||
}
|
||||
for (final CardColor col : cardToConvoke.getColor()) {
|
||||
for (final String strCol : col.toStringList()) {
|
||||
if (strCol.equals("colorless")) {
|
||||
continue;
|
||||
}
|
||||
if (toString().contains(MagicColor.toShortString(strCol))) {
|
||||
usableColors.add(strCol.toString());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return usableColors;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -358,28 +358,26 @@ public class StaticAbility {
|
||||
* the originalCost
|
||||
* @return the modified ManaCost
|
||||
*/
|
||||
public final ManaCostBeingPaid applyAbility(final String mode, final SpellAbility sa, final ManaCostBeingPaid originalCost) {
|
||||
public final void applyAbility(final String mode, final SpellAbility sa, final ManaCostBeingPaid originalCost) {
|
||||
|
||||
// don't apply the ability if it hasn't got the right mode
|
||||
if (!this.params.get("Mode").equals(mode)) {
|
||||
return originalCost;
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.isSuppressed() || !this.checkConditions()) {
|
||||
return originalCost;
|
||||
return;
|
||||
}
|
||||
|
||||
if (mode.equals("RaiseCost")) {
|
||||
return StaticAbilityCostChange.applyRaiseCostAbility(this, sa, originalCost);
|
||||
StaticAbilityCostChange.applyRaiseCostAbility(this, sa, originalCost);
|
||||
}
|
||||
if (mode.equals("ReduceCost")) {
|
||||
return StaticAbilityCostChange.applyReduceCostAbility(this, sa, originalCost);
|
||||
StaticAbilityCostChange.applyReduceCostAbility(this, sa, originalCost);
|
||||
}
|
||||
if (mode.equals("SetCost")) { //Set cost is only used by Trinisphere
|
||||
return StaticAbilityCostChange.applyRaiseCostAbility(this, sa, originalCost);
|
||||
StaticAbilityCostChange.applyRaiseCostAbility(this, sa, originalCost);
|
||||
}
|
||||
|
||||
return originalCost;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -45,51 +45,50 @@ public class StaticAbilityCostChange {
|
||||
* @param originalCost
|
||||
* a ManaCost
|
||||
*/
|
||||
public static ManaCostBeingPaid applyRaiseCostAbility(final StaticAbility staticAbility, final SpellAbility sa
|
||||
, final ManaCostBeingPaid originalCost) {
|
||||
public static void applyRaiseCostAbility(final StaticAbility staticAbility, final SpellAbility sa, final ManaCostBeingPaid manaCost) {
|
||||
final HashMap<String, String> params = staticAbility.getMapParams();
|
||||
final Card hostCard = staticAbility.getHostCard();
|
||||
final Player activator = sa.getActivatingPlayer();
|
||||
final Card card = sa.getSourceCard();
|
||||
final String amount = params.get("Amount");
|
||||
final ManaCostBeingPaid manaCost = new ManaCostBeingPaid(originalCost.toString());
|
||||
|
||||
|
||||
if (params.containsKey("ValidCard")
|
||||
&& !card.isValid(params.get("ValidCard").split(","), hostCard.getController(), hostCard)) {
|
||||
return originalCost;
|
||||
return;
|
||||
}
|
||||
|
||||
if (params.containsKey("Activator") && ((activator == null)
|
||||
|| !activator.isValid(params.get("Activator"), hostCard.getController(), hostCard))) {
|
||||
return originalCost;
|
||||
return;
|
||||
}
|
||||
|
||||
if (params.containsKey("Type")) {
|
||||
if (params.get("Type").equals("Spell")) {
|
||||
if (!sa.isSpell()) {
|
||||
return originalCost;
|
||||
return;
|
||||
}
|
||||
} else if (params.get("Type").equals("Ability")) {
|
||||
if (!(sa instanceof AbilityActivated)) {
|
||||
return originalCost;
|
||||
return;
|
||||
}
|
||||
} else if (params.get("Type").equals("NonManaAbility")) {
|
||||
if (!(sa instanceof AbilityActivated) || sa.isManaAbility()) {
|
||||
return originalCost;
|
||||
return;
|
||||
}
|
||||
} else if (params.get("Type").equals("Flashback")) {
|
||||
if (!sa.isFlashBackAbility()) {
|
||||
return originalCost;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (params.containsKey("AffectedZone") && !card.isInZone(ZoneType.smartValueOf(params.get("AffectedZone")))) {
|
||||
return originalCost;
|
||||
return;
|
||||
}
|
||||
if (params.containsKey("ValidTarget")) {
|
||||
Target tgt = sa.getTarget();
|
||||
if (tgt == null) {
|
||||
return originalCost;
|
||||
return;
|
||||
}
|
||||
boolean targetValid = false;
|
||||
for (Object target : tgt.getTargets()) {
|
||||
@@ -101,13 +100,13 @@ public class StaticAbilityCostChange {
|
||||
}
|
||||
}
|
||||
if (!targetValid) {
|
||||
return originalCost;
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (params.containsKey("ValidSpellTarget")) {
|
||||
Target tgt = sa.getTarget();
|
||||
if (tgt == null) {
|
||||
return originalCost;
|
||||
return;
|
||||
}
|
||||
boolean targetValid = false;
|
||||
for (Object target : tgt.getTargets()) {
|
||||
@@ -119,7 +118,7 @@ public class StaticAbilityCostChange {
|
||||
}
|
||||
}
|
||||
if (!targetValid) {
|
||||
return originalCost;
|
||||
return;
|
||||
}
|
||||
}
|
||||
int value = 0;
|
||||
@@ -155,8 +154,6 @@ public class StaticAbilityCostChange {
|
||||
manaCost.increaseShard(ManaCostShard.GREEN, value);
|
||||
}
|
||||
}
|
||||
|
||||
return manaCost;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -169,58 +166,57 @@ public class StaticAbilityCostChange {
|
||||
* @param originalCost
|
||||
* a ManaCost
|
||||
*/
|
||||
public static ManaCostBeingPaid applyReduceCostAbility(final StaticAbility staticAbility, final SpellAbility sa
|
||||
, final ManaCostBeingPaid originalCost) {
|
||||
public static void applyReduceCostAbility(final StaticAbility staticAbility, final SpellAbility sa, final ManaCostBeingPaid manaCost) {
|
||||
//Can't reduce zero cost
|
||||
if (originalCost.toString().equals("0")) {
|
||||
return originalCost;
|
||||
if (manaCost.toString().equals("0")) {
|
||||
return;
|
||||
}
|
||||
final HashMap<String, String> params = staticAbility.getMapParams();
|
||||
final Card hostCard = staticAbility.getHostCard();
|
||||
final Player activator = sa.getActivatingPlayer();
|
||||
final Card card = sa.getSourceCard();
|
||||
final String amount = params.get("Amount");
|
||||
final ManaCostBeingPaid manaCost = new ManaCostBeingPaid(originalCost.toString());
|
||||
|
||||
|
||||
if (params.containsKey("ValidCard")
|
||||
&& !card.isValid(params.get("ValidCard").split(","), hostCard.getController(), hostCard)) {
|
||||
return originalCost;
|
||||
return;
|
||||
}
|
||||
if (params.containsKey("Activator") && ((activator == null)
|
||||
|| !activator.isValid(params.get("Activator"), hostCard.getController(), hostCard))) {
|
||||
return originalCost;
|
||||
return;
|
||||
}
|
||||
if (params.containsKey("Type")) {
|
||||
if (params.get("Type").equals("Spell")) {
|
||||
if (!sa.isSpell()) {
|
||||
return originalCost;
|
||||
return;
|
||||
}
|
||||
} else if (params.get("Type").equals("Ability")) {
|
||||
if (!(sa instanceof AbilityActivated)) {
|
||||
return originalCost;
|
||||
return;
|
||||
}
|
||||
} else if (params.get("Type").equals("Buyback")) {
|
||||
if (!sa.isBuyBackAbility()) {
|
||||
return originalCost;
|
||||
return;
|
||||
}
|
||||
} else if (params.get("Type").equals("Cycling")) {
|
||||
if (!sa.isCycling()) {
|
||||
return originalCost;
|
||||
return;
|
||||
}
|
||||
} else if (params.get("Type").equals("Equip")) {
|
||||
if (!(sa instanceof AbilityActivated) || !sa.hasParam("Equip")) {
|
||||
return originalCost;
|
||||
return;
|
||||
}
|
||||
} else if (params.get("Type").equals("Flashback")) {
|
||||
if (!sa.isFlashBackAbility()) {
|
||||
return originalCost;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (params.containsKey("ValidTarget")) {
|
||||
Target tgt = sa.getTarget();
|
||||
if (tgt == null) {
|
||||
return originalCost;
|
||||
return;
|
||||
}
|
||||
boolean targetValid = false;
|
||||
for (Object target : tgt.getTargets()) {
|
||||
@@ -232,11 +228,11 @@ public class StaticAbilityCostChange {
|
||||
}
|
||||
}
|
||||
if (!targetValid) {
|
||||
return originalCost;
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (params.containsKey("AffectedZone") && !card.isInZone(ZoneType.smartValueOf(params.get("AffectedZone")))) {
|
||||
return originalCost;
|
||||
return;
|
||||
}
|
||||
int value = 0;
|
||||
if ("X".equals(amount)) {
|
||||
@@ -259,8 +255,5 @@ public class StaticAbilityCostChange {
|
||||
manaCost.decreaseShard(ManaCostShard.GREEN, value);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return manaCost;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,27 +1,15 @@
|
||||
package forge.game;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import com.google.common.collect.Lists;
|
||||
|
||||
import forge.Card;
|
||||
import forge.CardColor;
|
||||
import forge.CardLists;
|
||||
import forge.CardPredicates;
|
||||
import forge.FThreads;
|
||||
import forge.card.MagicColor;
|
||||
import forge.card.ability.ApiType;
|
||||
import forge.card.ability.effects.CharmEffect;
|
||||
import forge.card.cost.CostPayment;
|
||||
import forge.card.mana.ManaCostBeingPaid;
|
||||
import forge.card.mana.ManaCostShard;
|
||||
import forge.card.spellability.SpellAbility;
|
||||
import forge.card.spellability.HumanPlaySpellAbility;
|
||||
import forge.card.staticability.StaticAbility;
|
||||
import forge.game.ai.ComputerUtilCard;
|
||||
import forge.game.player.Player;
|
||||
import forge.game.zone.ZoneType;
|
||||
import forge.gui.GuiChoose;
|
||||
|
||||
/**
|
||||
* TODO: Write javadoc for this type.
|
||||
@@ -84,266 +72,4 @@ public class GameActionPlay {
|
||||
game.getStack().add(sa, x);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* getSpellCostChange.
|
||||
* </p>
|
||||
*
|
||||
* @param sa
|
||||
* a {@link forge.card.spellability.SpellAbility} object.
|
||||
* @param originalCost
|
||||
* a {@link forge.card.mana.ManaCostBeingPaid} object.
|
||||
* @return a {@link forge.card.mana.ManaCostBeingPaid} object.
|
||||
*/
|
||||
public final ManaCostBeingPaid getSpellCostChange(final SpellAbility sa, final ManaCostBeingPaid originalCost) {
|
||||
// Beached
|
||||
final Card originalCard = sa.getSourceCard();
|
||||
final SpellAbility spell = sa;
|
||||
String mana = originalCost.toString();
|
||||
ManaCostBeingPaid manaCost = new ManaCostBeingPaid(mana);
|
||||
if (sa.isXCost() && !originalCard.isCopiedSpell()) {
|
||||
originalCard.setXManaCostPaid(0);
|
||||
}
|
||||
|
||||
if (game == null || sa.isTrigger()) {
|
||||
return manaCost;
|
||||
}
|
||||
|
||||
if (spell.isSpell()) {
|
||||
if (spell.isDelve()) {
|
||||
manaCost = getCostAfterDelve(originalCost, originalCard);
|
||||
} else if (spell.getSourceCard().hasKeyword("Convoke")) {
|
||||
ManaCostBeingPaid convokeCost = getCostAfterConvoke(sa, originalCost, spell);
|
||||
if ( null != convokeCost )
|
||||
manaCost = convokeCost;
|
||||
}
|
||||
} // isSpell
|
||||
|
||||
List<Card> cardsOnBattlefield = Lists.newArrayList(game.getCardsIn(ZoneType.Battlefield));
|
||||
cardsOnBattlefield.addAll(game.getCardsIn(ZoneType.Stack));
|
||||
cardsOnBattlefield.addAll(game.getCardsIn(ZoneType.Command));
|
||||
if (!cardsOnBattlefield.contains(originalCard)) {
|
||||
cardsOnBattlefield.add(originalCard);
|
||||
}
|
||||
final ArrayList<StaticAbility> raiseAbilities = new ArrayList<StaticAbility>();
|
||||
final ArrayList<StaticAbility> reduceAbilities = new ArrayList<StaticAbility>();
|
||||
final ArrayList<StaticAbility> setAbilities = new ArrayList<StaticAbility>();
|
||||
|
||||
// Sort abilities to apply them in proper order
|
||||
for (Card c : cardsOnBattlefield) {
|
||||
final ArrayList<StaticAbility> staticAbilities = c.getStaticAbilities();
|
||||
for (final StaticAbility stAb : staticAbilities) {
|
||||
if (stAb.getMapParams().get("Mode").equals("RaiseCost")) {
|
||||
raiseAbilities.add(stAb);
|
||||
} else if (stAb.getMapParams().get("Mode").equals("ReduceCost")) {
|
||||
reduceAbilities.add(stAb);
|
||||
} else if (stAb.getMapParams().get("Mode").equals("SetCost")) {
|
||||
setAbilities.add(stAb);
|
||||
}
|
||||
}
|
||||
}
|
||||
// Raise cost
|
||||
for (final StaticAbility stAb : raiseAbilities) {
|
||||
manaCost = stAb.applyAbility("RaiseCost", spell, manaCost);
|
||||
}
|
||||
|
||||
// Reduce cost
|
||||
for (final StaticAbility stAb : reduceAbilities) {
|
||||
manaCost = stAb.applyAbility("ReduceCost", spell, manaCost);
|
||||
}
|
||||
|
||||
// Set cost (only used by Trinisphere) is applied last
|
||||
for (final StaticAbility stAb : setAbilities) {
|
||||
manaCost = stAb.applyAbility("SetCost", spell, manaCost);
|
||||
}
|
||||
|
||||
return manaCost;
|
||||
} // GetSpellCostChange
|
||||
|
||||
private ManaCostBeingPaid getCostAfterConvoke(final SpellAbility sa, final ManaCostBeingPaid originalCost, final SpellAbility spell) {
|
||||
|
||||
List<Card> untappedCreats = CardLists.filter(spell.getActivatingPlayer().getCardsIn(ZoneType.Battlefield), CardPredicates.Presets.CREATURES);
|
||||
untappedCreats = CardLists.filter(untappedCreats, CardPredicates.Presets.UNTAPPED);
|
||||
|
||||
if (!untappedCreats.isEmpty()) {
|
||||
final List<Card> choices = new ArrayList<Card>();
|
||||
choices.addAll(untappedCreats);
|
||||
ArrayList<String> usableColors = new ArrayList<String>();
|
||||
ManaCostBeingPaid newCost = new ManaCostBeingPaid(originalCost.toString());
|
||||
Card tapForConvoke = null;
|
||||
if (sa.getActivatingPlayer().isHuman()) {
|
||||
tapForConvoke = GuiChoose.oneOrNone("Tap for Convoke? " + newCost.toString(), choices);
|
||||
} else {
|
||||
// TODO: AI to choose a creature to tap would go here
|
||||
// Probably along with deciding how many creatures to
|
||||
// tap
|
||||
}
|
||||
while (tapForConvoke != null && !untappedCreats.isEmpty()) {
|
||||
final Card workingCard = (Card) tapForConvoke;
|
||||
usableColors = GameActionPlay.getConvokableColors(workingCard, newCost);
|
||||
|
||||
if (usableColors.size() != 0) {
|
||||
String chosenColor = usableColors.get(0);
|
||||
if (usableColors.size() > 1) {
|
||||
if (sa.getActivatingPlayer().isHuman()) {
|
||||
chosenColor = GuiChoose.one("Convoke for which color?", usableColors);
|
||||
} else {
|
||||
// TODO: AI for choosing which color to
|
||||
// convoke goes here.
|
||||
}
|
||||
}
|
||||
|
||||
if (chosenColor.equals("colorless")) {
|
||||
newCost.decreaseColorlessMana(1);
|
||||
} else {
|
||||
String newCostStr = newCost.toString();
|
||||
newCostStr = newCostStr.replaceFirst(
|
||||
MagicColor.toShortString(chosenColor), "").replaceFirst(" ", " ");
|
||||
newCost = new ManaCostBeingPaid(newCostStr.trim());
|
||||
}
|
||||
|
||||
sa.addTappedForConvoke(workingCard);
|
||||
choices.remove(workingCard);
|
||||
untappedCreats.remove(workingCard);
|
||||
if (choices.isEmpty() || (newCost.getConvertedManaCost() == 0)) {
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
untappedCreats.remove(workingCard);
|
||||
}
|
||||
|
||||
if (sa.getActivatingPlayer().isHuman()) {
|
||||
tapForConvoke = GuiChoose.oneOrNone("Tap for Convoke? " + newCost.toString(), choices);
|
||||
} else {
|
||||
// TODO: AI to choose a creature to tap would go
|
||||
// here
|
||||
}
|
||||
}
|
||||
|
||||
// will only be null if user cancelled.
|
||||
if (!sa.getTappedForConvoke().isEmpty()) {
|
||||
// Convoked creats are tapped here with triggers
|
||||
// suppressed,
|
||||
// Then again when payment is done(In
|
||||
// InputPayManaCost.done()) with suppression cleared.
|
||||
// This is to make sure that triggers go off at the
|
||||
// right time
|
||||
// AND that you can't use mana tapabilities of convoked
|
||||
// creatures
|
||||
// to pay the convoked cost.
|
||||
for (final Card c : sa.getTappedForConvoke()) {
|
||||
c.setTapped(true);
|
||||
}
|
||||
|
||||
return newCost;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private ManaCostBeingPaid getCostAfterDelve(final ManaCostBeingPaid originalCost, final Card originalCard) {
|
||||
ManaCostBeingPaid manaCost;
|
||||
final int cardsInGrave = originalCard.getController().getCardsIn(ZoneType.Graveyard).size();
|
||||
|
||||
final Player pc = originalCard.getController();
|
||||
if (pc.isHuman()) {
|
||||
final Integer[] cntChoice = new Integer[cardsInGrave + 1];
|
||||
for (int i = 0; i <= cardsInGrave; i++) {
|
||||
cntChoice[i] = Integer.valueOf(i);
|
||||
}
|
||||
|
||||
final Integer chosenAmount = GuiChoose.one("Exile how many cards?", cntChoice);
|
||||
System.out.println("Delve for " + chosenAmount);
|
||||
final List<Card> choices = new ArrayList<Card>(pc.getCardsIn(ZoneType.Graveyard));
|
||||
final List<Card> chosen = new ArrayList<Card>();
|
||||
for (int i = 0; i < chosenAmount; i++) {
|
||||
final Card nowChosen = GuiChoose.oneOrNone("Exile which card?", choices);
|
||||
|
||||
if (nowChosen == null) {
|
||||
// User canceled,abort delving.
|
||||
chosen.clear();
|
||||
break;
|
||||
}
|
||||
|
||||
choices.remove(nowChosen);
|
||||
chosen.add(nowChosen);
|
||||
}
|
||||
|
||||
for (final Card c : chosen) {
|
||||
game.getAction().exile(c);
|
||||
}
|
||||
|
||||
manaCost = new ManaCostBeingPaid(originalCost.toString());
|
||||
manaCost.decreaseColorlessMana(chosenAmount);
|
||||
} else {
|
||||
// AI
|
||||
int numToExile = 0;
|
||||
final int colorlessCost = originalCost.getColorlessManaAmount();
|
||||
|
||||
if (cardsInGrave <= colorlessCost) {
|
||||
numToExile = cardsInGrave;
|
||||
} else {
|
||||
numToExile = colorlessCost;
|
||||
}
|
||||
|
||||
for (int i = 0; i < numToExile; i++) {
|
||||
final List<Card> grave = pc.getZone(ZoneType.Graveyard).getCards();
|
||||
Card chosen = null;
|
||||
for (final Card c : grave) { // Exile noncreatures first
|
||||
// in
|
||||
// case we can revive. Might
|
||||
// wanna do some additional
|
||||
// checking here for Flashback
|
||||
// and the like.
|
||||
if (!c.isCreature()) {
|
||||
chosen = c;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (chosen == null) {
|
||||
chosen = ComputerUtilCard.getWorstCreatureAI(grave);
|
||||
}
|
||||
|
||||
if (chosen == null) {
|
||||
// Should never get here but... You know how it is.
|
||||
chosen = grave.get(0);
|
||||
}
|
||||
|
||||
game.getAction().exile(chosen);
|
||||
}
|
||||
manaCost = new ManaCostBeingPaid(originalCost.toString());
|
||||
manaCost.decreaseColorlessMana(numToExile);
|
||||
}
|
||||
return manaCost;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the convokable colors.
|
||||
*
|
||||
* @param cardToConvoke
|
||||
* the card to convoke
|
||||
* @param cost
|
||||
* the cost
|
||||
* @return the convokable colors
|
||||
*/
|
||||
public static ArrayList<String> getConvokableColors(final Card cardToConvoke, final ManaCostBeingPaid cost) {
|
||||
final ArrayList<String> usableColors = new ArrayList<String>();
|
||||
|
||||
if (cost.getColorlessManaAmount() > 0) {
|
||||
usableColors.add("colorless");
|
||||
}
|
||||
for (final CardColor col : cardToConvoke.getColor()) {
|
||||
for (final String strCol : col.toStringList()) {
|
||||
if (strCol.equals("colorless")) {
|
||||
continue;
|
||||
}
|
||||
if (cost.toString().contains(MagicColor.toShortString(strCol))) {
|
||||
usableColors.add(strCol.toString());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return usableColors;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -864,5 +864,35 @@ public class AiController {
|
||||
} while ( sa != null );
|
||||
}
|
||||
|
||||
public List<Card> chooseCardsToDelve(int colorlessCost, List<Card> grave) {
|
||||
List<Card> toExile = new ArrayList<Card>();
|
||||
int numToExile = Math.min(grave.size(), colorlessCost);
|
||||
|
||||
for (int i = 0; i < numToExile; i++) {
|
||||
Card chosen = null;
|
||||
for (final Card c : grave) { // Exile noncreatures first in
|
||||
// case we can revive. Might
|
||||
// wanna do some additional
|
||||
// checking here for Flashback
|
||||
// and the like.
|
||||
if (!c.isCreature()) {
|
||||
chosen = c;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (chosen == null) {
|
||||
chosen = ComputerUtilCard.getWorstCreatureAI(grave);
|
||||
}
|
||||
|
||||
if (chosen == null) {
|
||||
// Should never get here but... You know how it is.
|
||||
chosen = grave.get(0);
|
||||
}
|
||||
|
||||
toExile.add(chosen);
|
||||
grave.remove(chosen);
|
||||
}
|
||||
return toExile;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -13,7 +13,6 @@ import forge.Card;
|
||||
import forge.CardLists;
|
||||
import forge.CardUtil;
|
||||
import forge.Constant;
|
||||
import forge.Singletons;
|
||||
import forge.card.MagicColor;
|
||||
import forge.card.ability.AbilityUtils;
|
||||
import forge.card.ability.ApiType;
|
||||
@@ -398,8 +397,7 @@ public class ComputerUtilMana {
|
||||
final ManaCost mana = sa.getPayCosts() != null ? sa.getPayCosts().getTotalMana() : sa.getManaCost();
|
||||
|
||||
ManaCostBeingPaid cost = new ManaCostBeingPaid(mana);
|
||||
|
||||
cost = Singletons.getModel().getGame().getActionPlay().getSpellCostChange(sa, cost);
|
||||
cost.applySpellCostChange(sa);
|
||||
|
||||
final Card card = sa.getSourceCard();
|
||||
// Tack xMana Payments into mana here if X is a set value
|
||||
|
||||
@@ -144,7 +144,8 @@ public class HumanPlayer extends Player {
|
||||
if (sa.getSourceCard().isCopiedSpell() && sa.isSpell()) {
|
||||
manaCost = new ManaCostBeingPaid("0");
|
||||
} else {
|
||||
manaCost = game.getActionPlay().getSpellCostChange(sa, new ManaCostBeingPaid(sa.getManaCost()));
|
||||
manaCost = new ManaCostBeingPaid(sa.getManaCost());
|
||||
manaCost.applySpellCostChange(sa);
|
||||
}
|
||||
|
||||
if (!manaCost.isPaid()) {
|
||||
@@ -193,7 +194,8 @@ public class HumanPlayer extends Player {
|
||||
if (sa.getSourceCard().isCopiedSpell() && sa.isSpell()) {
|
||||
manaCost = new ManaCostBeingPaid("0");
|
||||
} else {
|
||||
manaCost = game.getActionPlay().getSpellCostChange(sa, new ManaCostBeingPaid(sa.getManaCost()));
|
||||
manaCost = new ManaCostBeingPaid(sa.getManaCost());
|
||||
manaCost.applySpellCostChange(sa);
|
||||
}
|
||||
|
||||
if( !manaCost.isPaid() ) {
|
||||
|
||||
@@ -118,4 +118,5 @@ public abstract class PlayerController {
|
||||
|
||||
public abstract void playMiracle(SpellAbility miracle, Card card);
|
||||
public abstract void playMadness(SpellAbility madness);
|
||||
public abstract List<Card> chooseCardsToDelve(int colorLessAmount, List<Card> grave);
|
||||
}
|
||||
|
||||
@@ -244,4 +244,12 @@ public class PlayerControllerAi extends PlayerController {
|
||||
getAi().chooseAndPlaySa(false, false, madness);
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see forge.game.player.PlayerController#chooseCardsToDelve(int, java.util.List)
|
||||
*/
|
||||
@Override
|
||||
public List<Card> chooseCardsToDelve(int colorlessCost, List<Card> grave) {
|
||||
return getAi().chooseCardsToDelve(colorlessCost, grave);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -374,4 +374,31 @@ public class PlayerControllerHuman extends PlayerController {
|
||||
player.playSpellAbility(madness);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Card> chooseCardsToDelve(int colorLessAmount, List<Card> grave) {
|
||||
List<Card> toExile = new ArrayList<Card>();
|
||||
int cardsInGrave = grave.size();
|
||||
final Integer[] cntChoice = new Integer[cardsInGrave + 1];
|
||||
for (int i = 0; i <= cardsInGrave; i++) {
|
||||
cntChoice[i] = Integer.valueOf(i);
|
||||
}
|
||||
|
||||
final Integer chosenAmount = GuiChoose.one("Exile how many cards?", cntChoice);
|
||||
System.out.println("Delve for " + chosenAmount);
|
||||
|
||||
for (int i = 0; i < chosenAmount; i++) {
|
||||
final Card nowChosen = GuiChoose.oneOrNone("Exile which card?", grave);
|
||||
|
||||
if (nowChosen == null) {
|
||||
// User canceled,abort delving.
|
||||
toExile.clear();
|
||||
break;
|
||||
}
|
||||
|
||||
grave.remove(nowChosen);
|
||||
toExile.add(nowChosen);
|
||||
}
|
||||
return toExile;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user