From 356131b77e5f83e2f79b3710cf8c55e3564f62e0 Mon Sep 17 00:00:00 2001 From: swordshine Date: Thu, 13 Jun 2013 00:29:58 +0000 Subject: [PATCH] - Added Power Conduit --- .gitattributes | 2 + res/cardsfolder/p/power_conduit.txt | 8 + src/main/java/forge/card/cost/Cost.java | 6 + .../forge/card/cost/CostRemoveAnyCounter.java | 229 ++++++++++++++++++ 4 files changed, 245 insertions(+) create mode 100644 res/cardsfolder/p/power_conduit.txt create mode 100644 src/main/java/forge/card/cost/CostRemoveAnyCounter.java diff --git a/.gitattributes b/.gitattributes index b9d15b5f8d2..976d7ae02ab 100644 --- a/.gitattributes +++ b/.gitattributes @@ -8174,6 +8174,7 @@ res/cardsfolder/p/pouncing_wurm.txt -text res/cardsfolder/p/powder_keg.txt svneol=native#text/plain res/cardsfolder/p/power_armor.txt svneol=native#text/plain res/cardsfolder/p/power_artifact.txt svneol=native#text/plain +res/cardsfolder/p/power_conduit.txt -text res/cardsfolder/p/power_matrix.txt svneol=native#text/plain res/cardsfolder/p/power_of_fire.txt svneol=native#text/plain res/cardsfolder/p/power_sink.txt svneol=native#text/plain @@ -14219,6 +14220,7 @@ src/main/java/forge/card/cost/CostPayLife.java -text src/main/java/forge/card/cost/CostPayment.java svneol=native#text/plain src/main/java/forge/card/cost/CostPutCardToLib.java -text src/main/java/forge/card/cost/CostPutCounter.java -text +src/main/java/forge/card/cost/CostRemoveAnyCounter.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/CostReveal.java -text diff --git a/res/cardsfolder/p/power_conduit.txt b/res/cardsfolder/p/power_conduit.txt new file mode 100644 index 00000000000..2e947e31ea9 --- /dev/null +++ b/res/cardsfolder/p/power_conduit.txt @@ -0,0 +1,8 @@ +Name:Power Conduit +ManaCost:2 +Types:Artifact +A:AB$ Charm | Cost$ T RemoveAnyCounter<1/Permanent.YouCtrl/a permanent you control> | Choices$ ConduitP1P1,ConduitCharge | Defined$ You | SpellDescription$ Choose one - Put a charge counter on target artifact; or put a +1/+1 counter on target creature. +SVar:ConduitCharge:DB$ PutCounter | ValidTgts$ Artifact | TgtPrompt$ Select target artifact | CounterType$ CHARGE | CounterNum$ 1 | SpellDescription$ Put a charge counter on target artifact; +SVar:ConduitP1P1:DB$ PutCounter | ValidTgts$ Creature | TgtPrompt$ Select target creature | CounterType$ P1P1 | CounterNum$ 1 | SpellDescription$ or put a +1/+1 counter on target creature. +SVar:Picture:http://www.wizards.com/global/images/magic/general/power_conduit.jpg +Oracle:{T}, Remove a counter from a permanent you control: Choose one - Put a charge counter on target artifact; or put a +1/+1 counter on target creature. diff --git a/src/main/java/forge/card/cost/Cost.java b/src/main/java/forge/card/cost/Cost.java index 2a9859c17de..8a207041d8b 100644 --- a/src/main/java/forge/card/cost/Cost.java +++ b/src/main/java/forge/card/cost/Cost.java @@ -262,6 +262,12 @@ public class Cost { return new CostSacrifice(splitStr[0], splitStr[1], description); } + if (parse.startsWith("RemoveAnyCounter<")) { + final String[] splitStr = abCostParse(parse, 3); + final String description = splitStr.length > 2 ? splitStr[2] : null; + return new CostRemoveAnyCounter(splitStr[0], splitStr[1], description); + } + if (parse.startsWith("Exile<")) { final String[] splitStr = abCostParse(parse, 3); final String description = splitStr.length > 2 ? splitStr[2] : null; diff --git a/src/main/java/forge/card/cost/CostRemoveAnyCounter.java b/src/main/java/forge/card/cost/CostRemoveAnyCounter.java new file mode 100644 index 00000000000..83f31ed57a7 --- /dev/null +++ b/src/main/java/forge/card/cost/CostRemoveAnyCounter.java @@ -0,0 +1,229 @@ +/* + * 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 . + */ +package forge.card.cost; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + +import com.google.common.base.Predicate; +import forge.Card; +import forge.CardLists; +import forge.CounterType; +import forge.Singletons; +import forge.card.ability.AbilityUtils; +import forge.card.spellability.SpellAbility; +import forge.game.Game; +import forge.game.player.Player; +import forge.game.zone.ZoneType; +import forge.gui.GuiChoose; +import forge.gui.input.InputSelectCards; +import forge.gui.input.InputSelectCardsFromList; + +/** + * The Class CostRemoveAnyCounter. + */ +public class CostRemoveAnyCounter extends CostPartWithList { + // RemoveAnyCounter + // Power Conduit and Chisei, Heart of Oceans + // Both cards have "Remove a counter from a permanent you control" + private CounterType counterType; + /** + * Instantiates a new cost CostRemoveAnyCounter. + * + * @param amount + * the amount + */ + public CostRemoveAnyCounter(final String amount, final String type, final String description) { + super(amount, type, description); + } + + /* (non-Javadoc) + * @see forge.card.cost.CostPartWithList#getHashForList() + */ + @Override + public String getHashForList() { + return "CounterRemove"; + } + + /** + * Gets the counter. + * + * @return the counter + */ + private CounterType getCounter() { + return this.counterType; + } + + /* + * (non-Javadoc) + * + * @see + * forge.card.cost.CostPart#canPay(forge.card.spellability.SpellAbility, + * forge.Card, forge.Player, forge.card.cost.Cost) + */ + @Override + public final boolean canPay(final SpellAbility ability) { + final Player activator = ability.getActivatingPlayer(); + final Card source = ability.getSourceCard(); + List validCards = new ArrayList(activator.getCardsIn(ZoneType.Battlefield)); + validCards = CardLists.getValidCards(validCards, this.getType().split(";"), activator, source); + validCards = CardLists.filter(validCards, new Predicate() { + @Override + public boolean apply(final Card c) { + return c.hasCounters(); + } + }); + if (validCards.isEmpty()) { + return false; + } + Integer i = this.convertAmount(); + + if (i == null) { + i = AbilityUtils.calculateAmount(source, this.getAmount(), ability); + } + int allCounters = 0; + for (Card c : validCards) { + final Map tgtCounters = c.getCounters(); + for (Integer value : tgtCounters.values()) { + allCounters += value; + } + } + + return i <= allCounters; + } + + @Override + public final boolean payHuman(final SpellAbility ability, final Game game) { + final Card source = ability.getSourceCard(); + Integer c = this.convertAmount(); + final String type = this.getType(); + final Player activator = ability.getActivatingPlayer(); + + if (c == null) { + c = AbilityUtils.calculateAmount(source, this.getAmount(), ability); + } + + List list = new ArrayList(activator.getCardsIn(ZoneType.Battlefield)); + list = CardLists.getValidCards(list, type.split(";"), activator, source); + int nNeed = c.intValue(); + while (nNeed > 0) { + list = CardLists.filter(list, new Predicate() { + @Override + public boolean apply(final Card card) { + return card.hasCounters(); + } + }); + InputSelectCards inp = new InputSelectCardsFromList(1, 1, list); + inp.setMessage("Select " + this.getDescriptiveType() + " to remove a counter"); + inp.setCancelAllowed(false); + Singletons.getControl().getInputQueue().setInputAndWait(inp); + Card selected = inp.getSelected().get(0); + final Map tgtCounters = selected.getCounters(); + final ArrayList typeChoices = new ArrayList(); + for (CounterType key : tgtCounters.keySet()) { + if (tgtCounters.get(key) > 0) { + typeChoices.add(key); + } + } + if (typeChoices.size() > 1) { + String prompt = "Select type counters to remove"; + counterType = GuiChoose.one(prompt, typeChoices); + } else { + counterType = typeChoices.get(0); + } + executePayment(ability, selected); + nNeed--; + } + source.setSVar("CostCountersRemoved", Integer.toString(c)); + return true; + } + + /* + * (non-Javadoc) + * + * @see forge.card.cost.CostPart#toString() + */ + @Override + public final String toString() { + final StringBuilder sb = new StringBuilder(); + + sb.append("Remove "); + sb.append(Cost.convertIntAndTypeToWords(this.convertAmount(), "counter")); + final String desc = this.getTypeDescription() == null ? this.getType() : this.getTypeDescription(); + sb.append(" from " + desc); + + return sb.toString(); + } + + /* (non-Javadoc) + * @see forge.card.cost.CostPartWithList#payAI(forge.card.cost.PaymentDecision, forge.game.player.AIPlayer, forge.card.spellability.SpellAbility, forge.Card) + */ + @Override + public void payAI(PaymentDecision decision, Player ai, SpellAbility ability, Card source) { + final String amount = this.getAmount(); + Integer c = this.convertAmount(); + if (c == null) { + c = AbilityUtils.calculateAmount(source, amount, ability); + } + Card valid = decision.cards.get(0); + for (CounterType c1 : valid.getCounters().keySet()) { + if (valid.getCounters(c1) >= c && c1.isNegativeCounter()) { + counterType = c1; + break; + } + } + for (int i = 0; i < c; i++) { + executePayment(ability, valid); + } + source.setSVar("CostCountersRemoved", Integer.toString(c)); + } + + @Override + protected void doPayment(SpellAbility ability, Card targetCard){ + targetCard.subtractCounter(this.getCounter(), 1); + } + + + + /* (non-Javadoc) + * @see forge.card.cost.CostPart#decideAIPayment(forge.game.player.AIPlayer, forge.card.spellability.SpellAbility, forge.Card) + */ + @Override + public PaymentDecision decideAIPayment(Player ai, SpellAbility ability, Card source) { + final String amount = this.getAmount(); + final int c = AbilityUtils.calculateAmount(source, amount, ability); + final String type = this.getType(); + + List typeList = CardLists.getValidCards(ai.getCardsIn(ZoneType.Battlefield), type.split(";"), ai, source); + List hperms = CardLists.filter(typeList, new Predicate() { + @Override + public boolean apply(final Card crd) { + for (final CounterType c1 : CounterType.values()) { + if (crd.getCounters(c1) >= c && c1.isNegativeCounter()) { + return true; + } + } + return false; + } + }); + // Only find cards with enough negative counters + // TODO: add ai for Chisei, Heart of Oceans + return hperms.isEmpty() ? null : new PaymentDecision(hperms); + } +}