'Fuse' Keyword support for DGM

CostUtil.java disbanded, it's method moved closer to usage places.
This commit is contained in:
Maxmtg
2013-04-08 09:29:25 +00:00
parent da6e2f55fe
commit 30ad587769
24 changed files with 184 additions and 188 deletions

1
.gitattributes vendored
View File

@@ -13790,7 +13790,6 @@ src/main/java/forge/card/cost/CostTapType.java -text
src/main/java/forge/card/cost/CostUnattach.java -text src/main/java/forge/card/cost/CostUnattach.java -text
src/main/java/forge/card/cost/CostUntap.java -text src/main/java/forge/card/cost/CostUntap.java -text
src/main/java/forge/card/cost/CostUntapType.java -text src/main/java/forge/card/cost/CostUntapType.java -text
src/main/java/forge/card/cost/CostUtil.java -text
src/main/java/forge/card/cost/InputPayCostBase.java -text src/main/java/forge/card/cost/InputPayCostBase.java -text
src/main/java/forge/card/cost/PaymentDecision.java -text src/main/java/forge/card/cost/PaymentDecision.java -text
src/main/java/forge/card/cost/package-info.java svneol=native#text/plain src/main/java/forge/card/cost/package-info.java svneol=native#text/plain

View File

@@ -9177,6 +9177,9 @@ public class Card extends GameEntity implements Comparable<Card> {
return; return;
} }
} }
if ( sa.getSourceCard().hasKeyword("Fuse") ) // it's ok that such card won't change its side
return;
throw new RuntimeException("Not found which part to choose for ability " + sa + " from card " + this); throw new RuntimeException("Not found which part to choose for ability " + sa + " from card " + this);
} }

View File

@@ -41,6 +41,44 @@ import forge.util.FileSection;
*/ */
public final class AbilityFactory { public final class AbilityFactory {
public enum AbilityRecordType {
Ability("AB"),
Spell("SP"),
SubAbility("DB");
private final String prefix;
private AbilityRecordType(String prefix) {
this.prefix = prefix;
}
public String getPrefix() {
return prefix;
}
public SpellAbility buildSpellAbility(ApiType api, Card hostCard, Cost abCost, Target abTgt, Map<String, String> mapParams ) {
switch(this) {
case Ability: return new AbilityApiBased(api, hostCard, abCost, abTgt, mapParams);
case Spell: return new SpellApiBased(api, hostCard, abCost, abTgt, mapParams);
case SubAbility: return new AbilitySub(api, hostCard, abTgt, mapParams);
}
return null; // exception here would be fine!
}
public ApiType getApiTypeOf(Map<String, String> abParams) {
return ApiType.smartValueOf(abParams.get(this.getPrefix()));
}
public static AbilityRecordType getRecordType(Map<String, String> abParams) {
if (abParams.containsKey(AbilityRecordType.Ability.getPrefix())) {
return AbilityRecordType.Ability;
} else if (abParams.containsKey(AbilityRecordType.Spell.getPrefix())) {
return AbilityRecordType.Spell;
} else if (abParams.containsKey(AbilityRecordType.SubAbility.getPrefix())) {
return AbilityRecordType.SubAbility;
} else {
return null;
}
}
}
/** /**
* <p> * <p>
* getAbility. * getAbility.
@@ -54,11 +92,6 @@ public final class AbilityFactory {
*/ */
public static final SpellAbility getAbility(final String abString, final Card hostCard) { public static final SpellAbility getAbility(final String abString, final Card hostCard) {
SpellAbility spellAbility = null;
boolean isAb = false;
boolean isSp = false;
boolean isDb = false;
Map<String, String> mapParams; Map<String, String> mapParams;
try { try {
@@ -69,34 +102,28 @@ public final class AbilityFactory {
} }
// parse universal parameters // parse universal parameters
AbilityRecordType type = AbilityRecordType.getRecordType(mapParams);
ApiType api = null; if( null == type )
if (mapParams.containsKey("AB")) {
isAb = true;
api = ApiType.smartValueOf(mapParams.get("AB"));
} else if (mapParams.containsKey("SP")) {
isSp = true;
api = ApiType.smartValueOf(mapParams.get("SP"));
} else if (mapParams.containsKey("DB")) {
isDb = true;
api = ApiType.smartValueOf(mapParams.get("DB"));
} else {
throw new RuntimeException("AbilityFactory : getAbility -- no API in " + hostCard.getName()); throw new RuntimeException("AbilityFactory : getAbility -- no API in " + hostCard.getName());
return getAbility(type, type.getApiTypeOf(mapParams), mapParams, parseAbilityCost(hostCard, mapParams, type), hostCard);
} }
public static Cost parseAbilityCost(final Card hostCard, Map<String, String> mapParams, AbilityRecordType type) {
Cost abCost = null; Cost abCost = null;
if (!isDb) { if (type != AbilityRecordType.SubAbility) {
if (!mapParams.containsKey("Cost")) { if (!mapParams.containsKey("Cost")) {
throw new RuntimeException("AbilityFactory : getAbility -- no Cost in " + hostCard.getName()); throw new RuntimeException("AbilityFactory : getAbility -- no Cost in " + hostCard.getName());
} }
abCost = new Cost(hostCard, mapParams.get("Cost"), isAb); abCost = new Cost(hostCard, mapParams.get("Cost"), type == AbilityRecordType.Ability);
}
return abCost;
} }
Target abTgt = mapParams.containsKey("ValidTgts") ? readTarget(hostCard, mapParams) : null; public static final SpellAbility getAbility(AbilityRecordType type, ApiType api, Map<String, String> mapParams, Cost abCost, Card hostCard) {
// ***********************************
// Match API keywords. These are listed in alphabetical order. Target abTgt = mapParams.containsKey("ValidTgts") ? readTarget(hostCard, mapParams) : null;
if (api == ApiType.CopySpellAbility) { if (api == ApiType.CopySpellAbility) {
@@ -119,20 +146,13 @@ public final class AbilityFactory {
else if (api == ApiType.PermanentCreature || api == ApiType.PermanentNoncreature) { else if (api == ApiType.PermanentCreature || api == ApiType.PermanentNoncreature) {
// If API is a permanent type, and creating AF Spell // If API is a permanent type, and creating AF Spell
// Clear out the auto created SpellPemanent spell // Clear out the auto created SpellPemanent spell
if (isSp) { if (type == AbilityRecordType.Spell) {
hostCard.clearFirstSpell(); hostCard.clearFirstSpell();
} }
} }
if (isAb) { SpellAbility spellAbility = type.buildSpellAbility(api, hostCard, abCost, abTgt, mapParams);
spellAbility = new AbilityApiBased(api, hostCard, abCost, abTgt, mapParams);
} else if (isSp) {
spellAbility = new SpellApiBased(api, hostCard, abCost, abTgt, mapParams);
} else if (isDb) {
spellAbility = new AbilitySub(api, hostCard, abTgt, mapParams);
}
if (spellAbility == null) { if (spellAbility == null) {
@@ -163,7 +183,7 @@ public final class AbilityFactory {
} else if (mapParams.containsKey("SpellDescription")) { } else if (mapParams.containsKey("SpellDescription")) {
final StringBuilder sb = new StringBuilder(); final StringBuilder sb = new StringBuilder();
if (!isDb) { // SubAbilities don't have Costs or Cost if (type != AbilityRecordType.SubAbility) { // SubAbilities don't have Costs or Cost
// descriptors // descriptors
if (mapParams.containsKey("PrecostDesc")) { if (mapParams.containsKey("PrecostDesc")) {
sb.append(mapParams.get("PrecostDesc")).append(" "); sb.append(mapParams.get("PrecostDesc")).append(" ");

View File

@@ -13,7 +13,8 @@ import forge.Singletons;
import forge.card.ability.AbilityUtils; import forge.card.ability.AbilityUtils;
import forge.card.ability.SpellAbilityAi; import forge.card.ability.SpellAbilityAi;
import forge.card.cost.Cost; import forge.card.cost.Cost;
import forge.card.cost.CostUtil; import forge.card.cost.CostPart;
import forge.card.cost.CostTapType;
import forge.card.spellability.SpellAbility; import forge.card.spellability.SpellAbility;
import forge.card.spellability.SpellAbilityRestriction; import forge.card.spellability.SpellAbilityRestriction;
import forge.card.spellability.Target; import forge.card.spellability.Target;
@@ -29,6 +30,19 @@ import forge.game.zone.ZoneType;
public class PumpAi extends PumpAiBase { public class PumpAi extends PumpAiBase {
private static boolean hasTapCost(final Cost cost, final Card source) {
if (cost == null) {
return true;
}
for (final CostPart part : cost.getCostParts()) {
if (part instanceof CostTapType) {
return true;
}
}
return false;
}
/* (non-Javadoc) /* (non-Javadoc)
* @see forge.card.abilityfactory.SpellAiLogic#canPlayAI(forge.game.player.Player, java.util.Map, forge.card.spellability.SpellAbility) * @see forge.card.abilityfactory.SpellAiLogic#canPlayAI(forge.game.player.Player, java.util.Map, forge.card.spellability.SpellAbility)
*/ */
@@ -56,7 +70,7 @@ public class PumpAi extends PumpAiBase {
return false; return false;
} }
if (Singletons.getModel().getGame().getStack().isEmpty() && CostUtil.hasTapCost(cost, sa.getSourceCard())) { if (Singletons.getModel().getGame().getStack().isEmpty() && hasTapCost(cost, sa.getSourceCard())) {
if (ph.getPhase().isBefore(PhaseType.COMBAT_DECLARE_ATTACKERS) && ph.isPlayerTurn(ai)) { if (ph.getPhase().isBefore(PhaseType.COMBAT_DECLARE_ATTACKERS) && ph.isPlayerTurn(ai)) {
return false; return false;
} }

View File

@@ -292,6 +292,7 @@ public class CardFactory {
if ( state == CardCharacteristicName.LeftSplit || state == CardCharacteristicName.RightSplit ) if ( state == CardCharacteristicName.LeftSplit || state == CardCharacteristicName.RightSplit )
{ {
card.getState(CardCharacteristicName.Original).getSpellAbility().addAll(card.getCharacteristics().getSpellAbility()); card.getState(CardCharacteristicName.Original).getSpellAbility().addAll(card.getCharacteristics().getSpellAbility());
card.getState(CardCharacteristicName.Original).getIntrinsicKeyword().addAll(card.getIntrinsicKeyword()); // Copy 'Fuse' to original side
} }
} }

View File

@@ -2371,7 +2371,29 @@ public class CardFactoryUtil {
} }
card.addSpellAbility(sa); card.addSpellAbility(sa);
} }
}
public static final SpellAbility buildFusedAbility(final Card card) {
if(!card.isSplitCard())
throw new IllegalStateException("Fuse ability may be built only on split cards");
final String strLeftAbility = card.getState(CardCharacteristicName.LeftSplit).getIntrinsicAbility().get(0);
Map<String, String> leftMap = AbilityFactory.getMapParams(strLeftAbility);
AbilityFactory.AbilityRecordType leftType = AbilityFactory.AbilityRecordType.getRecordType(leftMap);
Cost leftCost = AbilityFactory.parseAbilityCost(card, leftMap, leftType);
ApiType leftApi = leftType.getApiTypeOf(leftMap);
final String strRightAbility = card.getState(CardCharacteristicName.RightSplit).getIntrinsicAbility().get(0);
Map<String, String> rightMap = AbilityFactory.getMapParams(strRightAbility);
AbilityFactory.AbilityRecordType rightType = AbilityFactory.AbilityRecordType.getRecordType(leftMap);
Cost rightCost = AbilityFactory.parseAbilityCost(card, rightMap, rightType);
ApiType rightApi = leftType.getApiTypeOf(rightMap);
Cost joinedCost = Cost.combine(rightCost, leftCost);
final SpellAbility left = AbilityFactory.getAbility(leftType, leftApi, leftMap, joinedCost, card);
final AbilitySub right = (AbilitySub) AbilityFactory.getAbility(AbilityFactory.AbilityRecordType.SubAbility, rightApi, rightMap, null, card);
left.appendSubAbility(right);
return left;
} }
/** /**
@@ -2418,6 +2440,10 @@ public class CardFactoryUtil {
} }
} }
if(CardFactoryUtil.hasKeyword(card, "Fuse") != -1) {
card.getState(CardCharacteristicName.Original).getSpellAbility().add(buildFusedAbility(card));
}
final int evokePos = CardFactoryUtil.hasKeyword(card, "Evoke"); final int evokePos = CardFactoryUtil.hasKeyword(card, "Evoke");
if (evokePos != -1) { if (evokePos != -1) {
card.addSpellAbility(makeEvokeSpell(card, card.getKeyword().get(evokePos))); card.addSpellAbility(makeEvokeSpell(card, card.getKeyword().get(evokePos)));
@@ -3197,12 +3223,7 @@ public class CardFactoryUtil {
private static final Map<String,String> emptyMap = new TreeMap<String,String>(); private static final Map<String,String> emptyMap = new TreeMap<String,String>();
public static void setupETBReplacementAbility(SpellAbility sa) { public static void setupETBReplacementAbility(SpellAbility sa) {
SpellAbility tailend = sa; sa.appendSubAbility(new AbilitySub(ApiType.InternalEtbReplacement, sa.getSourceCard(), null, emptyMap));
while (tailend.getSubAbility() != null) {
tailend = tailend.getSubAbility();
}
tailend.setSubAbility(new AbilitySub(ApiType.InternalEtbReplacement, sa.getSourceCard(), null, emptyMap));
// ETBReplacementMove(sa.getSourceCard(), null)); // ETBReplacementMove(sa.getSourceCard(), null));
} }

View File

@@ -28,6 +28,7 @@ import forge.card.mana.ManaCostBeingPaid;
import forge.card.mana.ManaCostParser; import forge.card.mana.ManaCostParser;
import forge.card.spellability.SpellAbility; import forge.card.spellability.SpellAbility;
import forge.game.zone.ZoneType; import forge.game.zone.ZoneType;
import forge.gui.GuiChoose;
import forge.util.TextUtil; import forge.util.TextUtil;
/** /**
@@ -647,4 +648,42 @@ public class Cost {
return sb.toString(); return sb.toString();
} }
public static Cost combine(Cost cost1, Cost cost2) {
if (cost1 == null) return cost2;
if (cost2 == null) return cost1;
CostPartMana costPart2 = cost2.getCostMana();
for (final CostPart part : cost1.getCostParts()) {
if (part instanceof CostPartMana && costPart2 != null) {
ManaCostBeingPaid oldManaCost = new ManaCostBeingPaid(((CostPartMana) part).getMana());
boolean xCanBe0 = ((CostPartMana) part).canXbe0() && costPart2.canXbe0();
oldManaCost.combineManaCost(costPart2.getMana());
String r2 = costPart2.getRestiction();
String r1 = ((CostPartMana) part).getRestiction();
String r = r1 == null ? r2 : ( r2 == null ? r1 : r1+"."+r2);
cost2.getCostParts().remove(costPart2);
cost2.getCostParts().add(0, new CostPartMana(oldManaCost.toManaCost(), r, !xCanBe0));
} else {
cost2.getCostParts().add(part);
}
}
return cost2;
}
public static int chooseXValue(final Card card, final SpellAbility sa, final int maxValue) {
/*final String chosen = sa.getSVar("ChosenX");
if (chosen.length() > 0) {
return AbilityFactory.calculateAmount(card, "ChosenX", null);
}*/
final Integer[] choiceArray = new Integer[maxValue + 1];
for (int i = 0; i < choiceArray.length; i++) {
choiceArray[i] = i;
}
final Integer chosenX = GuiChoose.one(card.toString() + " - Choose a Value for X", choiceArray);
sa.setSVar("ChosenX", Integer.toString(chosenX));
card.setSVar("ChosenX", Integer.toString(chosenX));
return chosenX;
}
} }

View File

@@ -88,7 +88,7 @@ public class CostDamage extends CostPart {
final String sVar = ability.getSVar(amount); final String sVar = ability.getSVar(amount);
// Generalize this // Generalize this
if (sVar.equals("XChoice")) { if (sVar.equals("XChoice")) {
c = CostUtil.chooseXValue(source, ability, life); c = Cost.chooseXValue(source, ability, life);
} else { } else {
c = AbilityUtils.calculateAmount(source, amount, ability); c = AbilityUtils.calculateAmount(source, amount, ability);
} }

View File

@@ -184,7 +184,7 @@ public class CostDiscard extends CostPartWithList {
final String sVar = ability.getSVar(amount); final String sVar = ability.getSVar(amount);
// Generalize this // Generalize this
if (sVar.equals("XChoice")) { if (sVar.equals("XChoice")) {
c = CostUtil.chooseXValue(source, ability, handList.size()); c = Cost.chooseXValue(source, ability, handList.size());
} else { } else {
c = AbilityUtils.calculateAmount(source, amount, ability); c = AbilityUtils.calculateAmount(source, amount, ability);
} }
@@ -220,7 +220,7 @@ public class CostDiscard extends CostPartWithList {
final String sVar = ability.getSVar(amount); final String sVar = ability.getSVar(amount);
// Generalize this // Generalize this
if (sVar.equals("XChoice")) { if (sVar.equals("XChoice")) {
c = CostUtil.chooseXValue(source, ability, handList.size()); c = Cost.chooseXValue(source, ability, handList.size());
} else { } else {
c = AbilityUtils.calculateAmount(source, amount, ability); c = AbilityUtils.calculateAmount(source, amount, ability);
} }

View File

@@ -541,7 +541,7 @@ public class CostExile extends CostPartWithList {
final String sVar = ability.getSVar(amount); final String sVar = ability.getSVar(amount);
// Generalize this // Generalize this
if (sVar.equals("XChoice")) { if (sVar.equals("XChoice")) {
c = CostUtil.chooseXValue(source, ability, list.size()); c = Cost.chooseXValue(source, ability, list.size());
} else { } else {
c = AbilityUtils.calculateAmount(source, amount, ability); c = AbilityUtils.calculateAmount(source, amount, ability);
} }

View File

@@ -128,7 +128,7 @@ public class CostGainLife extends CostPart {
final String sVar = ability.getSVar(amount); final String sVar = ability.getSVar(amount);
// Generalize this // Generalize this
if (sVar.equals("XChoice")) { if (sVar.equals("XChoice")) {
c = CostUtil.chooseXValue(source, ability, life); c = Cost.chooseXValue(source, ability, life);
} else { } else {
c = AbilityUtils.calculateAmount(source, amount, ability); c = AbilityUtils.calculateAmount(source, amount, ability);
} }

View File

@@ -99,7 +99,7 @@ public class CostMill extends CostPartWithList {
final String sVar = ability.getSVar(amount); final String sVar = ability.getSVar(amount);
// Generalize this // Generalize this
if (sVar.equals("XChoice")) { if (sVar.equals("XChoice")) {
c = CostUtil.chooseXValue(source, ability, this.getList().size()); c = Cost.chooseXValue(source, ability, this.getList().size());
} else { } else {
c = AbilityUtils.calculateAmount(source, amount, ability); c = AbilityUtils.calculateAmount(source, amount, ability);
} }

View File

@@ -120,7 +120,7 @@ public class CostPayLife extends CostPart {
limit = AbilityUtils.calculateAmount(source, sVar.split("LimitMax.")[1], ability); limit = AbilityUtils.calculateAmount(source, sVar.split("LimitMax.")[1], ability);
} }
int maxLifePayment = limit < life ? limit : life; int maxLifePayment = limit < life ? limit : life;
c = CostUtil.chooseXValue(source, ability, maxLifePayment); c = Cost.chooseXValue(source, ability, maxLifePayment);
} else { } else {
c = AbilityUtils.calculateAmount(source, amount, ability); c = AbilityUtils.calculateAmount(source, amount, ability);
} }

View File

@@ -136,7 +136,7 @@ public class CostRemoveCounter extends CostPartWithList {
if (amount.equals("All")) if (amount.equals("All"))
cntRemoved = maxCounters; cntRemoved = maxCounters;
else if ( c == null && "XChoice".equals(sVarAmount)) { else if ( c == null && "XChoice".equals(sVarAmount)) {
cntRemoved = CostUtil.chooseXValue(source, ability, maxCounters); cntRemoved = Cost.chooseXValue(source, ability, maxCounters);
} }
if (maxCounters < cntRemoved) if (maxCounters < cntRemoved)

View File

@@ -131,7 +131,7 @@ public class CostReturn extends CostPartWithList {
final String sVar = ability.getSVar(amount); final String sVar = ability.getSVar(amount);
// Generalize this // Generalize this
if (sVar.equals("XChoice")) { if (sVar.equals("XChoice")) {
c = CostUtil.chooseXValue(source, ability, list.size()); c = Cost.chooseXValue(source, ability, list.size());
} else { } else {
c = AbilityUtils.calculateAmount(source, amount, ability); c = AbilityUtils.calculateAmount(source, amount, ability);
} }

View File

@@ -157,7 +157,7 @@ public class CostReveal extends CostPartWithList {
if (num == null) { if (num == null) {
final String sVar = ability.getSVar(amount); final String sVar = ability.getSVar(amount);
if (sVar.equals("XChoice")) { if (sVar.equals("XChoice")) {
num = CostUtil.chooseXValue(source, ability, handList.size()); num = Cost.chooseXValue(source, ability, handList.size());
} else { } else {
num = AbilityUtils.calculateAmount(source, amount, ability); num = AbilityUtils.calculateAmount(source, amount, ability);
} }

View File

@@ -153,7 +153,7 @@ public class CostSacrifice extends CostPartWithList {
if (c == null) { if (c == null) {
// Generalize this // Generalize this
if (ability.getSVar(amount).equals("XChoice")) { if (ability.getSVar(amount).equals("XChoice")) {
c = CostUtil.chooseXValue(source, ability, list.size()); c = Cost.chooseXValue(source, ability, list.size());
} else { } else {
c = AbilityUtils.calculateAmount(source, amount, ability); c = AbilityUtils.calculateAmount(source, amount, ability);
} }

View File

@@ -189,7 +189,7 @@ public class CostTapType extends CostPartWithList {
final String sVar = ability.getSVar(amount); final String sVar = ability.getSVar(amount);
// Generalize this // Generalize this
if (sVar.equals("XChoice")) { if (sVar.equals("XChoice")) {
c = CostUtil.chooseXValue(source, ability, typeList.size()); c = Cost.chooseXValue(source, ability, typeList.size());
} else { } else {
c = AbilityUtils.calculateAmount(source, amount, ability); c = AbilityUtils.calculateAmount(source, amount, ability);
} }

View File

@@ -146,7 +146,7 @@ public class CostUntapType extends CostPartWithList {
final String sVar = ability.getSVar(amount); final String sVar = ability.getSVar(amount);
// Generalize this // Generalize this
if (sVar.equals("XChoice")) { if (sVar.equals("XChoice")) {
c = CostUtil.chooseXValue(source, ability, typeList.size()); c = Cost.chooseXValue(source, ability, typeList.size());
} else { } else {
c = AbilityUtils.calculateAmount(source, amount, ability); c = AbilityUtils.calculateAmount(source, amount, ability);
} }

View File

@@ -1,122 +0,0 @@
/*
* Forge: Play Magic: the Gathering.
* Copyright (C) 2011 Forge Team
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package forge.card.cost;
import forge.Card;
import forge.card.mana.ManaCostBeingPaid;
import forge.card.spellability.SpellAbility;
import forge.gui.GuiChoose;
/**
* The Class CostUtil.
*/
public class CostUtil {
/**
* Checks for discard hand cost.
*
* @param cost
* the cost
* @return true, if successful
*/
public static boolean hasDiscardHandCost(final Cost cost) {
if (cost == null) {
return false;
}
for (final CostPart part : cost.getCostParts()) {
if (part instanceof CostDiscard) {
final CostDiscard disc = (CostDiscard) part;
if (disc.getType().equals("Hand")) {
return true;
}
}
}
return false;
}
/**
* hasTapCost.
*
* @param cost
* the cost
* @param source
* the source
* @return true, if successful
*/
public static boolean hasTapCost(final Cost cost, final Card source) {
if (cost == null) {
return true;
}
for (final CostPart part : cost.getCostParts()) {
if (part instanceof CostTapType) {
return true;
}
}
return false;
}
/**
* Choose x value.
*
* @param card
* the card
* @param sa
* the SpellAbility
* @param maxValue
* the max value
* @return the int
*/
public static int chooseXValue(final Card card, final SpellAbility sa, final int maxValue) {
/*final String chosen = sa.getSVar("ChosenX");
if (chosen.length() > 0) {
return AbilityFactory.calculateAmount(card, "ChosenX", null);
}*/
final Integer[] choiceArray = new Integer[maxValue + 1];
for (int i = 0; i < choiceArray.length; i++) {
choiceArray[i] = i;
}
final Integer chosenX = GuiChoose.one(card.toString() + " - Choose a Value for X", choiceArray);
sa.setSVar("ChosenX", Integer.toString(chosenX));
card.setSVar("ChosenX", Integer.toString(chosenX));
return chosenX;
}
public static Cost combineCosts(Cost cost1, Cost cost2) {
if (cost1 == null) return cost2;
if (cost2 == null) return cost1;
CostPartMana costPart2 = cost2.getCostMana();
for (final CostPart part : cost1.getCostParts()) {
if (part instanceof CostPartMana && costPart2 != null) {
ManaCostBeingPaid oldManaCost = new ManaCostBeingPaid(((CostPartMana) part).getMana());
boolean xCanBe0 = ((CostPartMana) part).canXbe0() && costPart2.canXbe0();
oldManaCost.combineManaCost(costPart2.getMana());
String r2 = costPart2.getRestiction();
String r1 = ((CostPartMana) part).getRestiction();
String r = r1 == null ? r2 : ( r2 == null ? r1 : r1+"."+r2);
cost2.getCostParts().remove(costPart2);
cost2.getCostParts().add(0, new CostPartMana(oldManaCost.toManaCost(), r, !xCanBe0));
} else {
cost2.getCostParts().add(part);
}
}
return cost2;
}
}

View File

@@ -959,6 +959,15 @@ public abstract class SpellAbility implements ISpellAbility {
return sb.toString(); return sb.toString();
} }
public void appendSubAbility(final AbilitySub toAdd) {
SpellAbility tailend = this;
while (tailend.getSubAbility() != null) {
tailend = tailend.getSubAbility();
}
tailend.setSubAbility(toAdd);
}
/** /**
* <p> * <p>
* Setter for the field <code>subAbility</code>. * Setter for the field <code>subAbility</code>.

View File

@@ -53,7 +53,6 @@ import forge.card.cost.CostReturn;
import forge.card.cost.CostReveal; import forge.card.cost.CostReveal;
import forge.card.cost.CostSacrifice; import forge.card.cost.CostSacrifice;
import forge.card.cost.CostTapType; import forge.card.cost.CostTapType;
import forge.card.cost.CostUtil;
import forge.card.mana.ManaCost; import forge.card.mana.ManaCost;
import forge.card.spellability.Ability; import forge.card.spellability.Ability;
import forge.card.spellability.AbilityManaPart; import forge.card.spellability.AbilityManaPart;
@@ -1250,10 +1249,8 @@ public final class GameActionUtil {
return alternatives; return alternatives;
} }
public static Cost combineCosts(SpellAbility sa, String additionalCost) { private static Cost combineCosts(SpellAbility sa, String additionalCost) {
final Cost newCost = new Cost(sa.getSourceCard(), additionalCost, false); return Cost.combine(sa.getPayCosts(), new Cost(sa.getSourceCard(), additionalCost, false));
Cost oldCost = sa.getPayCosts();
return CostUtil.combineCosts(oldCost, newCost);
} }
/** /**

View File

@@ -36,8 +36,9 @@ import forge.card.ability.ApiType;
import forge.card.ability.effects.CharmEffect; import forge.card.ability.effects.CharmEffect;
import forge.card.cardfactory.CardFactoryUtil; import forge.card.cardfactory.CardFactoryUtil;
import forge.card.cost.Cost; import forge.card.cost.Cost;
import forge.card.cost.CostDiscard;
import forge.card.cost.CostPart;
import forge.card.cost.CostPayment; import forge.card.cost.CostPayment;
import forge.card.cost.CostUtil;
import forge.card.spellability.AbilityStatic; import forge.card.spellability.AbilityStatic;
import forge.card.spellability.SpellAbility; import forge.card.spellability.SpellAbility;
import forge.card.spellability.Target; import forge.card.spellability.Target;
@@ -124,6 +125,21 @@ public class ComputerUtil {
return false; return false;
} }
private static boolean hasDiscardHandCost(final Cost cost) {
if (cost == null) {
return false;
}
for (final CostPart part : cost.getCostParts()) {
if (part instanceof CostDiscard) {
final CostDiscard disc = (CostDiscard) part;
if (disc.getType().equals("Hand")) {
return true;
}
}
}
return false;
}
/** /**
* <p> * <p>
* counterSpellRestriction. * counterSpellRestriction.
@@ -149,7 +165,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 (CostUtil.hasDiscardHandCost(cost)) { if (hasDiscardHandCost(cost)) {
// Null Brooch aid // Null Brooch aid
restrict -= (ai.getCardsIn(ZoneType.Hand).size() * 20); restrict -= (ai.getCardsIn(ZoneType.Hand).size() * 20);
} }

View File

@@ -39,7 +39,6 @@ import forge.card.CardType;
import forge.card.ability.ApiType; import forge.card.ability.ApiType;
import forge.card.cardfactory.CardFactoryUtil; import forge.card.cardfactory.CardFactoryUtil;
import forge.card.cost.Cost; import forge.card.cost.Cost;
import forge.card.cost.CostUtil;
import forge.card.mana.ManaCost; import forge.card.mana.ManaCost;
import forge.card.spellability.Ability; import forge.card.spellability.Ability;
import forge.card.spellability.AbilityStatic; import forge.card.spellability.AbilityStatic;
@@ -1131,7 +1130,7 @@ public class CombatUtil {
final ArrayList<StaticAbility> staticAbilities = card.getStaticAbilities(); final ArrayList<StaticAbility> staticAbilities = card.getStaticAbilities();
for (final StaticAbility stAb : staticAbilities) { for (final StaticAbility stAb : staticAbilities) {
Cost additionalCost = stAb.getCostAbility("CantAttackUnless", c, game.getCombat().getDefenderByAttacker(c)); Cost additionalCost = stAb.getCostAbility("CantAttackUnless", c, game.getCombat().getDefenderByAttacker(c));
attackCost = CostUtil.combineCosts(attackCost, additionalCost); attackCost = Cost.combine(attackCost, additionalCost);
} }
} }
if (attackCost.toSimpleString().equals("")) { if (attackCost.toSimpleString().equals("")) {