Issue 92: Reorganization of Costs

- Fix a few cards to adhere to new Cost requirements
This commit is contained in:
Sol
2011-08-22 02:19:10 +00:00
parent 1df5c1aa55
commit c0e68b19d2
66 changed files with 3234 additions and 3804 deletions

19
.gitattributes vendored
View File

@@ -9584,6 +9584,23 @@ src/main/java/forge/card/cardFactory/CardFactory_Sorceries.java svneol=native#te
src/main/java/forge/card/cardFactory/LazyCardFactory.java svneol=native#text/plain src/main/java/forge/card/cardFactory/LazyCardFactory.java svneol=native#text/plain
src/main/java/forge/card/cardFactory/PreloadingCardFactory.java svneol=native#text/plain src/main/java/forge/card/cardFactory/PreloadingCardFactory.java svneol=native#text/plain
src/main/java/forge/card/cardFactory/package-info.java svneol=native#text/plain src/main/java/forge/card/cardFactory/package-info.java svneol=native#text/plain
src/main/java/forge/card/cost/Cost.java svneol=native#text/plain
src/main/java/forge/card/cost/CostDiscard.java -text
src/main/java/forge/card/cost/CostExile.java -text
src/main/java/forge/card/cost/CostMana.java -text
src/main/java/forge/card/cost/CostPart.java -text
src/main/java/forge/card/cost/CostPartWithList.java -text
src/main/java/forge/card/cost/CostPayLife.java -text
src/main/java/forge/card/cost/CostPutCounter.java -text
src/main/java/forge/card/cost/CostRemoveCounter.java -text
src/main/java/forge/card/cost/CostReturn.java -text
src/main/java/forge/card/cost/CostSacrifice.java -text
src/main/java/forge/card/cost/CostTap.java -text
src/main/java/forge/card/cost/CostTapType.java -text
src/main/java/forge/card/cost/CostUntap.java -text
src/main/java/forge/card/cost/CostUtil.java -text
src/main/java/forge/card/cost/Cost_Input.java -text
src/main/java/forge/card/cost/Cost_Payment.java svneol=native#text/plain
src/main/java/forge/card/mana/Mana.java svneol=native#text/plain src/main/java/forge/card/mana/Mana.java svneol=native#text/plain
src/main/java/forge/card/mana/ManaCost.java svneol=native#text/plain src/main/java/forge/card/mana/ManaCost.java svneol=native#text/plain
src/main/java/forge/card/mana/ManaPool.java svneol=native#text/plain src/main/java/forge/card/mana/ManaPool.java svneol=native#text/plain
@@ -9601,8 +9618,6 @@ src/main/java/forge/card/spellability/Ability_Mana.java svneol=native#text/plain
src/main/java/forge/card/spellability/Ability_Static.java svneol=native#text/plain src/main/java/forge/card/spellability/Ability_Static.java svneol=native#text/plain
src/main/java/forge/card/spellability/Ability_Sub.java svneol=native#text/plain src/main/java/forge/card/spellability/Ability_Sub.java svneol=native#text/plain
src/main/java/forge/card/spellability/Ability_Triggered.java svneol=native#text/plain src/main/java/forge/card/spellability/Ability_Triggered.java svneol=native#text/plain
src/main/java/forge/card/spellability/Cost.java svneol=native#text/plain
src/main/java/forge/card/spellability/Cost_Payment.java svneol=native#text/plain
src/main/java/forge/card/spellability/Spell.java svneol=native#text/plain src/main/java/forge/card/spellability/Spell.java svneol=native#text/plain
src/main/java/forge/card/spellability/SpellAbility.java svneol=native#text/plain src/main/java/forge/card/spellability/SpellAbility.java svneol=native#text/plain
src/main/java/forge/card/spellability/SpellAbilityList.java svneol=native#text/plain src/main/java/forge/card/spellability/SpellAbilityList.java svneol=native#text/plain

View File

@@ -4,8 +4,9 @@ Types:Artifact Creature Angel
Text:no text Text:no text
PT:2/2 PT:2/2
K:Flying K:Flying
A:AB$PutCounter | Cost$ T Sac<X/Land> | Defined$ Self | CounterType$ P1P1 | CounterNum$ X | SpellDescription$ Put X +1/+1 counters on CARDNAME. A:AB$PutCounter | Cost$ T Sac<X/Land> | Defined$ Self | CounterType$ P1P1 | CounterNum$ ChosenX | SpellDescription$ Put X +1/+1 counters on CARDNAME.
SVar:X:Sacrificed$Amount SVar:X:XChoice
#ChosenX SVar created by Cost payment
SVar:RemAIDeck:True SVar:RemAIDeck:True
SVar:Rarity:Rare SVar:Rarity:Rare
SVar:Picture:http://www.wizards.com/global/images/magic/general/copper_leaf_angel.jpg SVar:Picture:http://www.wizards.com/global/images/magic/general/copper_leaf_angel.jpg

View File

@@ -2,8 +2,9 @@ Name:Devastating Summons
ManaCost:R ManaCost:R
Types:Sorcery Types:Sorcery
Text:no text Text:no text
A:SP$ Token | Cost$ R Sac<X/Land> | TokenAmount$ 2 | TokenName$ Elemental | TokenTypes$ Creature,Elemental | TokenOwner$ You | TokenColors$ Red | TokenPower$ X | TokenToughness$ X | SpellDescription$ Put two X/X red Elemental creature tokens onto the battlefield. A:SP$ Token | Cost$ R Sac<X/Land> | TokenAmount$ 2 | TokenName$ Elemental | TokenTypes$ Creature,Elemental | TokenOwner$ You | TokenColors$ Red | TokenPower$ ChosenX | TokenToughness$ ChosenX | SpellDescription$ Put two X/X red Elemental creature tokens onto the battlefield.
SVar:X:Sacrificed$Amount SVar:X:XChoice
#ChosenX SVar created by Cost payment
SVar:RemAIDeck:True SVar:RemAIDeck:True
SVar:Rarity:Rare SVar:Rarity:Rare
SVar:Picture:http://www.wizards.com/global/images/magic/general/devastating_summons.jpg SVar:Picture:http://www.wizards.com/global/images/magic/general/devastating_summons.jpg

View File

@@ -3,9 +3,11 @@ ManaCost:X R R
Types:Sorcery Types:Sorcery
Text:no text Text:no text
A:SP$ Token | Cost$ X R R | TokenAmount$ X | TokenName$ Elemental Cat | TokenTypes$ Creature,Elemental,Cat | TokenOwner$ You | TokenColors$ Red | TokenPower$ 1 | TokenToughness$ 1 | TokenKeywords$ Haste<>At the beginning of the end step, exile CARDNAME. | SpellDescription$ Put X 1/1 red Elemental Cat creature tokens with haste onto the battlefield. Exile them at the beginning of the next end step. A:SP$ Token | Cost$ X R R | TokenAmount$ X | TokenName$ Elemental Cat | TokenTypes$ Creature,Elemental,Cat | TokenOwner$ You | TokenColors$ Red | TokenPower$ 1 | TokenToughness$ 1 | TokenKeywords$ Haste<>At the beginning of the end step, exile CARDNAME. | SpellDescription$ Put X 1/1 red Elemental Cat creature tokens with haste onto the battlefield. Exile them at the beginning of the next end step.
A:SP$ Token | Cost$ R R Sac<X/Mountain> | TokenAmount$ Y | TokenName$ Elemental Cat | TokenTypes$ Creature,Elemental,Cat | TokenOwner$ You | TokenColors$ Red | TokenPower$ 1 | TokenToughness$ 1 | TokenKeywords$ Haste<>At the beginning of the end step, exile CARDNAME. | Flashback$ True | CostDesc$ Flashback - R R, Sacrifice X Mountains. | SpellDescription$ (You may cast this card from your graveyard for its flashback cost. Then exile it.) A:SP$ Token | Cost$ R R Sac<Y/Mountain> | TokenAmount$ ChosenX | TokenName$ Elemental Cat | TokenTypes$ Creature,Elemental,Cat | TokenOwner$ You | TokenColors$ Red | TokenPower$ 1 | TokenToughness$ 1 | TokenKeywords$ Haste<>At the beginning of the end step, exile CARDNAME. | Flashback$ True | CostDesc$ Flashback - R R, Sacrifice X Mountains. | SpellDescription$ (You may cast this card from your graveyard for its flashback cost. Then exile it.)
SVar:X:Count$xPaid SVar:X:Count$xPaid
SVar:Y:Sacrificed$Amount SVar:Y:XChoice
#Flashback uses Y because SVars can't overlap
#ChosenX SVar created by Cost payment
SVar:RemAIDeck:True SVar:RemAIDeck:True
SVar:Rarity:Uncommon SVar:Rarity:Uncommon
SVar:Picture:http://www.wizards.com/global/images/magic/general/firecat_blitz.jpg SVar:Picture:http://www.wizards.com/global/images/magic/general/firecat_blitz.jpg

View File

@@ -175,6 +175,8 @@ public class Card extends MyObservable implements Comparable<Card> {
private Map<Counters, Integer> counters = new TreeMap<Counters, Integer>(); private Map<Counters, Integer> counters = new TreeMap<Counters, Integer>();
private Map<String, String> SVars = new TreeMap<String, String>(); private Map<String, String> SVars = new TreeMap<String, String>();
private static String[] storableSVars = { "ChosenX" };
public static String[] getStorableSVars() { return storableSVars; }
//hacky code below, used to limit the number of times an ability //hacky code below, used to limit the number of times an ability
//can be used per turn like Vampire Bats //can be used per turn like Vampire Bats

View File

@@ -451,4 +451,17 @@ public class CardListUtil {
return cmc; return cmc;
}//sumCMC }//sumCMC
public static CardList getRandomSubList(CardList c, int amount){
if (c.size() < amount)
return null;
CardList subList = new CardList();
while(subList.size() < amount){
c.shuffle();
subList.add(c.get(0));
c.remove(0);
}
return subList;
}
} }

View File

@@ -2,6 +2,9 @@ package forge;
import forge.card.abilityFactory.AbilityFactory; import forge.card.abilityFactory.AbilityFactory;
import forge.card.cardFactory.CardFactoryUtil; import forge.card.cardFactory.CardFactoryUtil;
import forge.card.cost.Cost;
import forge.card.cost.CostUtil;
import forge.card.cost.Cost_Payment;
import forge.card.mana.ManaCost; import forge.card.mana.ManaCost;
import forge.card.mana.ManaPool; import forge.card.mana.ManaPool;
import forge.card.spellability.*; import forge.card.spellability.*;
@@ -128,7 +131,7 @@ public class ComputerUtil {
//String totalMana = source.getSVar("PayX"); // + cost.getCMC() //String totalMana = source.getSVar("PayX"); // + cost.getCMC()
// Consider the costs here for relative "scoring" // Consider the costs here for relative "scoring"
if (cost.getDiscardType().equals("Hand")) { if (CostUtil.hasDiscardHandCost(cost)) {
// Null Brooch aid // Null Brooch aid
restrict -= (AllZoneUtil.getPlayerHand(AllZone.getComputerPlayer()).size() * 20); restrict -= (AllZoneUtil.getPlayerHand(AllZone.getComputerPlayer()).size() * 20);
} }
@@ -418,160 +421,11 @@ public class ComputerUtil {
* @return a boolean. * @return a boolean.
*/ */
static public boolean canPayAdditionalCosts(SpellAbility sa, Player player) { static public boolean canPayAdditionalCosts(SpellAbility sa, Player player) {
// Add additional cost checks here before attempting to activate abilities if (sa.getActivatingPlayer() == null){
Cost cost = sa.getPayCosts(); System.out.println(sa.getSourceCard() + " in ComputerUtil.canPayAdditionalCosts() without an activating player");
if (cost == null) sa.setActivatingPlayer(player);
return true;
Card card = sa.getSourceCard();
if (cost.getTap() && (card.isTapped() || card.isSick()))
return false;
if (cost.getUntap() && (card.isUntapped() || card.isSick()))
return false;
if (cost.getTapXTypeCost()) {
CardList typeList = AllZoneUtil.getPlayerCardsInPlay(player);
typeList = typeList.getValidCards(cost.getTapXType().split(","), sa.getActivatingPlayer(), sa.getSourceCard());
if (cost.getTap())
typeList.remove(sa.getSourceCard());
typeList = typeList.filter(AllZoneUtil.untapped);
if (cost.getTapXTypeAmount() > typeList.size())
return false;
} }
return Cost_Payment.canPayAdditionalCosts(sa.getPayCosts(), sa);
if (cost.getSubCounter()) {
Counters c = cost.getCounterType();
if (card.getCounters(c) - cost.getCounterNum() < 0 || !AllZoneUtil.isCardInPlay(card)) {
return false;
}
}
if (cost.getAddCounter()) {
// this should always be true
}
if (cost.getLifeCost()) {
if (player.getLife() <= cost.getLifeAmount())
return false;
}
if (cost.getDiscardCost()) {
CardList handList = AllZoneUtil.getPlayerHand(player);
String discType = cost.getDiscardType();
int discAmount = cost.getDiscardAmount();
if (cost.getDiscardThis()) {
if (!AllZone.getZone(card).getZoneName().equals(Constant.Zone.Hand))
return false;
} else if (discType.equals("LastDrawn")) {
//compy can't yet use this effectively
return false;
} else if (discType.equals("Hand")) {
// this will always work
} else {
if (!discType.equals("Any") && !discType.equals("Random")) {
String validType[] = discType.split(",");
handList = handList.getValidCards(validType, sa.getActivatingPlayer(), sa.getSourceCard());
}
if (discAmount > handList.size()) {
// not enough cards in hand to pay
return false;
}
}
}
if (cost.getSacCost()) {
// if there's a sacrifice in the cost, just because we can Pay it doesn't mean we want to.
if (!cost.getSacThis()) {
CardList typeList = AllZoneUtil.getPlayerCardsInPlay(player);
typeList = typeList.getValidCards(cost.getSacType().split(","), sa.getActivatingPlayer(), sa.getSourceCard());
Card target = sa.getTargetCard();
if (target != null && target.getController().isPlayer(player)) // don't sacrifice the card we're pumping
typeList.remove(target);
if (cost.getSacAmount() > typeList.size())
return false;
} else if (cost.getSacThis() && !AllZoneUtil.isCardInPlay(card))
return false;
}
if (cost.getExileCost()) {
// if there's an exile in the cost, just because we can Pay it doesn't mean we want to.
if (!cost.getExileThis()) {
CardList typeList = AllZoneUtil.getPlayerCardsInPlay(player);
typeList = typeList.getValidCards(cost.getExileType().split(","), sa.getActivatingPlayer(), sa.getSourceCard());
Card target = sa.getTargetCard();
if (target != null && target.getController().isPlayer(player)) // don't exile the card we're pumping
typeList.remove(target);
if (cost.getExileAmount() > typeList.size())
return false;
} else if (cost.getExileThis() && !AllZoneUtil.isCardInPlay(card))
return false;
}
if (cost.getExileFromHandCost()) {
// if there's an exile in the cost, just because we can Pay it doesn't mean we want to.
if (!cost.getExileFromHandThis()) {
CardList typeList = AllZoneUtil.getPlayerHand(player);
typeList = typeList.getValidCards(cost.getExileFromHandType().split(","), sa.getActivatingPlayer(), sa.getSourceCard());
Card target = sa.getTargetCard();
if (target != null && target.getController().isPlayer(player)) // don't exile the card we're pumping
typeList.remove(target);
if (cost.getExileFromHandAmount() > typeList.size())
return false;
} else if (cost.getExileFromHandThis() && !AllZoneUtil.isCardInPlayerHand(player, card))
return false;
}
if (cost.getExileFromGraveCost()) {
if (!cost.getExileFromGraveThis()) {
CardList typeList = AllZoneUtil.getPlayerGraveyard(player);
typeList = typeList.getValidCards(cost.getExileFromGraveType().split(","), sa.getActivatingPlayer(), sa.getSourceCard());
Card target = sa.getTargetCard();
if (target != null && target.getController().isPlayer(player)) // don't exile the card we're pumping
typeList.remove(target);
if (cost.getExileFromGraveAmount() > typeList.size())
return false;
} else if (cost.getExileFromGraveThis() && !AllZoneUtil.isCardInPlayerGraveyard(player, card))
return false;
}
if (cost.getExileFromTopCost()) {
if (!cost.getExileFromTopThis()) {
CardList typeList = AllZoneUtil.getPlayerCardsInLibrary(player);
typeList = typeList.getValidCards(cost.getExileFromTopType().split(","), sa.getActivatingPlayer(), sa.getSourceCard());
Card target = sa.getTargetCard();
if (target != null && target.getController().isPlayer(player)) // don't exile the card we're pumping
typeList.remove(target);
if (cost.getExileFromTopAmount() > typeList.size())
return false;
} else if (cost.getExileFromTopThis() && !AllZoneUtil.isCardInPlayerLibrary(player, card))
return false;
}
if (cost.getReturnCost()) {
// if there's a return in the cost, just because we can Pay it doesn't mean we want to.
if (!cost.getReturnThis()) {
CardList typeList = AllZoneUtil.getPlayerCardsInPlay(player);
typeList = typeList.getValidCards(cost.getReturnType().split(","), sa.getActivatingPlayer(), sa.getSourceCard());
Card target = sa.getTargetCard();
if (target != null && target.getController().isPlayer(player)) // don't bounce the card we're pumping
typeList.remove(target);
if (cost.getReturnAmount() > typeList.size())
return false;
} else if (!AllZoneUtil.isCardInPlay(card))
return false;
}
return true;
} }
/** /**
@@ -651,7 +505,7 @@ public class ComputerUtil {
for (Ability_Mana m : manaAbilities) { for (Ability_Mana m : manaAbilities) {
if (used) break; //mana source already used in the test if (used) break; //mana source already used in the test
m.setActivatingPlayer(player);
//if the AI can't pay the additional costs skip the mana ability //if the AI can't pay the additional costs skip the mana ability
if (m.getPayCosts() != null) { if (m.getPayCosts() != null) {
if (!canPayAdditionalCosts(m, player)) if (!canPayAdditionalCosts(m, player))
@@ -799,15 +653,14 @@ public class ComputerUtil {
for (Ability_Mana m : manaAbilities) { for (Ability_Mana m : manaAbilities) {
Cost cost = m.getPayCosts(); Cost cost = m.getPayCosts();
needsLimitedResources |= !cost.isReusuableResource();
//if the AI can't pay the additional costs skip the mana ability //if the AI can't pay the additional costs skip the mana ability
m.setActivatingPlayer(AllZone.getComputerPlayer());
if (cost != null) { if (cost != null) {
if (!canPayAdditionalCosts(m, player)) if (!canPayAdditionalCosts(m, player))
continue; continue;
if (cost.getSubCounter() || cost.getLifeCost()) }
needsLimitedResources = true;
} else if (card.isTapped())
continue;
//don't use abilities with dangerous drawbacks //don't use abilities with dangerous drawbacks
if (m.getSubAbility() != null) { if (m.getSubAbility() != null) {
@@ -837,15 +690,12 @@ public class ComputerUtil {
for (Ability_Mana m : manaAbilities) { for (Ability_Mana m : manaAbilities) {
Cost cost = m.getPayCosts(); Cost cost = m.getPayCosts();
needsLimitedResources |= !cost.isReusuableResource();
//if the AI can't pay the additional costs skip the mana ability //if the AI can't pay the additional costs skip the mana ability
if (cost != null) { if (cost != null) {
if (!canPayAdditionalCosts(m, player)) if (!canPayAdditionalCosts(m, player))
continue; continue;
if (cost.getSubCounter() || cost.getLifeCost()) }
needsLimitedResources = true;
} else if (card.isTapped())
continue;
//don't use abilities with dangerous drawbacks //don't use abilities with dangerous drawbacks
if (m.getSubAbility() != null) { if (m.getSubAbility() != null) {
@@ -1035,7 +885,7 @@ public class ComputerUtil {
if (target != null && target.getController().isComputer() && typeList.contains(target)) if (target != null && target.getController().isComputer() && typeList.contains(target))
typeList.remove(target); // don't sacrifice the card we're pumping typeList.remove(target); // don't sacrifice the card we're pumping
if (typeList.size() == 0) if (typeList.size() < amount)
return null; return null;
CardList sacList = new CardList(); CardList sacList = new CardList();
@@ -1112,7 +962,7 @@ public class ComputerUtil {
if (target != null && target.getController().isComputer() && typeList.contains(target)) if (target != null && target.getController().isComputer() && typeList.contains(target))
typeList.remove(target); // don't exile the card we're pumping typeList.remove(target); // don't exile the card we're pumping
if (typeList.size() == 0) if (typeList.size() < amount)
return null; return null;
CardListUtil.sortAttackLowFirst(typeList); CardListUtil.sortAttackLowFirst(typeList);
@@ -1141,7 +991,7 @@ public class ComputerUtil {
if (tap) if (tap)
typeList.remove(activate); typeList.remove(activate);
if (typeList.size() == 0 || amount >= typeList.size()) if (typeList.size() < amount)
return null; return null;
CardListUtil.sortAttackLowFirst(typeList); CardListUtil.sortAttackLowFirst(typeList);
@@ -1167,7 +1017,7 @@ public class ComputerUtil {
if (target != null && target.getController().isComputer() && typeList.contains(target)) // don't bounce the card we're pumping if (target != null && target.getController().isComputer() && typeList.contains(target)) // don't bounce the card we're pumping
typeList.remove(target); typeList.remove(target);
if (typeList.size() == 0) if (typeList.size() < amount)
return null; return null;
CardListUtil.sortAttackLowFirst(typeList); CardListUtil.sortAttackLowFirst(typeList);

View File

@@ -5,6 +5,8 @@ import forge.card.abilityFactory.AbilityFactory;
import forge.card.abilityFactory.AbilityFactory_Attach; import forge.card.abilityFactory.AbilityFactory_Attach;
import forge.card.cardFactory.CardFactoryInterface; import forge.card.cardFactory.CardFactoryInterface;
import forge.card.cardFactory.CardFactoryUtil; import forge.card.cardFactory.CardFactoryUtil;
import forge.card.cost.Cost;
import forge.card.cost.Cost_Payment;
import forge.card.mana.ManaCost; import forge.card.mana.ManaCost;
import forge.card.mana.ManaPool; import forge.card.mana.ManaPool;
import forge.card.spellability.*; import forge.card.spellability.*;
@@ -475,26 +477,30 @@ public class GameAction {
return moveToStack(c); return moveToStack(c);
} }
/** /**
* <p>AI_discardNumType.</p> * <p>AI_discardNumType.</p>
* *
* @param numDiscard a int. * @param numDiscard a int.
* @param uTypes an array of {@link java.lang.String} objects. * @param uTypes an array of {@link java.lang.String} objects.
* @param sa a {@link forge.card.spellability.SpellAbility} object. * @param sa a {@link forge.card.spellability.SpellAbility} object.
* @return a boolean. * @return a CardList of discarded cards.
*/ */
public boolean AI_discardNumType(int numDiscard, String[] uTypes, SpellAbility sa) { public CardList AI_discardNumType(int numDiscard, String[] uTypes, SpellAbility sa) {
CardList hand = AllZoneUtil.getPlayerHand(AllZone.getComputerPlayer()); CardList hand = AllZoneUtil.getPlayerHand(AllZone.getComputerPlayer());
CardList tHand = hand.getValidCards(uTypes, sa.getActivatingPlayer(), sa.getSourceCard()); hand = hand.getValidCards(uTypes, sa.getActivatingPlayer(), sa.getSourceCard());
if (tHand.size() >= numDiscard) { if (hand.size() < numDiscard)
CardListUtil.sortCMC(tHand); return null;
tHand.reverse();
CardList discard = new CardList();
CardListUtil.sortCMC(hand);
hand.reverse();
for (int i = 0; i < numDiscard; i++) for (int i = 0; i < numDiscard; i++)
tHand.get(i).getController().discard(tHand.get(i), sa); discard.add(hand.get(i));
return true;
} return discard;
return false;
} }
/** /**

View File

@@ -3,6 +3,7 @@ package forge;
import forge.card.abilityFactory.AbilityFactory; import forge.card.abilityFactory.AbilityFactory;
import forge.card.cardFactory.CardFactoryUtil; import forge.card.cardFactory.CardFactoryUtil;
import forge.card.cost.Cost;
import forge.card.spellability.*; import forge.card.spellability.*;
import forge.game.GameLossReason; import forge.game.GameLossReason;
import forge.gui.GuiUtils; import forge.gui.GuiUtils;

View File

@@ -2,6 +2,7 @@ package forge.card.abilityFactory;
import forge.*; import forge.*;
import forge.card.cardFactory.CardFactoryUtil; import forge.card.cardFactory.CardFactoryUtil;
import forge.card.cost.Cost;
import forge.card.spellability.*; import forge.card.spellability.*;
import java.util.ArrayList; import java.util.ArrayList;
@@ -73,7 +74,7 @@ public class AbilityFactory {
/** /**
* <p>Getter for the field <code>abCost</code>.</p> * <p>Getter for the field <code>abCost</code>.</p>
* *
* @return a {@link forge.card.spellability.Cost} object. * @return a {@link forge.card.cost.Cost} object.
*/ */
public Cost getAbCost() { public Cost getAbCost() {
return abCost; return abCost;

View File

@@ -1,6 +1,8 @@
package forge.card.abilityFactory; package forge.card.abilityFactory;
import forge.*; import forge.*;
import forge.card.cost.Cost;
import forge.card.cost.CostUtil;
import forge.card.spellability.*; import forge.card.spellability.*;
import java.util.ArrayList; import java.util.ArrayList;
@@ -201,32 +203,19 @@ public class AbilityFactory_AlterLife {
if (lifeAmount <= 0) return false; if (lifeAmount <= 0) return false;
if (abCost != null) { if (abCost != null) {
if (abCost.getSacCost() && life > 4) { if (life > 5){
if (abCost.getSacThis() && life > 6) if (!CostUtil.checkSacrificeCost(abCost, source))
return false; return false;
else {
//only sacrifice something that's supposed to be sacrificed
String type = abCost.getSacType();
CardList typeList = AllZoneUtil.getPlayerCardsInPlay(AllZone.getComputerPlayer());
typeList = typeList.getValidCards(type.split(","), source.getController(), source);
if (ComputerUtil.getCardPreference(source, "SacCost", typeList) == null)
return false;
}
}
if (abCost.getLifeCost() && life > 5) return false;
if (abCost.getDiscardCost() && life > 5) return false;
if (abCost.getSubCounter()) { if (!CostUtil.checkLifeCost(abCost, source, 4))
//non +1/+1 counters should be used return false;
if (abCost.getCounterType().equals(Counters.P1P1)) {
// A card has a 25% chance per counter to be able to pass through here if (!CostUtil.checkDiscardCost(abCost, source))
// 4+ counters will always pass. 0 counters will never return false;
int currentNum = source.getCounters(abCost.getCounterType());
double percent = .25 * (currentNum / abCost.getCounterNum());
if (percent <= r.nextFloat())
return false;
}
} }
if (!CostUtil.checkRemoveCounterCost(abCost, source))
return false;
} }
if (!AllZone.getComputerPlayer().canGainLife()) if (!AllZone.getComputerPlayer().canGainLife())
@@ -507,8 +496,6 @@ public class AbilityFactory_AlterLife {
Cost abCost = sa.getPayCosts(); Cost abCost = sa.getPayCosts();
final Card source = sa.getSourceCard(); final Card source = sa.getSourceCard();
HashMap<String, String> params = af.getMapParams(); HashMap<String, String> params = af.getMapParams();
int humanLife = AllZone.getHumanPlayer().getLife();
int aiLife = AllZone.getComputerPlayer().getLife();
String amountStr = params.get("LifeAmount"); String amountStr = params.get("LifeAmount");
@@ -517,29 +504,17 @@ public class AbilityFactory_AlterLife {
if (abCost != null) { if (abCost != null) {
// AI currently disabled for these costs // AI currently disabled for these costs
if (abCost.getSacCost()) { if (!CostUtil.checkLifeCost(abCost, source, amount))
if (amountStr.contains("X")) return false;
return false;
if (!abCost.getSacThis()) {
//only sacrifice something that's supposed to be sacrificed
String type = abCost.getSacType();
CardList typeList = AllZoneUtil.getPlayerCardsInPlay(AllZone.getComputerPlayer());
typeList = typeList.getValidCards(type.split(","), source.getController(), source);
if (ComputerUtil.getCardPreference(source, "SacCost", typeList) == null)
return false;
}
}
if (abCost.getLifeCost() && aiLife - abCost.getLifeAmount() < humanLife - amount) return false;
if (abCost.getDiscardCost()) return false;
if (abCost.getSubCounter()) { if (!CostUtil.checkDiscardCost(abCost, source))
// A card has a 25% chance per counter to be able to pass through here return false;
// 4+ counters will always pass. 0 counters will never
int currentNum = source.getCounters(abCost.getCounterType()); if (!CostUtil.checkSacrificeCost(abCost, source))
double percent = .25 * (currentNum / abCost.getCounterNum()); return false;
if (percent <= r.nextFloat())
return false; if (!CostUtil.checkRemoveCounterCost(abCost, source))
} return false;
} }
if (!AllZone.getHumanPlayer().canLoseLife()) if (!AllZone.getHumanPlayer().canLoseLife())
@@ -892,27 +867,17 @@ public class AbilityFactory_AlterLife {
//int humanPoison = AllZone.getHumanPlayer().getPoisonCounters(); //int humanPoison = AllZone.getHumanPlayer().getPoisonCounters();
//int humanLife = AllZone.getHumanPlayer().getLife(); //int humanLife = AllZone.getHumanPlayer().getLife();
//int aiPoison = AllZone.getComputerPlayer().getPoisonCounters(); //int aiPoison = AllZone.getComputerPlayer().getPoisonCounters();
int aiLife = AllZone.getComputerPlayer().getLife();
String amountStr = params.get("Num");
// TODO handle proper calculation of X values based on Cost and what would be paid // TODO handle proper calculation of X values based on Cost and what would be paid
//final int amount = AbilityFactory.calculateAmount(af.getHostCard(), amountStr, sa); //final int amount = AbilityFactory.calculateAmount(af.getHostCard(), amountStr, sa);
if (abCost != null) { if (abCost != null) {
// AI currently disabled for these costs // AI currently disabled for these costs
if (abCost.getSacCost()) { if (!CostUtil.checkLifeCost(abCost, source, 1))
if (amountStr.contains("X")) return false;
return false;
if (!abCost.getSacThis()) { if (!CostUtil.checkSacrificeCost(abCost, source))
//only sacrifice something that's supposed to be sacrificed return false;
String type = abCost.getSacType();
CardList typeList = AllZoneUtil.getPlayerCardsInPlay(AllZone.getComputerPlayer());
typeList = typeList.getValidCards(type.split(","), source.getController(), source);
if (ComputerUtil.getCardPreference(source, "SacCost", typeList) == null)
return false;
}
}
if (abCost.getLifeCost() && aiLife - abCost.getLifeAmount() <= 0) return false;
} }
//Don't use poison before main 2 if possible //Don't use poison before main 2 if possible

View File

@@ -15,13 +15,12 @@ import forge.CombatUtil;
import forge.Command; import forge.Command;
import forge.ComputerUtil; import forge.ComputerUtil;
import forge.Constant; import forge.Constant;
import forge.Counters;
import forge.MyRandom; import forge.MyRandom;
import forge.Player; import forge.Player;
import forge.card.cardFactory.CardFactoryUtil; import forge.card.cardFactory.CardFactoryUtil;
import forge.card.cost.Cost;
import forge.card.spellability.Ability_Sub; import forge.card.spellability.Ability_Sub;
import forge.card.spellability.Cost;
import forge.card.spellability.Spell; import forge.card.spellability.Spell;
import forge.card.spellability.SpellAbility; import forge.card.spellability.SpellAbility;
import forge.card.spellability.Spell_Permanent; import forge.card.spellability.Spell_Permanent;
@@ -521,24 +520,6 @@ public class AbilityFactory_Attach {
if (abCost != null){ if (abCost != null){
// No Aura spells have Additional Costs // No Aura spells have Additional Costs
// AI currently disabled for these costs
if (abCost.getSacCost()){
}
if (abCost.getLifeCost()) return false;
if (abCost.getDiscardCost()) return false;
if (abCost.getSubCounter()){
//non +1/+1 counters should be used
if (abCost.getCounterType().equals(Counters.P1P1)){
// A card has a 25% chance per counter to be able to pass through here
// 4+ counters will always pass. 0 counters will never
int currentNum = source.getCounters(abCost.getCounterType());
double percent = .25 * (currentNum / abCost.getCounterNum());
if (percent <= r.nextFloat())
return false;
}
}
} }
// prevent run-away activations - first time will always return true // prevent run-away activations - first time will always return true
@@ -552,7 +533,7 @@ public class AbilityFactory_Attach {
return false; return false;
} }
if (abCost.getMana().contains("X") && source.getSVar("X").equals("Count$xPaid")){ if (abCost.getTotalMana().contains("X") && source.getSVar("X").equals("Count$xPaid")){
// Set PayX here to maximum value. (Endless Scream and Venarian Gold) // Set PayX here to maximum value. (Endless Scream and Venarian Gold)
int xPay = ComputerUtil.determineLeftoverMana(sa); int xPay = ComputerUtil.determineLeftoverMana(sa);

View File

@@ -2,6 +2,8 @@ package forge.card.abilityFactory;
import forge.*; import forge.*;
import forge.card.cardFactory.CardFactoryUtil; import forge.card.cardFactory.CardFactoryUtil;
import forge.card.cost.Cost;
import forge.card.cost.CostUtil;
import forge.card.spellability.*; import forge.card.spellability.*;
import forge.gui.GuiUtils; import forge.gui.GuiUtils;
@@ -283,22 +285,14 @@ public class AbilityFactory_ChangeZone {
if (abCost != null) { if (abCost != null) {
// AI currently disabled for these costs // AI currently disabled for these costs
if (abCost.getSacCost() && !abCost.getSacThis()) { if (!CostUtil.checkSacrificeCost(abCost, source))
//only sacrifice something that's supposed to be sacrificed return false;
String type = abCost.getSacType();
CardList typeList = AllZoneUtil.getPlayerCardsInPlay(AllZone.getComputerPlayer());
typeList = typeList.getValidCards(type.split(","), source.getController(), source);
if (ComputerUtil.getCardPreference(source, "SacCost", typeList) == null)
return false;
}
if (abCost.getLifeCost()) {
if (AllZone.getComputerPlayer().getLife() - abCost.getLifeAmount() < 4)
return false;
}
if (abCost.getDiscardCost()) return false;
if (abCost.getSubCounter()) ; // SubCounter is fine if (!CostUtil.checkLifeCost(abCost, source, 4))
return false;
if (!CostUtil.checkDiscardCost(abCost, source))
return false;
} }
Random r = MyRandom.random; Random r = MyRandom.random;
@@ -897,28 +891,17 @@ public class AbilityFactory_ChangeZone {
if (abCost != null) { if (abCost != null) {
// AI currently disabled for these costs // AI currently disabled for these costs
if (abCost.getSacCost() && !abCost.getSacThis()) { if (!CostUtil.checkSacrificeCost(abCost, source))
//only sacrifice something that's supposed to be sacrificed return false;
String type = abCost.getSacType();
CardList typeList = AllZoneUtil.getPlayerCardsInPlay(AllZone.getComputerPlayer());
typeList = typeList.getValidCards(type.split(","), source.getController(), source);
if (ComputerUtil.getCardPreference(source, "SacCost", typeList) == null)
return false;
}
if (abCost.getLifeCost()) {
if (AllZone.getComputerPlayer().getLife() - abCost.getLifeAmount() < 4)
return false;
}
if (abCost.getDiscardCost()) return false;
if (abCost.getSubCounter()) { if (!CostUtil.checkLifeCost(abCost, source, 4))
// A card has a 25% chance per counter to be able to pass through here return false;
// 4+ counters will always pass. 0 counters will never
int currentNum = source.getCounters(abCost.getCounterType()); if (!CostUtil.checkDiscardCost(abCost, source))
double percent = .25 * (currentNum / abCost.getCounterNum()); return false;
if (percent <= r.nextFloat())
return false; if (!CostUtil.checkRemoveCounterCost(abCost, source))
} return false;
} }
// prevent run-away activations - first time will always return true // prevent run-away activations - first time will always return true
@@ -1565,24 +1548,19 @@ public class AbilityFactory_ChangeZone {
private static boolean changeZoneAllCanPlayAI(AbilityFactory af, SpellAbility sa) { private static boolean changeZoneAllCanPlayAI(AbilityFactory af, SpellAbility sa) {
// Change Zone All, can be any type moving from one zone to another // Change Zone All, can be any type moving from one zone to another
Cost abCost = af.getAbCost(); Cost abCost = af.getAbCost();
//Card source = af.getHostCard(); Card source = sa.getSourceCard();
HashMap<String, String> params = af.getMapParams(); HashMap<String, String> params = af.getMapParams();
String destination = params.get("Destination"); String destination = params.get("Destination");
String origin = params.get("Origin"); String origin = params.get("Origin");
if (abCost != null) { if (abCost != null) {
// AI currently disabled for these costs // AI currently disabled for these costs
if (abCost.getSacCost()) { if (!CostUtil.checkLifeCost(abCost, source, 4))
// Sac is ok in general, but should add some decision making based off what we Sacrifice and what we might get return false;
}
if (abCost.getLifeCost()) {
if (AllZone.getComputerPlayer().getLife() - abCost.getLifeAmount() < 4)
return false;
}
if (abCost.getDiscardCost()) return false;
if (abCost.getSubCounter()) if (!CostUtil.checkDiscardCost(abCost, source))
; // subcounter is fine return false;
} }

View File

@@ -2,6 +2,8 @@ package forge.card.abilityFactory;
import forge.*; import forge.*;
import forge.card.cardFactory.CardFactoryUtil; import forge.card.cardFactory.CardFactoryUtil;
import forge.card.cost.Cost;
import forge.card.cost.CostUtil;
import forge.card.spellability.*; import forge.card.spellability.*;
import java.util.ArrayList; import java.util.ArrayList;
@@ -171,18 +173,10 @@ public class AbilityFactory_CounterMagic {
if (abCost != null) { if (abCost != null) {
// AI currently disabled for these costs // AI currently disabled for these costs
if (abCost.getSacCost() && !abCost.getSacThis()) { if (!CostUtil.checkSacrificeCost(abCost, source))
//only sacrifice something that's supposed to be sacrificed return false;
String type = abCost.getSacType(); if (!CostUtil.checkLifeCost(abCost, source, 4))
CardList typeList = AllZoneUtil.getPlayerCardsInPlay(AllZone.getComputerPlayer()); return false;
typeList = typeList.getValidCards(type.split(","), source.getController(), source);
if (ComputerUtil.getCardPreference(source, "SacCost", typeList) == null)
return false;
}
if (abCost.getLifeCost()) {
if (AllZone.getComputerPlayer().getLife() - abCost.getLifeAmount() < 4)
return false;
}
} }
Target tgt = sa.getTarget(); Target tgt = sa.getTarget();

View File

@@ -2,6 +2,8 @@ package forge.card.abilityFactory;
import forge.*; import forge.*;
import forge.card.cardFactory.CardFactoryUtil; import forge.card.cardFactory.CardFactoryUtil;
import forge.card.cost.Cost;
import forge.card.cost.CostUtil;
import forge.card.spellability.*; import forge.card.spellability.*;
import forge.gui.GuiUtils; import forge.gui.GuiUtils;
import forge.gui.input.Input; import forge.gui.input.Input;
@@ -221,25 +223,20 @@ public class AbilityFactory_Counters {
if (abCost != null) { if (abCost != null) {
// AI currently disabled for these costs // AI currently disabled for these costs
if (abCost.getSacCost() && (!abCost.getSacThis() || source.isCreature())) { if (!CostUtil.checkLifeCost(abCost, source, 4))
//only sacrifice something that's supposed to be sacrificed return false;
String sacType = abCost.getSacType();
CardList typeList = AllZoneUtil.getPlayerCardsInPlay(AllZone.getComputerPlayer());
typeList = typeList.getValidCards(sacType.split(","), source.getController(), source);
if (ComputerUtil.getCardPreference(source, "SacCost", typeList) == null)
return false;
}
if (abCost.getLifeCost()) return false;
if (abCost.getDiscardCost()) return false;
if (abCost.getSubCounter()) { if (!CostUtil.checkDiscardCost(abCost, source))
// A card has a 25% chance per counter to be able to pass through here return false;
// 4+ counters will always pass. 0 counters will never
int currentNum = source.getCounters(abCost.getCounterType()); if (!CostUtil.checkSacrificeCost(abCost, source))
double percent = .25 * (currentNum / abCost.getCounterNum()); return false;
if (percent <= r.nextFloat())
return false; if (CostUtil.checkCreatureSacrificeCost(abCost, source))
} return false;
if (!CostUtil.checkRemoveCounterCost(abCost, source))
return false;
} }
// TODO handle proper calculation of X values based on Cost // TODO handle proper calculation of X values based on Cost
@@ -743,25 +740,17 @@ public class AbilityFactory_Counters {
if (abCost != null) { if (abCost != null) {
// AI currently disabled for these costs // AI currently disabled for these costs
if (abCost.getSacCost() && !abCost.getSacThis()) { if (!CostUtil.checkLifeCost(abCost, source, 4))
//only sacrifice something that's supposed to be sacrificed return false;
String sacType = abCost.getSacType();
CardList typeList = AllZoneUtil.getPlayerCardsInPlay(AllZone.getComputerPlayer());
typeList = typeList.getValidCards(sacType.split(","), source.getController(), source);
if (ComputerUtil.getCardPreference(source, "SacCost", typeList) == null)
return false;
}
if (abCost.getLifeCost()) return false;
if (abCost.getDiscardCost()) return false;
if (abCost.getSubCounter()) { if (!CostUtil.checkDiscardCost(abCost, source))
// A card has a 25% chance per counter to be able to pass through here return false;
// 4+ counters will always pass. 0 counters will never
int currentNum = source.getCounters(abCost.getCounterType()); if (!CostUtil.checkSacrificeCost(abCost, source))
double percent = .25 * (currentNum / abCost.getCounterNum()); return false;
if (percent <= r.nextFloat())
return false; if (!CostUtil.checkRemoveCounterCost(abCost, source))
} return false;
} }
// TODO handle proper calculation of X values based on Cost // TODO handle proper calculation of X values based on Cost
@@ -1363,11 +1352,14 @@ public class AbilityFactory_Counters {
if (abCost != null) { if (abCost != null) {
// AI currently disabled for these costs // AI currently disabled for these costs
if (abCost.getSacCost()) { if (!CostUtil.checkLifeCost(abCost, source, 8))
return false;
if (!CostUtil.checkDiscardCost(abCost, source))
return false;
if (!CostUtil.checkSacrificeCost(abCost, source))
return false; return false;
}
if (abCost.getLifeCost()) return false;
if (abCost.getDiscardCost()) return false;
} }
if (tgt != null) { if (tgt != null) {

View File

@@ -2,6 +2,8 @@ package forge.card.abilityFactory;
import forge.*; import forge.*;
import forge.card.cardFactory.CardFactoryUtil; import forge.card.cardFactory.CardFactoryUtil;
import forge.card.cost.Cost;
import forge.card.cost.CostUtil;
import forge.card.spellability.*; import forge.card.spellability.*;
import java.util.ArrayList; import java.util.ArrayList;
@@ -238,23 +240,14 @@ public class AbilityFactory_DealDamage {
boolean rr = AF.isSpell(); boolean rr = AF.isSpell();
// temporarily disabled until better AI // temporarily disabled until better AI
if (abCost.getSacCost() && !abCost.getSacThis() && AllZone.getHumanPlayer().getLife() - dmg > 0) { if (!CostUtil.checkLifeCost(abCost, source, 4))
//only sacrifice something that's supposed to be sacrificed return false;
String sacType = abCost.getSacType();
CardList typeList = AllZoneUtil.getPlayerCardsInPlay(AllZone.getComputerPlayer()); if (!CostUtil.checkSacrificeCost(abCost, source))
typeList = typeList.getValidCards(sacType.split(","), source.getController(), source); return false;
if (ComputerUtil.getCardPreference(source, "SacCost", typeList) == null)
return false; if (!CostUtil.checkRemoveCounterCost(abCost, source))
} return false;
if (AF.getAbCost().getSubCounter()) {
// +1/+1 counters only if damage from this ability would kill the human, otherwise ok
if (AllZone.getHumanPlayer().getLife() - dmg > 0 && AF.getAbCost().getCounterType().equals(Counters.P1P1))
return false;
}
if (AF.getAbCost().getLifeCost()) {
if (AllZone.getHumanPlayer().getLife() - dmg > 0) // only if damage from this ability would kill the human
return false;
}
if (source.getName().equals("Stuffy Doll")) { if (source.getName().equals("Stuffy Doll")) {
// Now stuffy sits around for blocking // Now stuffy sits around for blocking
@@ -805,18 +798,8 @@ public class AbilityFactory_DealDamage {
//abCost stuff that should probably be centralized... //abCost stuff that should probably be centralized...
if (abCost != null) { if (abCost != null) {
// AI currently disabled for some costs // AI currently disabled for some costs
if (abCost.getSacCost()) { if (!CostUtil.checkLifeCost(abCost, source, 4))
//OK return false;
}
if (abCost.getLifeCost()) {
if (AllZone.getComputerPlayer().getLife() - abCost.getLifeAmount() < 4)
return false;
}
if (abCost.getDiscardCost()) ; //OK
if (abCost.getSubCounter()) {
// OK
}
} }
// TODO: if damage is dependant on mana paid, maybe have X be human's max life // TODO: if damage is dependant on mana paid, maybe have X be human's max life

View File

@@ -2,6 +2,8 @@ package forge.card.abilityFactory;
import forge.*; import forge.*;
import forge.card.cardFactory.CardFactoryUtil; import forge.card.cardFactory.CardFactoryUtil;
import forge.card.cost.Cost;
import forge.card.cost.CostUtil;
import forge.card.spellability.*; import forge.card.spellability.*;
import java.util.*; import java.util.*;
@@ -194,28 +196,21 @@ public class AbilityFactory_Debuff {
*/ */
private static boolean debuffCanPlayAI(final AbilityFactory af, final SpellAbility sa) { private static boolean debuffCanPlayAI(final AbilityFactory af, final SpellAbility sa) {
// if there is no target and host card isn't in play, don't activate // if there is no target and host card isn't in play, don't activate
if (af.getAbTgt() == null && !AllZoneUtil.isCardInPlay(af.getHostCard())) Card source = sa.getSourceCard();
if (sa.getTarget() == null && !AllZoneUtil.isCardInPlay(source))
return false; return false;
Cost cost = sa.getPayCosts();
// temporarily disabled until AI is improved // temporarily disabled until AI is improved
if (af.getAbCost().getSacCost() && sa.getSourceCard().isCreature()) return false; if (!CostUtil.checkCreatureSacrificeCost(cost, source))
if (af.getAbCost().getLifeCost()) { return false;
if (!CostUtil.checkLifeCost(cost, source, 40))
return false;
if (!CostUtil.checkRemoveCounterCost(cost, source))
return false; return false;
}
if (af.getAbCost().getSubCounter()) {
// instead of never removing counters, we will have a random possibility of failure.
// all the other tests still need to pass if a counter will be removed
Counters count = af.getAbCost().getCounterType();
double chance = .66;
if (count.equals(Counters.P1P1)) { // 10% chance to remove +1/+1 to pump
chance = .1;
} else if (count.equals(Counters.CHARGE)) { // 50% chance to remove charge to pump
chance = .5;
}
Random r = MyRandom.random;
if (r.nextFloat() > chance)
return false;
}
HashMap<String, String> params = af.getMapParams(); HashMap<String, String> params = af.getMapParams();
SpellAbility_Restriction restrict = sa.getRestrictions(); SpellAbility_Restriction restrict = sa.getRestrictions();

View File

@@ -2,6 +2,8 @@ package forge.card.abilityFactory;
import forge.*; import forge.*;
import forge.card.cardFactory.CardFactoryUtil; import forge.card.cardFactory.CardFactoryUtil;
import forge.card.cost.Cost;
import forge.card.cost.CostUtil;
import forge.card.spellability.*; import forge.card.spellability.*;
import java.util.ArrayList; import java.util.ArrayList;
@@ -156,23 +158,14 @@ public class AbilityFactory_Destroy {
if (abCost != null) { if (abCost != null) {
// AI currently disabled for some costs // AI currently disabled for some costs
if (abCost.getSacCost() && !abCost.getSacThis()) { if (!CostUtil.checkSacrificeCost(abCost, source))
//only sacrifice something that's supposed to be sacrificed return false;
String sacType = abCost.getSacType();
CardList typeList = AllZoneUtil.getPlayerCardsInPlay(AllZone.getComputerPlayer());
typeList = typeList.getValidCards(sacType.split(","), source.getController(), source);
if (ComputerUtil.getCardPreference(source, "SacCost", typeList) == null)
return false;
}
if (abCost.getLifeCost()) {
if (AllZone.getComputerPlayer().getLife() - abCost.getLifeAmount() < 4)
return false;
}
if (abCost.getDiscardCost()) return false;
if (abCost.getSubCounter()) { if (!CostUtil.checkLifeCost(abCost, source, 4))
// OK return false;
}
if (!CostUtil.checkDiscardCost(abCost, source))
return false;
} }
// prevent run-away activations - first time will always return true // prevent run-away activations - first time will always return true
@@ -607,18 +600,9 @@ public class AbilityFactory_Destroy {
if (abCost != null) { if (abCost != null) {
// AI currently disabled for some costs // AI currently disabled for some costs
if (abCost.getSacCost()) {
//OK
}
if (abCost.getLifeCost()) {
if (AllZone.getComputerPlayer().getLife() - abCost.getLifeAmount() < 4)
return false;
}
if (abCost.getDiscardCost()) ;//OK
if (abCost.getSubCounter()) { if (!CostUtil.checkLifeCost(abCost, source, 4))
// OK return false;
}
} }
// prevent run-away activations - first time will always return true // prevent run-away activations - first time will always return true

View File

@@ -1,6 +1,7 @@
package forge.card.abilityFactory; package forge.card.abilityFactory;
import forge.*; import forge.*;
import forge.card.cost.Cost;
import forge.card.spellability.*; import forge.card.spellability.*;
import forge.gui.GuiUtils; import forge.gui.GuiUtils;
import forge.gui.input.Input_PayManaCostUtil; import forge.gui.input.Input_PayManaCostUtil;

View File

@@ -2,6 +2,8 @@ package forge.card.abilityFactory;
import forge.*; import forge.*;
import forge.card.cardFactory.CardFactoryUtil; import forge.card.cardFactory.CardFactoryUtil;
import forge.card.cost.Cost;
import forge.card.cost.CostUtil;
import forge.card.spellability.*; import forge.card.spellability.*;
import forge.gui.GuiUtils; import forge.gui.GuiUtils;
@@ -176,13 +178,13 @@ public class AbilityFactory_PermanentState {
*/ */
private static boolean untapCanPlayAI(final AbilityFactory af, SpellAbility sa) { private static boolean untapCanPlayAI(final AbilityFactory af, SpellAbility sa) {
// AI cannot use this properly until he can use SAs during Humans turn // AI cannot use this properly until he can use SAs during Humans turn
Target tgt = sa.getTarget();
Card source = sa.getSourceCard();
Cost cost = sa.getPayCosts();
if (af.getAbCost().getAddCounter())
if (af.getAbCost().getCounterType().equals(Counters.M1M1))
return false;
Target tgt = af.getAbTgt(); if (!CostUtil.checkAddM1M1CounterCost(cost, source))
//Card source = sa.getSourceCard(); return false;
Random r = MyRandom.random; Random r = MyRandom.random;
boolean randomReturn = r.nextFloat() <= Math.pow(.6667, sa.getActivationsThisTurn() + 1); boolean randomReturn = r.nextFloat() <= Math.pow(.6667, sa.getActivationsThisTurn() + 1);

View File

@@ -2,6 +2,8 @@ package forge.card.abilityFactory;
import forge.*; import forge.*;
import forge.card.cardFactory.CardFactoryUtil; import forge.card.cardFactory.CardFactoryUtil;
import forge.card.cost.Cost;
import forge.card.cost.CostUtil;
import forge.card.spellability.*; import forge.card.spellability.*;
import java.util.ArrayList; import java.util.ArrayList;
@@ -178,12 +180,20 @@ public class AbilityFactory_PreventDamage {
final Card hostCard = af.getHostCard(); final Card hostCard = af.getHostCard();
boolean chance = false; boolean chance = false;
Cost cost = sa.getPayCosts();
// temporarily disabled until better AI // temporarily disabled until better AI
if (af.getAbCost().getSacCost()) return false; if (!CostUtil.checkLifeCost(cost, hostCard, 4))
if (af.getAbCost().getSubCounter()) return false;
if (af.getAbCost().getCounterType().equals(Counters.P1P1))
return false; if (!CostUtil.checkDiscardCost(cost, hostCard))
if (af.getAbCost().getLifeCost()) return false; return false;
if (!CostUtil.checkSacrificeCost(cost, hostCard))
return false;
if (!CostUtil.checkRemoveCounterCost(cost, hostCard))
return false;
Target tgt = af.getAbTgt(); Target tgt = af.getAbTgt();
if (tgt == null) { if (tgt == null) {

View File

@@ -2,6 +2,8 @@ package forge.card.abilityFactory;
import forge.*; import forge.*;
import forge.card.cardFactory.CardFactoryUtil; import forge.card.cardFactory.CardFactoryUtil;
import forge.card.cost.Cost;
import forge.card.cost.CostUtil;
import forge.card.spellability.*; import forge.card.spellability.*;
import forge.gui.GuiUtils; import forge.gui.GuiUtils;
@@ -209,28 +211,20 @@ public class AbilityFactory_Protection {
if(af.getAbTgt() == null && !AllZoneUtil.isCardInPlay(hostCard)) if(af.getAbTgt() == null && !AllZoneUtil.isCardInPlay(hostCard))
return false; return false;
// temporarily disabled until AI is improved Cost cost = sa.getPayCosts();
if(af.getAbCost().getSacCost() && sa.getSourceCard().isCreature()) return false;
if(af.getAbCost().getLifeCost()) { // temporarily disabled until better AI
if(!af.isCurse()) return false; //Use life only to kill creatures if (!CostUtil.checkLifeCost(cost, hostCard, 4))
if(AllZone.getComputerPlayer().getLife() - af.getAbCost().getLifeAmount() < 4) return false;
return false;
} if (!CostUtil.checkDiscardCost(cost, hostCard))
if(af.getAbCost().getSubCounter()) { return false;
// instead of never removing counters, we will have a random possibility of failure.
// all the other tests still need to pass if a counter will be removed if (!CostUtil.checkCreatureSacrificeCost(cost, hostCard))
Counters count = af.getAbCost().getCounterType(); return false;
double chance = .66;
if(count.equals(Counters.P1P1)) { // 10% chance to remove +1/+1 to protect if (!CostUtil.checkRemoveCounterCost(cost, hostCard))
chance = .1; return false;
}
else if(count.equals(Counters.CHARGE)) { // 50% chance to remove charge to protect
chance = .5;
}
Random r = MyRandom.random;
if(r.nextFloat() > chance)
return false;
}
// Phase Restrictions // Phase Restrictions
if(AllZone.getStack().size() == 0 && AllZone.getPhase().isBefore(Constant.Phase.Combat_FirstStrikeDamage)) { if(AllZone.getStack().size() == 0 && AllZone.getPhase().isBefore(Constant.Phase.Combat_FirstStrikeDamage)) {
@@ -768,14 +762,20 @@ public class AbilityFactory_Protection {
if(af.getAbTgt() == null && !AllZoneUtil.isCardInPlay(hostCard)) if(af.getAbTgt() == null && !AllZoneUtil.isCardInPlay(hostCard))
return false; return false;
// temporarily disabled until AI is improved Cost cost = sa.getPayCosts();
if(af.getAbCost().getSacCost()) return false;
if(af.getAbCost().getLifeCost()) { // temporarily disabled until better AI
return false; if (!CostUtil.checkLifeCost(cost, hostCard, 4))
} return false;
if(af.getAbCost().getSubCounter()) {
return false; if (!CostUtil.checkDiscardCost(cost, hostCard))
} return false;
if (!CostUtil.checkSacrificeCost(cost, hostCard))
return false;
if (!CostUtil.checkRemoveCounterCost(cost, hostCard))
return false;
return false; return false;
}//protectAllCanPlayAI() }//protectAllCanPlayAI()

View File

@@ -2,6 +2,8 @@ package forge.card.abilityFactory;
import forge.*; import forge.*;
import forge.card.cardFactory.CardFactoryUtil; import forge.card.cardFactory.CardFactoryUtil;
import forge.card.cost.Cost;
import forge.card.cost.CostUtil;
import forge.card.spellability.*; import forge.card.spellability.*;
import java.util.ArrayList; import java.util.ArrayList;
@@ -303,30 +305,20 @@ public class AbilityFactory_Pump {
if (AF.getAbTgt() == null && !AllZoneUtil.isCardInPlay(hostCard)) if (AF.getAbTgt() == null && !AllZoneUtil.isCardInPlay(hostCard))
return false; return false;
Cost cost = sa.getPayCosts();
// temporarily disabled until AI is improved // temporarily disabled until AI is improved
if (AF.getAbCost().getSacCost() && sa.getSourceCard().isCreature()) return false; if (!CostUtil.checkLifeCost(cost, hostCard, 4))
if (AF.getAbCost().getLifeCost()) { return false;
if (!AF.isCurse()) return false; //Use life only to kill creatures
if (AllZone.getComputerPlayer().getLife() - AF.getAbCost().getLifeAmount() < 4) if (!CostUtil.checkDiscardCost(cost, hostCard))
return false; return false;
}
if (AF.getAbCost().getDiscardCost() && !AF.isCurse()) { if (!CostUtil.checkCreatureSacrificeCost(cost, hostCard))
return false; return false;
}
if (AF.getAbCost().getSubCounter()) { if (!CostUtil.checkRemoveCounterCost(cost, hostCard))
// instead of never removing counters, we will have a random possibility of failure. return false;
// all the other tests still need to pass if a counter will be removed
Counters count = AF.getAbCost().getCounterType();
double chance = .66;
if (count.equals(Counters.P1P1)) { // 10% chance to remove +1/+1 to pump
chance = .1;
} else if (count.equals(Counters.CHARGE)) { // 50% chance to remove charge to pump
chance = .5;
}
Random r = MyRandom.random;
if (r.nextFloat() > chance)
return false;
}
SpellAbility_Restriction restrict = sa.getRestrictions(); SpellAbility_Restriction restrict = sa.getRestrictions();

View File

@@ -2,6 +2,8 @@ package forge.card.abilityFactory;
import forge.*; import forge.*;
import forge.card.cardFactory.CardFactoryUtil; import forge.card.cardFactory.CardFactoryUtil;
import forge.card.cost.Cost;
import forge.card.cost.CostUtil;
import forge.card.spellability.*; import forge.card.spellability.*;
import java.util.ArrayList; import java.util.ArrayList;
@@ -183,18 +185,14 @@ public class AbilityFactory_Regenerate {
Cost abCost = af.getAbCost(); Cost abCost = af.getAbCost();
if (abCost != null) { if (abCost != null) {
// AI currently disabled for these costs // AI currently disabled for these costs
if (abCost.getSacCost() && !abCost.getSacThis()) { if (!CostUtil.checkLifeCost(abCost, hostCard, 4))
//only sacrifice something that's supposed to be sacrificed return false;
String type = abCost.getSacType();
CardList typeList = AllZoneUtil.getPlayerCardsInPlay(AllZone.getComputerPlayer()); if (!CostUtil.checkSacrificeCost(abCost, hostCard))
typeList = typeList.getValidCards(type.split(","), hostCard.getController(), hostCard); return false;
if (ComputerUtil.getCardPreference(hostCard, "SacCost", typeList) == null)
return false; if (CostUtil.checkCreatureSacrificeCost(abCost, hostCard))
} return false;
if (abCost.getLifeCost()) {
if (AllZone.getComputerPlayer().getLife() - abCost.getLifeAmount() < 4)
return false;
}
} }
Target tgt = sa.getTarget(); Target tgt = sa.getTarget();
@@ -550,18 +548,14 @@ public class AbilityFactory_Regenerate {
Cost abCost = af.getAbCost(); Cost abCost = af.getAbCost();
if (abCost != null) { if (abCost != null) {
// AI currently disabled for these costs // AI currently disabled for these costs
if (abCost.getSacCost() && !abCost.getSacThis()) { if (!CostUtil.checkSacrificeCost(abCost, hostCard))
//only sacrifice something that's supposed to be sacrificed return false;
String type = abCost.getSacType();
CardList typeList = AllZoneUtil.getPlayerCardsInPlay(AllZone.getComputerPlayer()); if (CostUtil.checkCreatureSacrificeCost(abCost, hostCard))
typeList = typeList.getValidCards(type.split(","), hostCard.getController(), hostCard); return false;
if (ComputerUtil.getCardPreference(hostCard, "SacCost", typeList) == null)
return false; if (!CostUtil.checkLifeCost(abCost, hostCard, 4))
} return false;
if (abCost.getLifeCost()) {
if (AllZone.getComputerPlayer().getLife() - abCost.getLifeAmount() < 4)
return false;
}
} }
// filter AIs battlefield by what I can target // filter AIs battlefield by what I can target

View File

@@ -1,6 +1,8 @@
package forge.card.abilityFactory; package forge.card.abilityFactory;
import forge.*; import forge.*;
import forge.card.cost.Cost;
import forge.card.cost.CostUtil;
import forge.card.spellability.*; import forge.card.spellability.*;
import forge.gui.GuiUtils; import forge.gui.GuiUtils;
@@ -595,22 +597,22 @@ public class AbilityFactory_Reveal {
*/ */
private static boolean revealHandCanPlayAI(final AbilityFactory af, SpellAbility sa) { private static boolean revealHandCanPlayAI(final AbilityFactory af, SpellAbility sa) {
// AI cannot use this properly until he can use SAs during Humans turn // AI cannot use this properly until he can use SAs during Humans turn
Cost abCost = af.getAbCost(); Cost abCost = sa.getPayCosts();
Card source = sa.getSourceCard();
if (abCost != null) { if (abCost != null) {
// AI currently disabled for these costs // AI currently disabled for these costs
if (abCost.getSacCost()) { if (!CostUtil.checkLifeCost(abCost, source, 4))
return false; return false;
}
if (abCost.getLifeCost()) {
if (AllZone.getComputerPlayer().getLife() - abCost.getLifeAmount() < 4)
return false;
}
if (abCost.getDiscardCost()) return false;
if (abCost.getSubCounter()) { if (!CostUtil.checkDiscardCost(abCost, source))
if (abCost.getCounterType().equals(Counters.P1P1)) return false; // Other counters should be used return false;
}
if (!CostUtil.checkSacrificeCost(abCost, source))
return false;
if (!CostUtil.checkRemoveCounterCost(abCost, source))
return false;
} }

View File

@@ -2,6 +2,8 @@ package forge.card.abilityFactory;
import forge.*; import forge.*;
import forge.card.cardFactory.CardFactoryUtil; import forge.card.cardFactory.CardFactoryUtil;
import forge.card.cost.Cost;
import forge.card.cost.CostUtil;
import forge.card.spellability.*; import forge.card.spellability.*;
import java.util.ArrayList; import java.util.ArrayList;
@@ -348,14 +350,9 @@ public class AbilityFactory_Sacrifice {
msg = "Sacrifice a " + msg; msg = "Sacrifice a " + msg;
boolean remSacrificed = params.containsKey("RememberSacrificed");
if (remSacrificed)
card.clearRemembered();
if (valid.equals("Self")) { if (valid.equals("Self")) {
if (AllZone.getZone(sa.getSourceCard()).is(Constant.Zone.Battlefield)) if (AllZone.getZone(sa.getSourceCard()).is(Constant.Zone.Battlefield))
if (AllZone.getGameAction().sacrifice(sa.getSourceCard()) && remSacrificed) AllZone.getGameAction().sacrifice(sa.getSourceCard());
card.addRemembered(sa.getSourceCard());
} }
//TODO - maybe this can be done smarter... //TODO - maybe this can be done smarter...
else if (valid.equals("Card.AttachedBy")) { else if (valid.equals("Card.AttachedBy")) {
@@ -592,18 +589,8 @@ public class AbilityFactory_Sacrifice {
if (abCost != null) { if (abCost != null) {
// AI currently disabled for some costs // AI currently disabled for some costs
if (abCost.getSacCost()) { if (!CostUtil.checkLifeCost(abCost, source, 4))
//OK return false;
}
if (abCost.getLifeCost()) {
if (AllZone.getComputerPlayer().getLife() - abCost.getLifeAmount() < 4)
return false;
}
if (abCost.getDiscardCost()) ;//OK
if (abCost.getSubCounter()) {
// OK
}
} }
// prevent run-away activations - first time will always return true // prevent run-away activations - first time will always return true

View File

@@ -10,16 +10,16 @@ import forge.CardList;
import forge.Command; import forge.Command;
import forge.ComputerUtil; import forge.ComputerUtil;
import forge.Constant; import forge.Constant;
import forge.Counters;
import forge.MyRandom; import forge.MyRandom;
import forge.Player; import forge.Player;
import forge.card.cardFactory.CardFactoryUtil; import forge.card.cardFactory.CardFactoryUtil;
import forge.card.spellability.Ability_Activated; import forge.card.spellability.Ability_Activated;
import forge.card.spellability.Ability_Sub; import forge.card.spellability.Ability_Sub;
import forge.card.spellability.Cost;
import forge.card.spellability.Spell; import forge.card.spellability.Spell;
import forge.card.spellability.SpellAbility; import forge.card.spellability.SpellAbility;
import forge.card.spellability.Target; import forge.card.spellability.Target;
import forge.card.cost.Cost;
import forge.card.cost.CostUtil;
import forge.card.trigger.Trigger; import forge.card.trigger.Trigger;
import forge.card.trigger.TriggerHandler; import forge.card.trigger.TriggerHandler;
@@ -266,28 +266,17 @@ public class AbilityFactory_Token extends AbilityFactory {
} }
if (cost != null) { if (cost != null) {
if (cost.getSacCost() && !cost.getSacThis()) { if (!CostUtil.checkLifeCost(cost, source, 4))
//only sacrifice something that's supposed to be sacrificed return false;
String type = cost.getSacType();
CardList typeList = AllZoneUtil.getPlayerCardsInPlay(AllZone.getComputerPlayer()); if (!CostUtil.checkDiscardCost(cost, source))
typeList = typeList.getValidCards(type.split(","), source.getController(), source); return false;
if (ComputerUtil.getCardPreference(source, "SacCost", typeList) == null)
return false; if (!CostUtil.checkSacrificeCost(cost, source))
} return false;
if (cost.getSubCounter()) {
if (cost.getCounterType().equals(Counters.P1P1)) { if (!CostUtil.checkRemoveCounterCost(cost, source))
// A card has a 25% chance per counter to be able to pass through here return false;
// 4+ counters will always pass. 0 counters will never
int currentNum = source.getCounters(cost.getCounterType());
double percent = .25 * (currentNum / cost.getCounterNum());
if (percent <= r.nextFloat())
return false;
}
}
if (cost.getLifeCost()) {
if (AllZone.getComputerPlayer().getLife() - cost.getLifeAmount() < 4)
return false;
}
} }
if (tokenAmount.equals("X")) { if (tokenAmount.equals("X")) {

View File

@@ -2,6 +2,8 @@ package forge.card.abilityFactory;
import forge.*; import forge.*;
import forge.card.cardFactory.CardFactoryUtil; import forge.card.cardFactory.CardFactoryUtil;
import forge.card.cost.Cost;
import forge.card.cost.CostUtil;
import forge.card.spellability.*; import forge.card.spellability.*;
import forge.gui.GuiUtils; import forge.gui.GuiUtils;
@@ -186,24 +188,23 @@ public class AbilityFactory_ZoneAffecting {
private static boolean drawCanPlayAI(final AbilityFactory af, SpellAbility sa) { private static boolean drawCanPlayAI(final AbilityFactory af, SpellAbility sa) {
HashMap<String, String> params = af.getMapParams(); HashMap<String, String> params = af.getMapParams();
Target tgt = af.getAbTgt(); Target tgt = sa.getTarget();
Card source = sa.getSourceCard(); Card source = sa.getSourceCard();
Cost abCost = af.getAbCost(); Cost abCost = sa.getPayCosts();
if (abCost != null) { if (abCost != null) {
// AI currently disabled for these costs // AI currently disabled for these costs
if (abCost.getSacCost() && source.isCreature()) { if (CostUtil.checkCreatureSacrificeCost(abCost, source))
return false; return false;
}
if (abCost.getLifeCost()) {
if (AllZone.getComputerPlayer().getLife() - abCost.getLifeAmount() < 4)
return false;
}
if (abCost.getDiscardCost()) return false;
if (abCost.getSubCounter()) { if (!CostUtil.checkLifeCost(abCost, source, 4))
if (abCost.getCounterType().equals(Counters.P1P1)) return false; // Other counters should be used return false;
}
if (!CostUtil.checkDiscardCost(abCost, source))
return false;
if (!CostUtil.checkRemoveCounterCost(abCost, source))
return false;
} }
@@ -595,18 +596,17 @@ public class AbilityFactory_ZoneAffecting {
if (abCost != null) { if (abCost != null) {
// AI currently disabled for these costs // AI currently disabled for these costs
if (abCost.getSacCost()) { if (!CostUtil.checkLifeCost(abCost, source, 4))
return false; return false;
}
if (abCost.getLifeCost()) {
if (AllZone.getComputerPlayer().getLife() - abCost.getLifeAmount() < 4)
return false;
}
if (abCost.getDiscardCost()) return false;
if (abCost.getSubCounter()) { if (!CostUtil.checkDiscardCost(abCost, source))
if (abCost.getCounterType().equals(Counters.P1P1)) return false; // Other counters should be used return false;
}
if (!CostUtil.checkSacrificeCost(abCost, source))
return false;
if (!CostUtil.checkRemoveCounterCost(abCost, source))
return false;
} }
@@ -1105,24 +1105,23 @@ public class AbilityFactory_ZoneAffecting {
private static boolean discardCanPlayAI(final AbilityFactory af, SpellAbility sa) { private static boolean discardCanPlayAI(final AbilityFactory af, SpellAbility sa) {
HashMap<String, String> params = af.getMapParams(); HashMap<String, String> params = af.getMapParams();
Target tgt = af.getAbTgt(); Target tgt = sa.getTarget();
Card source = sa.getSourceCard(); Card source = sa.getSourceCard();
Cost abCost = af.getAbCost(); Cost abCost = sa.getPayCosts();
if (abCost != null) { if (abCost != null) {
// AI currently disabled for these costs // AI currently disabled for these costs
if (abCost.getSacCost()) { if (!CostUtil.checkSacrificeCost(abCost, source))
return false; return false;
}
if (abCost.getLifeCost()) {
if (AllZone.getComputerPlayer().getLife() - abCost.getLifeAmount() < 4)
return false;
}
if (abCost.getDiscardCost()) return false;
if (abCost.getSubCounter()) { if (!CostUtil.checkLifeCost(abCost, source, 4))
if (abCost.getCounterType().equals(Counters.P1P1)) return false; // Other counters should be used return false;
}
if (!CostUtil.checkDiscardCost(abCost, source))
return false;
if (!CostUtil.checkRemoveCounterCost(abCost, source))
return false;
} }

View File

@@ -24,6 +24,7 @@ import forge.FileUtil;
import forge.Player; import forge.Player;
import forge.PlayerZone; import forge.PlayerZone;
import forge.card.abilityFactory.AbilityFactory; import forge.card.abilityFactory.AbilityFactory;
import forge.card.cost.Cost;
import forge.card.spellability.*; import forge.card.spellability.*;
import forge.card.trigger.Trigger; import forge.card.trigger.Trigger;
import forge.game.GameLossReason; import forge.game.GameLossReason;

View File

@@ -2,6 +2,7 @@ package forge.card.cardFactory;
import com.esotericsoftware.minlog.Log; import com.esotericsoftware.minlog.Log;
import forge.*; import forge.*;
import forge.card.cost.Cost;
import forge.card.mana.ManaCost; import forge.card.mana.ManaCost;
import forge.card.spellability.*; import forge.card.spellability.*;
import forge.card.trigger.Trigger; import forge.card.trigger.Trigger;
@@ -907,7 +908,7 @@ public class CardFactoryUtil {
* @param sourceCard * @param sourceCard
* a {@link forge.Card} object. * a {@link forge.Card} object.
* @param cost * @param cost
* a {@link forge.card.spellability.Cost} object. * a {@link forge.card.cost.Cost} object.
* @param orgManaCost * @param orgManaCost
* a {@link java.lang.String} object. * a {@link java.lang.String} object.
* @param a * @param a
@@ -1258,7 +1259,7 @@ public class CardFactoryUtil {
* @param extrinsicKeywords * @param extrinsicKeywords
* an array of {@link java.lang.String} objects. * an array of {@link java.lang.String} objects.
* @param abCost * @param abCost
* a {@link forge.card.spellability.Cost} object. * a {@link forge.card.cost.Cost} object.
* @return a {@link forge.card.spellability.SpellAbility} object. * @return a {@link forge.card.spellability.SpellAbility} object.
*/ */
public static SpellAbility eqPump_Equip(final Card sourceCard, final int Power, final int Tough, public static SpellAbility eqPump_Equip(final Card sourceCard, final int Power, final int Tough,
@@ -1370,7 +1371,7 @@ public class CardFactoryUtil {
* @param extrinsicKeywords * @param extrinsicKeywords
* an array of {@link java.lang.String} objects. * an array of {@link java.lang.String} objects.
* @param abCost * @param abCost
* a {@link forge.card.spellability.Cost} object. * a {@link forge.card.cost.Cost} object.
* @return a {@link forge.Command} object. * @return a {@link forge.Command} object.
*/ */
public static Command eqPump_onEquip(final Card sourceCard, final int Power, final int Tough, public static Command eqPump_onEquip(final Card sourceCard, final int Power, final int Tough,
@@ -1414,7 +1415,7 @@ public class CardFactoryUtil {
* @param extrinsicKeywords * @param extrinsicKeywords
* an array of {@link java.lang.String} objects. * an array of {@link java.lang.String} objects.
* @param abCost * @param abCost
* a {@link forge.card.spellability.Cost} object. * a {@link forge.card.cost.Cost} object.
* @return a {@link forge.Command} object. * @return a {@link forge.Command} object.
*/ */
public static Command eqPump_unEquip(final Card sourceCard, final int Power, final int Tough, public static Command eqPump_unEquip(final Card sourceCard, final int Power, final int Tough,

View File

@@ -13,8 +13,8 @@ import forge.Command;
import forge.Constant; import forge.Constant;
import forge.Player; import forge.Player;
import forge.PlayerZone; import forge.PlayerZone;
import forge.card.cost.Cost;
import forge.card.spellability.Ability; import forge.card.spellability.Ability;
import forge.card.spellability.Cost;
import forge.card.spellability.Spell; import forge.card.spellability.Spell;
import forge.card.spellability.SpellAbility; import forge.card.spellability.SpellAbility;
import forge.card.spellability.Spell_Permanent; import forge.card.spellability.Spell_Permanent;

View File

@@ -4,6 +4,7 @@ package forge.card.cardFactory;
import com.esotericsoftware.minlog.Log; import com.esotericsoftware.minlog.Log;
import forge.*; import forge.*;
import forge.card.abilityFactory.AbilityFactory; import forge.card.abilityFactory.AbilityFactory;
import forge.card.cost.Cost;
import forge.card.spellability.*; import forge.card.spellability.*;
import forge.card.trigger.Trigger; import forge.card.trigger.Trigger;
import forge.card.trigger.TriggerHandler; import forge.card.trigger.TriggerHandler;

View File

@@ -2,6 +2,7 @@ package forge.card.cardFactory;
import forge.*; import forge.*;
import forge.card.cost.Cost;
import forge.card.spellability.*; import forge.card.spellability.*;
import forge.card.trigger.Trigger; import forge.card.trigger.Trigger;
import forge.card.trigger.TriggerHandler; import forge.card.trigger.TriggerHandler;

View File

@@ -1,6 +1,7 @@
package forge.card.cardFactory; package forge.card.cardFactory;
import forge.*; import forge.*;
import forge.card.cost.Cost;
import forge.card.spellability.*; import forge.card.spellability.*;
import forge.gui.GuiUtils; import forge.gui.GuiUtils;
import forge.gui.input.Input; import forge.gui.input.Input;

View File

@@ -1,6 +1,7 @@
package forge.card.cardFactory; package forge.card.cardFactory;
import forge.*; import forge.*;
import forge.card.cost.Cost;
import forge.card.spellability.*; import forge.card.spellability.*;
import forge.gui.GuiUtils; import forge.gui.GuiUtils;
import forge.gui.input.Input; import forge.gui.input.Input;

View File

@@ -3,6 +3,7 @@ package forge.card.cardFactory;
import com.esotericsoftware.minlog.Log; import com.esotericsoftware.minlog.Log;
import forge.*; import forge.*;
import forge.card.cost.Cost;
import forge.card.spellability.*; import forge.card.spellability.*;
import forge.gui.GuiUtils; import forge.gui.GuiUtils;
import forge.gui.input.Input; import forge.gui.input.Input;

View File

@@ -2,6 +2,7 @@ package forge.card.cardFactory;
import com.esotericsoftware.minlog.Log; import com.esotericsoftware.minlog.Log;
import forge.*; import forge.*;
import forge.card.cost.Cost;
import forge.card.spellability.*; import forge.card.spellability.*;
import forge.gui.GuiUtils; import forge.gui.GuiUtils;
import forge.gui.input.Input; import forge.gui.input.Input;

View File

@@ -0,0 +1,471 @@
package forge.card.cost;
import java.util.ArrayList;
import java.util.regex.Pattern;
import forge.AllZone;
import forge.Card;
import forge.Constant;
import forge.Counters;
import forge.card.mana.ManaCost;
import forge.card.spellability.SpellAbility;
/**
* <p>Cost class.</p>
*
* @author Forge
* @version $Id$
*/
public class Cost {
private boolean isAbility = true;
ArrayList<CostPart> costParts = new ArrayList<CostPart>();
public ArrayList<CostPart> getCostParts(){ return costParts; }
private boolean sacCost = false;
/**
* <p>Getter for the field <code>sacCost</code>.</p>
*
* @return a boolean.
*/
public boolean getSacCost() {
return sacCost;
}
private boolean tapCost = false;
/**
* <p>getTap.</p>
*
* @return a boolean.
*/
public boolean getTap() {
return tapCost;
}
/**
* <p>hasNoManaCost.</p>
*
* @return a boolean.
*/
public boolean hasNoManaCost() {
for(CostPart part : costParts)
if (part instanceof CostMana)
return false;
return true;
}
/**
* <p>isOnlyManaCost.</p>
*
* @return a boolean.
*/
public boolean isOnlyManaCost() {
// Only used by Morph and Equip... why do we need this?
for(CostPart part : costParts)
if (!(part instanceof CostMana))
return false;
return true;
}
/**
* <p>getTotalMana.</p>
*
* @return a {@link java.lang.String} object.
*/
public String getTotalMana() {
for(CostPart part : costParts)
if (part instanceof CostMana)
return part.toString();
return "0";
}
private String name;
// Parsing Strings
private final static String tapXStr = "tapXType<";
private final static String subStr = "SubCounter<";
private final static String addStr = "AddCounter<";
private final static String lifeStr = "PayLife<";
private final static String discStr = "Discard<";
private final static String sacStr = "Sac<";
private final static String exileStr = "Exile<";
private final static String exileFromHandStr = "ExileFromHand<";
private final static String exileFromGraveStr = "ExileFromGrave<";
private final static String exileFromTopStr = "ExileFromTop<";
private final static String returnStr = "Return<";
/**
* <p>Constructor for Cost.</p>
*
* @param parse a {@link java.lang.String} object.
* @param cardName a {@link java.lang.String} object.
* @param bAbility a boolean.
*/
public Cost(String parse, String cardName, boolean bAbility) {
isAbility = bAbility;
// when adding new costs for cost string, place them here
name = cardName;
while (parse.contains(tapXStr)) {
String[] splitStr = abCostParse(parse, tapXStr, 3);
parse = abUpdateParse(parse, tapXStr);
String description = splitStr.length > 2 ? splitStr[2] : null;
costParts.add(new CostTapType(splitStr[0], splitStr[1], description));
}
while (parse.contains(subStr)) {
// SubCounter<NumCounters/CounterType>
String[] splitStr = abCostParse(parse, subStr, 4);
parse = abUpdateParse(parse, subStr);
String type = splitStr.length > 2 ? splitStr[2] : null;
String description = splitStr.length > 3 ? splitStr[3] : null;
costParts.add(new CostRemoveCounter(splitStr[0], Counters.valueOf(splitStr[1]), type, description));
}
while (parse.contains(addStr)) {
// AddCounter<NumCounters/CounterType>
String[] splitStr = abCostParse(parse, addStr, 2);
parse = abUpdateParse(parse, addStr);
costParts.add(new CostPutCounter(splitStr[0], Counters.valueOf(splitStr[1])));
}
// While no card has "PayLife<2> PayLife<3> there might be a card that Changes Cost by adding a Life Payment
while (parse.contains(lifeStr)) {
// PayLife<LifeCost>
String[] splitStr = abCostParse(parse, lifeStr, 1);
parse = abUpdateParse(parse, lifeStr);
costParts.add(new CostPayLife(splitStr[0]));
}
while (parse.contains(discStr)) {
// Discard<NumCards/Type>
String[] splitStr = abCostParse(parse, discStr, 3);
parse = abUpdateParse(parse, discStr);
String description = splitStr.length > 2 ? splitStr[2] : null;
costParts.add(new CostDiscard(splitStr[0], splitStr[1], description));
}
while (parse.contains(sacStr)) {
sacCost = true;
String[] splitStr = abCostParse(parse, sacStr, 3);
parse = abUpdateParse(parse, sacStr);
String description = splitStr.length > 2 ? splitStr[2] : null;
costParts.add(new CostSacrifice(splitStr[0], splitStr[1], description));
}
while (parse.contains(exileStr)) {
String[] splitStr = abCostParse(parse, exileStr, 3);
parse = abUpdateParse(parse, exileStr);
String description = splitStr.length > 2 ? splitStr[2] : null;
costParts.add(new CostExile(splitStr[0], splitStr[1], description, Constant.Zone.Battlefield));
}
while (parse.contains(exileFromHandStr)) {
String[] splitStr = abCostParse(parse, exileFromHandStr, 3);
parse = abUpdateParse(parse, exileFromHandStr);
String description = splitStr.length > 2 ? splitStr[2] : null;
costParts.add(new CostExile(splitStr[0], splitStr[1], description, Constant.Zone.Hand));
}
while (parse.contains(exileFromGraveStr)) {
String[] splitStr = abCostParse(parse, exileFromGraveStr, 3);
parse = abUpdateParse(parse, exileFromGraveStr);
String description = splitStr.length > 2 ? splitStr[2] : null;
costParts.add(new CostExile(splitStr[0], splitStr[1], description, Constant.Zone.Graveyard));
}
while (parse.contains(exileFromTopStr)) {
String[] splitStr = abCostParse(parse, exileFromTopStr, 3);
parse = abUpdateParse(parse, exileFromTopStr);
String description = splitStr.length > 2 ? splitStr[2] : null;
costParts.add(new CostExile(splitStr[0], splitStr[1], description, Constant.Zone.Library));
}
while (parse.contains(returnStr)) {
String[] splitStr = abCostParse(parse, returnStr, 3);
parse = abUpdateParse(parse, returnStr);
String description = splitStr.length > 2 ? splitStr[2] : null;
costParts.add(new CostReturn(splitStr[0], splitStr[1], description));
}
// These won't show up with multiples
if (parse.contains("Untap")) {
parse = parse.replace("Untap", "").trim();
costParts.add(0, new CostUntap());
}
if (parse.contains("Q")) {
parse = parse.replace("Q", "").trim();
costParts.add(0, new CostUntap());
}
if (parse.contains("T")) {
tapCost = true;
parse = parse.replace("T", "").trim();
costParts.add(0, new CostTap());
}
String stripXCost = parse.replaceAll("X", "");
int amountX = parse.length() - stripXCost.length();
String mana = stripXCost.trim();
if (mana.equals(""))
mana = "0";
if (amountX > 0 || !mana.equals("0"))
costParts.add(0, new CostMana(mana, amountX));
}
/**
* <p>abCostParse.</p>
*
* @param parse a {@link java.lang.String} object.
* @param subkey a {@link java.lang.String} object.
* @param numParse a int.
* @return an array of {@link java.lang.String} objects.
*/
private String[] abCostParse(String parse, String subkey, int numParse) {
int startPos = parse.indexOf(subkey);
int endPos = parse.indexOf(">", startPos);
String str = parse.substring(startPos, endPos);
str = str.replace(subkey, "");
String[] splitStr = str.split("/", numParse);
return splitStr;
}
/**
* <p>abUpdateParse.</p>
*
* @param parse a {@link java.lang.String} object.
* @param subkey a {@link java.lang.String} object.
* @return a {@link java.lang.String} object.
*/
private String abUpdateParse(String parse, String subkey) {
int startPos = parse.indexOf(subkey);
int endPos = parse.indexOf(">", startPos);
String str = parse.substring(startPos, endPos + 1);
return parse.replace(str, "").trim();
}
/**
* <p>changeCost.</p>
*
* @param sa a {@link forge.card.spellability.SpellAbility} object.
*/
public void changeCost(SpellAbility sa) {
// TODO: Change where ChangeCost happens
for(CostPart part : costParts){
if (part instanceof CostMana){
CostMana costMana = (CostMana)part;
if (getTotalMana() != "0") { // 11/15/10 use getTotalMana() to account for X reduction
String mana = getTotalMana();
costMana.setAdjustedMana(AllZone.getGameAction().getSpellCostChange(sa, new ManaCost(mana)).toString());
}
}
}
}
/**
* <p>refundPaidCost.</p>
*
* @param source a {@link forge.Card} object.
*/
public void refundPaidCost(Card source) {
// prereq: isUndoable is called first
for(CostPart part : costParts)
part.refund(source);
}
/**
* <p>isUndoable.</p>
*
* @return a boolean.
*/
public boolean isUndoable() {
for(CostPart part : costParts)
if (!part.isUndoable())
return false;
return true;
}
/**
* <p>isReusuableResource.</p>
*
* @return a boolean.
*/
public boolean isReusuableResource() {
for(CostPart part : costParts)
if (!part.isReusable())
return false;
return isAbility;
}
/**
* <p>toString.</p>
*
* @return a {@link java.lang.String} object.
*/
public String toString() {
if (isAbility)
return abilityToString();
else
return spellToString(true);
}
// maybe add a conversion method that turns the amounts into words 1=a(n), 2=two etc.
/**
* <p>toStringAlt.</p>
*
* @return a {@link java.lang.String} object.
*/
public String toStringAlt() {
return spellToString(false);
}
/**
* <p>spellToString.</p>
*
* @param bFlag a boolean.
* @return a {@link java.lang.String} object.
*/
private String spellToString(boolean bFlag) {
StringBuilder cost = new StringBuilder();
boolean first = true;
if (bFlag)
cost.append("As an additional cost to cast ").append(name).append(", ");
else{
// usually no additional mana cost for spells
// only three Alliances cards have additional mana costs, but they are basically kicker/multikicker
/*
if (!getTotalMana().equals("0")) {
cost.append("pay ").append(getTotalMana());
first = false;
}
*/
}
for(CostPart part : costParts){
if (part instanceof CostMana)
continue;
if (!first)
cost.append("and ");
cost.append(part.toString()).append(" ");
first = false;
}
if (first)
return "";
if (bFlag)
cost.append(".").append("\n");
return cost.toString();
}
/**
* <p>abilityToString.</p>
*
* @return a {@link java.lang.String} object.
*/
private String abilityToString() {
StringBuilder cost = new StringBuilder();
boolean first = true;
for(CostPart part : costParts){
if (!first)
cost.append(", ");
cost.append(part.toString());
first = false;
}
if (first) // No costs, append 0
cost.append("0");
cost.append(": ");
return cost.toString();
}
// TODO: If a Cost needs to pay more than 10 of something, fill this array as appropriate
/** Constant <code>numNames="{zero, a, two, three, four, five, six, "{trunked}</code> */
private static final String[] numNames = {"zero", "a", "two", "three", "four", "five", "six", "seven", "eight", "nine", "ten"};
/** Constant <code>vowelPattern</code> */
private static final Pattern vowelPattern = Pattern.compile("^[aeiou]", Pattern.CASE_INSENSITIVE);
public static String convertAmountTypeToWords(Integer i, String amount, String type){
if (i == null)
return convertAmountTypeToWords(amount, type);
return convertIntAndTypeToWords(i.intValue(), type);
}
/**
* <p>convertIntAndTypeToWords.</p>
*
* @param i a int.
* @param type a {@link java.lang.String} object.
* @return a {@link java.lang.String} object.
*/
public static String convertIntAndTypeToWords(int i, String type) {
StringBuilder sb = new StringBuilder();
if (i >= numNames.length) {
sb.append(i);
} else if (1 == i && vowelPattern.matcher(type).find())
sb.append("an");
else
sb.append(numNames[i]);
sb.append(" ");
sb.append(type);
if (1 != i)
sb.append("s");
return sb.toString();
}
public static String convertAmountTypeToWords(String amount, String type) {
StringBuilder sb = new StringBuilder();
sb.append(amount);
sb.append(" ");
sb.append(type);
return sb.toString();
}
}

View File

@@ -0,0 +1,190 @@
package forge.card.cost;
import forge.AllZone;
import forge.AllZoneUtil;
import forge.Card;
import forge.CardList;
import forge.CardListUtil;
import forge.Constant;
import forge.Player;
import forge.card.abilityFactory.AbilityFactory;
import forge.card.spellability.SpellAbility;
public class CostDiscard extends CostPartWithList {
// Discard<Num/Type{/TypeDescription}>
public CostDiscard(String amount, String type, String description){
this.amount = amount;
this.type = type;
this.typeDescription = description;
}
@Override
public String toString() {
StringBuilder sb = new StringBuilder();
sb.append("Discard");
Integer i = convertAmount();
if (getThis()) {
sb.append(" ").append(type);
}
else if (type.equals("Hand")) {
sb.append(" your hand");
}
else if (type.equals("LastDrawn")) {
sb.append(" last drawn card");
}
else {
StringBuilder desc = new StringBuilder();
if (type.equals("Card") || type.equals("Random"))
desc.append("Card");
else
desc.append(typeDescription == null ? type : typeDescription).append(" card");
sb.append(Cost.convertAmountTypeToWords(i, amount, desc.toString()));
if (type.equals("Random"))
sb.append(" at random");
}
return sb.toString();
}
@Override
public void refund(Card source) {
// TODO Auto-generated method stub
}
@Override
public boolean canPay(SpellAbility ability, Card source, Player activator, Cost cost) {
CardList handList = AllZoneUtil.getPlayerHand(activator);
String type = getType();
Integer amount = convertAmount();
if (getThis()) {
if (!AllZone.getZone(source).is(Constant.Zone.Hand))
return false;
} else if (type.equals("Hand")) {
// this will always work
} else if (type.equals("LastDrawn")) {
Card c = activator.getLastDrawnCard();
return handList.contains(c);
} else {
if (!type.equals("Random")) {
handList = handList.getValidCards(type.split(";"), activator, source);
}
if (amount != null && amount > handList.size()) {
// not enough cards in hand to pay
return false;
}
}
return true;
}
@Override
public void payAI(SpellAbility ability, Card source, Cost_Payment payment) {
Player activator = ability.getActivatingPlayer();
for (Card c : list)
activator.discard(c, ability);
}
@Override
public boolean payHuman(SpellAbility ability, Card source, Cost_Payment payment) {
Player activator = ability.getActivatingPlayer();
CardList handList = AllZoneUtil.getPlayerHand(activator);
String discType = getType();
String amount = getAmount();
if (getThis()) {
activator.discard(source, ability);
payment.setPaidManaPart(this, true);
} else if (discType.equals("Hand")) {
activator.discardHand(ability);
payment.setPaidManaPart(this, true);
} else if (discType.equals("LastDrawn")) {
if (handList.contains(activator.getLastDrawnCard())) {
activator.discard(activator.getLastDrawnCard(), ability);
payment.setPaidManaPart(this, true);
}
} else {
Integer c = convertAmount();
if (discType.equals("Random")) {
if (c == null){
String sVar = source.getSVar(amount);
// Generalize this
if (sVar.equals("XChoice")){
c = CostUtil.chooseXValue(source, handList.size());
}
else{
c = AbilityFactory.calculateAmount(source, amount, ability);
}
}
activator.discardRandom(c, ability);
payment.setPaidManaPart(this, true);
} else {
String validType[] = discType.split(";");
handList = handList.getValidCards(validType, activator, ability.getSourceCard());
if (c == null){
String sVar = source.getSVar(amount);
// Generalize this
if (sVar.equals("XChoice")){
c = CostUtil.chooseXValue(source, handList.size());
}
else{
c = AbilityFactory.calculateAmount(source, amount, ability);
}
}
CostUtil.setInput(Cost_Input.input_discardCost(discType, handList, ability, payment, this, c));
return false;
}
}
return true;
}
@Override
public boolean decideAIPayment(SpellAbility ability, Card source, Cost_Payment payment) {
String type = getType();
Player activator = ability.getActivatingPlayer();
CardList hand = AllZoneUtil.getPlayerHand(activator);
resetList();
if (type.equals("LastDrawn")){
if (!hand.contains(activator.getLastDrawnCard()))
return false;
list.add(activator.getLastDrawnCard());
}
else if (getThis()){
if (!hand.contains(source))
return false;
list.add(source);
}
else if (type.equals("Hand")){
list.addAll(hand);
}
else{
Integer c = convertAmount();
if (c == null){
c = AbilityFactory.calculateAmount(source, amount, ability);
}
if (type.equals("Random")){
list = CardListUtil.getRandomSubList(hand, c);
}
else{
list = AllZone.getGameAction().AI_discardNumType(c, type.split(";"), ability);
}
}
return list != null;
}
}

View File

@@ -0,0 +1,127 @@
package forge.card.cost;
import forge.AllZone;
import forge.AllZoneUtil;
import forge.Card;
import forge.CardList;
import forge.ComputerUtil;
import forge.Constant;
import forge.Player;
import forge.PlayerZone;
import forge.card.abilityFactory.AbilityFactory;
import forge.card.spellability.SpellAbility;
public class CostExile extends CostPartWithList {
//Exile<Num/Type{/TypeDescription}>
//ExileFromHand<Num/Type{/TypeDescription}>
//ExileFromGraveyard<Num/Type{/TypeDescription}>
//ExileFromLibrary<Num/Type{/TypeDescription}>
private String from = Constant.Zone.Battlefield;
public String getFrom() {
return from;
}
public CostExile(String amount, String type, String description, String from){
this.amount = amount;
this.type = type;
this.typeDescription = description;
if (from != null)
this.from = from;
}
@Override
public String toString() {
StringBuilder sb = new StringBuilder();
sb.append("Exile ");
if (getThis()) {
sb.append(type);
}
else{
Integer i = convertAmount();
String desc = typeDescription == null ? type : typeDescription;
sb.append(Cost.convertAmountTypeToWords(i, amount, desc));
}
if (from.equals("Battlefield")){
if (!getThis())
sb.append(" you control");
}
else{
sb.append(" from your ").append(from);
}
return sb.toString();
}
@Override
public void refund(Card source) {
// TODO Auto-generated method stub
}
@Override
public boolean canPay(SpellAbility ability, Card source, Player activator, Cost cost) {
PlayerZone zone = AllZone.getZone(getFrom(), activator);
if (!getThis()) {
CardList typeList = AllZoneUtil.getCardsInZone(zone);
typeList = typeList.getValidCards(getType().split(";"), activator, source);
Integer amount = convertAmount();
if (amount != null && typeList.size() < amount)
return false;
} else if (!AllZoneUtil.isCardInZone(zone, source))
return false;
return true;
}
@Override
public void payAI(SpellAbility ability, Card source, Cost_Payment payment) {
for (Card c : list)
AllZone.getGameAction().exile(c);
}
@Override
public boolean payHuman(SpellAbility ability, Card source, Cost_Payment payment) {
String amount = getAmount();
Integer c = convertAmount();
CardList list = AllZoneUtil.getCardsInZone(getFrom(), ability.getActivatingPlayer());
if (c == null){
String sVar = source.getSVar(amount);
// Generalize this
if (sVar.equals("XChoice")){
c = CostUtil.chooseXValue(source, list.size());
}
else{
c = AbilityFactory.calculateAmount(source, amount, ability);
}
}
if (getThis())
CostUtil.setInput(Cost_Input.exileThis(ability, payment, this));
else
CostUtil.setInput(Cost_Input.exileType(ability, this, getType(), payment, c));
return false;
}
@Override
public boolean decideAIPayment(SpellAbility ability, Card source, Cost_Payment payment) {
resetList();
if (getThis())
list.add(source);
else{
Integer c = convertAmount();
if (c == null){
c = AbilityFactory.calculateAmount(source, amount, ability);
}
list = ComputerUtil.chooseExileFrom(getFrom(), getType(), source, ability.getTargetCard(), c);
if (list == null)
return false;
}
return true;
}
}

View File

@@ -0,0 +1,104 @@
package forge.card.cost;
import com.google.common.base.Strings;
import forge.Card;
import forge.ComputerUtil;
import forge.Player;
import forge.card.abilityFactory.AbilityFactory;
import forge.card.spellability.SpellAbility;
public class CostMana extends CostPart {
//"Leftover"
private String mana = "";
private int amountX = 0;
private String adjustedMana = "";
public String getMana() {
// Only used for Human to pay for non-X cost first
return mana;
}
public void setMana(String sCost) {
mana = sCost;
}
public boolean hasNoXManaCost() {
return amountX == 0;
}
public int getXMana() {
return amountX;
}
public void setXMana(int xCost) {
amountX = xCost;
}
public String getAdjustedMana() {
return adjustedMana;
}
public void setAdjustedMana(String adjustedMana) {
this.adjustedMana = adjustedMana;
}
public CostMana(String mana, int amount){
this.mana = mana.trim();
this.amountX = amount;
this.isUndoable = true;
this.isReusable = true;
}
@Override
public String toString() {
StringBuilder sb = new StringBuilder();
sb.append(Strings.repeat("X ", amountX));
if (!mana.equals("0"))
sb.append(mana);
return sb.toString().trim();
}
@Override
public void refund(Card source) {
// TODO Auto-generated method stub
}
@Override
public boolean canPay(SpellAbility ability, Card source, Player activator, Cost cost) {
// For now, this will always return true. But this should probably be checked at some point
return true;
}
@Override
public void payAI(SpellAbility ability, Card source, Cost_Payment payment) {
ComputerUtil.payManaCost(ability);
}
@Override
public boolean payHuman(SpellAbility ability, Card source, Cost_Payment payment) {
int manaToAdd = 0;
if (!hasNoXManaCost()) {
// if X cost is a defined value, other than xPaid
if (!source.getSVar("X").equals("Count$xPaid")) {
// this currently only works for things about Targeted object
manaToAdd = AbilityFactory.calculateAmount(source, "X", ability) * getXMana();
}
}
if (!getMana().equals("0") || manaToAdd > 0)
CostUtil.setInput(Cost_Input.input_payMana(ability, payment, this, manaToAdd));
else if (getXMana() > 0)
CostUtil.setInput(Cost_Input.input_payXMana(ability, payment, this, getXMana()));
// We return false here because the Inputs set above should recall payment.payCosts()
return false;
}
@Override
public boolean decideAIPayment(SpellAbility ability, Card source, Cost_Payment payment) {
return true;
}
}

View File

@@ -0,0 +1,68 @@
package forge.card.cost;
import forge.Card;
import forge.Player;
import forge.card.spellability.SpellAbility;
public abstract class CostPart {
protected boolean isReusable = false;
protected boolean isUndoable = false;
protected boolean optional = false;
protected String optionalType = null;
protected String amount = "1";
protected String type = "Card";
protected String typeDescription = null;
public String getAmount() {
return amount;
}
public String getType() {
return type;
}
public boolean getThis() {
return type.equals("CARDNAME");
}
public String getTypeDescription() {
return typeDescription;
}
public String getDescriptiveType(){
return typeDescription == null ? type : typeDescription;
}
public boolean isReusable(){
return isReusable;
}
public boolean isUndoable(){
return isUndoable;
}
public String getOptionalType() {
return optionalType;
}
public void setOptionalType(String optionalType) {
this.optionalType = optionalType;
}
public Integer convertAmount(){
Integer i = null;
try{
i = Integer.parseInt(amount);
}catch(NumberFormatException e){}
return i;
}
public abstract boolean canPay(SpellAbility ability, Card source, Player activator, Cost cost);
public abstract boolean decideAIPayment(SpellAbility ability, Card source, Cost_Payment payment);
public abstract void payAI(SpellAbility ability, Card source, Cost_Payment payment);
public abstract boolean payHuman(SpellAbility ability, Card source, Cost_Payment payment);
public abstract String toString();
public abstract void refund(Card source);
}

View File

@@ -0,0 +1,12 @@
package forge.card.cost;
import forge.Card;
import forge.CardList;
public abstract class CostPartWithList extends CostPart {
protected CardList list = null;
public CardList getList() { return list; }
public void setList(CardList setList) { list = setList; }
public void resetList() { list = new CardList(); }
public void addToList(Card c) { list.add(c); }
}

View File

@@ -0,0 +1,109 @@
package forge.card.cost;
import forge.AllZone;
import forge.Card;
import forge.GameActionUtil;
import forge.Player;
import forge.card.abilityFactory.AbilityFactory;
import forge.card.spellability.SpellAbility;
public class CostPayLife extends CostPart {
private int lastPaidAmount = 0;
public int getLastPaidAmount(){
return lastPaidAmount;
}
public void setLastPaidAmount(int paidAmount){
lastPaidAmount = paidAmount;
}
public CostPayLife(String amount){
this.amount = amount;
}
@Override
public String toString() {
StringBuilder sb = new StringBuilder();
sb.append("Pay ").append(amount).append(" Life");
return sb.toString();
}
@Override
public void refund(Card source) {
// Really should be activating player
source.getController().payLife(lastPaidAmount * -1, null);
}
@Override
public boolean canPay(SpellAbility ability, Card source, Player activator, Cost cost) {
Integer amount = convertAmount();
if (amount != null && !activator.canPayLife(amount)) {
return false;
}
return true;
}
@Override
public void payAI(SpellAbility ability, Card source, Cost_Payment payment) {
AllZone.getComputerPlayer().payLife(getLastPaidAmount(), null);
}
@Override
public boolean payHuman(SpellAbility ability, Card source, Cost_Payment payment) {
String amount = getAmount();
int life = ability.getActivatingPlayer().getLife();
Integer c = convertAmount();
if (c == null){
String sVar = source.getSVar(amount);
// Generalize this
if (sVar.equals("XChoice")){
c = CostUtil.chooseXValue(source, life);
}
else{
c = AbilityFactory.calculateAmount(source, amount, ability);
}
}
StringBuilder sb = new StringBuilder();
sb.append(source.getName()).append(" - Pay ").append(c).append(" Life?");
if (GameActionUtil.showYesNoDialog(source, sb.toString())) {
AllZone.getHumanPlayer().payLife(c, null);
setLastPaidAmount(c);
payment.setPaidManaPart(this, true);
} else {
payment.setCancel(true);
payment.getRequirements().finishPaying();
return false;
}
return true;
}
@Override
public boolean decideAIPayment(SpellAbility ability, Card source, Cost_Payment payment) {
Player activator = ability.getActivatingPlayer();
Integer c = convertAmount();
if (c == null){
String sVar = source.getSVar(amount);
// Generalize this
if (sVar.equals("XChoice")){
// This decision should be locked in the AF and be calculable at this state
//c = chooseXValue(life);
// Figure out what to do here
}
else{
c = AbilityFactory.calculateAmount(source, amount, ability);
}
}
if (!activator.canPayLife(c)){
return false;
}
setLastPaidAmount(c);
return true;
}
}

View File

@@ -0,0 +1,80 @@
package forge.card.cost;
import forge.Card;
import forge.Counters;
import forge.Player;
import forge.card.abilityFactory.AbilityFactory;
import forge.card.spellability.SpellAbility;
public class CostPutCounter extends CostPart {
// Put Counter doesn't really have a "Valid" portion of the cost
private Counters counter;
private int lastPaidAmount = 0;
public Counters getCounter() {
return counter;
}
public void setLastPaidAmount(int paidAmount){
lastPaidAmount = paidAmount;
}
public CostPutCounter(String amount, Counters counter){
this.type = "CARDNAME";
isReusable = true;
this.amount = amount;
this.counter = counter;
}
@Override
public String toString() {
StringBuilder sb = new StringBuilder();
if (counter.getName().equals("Loyalty"))
sb.append("+").append(amount);
else {
sb.append("Put ");
Integer i = convertAmount();
sb.append(Cost.convertAmountTypeToWords(i, amount, counter.getName()));
sb.append(" on ").append(type);
}
return sb.toString();
}
@Override
public void refund(Card source) {
source.subtractCounter(counter, lastPaidAmount);
}
@Override
public boolean canPay(SpellAbility ability, Card source, Player activator, Cost cost) {
// PutCounter can always be paid as a Cost
return true;
}
@Override
public void payAI(SpellAbility ability, Card source, Cost_Payment payment) {
Integer c = convertAmount();
if (c == null){
c = AbilityFactory.calculateAmount(source, amount, ability);
}
source.addCounterFromNonEffect(getCounter(), c);
}
@Override
public boolean payHuman(SpellAbility ability, Card source, Cost_Payment payment) {
Integer c = convertAmount();
if (c == null){
c = AbilityFactory.calculateAmount(source, amount, ability);
}
source.addCounterFromNonEffect(getCounter(), c);
payment.setPaidManaPart(this, true);
return true;
}
@Override
public boolean decideAIPayment(SpellAbility ability, Card source, Cost_Payment payment) {
return true;
}
}

View File

@@ -0,0 +1,126 @@
package forge.card.cost;
import forge.Card;
import forge.Counters;
import forge.Player;
import forge.card.abilityFactory.AbilityFactory;
import forge.card.spellability.SpellAbility;
public class CostRemoveCounter extends CostPart {
// SubCounter<Num/Counter/{Type/TypeDescription}>
private Counters counter;
private int lastPaidAmount = 0;
public Counters getCounter() {
return counter;
}
public void setLastPaidAmount(int paidAmount){
lastPaidAmount = paidAmount;
}
public CostRemoveCounter(String amount, Counters counter, String type, String description){
isReusable = true;
this.amount = amount;
this.counter = counter;
if (type != null)
this.type = type;
else
this.type = "CARDNAME";
this.typeDescription = description;
}
@Override
public String toString() {
StringBuilder sb = new StringBuilder();
if (counter.getName().equals("Loyalty"))
sb.append("-").append(amount);
else {
sb.append("Remove ");
Integer i = convertAmount();
sb.append(Cost.convertAmountTypeToWords(i, amount, counter.getName()));
sb.append(" from ").append(typeDescription == null ? type : typeDescription);
}
return sb.toString();
}
@Override
public void refund(Card source) {
source.addCounterFromNonEffect(counter, lastPaidAmount);
}
@Override
public boolean canPay(SpellAbility ability, Card source, Player activator, Cost cost) {
Counters c = getCounter();
Integer amount = convertAmount();
if (amount != null && source.getCounters(c) - amount < 0) {
return false;
}
return true;
}
@Override
public void payAI(SpellAbility ability, Card source, Cost_Payment payment) {
Integer c = convertAmount();
if (c == null){
c = AbilityFactory.calculateAmount(source, amount, ability);
}
source.subtractCounter(getCounter(), c);
}
@Override
public boolean payHuman(SpellAbility ability, Card source, Cost_Payment payment) {
String amount = getAmount();
Counters type = getCounter();
Integer c = convertAmount();
int maxCounters = source.getCounters(type);
if (amount.equals("All")){
c = maxCounters;
}
else{
if (c == null){
String sVar = source.getSVar(amount);
// Generalize this
if (sVar.equals("XChoice")){
c = CostUtil.chooseXValue(source, maxCounters);
}
else{
c = AbilityFactory.calculateAmount(source, amount, ability);
}
}
}
if (maxCounters >= c) {
source.setSVar("CostCountersRemoved", "Number$"+Integer.toString(c));
source.subtractCounter(type, c);
setLastPaidAmount(c);
payment.setPaidManaPart(this, true);
} else {
payment.setCancel(true);
payment.getRequirements().finishPaying();
return false;
}
return true;
}
@Override
public boolean decideAIPayment(SpellAbility ability, Card source, Cost_Payment payment) {
Integer c = convertAmount();
if (c == null){
c = AbilityFactory.calculateAmount(source, amount, ability);
}
if (c > source.getCounters(getCounter())) {
System.out.println("Not enough " + getCounter() + " on " + source.getName());
return false;
}
return true;
}
}

View File

@@ -0,0 +1,113 @@
package forge.card.cost;
import forge.AllZone;
import forge.AllZoneUtil;
import forge.Card;
import forge.CardList;
import forge.ComputerUtil;
import forge.Player;
import forge.card.abilityFactory.AbilityFactory;
import forge.card.spellability.SpellAbility;
public class CostReturn extends CostPartWithList {
// Return<Num/Type{/TypeDescription}>
public CostReturn(String amount, String type, String description){
this.amount = amount;
this.type = type;
this.typeDescription = description;
}
@Override
public String toString() {
StringBuilder sb = new StringBuilder();
sb.append("Return ");
Integer i = convertAmount();
String pronoun = "its";
if (getThis())
sb.append(type);
else {
String desc = typeDescription == null ? type : typeDescription;
if (i != null){
sb.append(Cost.convertIntAndTypeToWords(i, desc));
if (i > 1)
pronoun = "their";
}
else
sb.append(Cost.convertAmountTypeToWords(amount, desc));
sb.append(" you control");
}
sb.append(" to ").append(pronoun).append(" owner's hand");
return sb.toString();
}
@Override
public void refund(Card source) {
// TODO Auto-generated method stub
}
@Override
public boolean canPay(SpellAbility ability, Card source, Player activator, Cost cost) {
if (!getThis()) {
CardList typeList = AllZoneUtil.getPlayerCardsInPlay(activator);
typeList = typeList.getValidCards(getType().split(";"), activator, source);
Integer amount = convertAmount();
if (amount != null && typeList.size() < amount)
return false;
} else if (!AllZoneUtil.isCardInPlay(source))
return false;
return true;
}
@Override
public void payAI(SpellAbility ability, Card source, Cost_Payment payment) {
for (Card c : list)
AllZone.getGameAction().moveToHand(c);
}
@Override
public boolean payHuman(SpellAbility ability, Card source, Cost_Payment payment) {
String amount = getAmount();
Integer c = convertAmount();
Player activator = ability.getActivatingPlayer();
CardList list = AllZoneUtil.getPlayerCardsInPlay(activator);
if (c == null) {
String sVar = source.getSVar(amount);
// Generalize this
if (sVar.equals("XChoice")) {
c = CostUtil.chooseXValue(source, list.size());
} else {
c = AbilityFactory.calculateAmount(source, amount, ability);
}
}
if (getThis())
CostUtil.setInput(Cost_Input.returnThis(ability, payment, this));
else
CostUtil.setInput(Cost_Input.returnType(ability, getType(), payment, this, c));
return false;
}
@Override
public boolean decideAIPayment(SpellAbility ability, Card source, Cost_Payment payment) {
resetList();
if (getThis())
list.add(source);
else{
Integer c = convertAmount();
if (c == null){
c = AbilityFactory.calculateAmount(source, amount, ability);
}
list = ComputerUtil.chooseReturnType(getType(), source, ability.getTargetCard(), c);
if (list == null)
return false;
}
return true;
}
}

View File

@@ -0,0 +1,132 @@
package forge.card.cost;
import forge.AllZone;
import forge.AllZoneUtil;
import forge.Card;
import forge.CardList;
import forge.ComputerUtil;
import forge.Player;
import forge.card.abilityFactory.AbilityFactory;
import forge.card.spellability.SpellAbility;
public class CostSacrifice extends CostPartWithList {
public CostSacrifice(String amount, String type, String description){
this.amount = amount;
this.type = type;
this.typeDescription = description;
}
@Override
public String toString() {
StringBuilder sb = new StringBuilder();
sb.append("Sacrifice ");
Integer i = convertAmount();
if (getThis())
sb.append(type);
else{
String desc = typeDescription == null ? type : typeDescription;
if (i != null)
sb.append(Cost.convertIntAndTypeToWords(i, desc));
else
sb.append(Cost.convertAmountTypeToWords(amount, desc));
}
return sb.toString();
}
@Override
public void refund(Card source) {
// TODO Auto-generated method stub
}
@Override
public boolean canPay(SpellAbility ability, Card source, Player activator, Cost cost) {
// You can always sac all
if (!getThis()) {
CardList typeList = AllZoneUtil.getPlayerCardsInPlay(activator);
typeList = typeList.getValidCards(getType().split(";"), activator, source);
Integer amount = convertAmount();
if (amount != null && typeList.size() < amount)
return false;
// If amount is null, it's either "ALL" or "X"
// if X is defined, it needs to be calculated and checked, if X is choice, it can be Paid even if it's 0
} else if (!AllZoneUtil.isCardInPlay(source))
return false;
return true;
}
@Override
public void payAI(SpellAbility ability, Card source, Cost_Payment payment) {
for (Card c : list)
AllZone.getGameAction().sacrifice(c);
}
@Override
public boolean payHuman(SpellAbility ability, Card source, Cost_Payment payment) {
String amount = getAmount();
String type = getType();
Player activator = ability.getActivatingPlayer();
CardList list = AllZoneUtil.getPlayerCardsInPlay(activator);
list = list.getValidCards(type.split(";"), activator, source);
if (getThis()){
CostUtil.setInput(Cost_Input.sacrificeThis(ability, payment, this));
}
else if (amount.equals("All")){
Cost_Input.sacrificeAll(ability, payment, this, list);
return true;
}
else{
Integer c = convertAmount();
if (c == null){
String sVar = source.getSVar(amount);
// Generalize this
if (sVar.equals("XChoice")){
c = CostUtil.chooseXValue(source, list.size());
}
else{
c = AbilityFactory.calculateAmount(source, amount, ability);
}
}
CostUtil.setInput(Cost_Input.sacrificeFromList(ability, payment, this, list, c));
}
return false;
}
@Override
public boolean decideAIPayment(SpellAbility ability, Card source, Cost_Payment payment) {
resetList();
Player activator = ability.getActivatingPlayer();
if (getThis()){
list.add(source);
}
else if (amount.equals("All")) {
CardList typeList = AllZoneUtil.getPlayerCardsInPlay(activator);
typeList = typeList.getValidCards(type.split(","), activator, source);
// Does the AI want to use Sacrifice All?
return false;
} else{
Integer c = convertAmount();
if (c == null){
if (source.getSVar(amount).equals("XChoice")){
return false;
}
c = AbilityFactory.calculateAmount(source, amount, ability);
}
list = ComputerUtil.chooseSacrificeType(type, source, ability.getTargetCard(), c);
if (list == null)
return false;
}
return true;
}
}

View File

@@ -0,0 +1,47 @@
package forge.card.cost;
import forge.Card;
import forge.Player;
import forge.card.spellability.SpellAbility;
public class CostTap extends CostPart {
public CostTap(){
isReusable = true;
isUndoable = true;
}
@Override
public String toString() {
return "Tap";
}
@Override
public void refund(Card source) {
source.untap();
}
@Override
public boolean canPay(SpellAbility ability, Card source, Player activator, Cost cost) {
return !(source.isTapped() || source.isSick());
}
@Override
public void payAI(SpellAbility ability, Card source, Cost_Payment payment) {
source.tap();
}
@Override
public boolean payHuman(SpellAbility ability, Card source, Cost_Payment payment) {
//if (!canPay(ability, source, ability.getActivatingPlayer(), payment.getCost()))
// return false;
source.tap();
payment.setPaidManaPart(this, true);
return true;
}
@Override
public boolean decideAIPayment(SpellAbility ability, Card source, Cost_Payment payment) {
return true;
}
}

View File

@@ -0,0 +1,113 @@
package forge.card.cost;
import forge.AllZoneUtil;
import forge.Card;
import forge.CardList;
import forge.ComputerUtil;
import forge.Player;
import forge.card.abilityFactory.AbilityFactory;
import forge.card.spellability.SpellAbility;
public class CostTapType extends CostPartWithList {
public CostTapType(String amount, String type, String description){
list = new CardList();
isReusable = true;
this.amount = amount;
this.type = type;
this.typeDescription = description;
}
public String getDescription(){
return typeDescription == null ? type : typeDescription;
}
@Override
public String toString() {
StringBuilder sb = new StringBuilder();
sb.append("Tap ");
Integer i = convertAmount();
String desc = getDescription();
sb.append(Cost.convertAmountTypeToWords(i, amount, "untapped " + desc));
sb.append(" you control");
return sb.toString();
}
public void addToTappedList(Card c) {
list.add(c);
}
@Override
public void refund(Card source) {
for (Card c : list){
c.untap();
}
list.clear();
}
@Override
public boolean canPay(SpellAbility ability, Card source, Player activator, Cost cost) {
CardList typeList = AllZoneUtil.getPlayerCardsInPlay(activator);
typeList = typeList.getValidCards(getType().split(";"), activator, source);
if (cost.getTap())
typeList.remove(source);
typeList = typeList.filter(AllZoneUtil.untapped);
Integer amount = convertAmount();
if (typeList.size() == 0 || (amount != null && typeList.size() < amount))
return false;
return true;
}
@Override
public void payAI(SpellAbility ability, Card source, Cost_Payment payment) {
for (Card c : list)
c.tap();
}
@Override
public boolean payHuman(SpellAbility ability, Card source, Cost_Payment payment) {
CardList typeList = AllZoneUtil.getPlayerCardsInPlay(source.getController());
typeList = typeList.getValidCards(getType().split(";"), ability.getActivatingPlayer(), ability.getSourceCard());
String amount = getAmount();
Integer c = convertAmount();
if (c == null){
String sVar = source.getSVar(amount);
// Generalize this
if (sVar.equals("XChoice")){
c = CostUtil.chooseXValue(source, typeList.size());
}
else{
c = AbilityFactory.calculateAmount(source, amount, ability);
}
}
CostUtil.setInput(Cost_Input.input_tapXCost(this, typeList, ability, payment, c));
return false;
}
@Override
public boolean decideAIPayment(SpellAbility ability, Card source, Cost_Payment payment) {
boolean tap = payment.getCost().getTap();
Integer c = convertAmount();
if (c == null){
// Determine Amount
}
list = ComputerUtil.chooseTapType(getType(), source, tap, c);
if (list == null) {
System.out.println("Couldn't find a valid card to tap for: " + source.getName());
return false;
}
return true;
}
}

View File

@@ -0,0 +1,47 @@
package forge.card.cost;
import forge.Card;
import forge.Player;
import forge.card.spellability.SpellAbility;
public class CostUntap extends CostPart {
public CostUntap(){
isReusable = true;
isUndoable = true;
}
@Override
public String toString() {
return "Untap";
}
@Override
public void refund(Card source) {
source.tap();
}
@Override
public boolean canPay(SpellAbility ability, Card source, Player activator, Cost cost) {
return !(source.isUntapped() || source.isSick());
}
@Override
public void payAI(SpellAbility ability, Card source, Cost_Payment payment) {
source.untap();
}
@Override
public boolean payHuman(SpellAbility ability, Card source, Cost_Payment payment) {
//if (!canPay(ability, source, ability.getActivatingPlayer(), payment.getCost()))
// return false;
source.untap();
payment.setPaidManaPart(this, true);
return true;
}
@Override
public boolean decideAIPayment(SpellAbility ability, Card source, Cost_Payment payment) {
return true;
}
}

View File

@@ -0,0 +1,153 @@
package forge.card.cost;
import java.util.Random;
import forge.AllZone;
import forge.AllZoneUtil;
import forge.Card;
import forge.CardList;
import forge.ComputerUtil;
import forge.Counters;
import forge.card.abilityFactory.AbilityFactory;
import forge.card.spellability.SpellAbility;
import forge.gui.GuiUtils;
import forge.gui.input.Input;
public class CostUtil {
static private Random r = new Random();
static private double P1P1Percent = .1;
static private double OtherPercent = .25;
static public boolean checkSacrificeCost(Cost cost, Card source){
for(CostPart part : cost.getCostParts()){
if (part instanceof CostSacrifice){
CostSacrifice sac = (CostSacrifice)part;
String type = sac.getType();
CardList typeList = AllZoneUtil.getPlayerCardsInPlay(AllZone.getComputerPlayer());
typeList = typeList.getValidCards(type.split(","), source.getController(), source);
if (ComputerUtil.getCardPreference(source, "SacCost", typeList) == null)
return false;
}
}
return true;
}
static public boolean checkCreatureSacrificeCost(Cost cost, Card source){
for(CostPart part : cost.getCostParts()){
if (part instanceof CostSacrifice){
CostSacrifice sac = (CostSacrifice)part;
if (sac.getThis() && source.isCreature())
return false;
}
}
return true;
}
static public boolean checkLifeCost(Cost cost, Card source, int remainingLife){
for(CostPart part : cost.getCostParts()){
if (part instanceof CostPayLife){
CostPayLife payLife = (CostPayLife)part;
if (AllZone.getComputerPlayer().getLife() - payLife.convertAmount() < remainingLife)
return false;
}
}
return true;
}
static public boolean checkDiscardCost(Cost cost, Card source){
for(CostPart part : cost.getCostParts()){
if (part instanceof CostDiscard)
return false;
}
return true;
}
static public boolean checkRemoveCounterCost(Cost cost, Card source){
for(CostPart part : cost.getCostParts()){
if (part instanceof CostRemoveCounter){
CostRemoveCounter remCounter = (CostRemoveCounter)part;
// A card has a 25% chance per counter to be able to pass through here
// 4+ counters will always pass. 0 counters will never
Counters type = remCounter.getCounter();
double percent = type.name().equals("P1P1") ? P1P1Percent : OtherPercent;
int currentNum = source.getCounters(type);
double chance = percent * (currentNum / part.convertAmount());
if (chance <= r.nextFloat())
return false;
}
}
return true;
}
static public boolean checkAddM1M1CounterCost(Cost cost, Card source){
for(CostPart part : cost.getCostParts()){
if (part instanceof CostPutCounter){
CostPutCounter addCounter = (CostPutCounter)part;
Counters type = addCounter.getCounter();
if (type.equals(Counters.M1M1))
return false;
}
}
return true;
}
static public boolean hasDiscardHandCost(Cost cost){
for(CostPart part : cost.getCostParts()){
if (part instanceof CostDiscard){
CostDiscard disc = (CostDiscard)part;
if (disc.getType().equals("Hand"))
return true;
}
}
return false;
}
static public Integer determineAmount(CostPart part, Card source, SpellAbility ability, int maxChoice){
String amount = part.getAmount();
Integer c = part.convertAmount();
if (c == null){
String sVar = source.getSVar(amount);
// Generalize this
if (sVar.equals("XChoice")){
c = CostUtil.chooseXValue(source, maxChoice);
}
else{
c = AbilityFactory.calculateAmount(source, amount, ability);
}
}
return c;
}
static public int chooseXValue(Card card, int maxValue){
String chosen = card.getSVar("ChosenX");
if (chosen.length() > 0){
return AbilityFactory.calculateAmount(card, "ChosenX", null);
}
Integer[] choiceArray = new Integer[maxValue+1];
for(int i = 0; i < choiceArray.length; i++){
choiceArray[i] = i;
}
Object o = GuiUtils.getChoice(card.toString() + " - Choose a Value for X", choiceArray);
int chosenX = (Integer)o;
card.setSVar("ChosenX", "Number$"+Integer.toString(chosenX));
return chosenX;
}
/**
* <p>setInput.</p>
*
* @param in a {@link forge.gui.input.Input} object.
*/
static public void setInput(Input in) {
// Just a shortcut..
AllZone.getInputControl().setInput(in, true);
}
}

View File

@@ -0,0 +1,678 @@
package forge.card.cost;
import javax.swing.JOptionPane;
import forge.AllZone;
import forge.AllZoneUtil;
import forge.ButtonUtil;
import forge.Card;
import forge.CardList;
import forge.Constant;
import forge.Phase;
import forge.Player;
import forge.PlayerZone;
import forge.card.mana.ManaCost;
import forge.card.spellability.SpellAbility;
import forge.gui.input.Input;
import forge.gui.input.Input_PayManaCostUtil;
public class Cost_Input {
// ******************************************************************************
// *********** Inputs used by Cost_Payment below here ***************************
// ******************************************************************************
/**
* <p>input_payMana.</p>
*
* @param sa a {@link forge.card.spellability.SpellAbility} object.
* @param payment a {@link forge.card.cost.Cost_Payment} object.
* @param manaToAdd a int.
* @return a {@link forge.gui.input.Input} object.
*/
public static Input input_payMana(final SpellAbility sa, final Cost_Payment payment, final CostMana costMana, final int manaToAdd) {
final ManaCost manaCost;
if (Phase.getGameBegins() == 1) {
if (sa.getSourceCard().isCopiedSpell() && sa.isSpell()) {
manaCost = new ManaCost("0");
} else {
String mana = costMana.getMana();
manaCost = new ManaCost(mana);
manaCost.increaseColorlessMana(manaToAdd);
}
} else {
System.out.println("Is input_payMana ever called when the Game isn't in progress?");
manaCost = new ManaCost(sa.getManaCost());
}
Input payMana = new Input() {
private ManaCost mana = manaCost;
private static final long serialVersionUID = 3467312982164195091L;
private final String originalManaCost = costMana.getMana();
private int phyLifeToLose = 0;
private void resetManaCost() {
mana = new ManaCost(originalManaCost);
phyLifeToLose = 0;
}
@Override
public void selectCard(Card card, PlayerZone zone) {
// prevent cards from tapping themselves if ability is a tapability, although it should already be tapped
if (sa.getSourceCard().equals(card) && sa.isTapAbility()) {
return;
}
mana = Input_PayManaCostUtil.activateManaAbility(sa, card, mana);
if (mana.isPaid())
done();
else if (AllZone.getInputControl().getInput() == this)
showMessage();
}
@Override
public void selectPlayer(Player player) {
if (player.isHuman()) {
if (manaCost.payPhyrexian()) {
phyLifeToLose += 2;
}
showMessage();
}
}
private void done() {
Card source = sa.getSourceCard();
if (phyLifeToLose > 0)
AllZone.getHumanPlayer().payLife(phyLifeToLose, source);
source.setColorsPaid(mana.getColorsPaid());
source.setSunburstValue(mana.getSunburst());
resetManaCost();
stop();
if (costMana.hasNoXManaCost() || manaToAdd > 0){
payment.paidCost(costMana);
}
else{
source.setXManaCostPaid(0);
CostUtil.setInput(input_payXMana(sa, payment, costMana, costMana.getXMana()));
}
}
@Override
public void selectButtonCancel() {
stop();
resetManaCost();
payment.cancelCost();
AllZone.getHumanBattlefield().updateObservers();
}
@Override
public void showMessage() {
ButtonUtil.enableOnlyCancel();
String displayMana = mana.toString().replace("X", "").trim();
AllZone.getDisplay().showMessage("Pay Mana Cost: " + displayMana);
StringBuilder msg = new StringBuilder("Pay Mana Cost: " + displayMana);
if (phyLifeToLose > 0) {
msg.append(" (");
msg.append(phyLifeToLose);
msg.append(" life paid for phyrexian mana)");
}
if (mana.containsPhyrexianMana()) {
msg.append("\n(Click on your life total to pay life for phyrexian mana.)");
}
AllZone.getDisplay().showMessage(msg.toString());
if (mana.isPaid())
done();
}
};
return payMana;
}
/**
* <p>input_payXMana.</p>
* @param sa a {@link forge.card.spellability.SpellAbility} object.
* @param payment a {@link forge.card.cost.Cost_Payment} object.
* @param costMana TODO
* @param numX a int.
*
* @return a {@link forge.gui.input.Input} object.
*/
public static Input input_payXMana(final SpellAbility sa, final Cost_Payment payment, final CostMana costMana, final int numX) {
Input payX = new Input() {
private static final long serialVersionUID = -6900234444347364050L;
int xPaid = 0;
ManaCost manaCost = new ManaCost(Integer.toString(numX));
@Override
public void showMessage() {
if (manaCost.toString().equals(Integer.toString(numX))) // Can only cancel if partially paid an X value
ButtonUtil.enableAll();
else
ButtonUtil.enableOnlyCancel();
AllZone.getDisplay().showMessage("Pay X Mana Cost for " + sa.getSourceCard().getName() + "\n" + xPaid + " Paid so far.");
}
// selectCard
@Override
public void selectCard(Card card, PlayerZone zone) {
if (sa.getSourceCard().equals(card) && sa.isTapAbility()) {
// this really shouldn't happen but just in case
return;
}
manaCost = Input_PayManaCostUtil.activateManaAbility(sa, card, manaCost);
if (manaCost.isPaid()) {
manaCost = new ManaCost(Integer.toString(numX));
xPaid++;
}
if (AllZone.getInputControl().getInput() == this)
showMessage();
}
@Override
public void selectButtonCancel() {
stop();
payment.cancelCost();
AllZone.getHumanBattlefield().updateObservers();
}
@Override
public void selectButtonOK() {
stop();
payment.getCard().setXManaCostPaid(xPaid);
payment.paidCost(costMana);
}
};
return payX;
}
/**
* <p>input_discardCost.</p>
* @param discType a {@link java.lang.String} object.
* @param handList a {@link forge.CardList} object.
* @param sa a {@link forge.card.spellability.SpellAbility} object.
* @param payment a {@link forge.card.cost.Cost_Payment} object.
* @param part TODO
* @param nNeeded a int.
*
* @return a {@link forge.gui.input.Input} object.
*/
public static Input input_discardCost(final String discType, final CardList handList, SpellAbility sa, final Cost_Payment payment, final CostPart part, final int nNeeded) {
final SpellAbility sp = sa;
Input target = new Input() {
private static final long serialVersionUID = -329993322080934435L;
int nDiscard = 0;
@Override
public void showMessage() {
boolean any = discType.equals("Any") ? true : false;
if (AllZone.getHumanHand().size() == 0) stop();
StringBuilder type = new StringBuilder("");
if (any || !discType.equals("Card")) {
type.append(" ").append(discType);
}
StringBuilder sb = new StringBuilder();
sb.append("Select ");
if (any) {
sb.append("any ");
} else {
sb.append("a ").append(type.toString()).append(" ");
}
sb.append("card to discard.");
if (nNeeded > 1) {
sb.append(" You have ");
sb.append(nNeeded - nDiscard);
sb.append(" remaining.");
}
AllZone.getDisplay().showMessage(sb.toString());
ButtonUtil.enableOnlyCancel();
}
@Override
public void selectButtonCancel() {
cancel();
}
@Override
public void selectCard(Card card, PlayerZone zone) {
if (zone.is(Constant.Zone.Hand) && handList.contains(card)) {
// send in CardList for Typing
card.getController().discard(card, sp);
handList.remove(card);
nDiscard++;
//in case no more cards in hand
if (nDiscard == nNeeded)
done();
else if (AllZone.getHumanHand().size() == 0) // this really shouldn't happen
cancel();
else
showMessage();
}
}
public void cancel() {
stop();
payment.cancelCost();
}
public void done() {
stop();
payment.paidCost(part);
}
};
return target;
}//input_discard()
/**
* <p>sacrificeThis.</p>
*
* @param sa a {@link forge.card.spellability.SpellAbility} object.
* @param payment a {@link forge.card.cost.Cost_Payment} object.
* @param part TODO
* @return a {@link forge.gui.input.Input} object.
*/
public static Input sacrificeThis(final SpellAbility sa, final Cost_Payment payment, final CostPart part) {
Input target = new Input() {
private static final long serialVersionUID = 2685832214519141903L;
@Override
public void showMessage() {
Card card = sa.getSourceCard();
if (card.getController().isHuman() && AllZoneUtil.isCardInPlay(card)) {
StringBuilder sb = new StringBuilder();
sb.append(card.getName());
sb.append(" - Sacrifice?");
Object[] possibleValues = {"Yes", "No"};
Object choice = JOptionPane.showOptionDialog(null, sb.toString(), card.getName() + " - Cost",
JOptionPane.DEFAULT_OPTION, JOptionPane.INFORMATION_MESSAGE,
null, possibleValues, possibleValues[0]);
if (choice.equals(0)) {
payment.getAbility().addCostToHashList(card, "Sacrificed");
AllZone.getGameAction().sacrifice(card);
stop();
payment.paidCost(part);
} else {
stop();
payment.cancelCost();
}
}
}
};
return target;
}//input_sacrifice()
/**
* <p>sacrificeType.</p>
* @param sa a {@link forge.card.spellability.SpellAbility} object.
* @param payment a {@link forge.card.cost.Cost_Payment} object.
* @param part TODO
* @param typeList TODO
* @param num TODO
*
* @return a {@link forge.gui.input.Input} object.
*/
public static Input sacrificeFromList(final SpellAbility sa, final Cost_Payment payment, final CostSacrifice part, final CardList typeList, final int nNeeded) {
Input target = new Input() {
private static final long serialVersionUID = 2685832214519141903L;
private int nSacrifices = 0;
@Override
public void showMessage() {
StringBuilder msg = new StringBuilder("Sacrifice ");
int nLeft = nNeeded - nSacrifices;
msg.append(nLeft).append(" ");
msg.append(part.getDescriptiveType());
if (nLeft > 1) {
msg.append("s");
}
AllZone.getDisplay().showMessage(msg.toString());
ButtonUtil.enableOnlyCancel();
}
@Override
public void selectButtonCancel() {
cancel();
}
@Override
public void selectCard(Card card, PlayerZone zone) {
if (typeList.contains(card)) {
nSacrifices++;
payment.getAbility().addCostToHashList(card, "Sacrificed");
AllZone.getGameAction().sacrifice(card);
typeList.remove(card);
//in case nothing else to sacrifice
if (nSacrifices == nNeeded)
done();
else if (typeList.size() == 0) // this really shouldn't happen
cancel();
else
showMessage();
}
}
public void done() {
stop();
payment.paidCost(part);
}
public void cancel() {
stop();
payment.cancelCost();
}
};
return target;
}//sacrificeType()
/**
* <p>sacrificeAllType.</p>
*
* @param sa a {@link forge.card.spellability.SpellAbility} object.
* @param payment a {@link forge.card.cost.Cost_Payment} object.
* @param part TODO
* @param typeList TODO
*/
public static void sacrificeAll(final SpellAbility sa, final Cost_Payment payment, CostPart part, CardList typeList) {
// TODO Ask First
for (Card card : typeList) {
payment.getAbility().addCostToHashList(card, "Sacrificed");
AllZone.getGameAction().sacrifice(card);
}
payment.setPaidManaPart(part, true);
}
/**
* <p>exileThis.</p>
*
* @param sa a {@link forge.card.spellability.SpellAbility} object.
* @param payment a {@link forge.card.cost.Cost_Payment} object.
* @param costExile TODO
* @return a {@link forge.gui.input.Input} object.
*/
public static Input exileThis(final SpellAbility sa, final Cost_Payment payment, final CostExile part) {
Input target = new Input() {
private static final long serialVersionUID = 678668673002725001L;
@Override
public void showMessage() {
Card card = sa.getSourceCard();
if (sa.getActivatingPlayer().isHuman() && AllZoneUtil.isCardInZone(AllZone.getZone(part.getFrom(), sa.getActivatingPlayer()), card)) {
StringBuilder sb = new StringBuilder();
sb.append(card.getName());
sb.append(" - Exile?");
Object[] possibleValues = {"Yes", "No"};
Object choice = JOptionPane.showOptionDialog(null, sb.toString(), card.getName() + " - Cost",
JOptionPane.DEFAULT_OPTION, JOptionPane.INFORMATION_MESSAGE,
null, possibleValues, possibleValues[0]);
if (choice.equals(0)) {
payment.getAbility().addCostToHashList(card, "Exiled");
AllZone.getGameAction().exile(card);
stop();
payment.paidCost(part);
} else {
stop();
payment.cancelCost();
}
}
}
};
return target;
}//input_exile()
/**
* <p>exileType.</p>
*
* @param sa a {@link forge.card.spellability.SpellAbility} object.
* @param costExile TODO
* @param type a {@link java.lang.String} object.
* @param payment a {@link forge.card.cost.Cost_Payment} object.
* @return a {@link forge.gui.input.Input} object.
*/
public static Input exileType(final SpellAbility sa, final CostExile part, final String type, final Cost_Payment payment, final int nNeeded) {
Input target = new Input() {
private static final long serialVersionUID = 1403915758082824694L;
private CardList typeList;
private int nExiles = 0;
@Override
public void showMessage() {
StringBuilder msg = new StringBuilder("Exile ");
int nLeft = nNeeded - nExiles;
msg.append(nLeft).append(" ");
msg.append(type);
if (nLeft > 1) {
msg.append("s");
}
typeList = AllZoneUtil.getPlayerCardsInPlay(sa.getSourceCard().getController());
typeList = typeList.getValidCards(type.split(";"), sa.getActivatingPlayer(), sa.getSourceCard());
AllZone.getDisplay().showMessage(msg.toString());
ButtonUtil.enableOnlyCancel();
}
@Override
public void selectButtonCancel() {
cancel();
}
@Override
public void selectCard(Card card, PlayerZone zone) {
if (typeList.contains(card)) {
nExiles++;
payment.getAbility().addCostToHashList(card, "Exiled");
AllZone.getGameAction().exile(card);
typeList.remove(card);
//in case nothing else to exile
if (nExiles == nNeeded)
done();
else if (typeList.size() == 0) // this really shouldn't happen
cancel();
else
showMessage();
}
}
public void done() {
stop();
payment.paidCost(part);
}
public void cancel() {
stop();
payment.cancelCost();
}
};
return target;
}//exileType()
/**
* <p>input_tapXCost.</p>
*
* @param nCards a int.
* @param cardType a {@link java.lang.String} object.
* @param cardList a {@link forge.CardList} object.
* @param sa a {@link forge.card.spellability.SpellAbility} object.
* @param payment a {@link forge.card.cost.Cost_Payment} object.
* @return a {@link forge.gui.input.Input} object.
*/
public static Input input_tapXCost(final CostTapType tapType, final CardList cardList, SpellAbility sa, final Cost_Payment payment, final int nCards) {
Input target = new Input() {
private static final long serialVersionUID = 6438988130447851042L;
int nTapped = 0;
@Override
public void showMessage() {
if (cardList.size() == 0) stop();
int left = nCards - nTapped;
AllZone.getDisplay().showMessage("Select a " + tapType.getDescription() + " to tap (" + left + " left)");
ButtonUtil.enableOnlyCancel();
}
@Override
public void selectButtonCancel() {
cancel();
}
@Override
public void selectCard(Card card, PlayerZone zone) {
if (zone.is(Constant.Zone.Battlefield) && cardList.contains(card) && card.isUntapped()) {
// send in CardList for Typing
card.tap();
tapType.addToList(card);
cardList.remove(card);
payment.getAbility().addCostToHashList(card, "Tapped");
nTapped++;
if (nTapped == nCards)
done();
else if (cardList.size() == 0) // this really shouldn't happen
cancel();
else
showMessage();
}
}
public void cancel() {
stop();
payment.cancelCost();
}
public void done() {
stop();
payment.paidCost(tapType);
}
};
return target;
}//input_tapXCost()
/**
* <p>returnThis.</p>
*
* @param sa a {@link forge.card.spellability.SpellAbility} object.
* @param payment a {@link forge.card.cost.Cost_Payment} object.
* @param part TODO
* @return a {@link forge.gui.input.Input} object.
*/
public static Input returnThis(final SpellAbility sa, final Cost_Payment payment, final CostPart part) {
Input target = new Input() {
private static final long serialVersionUID = 2685832214519141903L;
@Override
public void showMessage() {
Card card = sa.getSourceCard();
if (card.getController().isHuman() && AllZoneUtil.isCardInPlay(card)) {
StringBuilder sb = new StringBuilder();
sb.append(card.getName());
sb.append(" - Return to Hand?");
Object[] possibleValues = {"Yes", "No"};
Object choice = JOptionPane.showOptionDialog(null, sb.toString(), card.getName() + " - Cost",
JOptionPane.DEFAULT_OPTION, JOptionPane.INFORMATION_MESSAGE,
null, possibleValues, possibleValues[0]);
if (choice.equals(0)) {
AllZone.getGameAction().moveToHand(card);
stop();
payment.paidCost(part);
} else {
stop();
payment.cancelCost();
}
}
}
};
return target;
}//input_sacrifice()
/**
* <p>returnType.</p>
*
* @param sa a {@link forge.card.spellability.SpellAbility} object.
* @param type a {@link java.lang.String} object.
* @param payment a {@link forge.card.cost.Cost_Payment} object.
* @param part TODO
* @return a {@link forge.gui.input.Input} object.
*/
public static Input returnType(final SpellAbility sa, final String type, final Cost_Payment payment, final CostPart part, final int nNeeded) {
Input target = new Input() {
private static final long serialVersionUID = 2685832214519141903L;
private CardList typeList;
private int nReturns = 0;
@Override
public void showMessage() {
StringBuilder msg = new StringBuilder("Return ");
int nLeft = nNeeded - nReturns;
msg.append(nLeft).append(" ");
msg.append(type);
if (nLeft > 1) {
msg.append("s");
}
typeList = AllZoneUtil.getPlayerCardsInPlay(sa.getSourceCard().getController());
typeList = typeList.getValidCards(type.split(";"), sa.getActivatingPlayer(), sa.getSourceCard());
AllZone.getDisplay().showMessage(msg.toString());
ButtonUtil.enableOnlyCancel();
}
@Override
public void selectButtonCancel() {
cancel();
}
@Override
public void selectCard(Card card, PlayerZone zone) {
if (typeList.contains(card)) {
nReturns++;
AllZone.getGameAction().moveToHand(card);
typeList.remove(card);
//in case nothing else to return
if (nReturns == nNeeded)
done();
else if (typeList.size() == 0) // this really shouldn't happen
cancel();
else
showMessage();
}
}
public void done() {
stop();
payment.paidCost(part);
}
public void cancel() {
stop();
payment.cancelCost();
}
};
return target;
}//returnType()
}

View File

@@ -0,0 +1,235 @@
package forge.card.cost;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;
import forge.AllZone;
import forge.Card;
import forge.Player;
import forge.card.spellability.SpellAbility;
import forge.card.spellability.SpellAbility_Requirements;
/**
* <p>Cost_Payment class.</p>
*
* @author Forge
* @version $Id$
*/
public class Cost_Payment {
private Cost cost = null;
private SpellAbility ability = null;
private Card card = null;
private SpellAbility_Requirements req = null;
private boolean bCancel = false;
private Map<CostPart, Boolean> paidCostParts = new HashMap<CostPart, Boolean>();
/**
* <p>Getter for the field <code>cost</code>.</p>
*
* @return a {@link forge.card.cost.Cost} object.
*/
public Cost getCost() {
return cost;
}
/**
* <p>Getter for the field <code>ability</code>.</p>
*
* @return a {@link forge.card.spellability.SpellAbility} object.
*/
public SpellAbility getAbility() {
return ability;
}
/**
* <p>Getter for the field <code>card</code>.</p>
*
* @return a {@link forge.Card} object.
*/
public Card getCard() {
return card;
}
/**
* <p>setRequirements.</p>
*
* @param reqs a {@link forge.card.spellability.SpellAbility_Requirements} object.
*/
public void setRequirements(SpellAbility_Requirements reqs) {
req = reqs;
}
public SpellAbility_Requirements getRequirements(){
return req;
}
/**
* <p>setCancel.</p>
*
* @param cancel a boolean.
*/
public void setCancel(boolean cancel) {
bCancel = cancel;
}
/**
* <p>isCanceled.</p>
*
* @return a boolean.
*/
public boolean isCanceled() {
return bCancel;
}
/**
* <p>Constructor for Cost_Payment.</p>
*
* @param cost a {@link forge.card.cost.Cost} object.
* @param abil a {@link forge.card.spellability.SpellAbility} object.
*/
public Cost_Payment(Cost cost, SpellAbility abil) {
this.cost = cost;
this.ability = abil;
card = abil.getSourceCard();
for(CostPart part : cost.getCostParts()){
paidCostParts.put(part, false);
}
}
/**
* <p>canPayAdditionalCosts.</p>
*
* @param cost a {@link forge.card.cost.Cost} object.
* @param ability a {@link forge.card.spellability.SpellAbility} object.
* @return a boolean.
*/
public static boolean canPayAdditionalCosts(Cost cost, SpellAbility ability) {
if (cost == null)
return true;
Player activator = ability.getActivatingPlayer();
final Card card = ability.getSourceCard();
for(CostPart part : cost.getCostParts()){
if (!part.canPay(ability, card, activator, cost))
return false;
}
return true;
}
public void setPaidManaPart(CostPart part, boolean bPaid){
paidCostParts.put(part, bPaid);
}
public void paidCost(CostPart part){
setPaidManaPart(part, true);
payCost();
}
public void cancelCost(){
setCancel(true);
req.finishPaying();
}
/**
* <p>payCost.</p>
*
* @return a boolean.
*/
public boolean payCost() {
// Nothing actually ever checks this return value, is it needed?
if (bCancel) {
req.finishPaying();
return false;
}
for(CostPart part : cost.getCostParts()){
// This portion of the cost is already paid for, keep moving
if (paidCostParts.get(part))
continue;
if (!part.payHuman(ability, card, this))
return false;
}
resetUndoList();
req.finishPaying();
return true;
}
/**
* <p>isAllPaid.</p>
*
* @return a boolean.
*/
public boolean isAllPaid() {
for(CostPart part : paidCostParts.keySet()){
if (!paidCostParts.get(part))
return false;
}
return true;
}
/**
* <p>resetUndoList.</p>
*/
public void resetUndoList() {
for(CostPart part : paidCostParts.keySet()){
if (part instanceof CostPartWithList){
((CostPartWithList)part).resetList();
}
}
}
/**
* <p>cancelPayment.</p>
*/
public void cancelPayment() {
for(CostPart part : paidCostParts.keySet()){
if (paidCostParts.get(part) && part.isUndoable())
part.refund(card);
}
// Move this to CostMana
AllZone.getManaPool().unpaid(ability, false);
}
/**
* <p>payComputerCosts.</p>
*
* @return a boolean.
*/
public boolean payComputerCosts() {
// canPayAdditionalCosts now Player Agnostic
// Just in case it wasn't set, but honestly it shouldn't have gotten here without being set
Player activator = AllZone.getComputerPlayer();
ability.setActivatingPlayer(activator);
Card source = ability.getSourceCard();
ArrayList<CostPart> parts = cost.getCostParts();
// Set all of the decisions before attempting to pay anything
for(CostPart part : parts){
if (!part.decideAIPayment(ability, source, this))
return false;
}
for(CostPart part : parts){
part.payAI(ability, ability.getSourceCard(), this);
}
return true;
}
/**
* <p>changeCost.</p>
*/
public void changeCost() {
cost.changeCost(ability);
}
}

View File

@@ -1,6 +1,8 @@
package forge.card.spellability; package forge.card.spellability;
import forge.*; import forge.*;
import forge.card.cost.Cost;
import forge.card.cost.Cost_Payment;
/** /**
@@ -27,7 +29,7 @@ abstract public class Ability_Activated extends SpellAbility implements java.io.
* <p>Constructor for Ability_Activated.</p> * <p>Constructor for Ability_Activated.</p>
* *
* @param sourceCard a {@link forge.Card} object. * @param sourceCard a {@link forge.Card} object.
* @param abCost a {@link forge.card.spellability.Cost} object. * @param abCost a {@link forge.card.cost.Cost} object.
* @param tgt a {@link forge.card.spellability.Target} object. * @param tgt a {@link forge.card.spellability.Target} object.
*/ */
public Ability_Activated(Card sourceCard, Cost abCost, Target tgt) { public Ability_Activated(Card sourceCard, Cost abCost, Target tgt) {

View File

@@ -4,6 +4,7 @@ import forge.AllZone;
import forge.AllZoneUtil; import forge.AllZoneUtil;
import forge.Card; import forge.Card;
import forge.Player; import forge.Player;
import forge.card.cost.Cost;
import forge.card.mana.ManaPool; import forge.card.mana.ManaPool;
import java.util.HashMap; import java.util.HashMap;
@@ -51,7 +52,7 @@ abstract public class Ability_Mana extends Ability_Activated implements java.io.
* <p>Constructor for Ability_Mana.</p> * <p>Constructor for Ability_Mana.</p>
* *
* @param sourceCard a {@link forge.Card} object. * @param sourceCard a {@link forge.Card} object.
* @param cost a {@link forge.card.spellability.Cost} object. * @param cost a {@link forge.card.cost.Cost} object.
* @param produced a {@link java.lang.String} object. * @param produced a {@link java.lang.String} object.
*/ */
public Ability_Mana(Card sourceCard, Cost cost, String produced) { public Ability_Mana(Card sourceCard, Cost cost, String produced) {
@@ -62,7 +63,7 @@ abstract public class Ability_Mana extends Ability_Activated implements java.io.
* <p>Constructor for Ability_Mana.</p> * <p>Constructor for Ability_Mana.</p>
* *
* @param sourceCard a {@link forge.Card} object. * @param sourceCard a {@link forge.Card} object.
* @param cost a {@link forge.card.spellability.Cost} object. * @param cost a {@link forge.card.cost.Cost} object.
* @param produced a {@link java.lang.String} object. * @param produced a {@link java.lang.String} object.
* @param num a int. * @param num a int.
*/ */
@@ -189,7 +190,7 @@ abstract public class Ability_Mana extends Ability_Activated implements java.io.
* @return a boolean. * @return a boolean.
*/ */
public boolean isSacrifice() { public boolean isSacrifice() {
return this.getPayCosts().getSacCost(); return payCosts.getSacCost();
} }
/** /**

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -1,6 +1,8 @@
package forge.card.spellability; package forge.card.spellability;
import forge.*; import forge.*;
import forge.card.cost.Cost;
import forge.card.cost.Cost_Payment;
import forge.error.ErrorViewer; import forge.error.ErrorViewer;
@@ -32,7 +34,7 @@ abstract public class Spell extends SpellAbility implements java.io.Serializable
* <p>Constructor for Spell.</p> * <p>Constructor for Spell.</p>
* *
* @param sourceCard a {@link forge.Card} object. * @param sourceCard a {@link forge.Card} object.
* @param abCost a {@link forge.card.spellability.Cost} object. * @param abCost a {@link forge.card.cost.Cost} object.
* @param abTgt a {@link forge.card.spellability.Target} object. * @param abTgt a {@link forge.card.spellability.Target} object.
*/ */
public Spell(Card sourceCard, Cost abCost, Target abTgt) { public Spell(Card sourceCard, Cost abCost, Target abTgt) {

View File

@@ -2,6 +2,7 @@ package forge.card.spellability;
import forge.*; import forge.*;
import forge.card.abilityFactory.AbilityFactory; import forge.card.abilityFactory.AbilityFactory;
import forge.card.cost.Cost;
import forge.card.mana.Mana; import forge.card.mana.Mana;
import forge.gui.input.Input; import forge.gui.input.Input;
@@ -505,7 +506,7 @@ public abstract class SpellAbility {
/** /**
* <p>Getter for the field <code>payCosts</code>.</p> * <p>Getter for the field <code>payCosts</code>.</p>
* *
* @return a {@link forge.card.spellability.Cost} object. * @return a {@link forge.card.cost.Cost} object.
*/ */
public Cost getPayCosts() { public Cost getPayCosts() {
return payCosts; return payCosts;
@@ -514,7 +515,7 @@ public abstract class SpellAbility {
/** /**
* <p>Setter for the field <code>payCosts</code>.</p> * <p>Setter for the field <code>payCosts</code>.</p>
* *
* @param abCost a {@link forge.card.spellability.Cost} object. * @param abCost a {@link forge.card.cost.Cost} object.
*/ */
public void setPayCosts(Cost abCost) { public void setPayCosts(Cost abCost) {
payCosts = abCost; payCosts = abCost;
@@ -752,6 +753,14 @@ public abstract class SpellAbility {
chosenTarget.resetTargets(); chosenTarget.resetTargets();
resetTriggeringObjects(); resetTriggeringObjects();
//Clear SVars
for(String store : Card.getStorableSVars()){
String value = sourceCard.getSVar(store);
if (value.length() > 0){
sourceCard.setSVar(store, "");
}
}
} }
/** /**

View File

@@ -4,6 +4,7 @@ import forge.AllZone;
import forge.Card; import forge.Card;
import forge.PlayerZone; import forge.PlayerZone;
import forge.card.abilityFactory.AbilityFactory; import forge.card.abilityFactory.AbilityFactory;
import forge.card.cost.Cost_Payment;
import java.util.ArrayList; import java.util.ArrayList;
@@ -46,7 +47,7 @@ public class SpellAbility_Requirements {
* *
* @param sa a {@link forge.card.spellability.SpellAbility} object. * @param sa a {@link forge.card.spellability.SpellAbility} object.
* @param ts a {@link forge.card.spellability.Target_Selection} object. * @param ts a {@link forge.card.spellability.Target_Selection} object.
* @param cp a {@link forge.card.spellability.Cost_Payment} object. * @param cp a {@link forge.card.cost.Cost_Payment} object.
*/ */
public SpellAbility_Requirements(SpellAbility sa, Target_Selection ts, Cost_Payment cp) { public SpellAbility_Requirements(SpellAbility sa, Target_Selection ts, Cost_Payment cp) {
ability = sa; ability = sa;

View File

@@ -45,6 +45,8 @@ public class SpellAbility_StackInstance {
// Triggers // Triggers
private HashMap<String, Object> triggeringObjects = new HashMap<String, Object>(); private HashMap<String, Object> triggeringObjects = new HashMap<String, Object>();
private HashMap<String, String> storedSVars = new HashMap<String, String>();
/** /**
* <p>Constructor for SpellAbility_StackInstance.</p> * <p>Constructor for SpellAbility_StackInstance.</p>
* *
@@ -76,6 +78,17 @@ public class SpellAbility_StackInstance {
tc = target.getTargetChoices(); tc = target.getTargetChoices();
ability.getTarget().resetTargets(); ability.getTarget().resetTargets();
} }
Card source = ability.getSourceCard();
//Store SVars and Clear
for(String store : Card.getStorableSVars()){
String value = source.getSVar(store);
if (value.length() > 0){
storedSVars.put(store, value);
source.setSVar(store, "");
}
}
} }
/** /**
@@ -101,6 +114,15 @@ public class SpellAbility_StackInstance {
// Triggered // Triggered
ability.setAllTriggeringObjects(triggeringObjects); ability.setAllTriggeringObjects(triggeringObjects);
// Add SVars back in
Card source = ability.getSourceCard();
for(String store : storedSVars.keySet()){
String value = storedSVars.get(store);
if (value.length() > 0){
source.setSVar(store, value);
}
}
return ability; return ability;
} }

View File

@@ -3,6 +3,7 @@ package forge.card.spellability;
import forge.*; import forge.*;
import forge.card.abilityFactory.AbilityFactory; import forge.card.abilityFactory.AbilityFactory;
import forge.card.cardFactory.CardFactoryUtil; import forge.card.cardFactory.CardFactoryUtil;
import forge.card.cost.Cost;
import forge.card.trigger.Trigger; import forge.card.trigger.Trigger;
import forge.gui.input.Input; import forge.gui.input.Input;
@@ -135,7 +136,7 @@ public class Spell_Permanent extends Spell {
* <p>Constructor for Spell_Permanent.</p> * <p>Constructor for Spell_Permanent.</p>
* *
* @param sourceCard a {@link forge.Card} object. * @param sourceCard a {@link forge.Card} object.
* @param cost a {@link forge.card.spellability.Cost} object. * @param cost a {@link forge.card.cost.Cost} object.
* @param tgt a {@link forge.card.spellability.Target} object. * @param tgt a {@link forge.card.spellability.Target} object.
*/ */
public Spell_Permanent(Card sourceCard, Cost cost, Target tgt) { public Spell_Permanent(Card sourceCard, Cost cost, Target tgt) {

View File

@@ -2,6 +2,7 @@ package forge.card.trigger;
import forge.*; import forge.*;
import forge.card.abilityFactory.AbilityFactory; import forge.card.abilityFactory.AbilityFactory;
import forge.card.cost.Cost;
import forge.card.spellability.*; import forge.card.spellability.*;
import forge.gui.input.Input; import forge.gui.input.Input;

View File

@@ -3,7 +3,7 @@ package forge.card.trigger;
import forge.AllZone; import forge.AllZone;
import forge.Card; import forge.Card;
import forge.Player; import forge.Player;
import forge.card.spellability.Cost; import forge.card.cost.Cost;
import forge.card.spellability.SpellAbility; import forge.card.spellability.SpellAbility;
import forge.card.spellability.SpellAbility_StackInstance; import forge.card.spellability.SpellAbility_StackInstance;

View File

@@ -3,8 +3,8 @@ package forge.quest.data.pet;
import forge.AllZone; import forge.AllZone;
import forge.Card; import forge.Card;
import forge.Constant; import forge.Constant;
import forge.card.cost.Cost;
import forge.card.spellability.Ability_Activated; import forge.card.spellability.Ability_Activated;
import forge.card.spellability.Cost;
import forge.card.spellability.SpellAbility; import forge.card.spellability.SpellAbility;
import forge.quest.data.bazaar.QuestStallManager; import forge.quest.data.bazaar.QuestStallManager;