diff --git a/.gitattributes b/.gitattributes index 3772b52c4fc..aed981bc538 100644 --- a/.gitattributes +++ b/.gitattributes @@ -4739,6 +4739,7 @@ res/cardsfolder/h/heartlash_cinder.txt svneol=native#text/plain res/cardsfolder/h/heartless_hidetsugu.txt svneol=native#text/plain res/cardsfolder/h/heartless_summoning.txt -text res/cardsfolder/h/heartmender.txt svneol=native#text/plain +res/cardsfolder/h/heartseeker.txt -text res/cardsfolder/h/heartstabber_mosquito.txt svneol=native#text/plain res/cardsfolder/h/heartstone.txt svneol=native#text/plain res/cardsfolder/h/heartwood_dryad.txt svneol=native#text/plain @@ -13888,6 +13889,7 @@ src/main/java/forge/card/cost/CostReveal.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/CostUnattach.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/CostUtil.java -text diff --git a/res/cardsfolder/h/heartseeker.txt b/res/cardsfolder/h/heartseeker.txt new file mode 100644 index 00000000000..8824f3b386c --- /dev/null +++ b/res/cardsfolder/h/heartseeker.txt @@ -0,0 +1,12 @@ +Name:Heartseeker +ManaCost:4 +Types:Artifact Equipment +Text:no text +K:Equip 5 +S:Mode$ Continuous | Affected$ Creature.EquippedBy | AddPower$ 2 | AddToughness$ 1 | AddAbility$ SeekerDestroy | Description$ Equipped creature gets +2/+1 and has "{T}, Unattach Heartseeker: Destroy target creature." +SVar:SeekerDestroy:AB$ Destroy | Cost$ T Unattach | ValidTgts$ Creature | SpellDescription$ Destroy target creature. +SVar:Rarity:Rare +SVar:Picture:http://www.wizards.com/global/images/magic/general/heartseeker.jpg +SetInfo:DST|Rare|http://magiccards.info/scans/en/ds/124.jpg +Oracle:Equipped creature gets +2/+1 and has "{T}, Unattach Heartseeker: Destroy target creature."\nEquip {5} ({5}: Attach to target creature you control. Equip only as a sorcery. This card enters the battlefield unattached and stays on the battlefield if the creature leaves.) +End \ No newline at end of file diff --git a/src/main/java/forge/card/cost/Cost.java b/src/main/java/forge/card/cost/Cost.java index 970b06faa67..026dcd58ee8 100644 --- a/src/main/java/forge/card/cost/Cost.java +++ b/src/main/java/forge/card/cost/Cost.java @@ -232,14 +232,21 @@ public class Cost { return new CostGainLife(splitStr[0], splitStr[1], cnt); } + if(parse.startsWith("Unattach<")) { + // Unattach + final String[] splitStr = abCostParse(parse, 2); + final String description = splitStr.length > 1 ? splitStr[1] : null; + return new CostUnattach(splitStr[0], description); + } + if(parse.startsWith("DamageYou<")) { - // PayLife + // Damage final String[] splitStr = abCostParse(parse, 1); return new CostDamage(splitStr[0]); } if(parse.startsWith("Mill<")) { - // PayLife + // Mill final String[] splitStr = abCostParse(parse, 1); return new CostMill(splitStr[0]); } diff --git a/src/main/java/forge/card/cost/CostUnattach.java b/src/main/java/forge/card/cost/CostUnattach.java new file mode 100644 index 00000000000..8eaa9d374c4 --- /dev/null +++ b/src/main/java/forge/card/cost/CostUnattach.java @@ -0,0 +1,158 @@ +/* + * 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.List; + +import forge.Card; +import forge.CardLists; +import forge.card.spellability.SpellAbility; +import forge.game.GameState; +import forge.game.player.AIPlayer; +import forge.game.player.Player; +import forge.gui.GuiDialog; + +/** + * The Class CostUnattach. + */ +public class CostUnattach extends CostPartWithList { + // Unattach if ability is on the Equipment + // Unattach if equipped creature has the ability + + /** + * Instantiates a new cost unattach. + */ + public CostUnattach(final String type, final String desc) { + super("1", type, desc); + } + + @Override + public boolean isUndoable() { return false; } + + + @Override + public boolean isReusable() { return false; } + + + /* + * (non-Javadoc) + * + * @see forge.card.cost.CostPart#toString() + */ + @Override + public final String toString() { + return String.format("Unattach %s", this.getTypeDescription()); + } + + /* + * (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 Card source, final Player activator, final Cost cost, final GameState game) { + final String type = this.getType(); + if (type.equals("CARDNAME")) { + if (source.isEquipping()) { + return true; + } + } else { + List equipped = source.getEquippedBy(); + if (CardLists.getValidCards(equipped, type, activator, source).size() > 0) { + return true; + } + } + + return false; + } + + /* + * (non-Javadoc) + * + * @see forge.card.cost.CostPart#payAI(forge.card.spellability.SpellAbility, + * forge.Card, forge.card.cost.Cost_Payment) + */ + @Override + public final void payAI(final AIPlayer ai, final SpellAbility ability, final Card source, final CostPayment payment, final GameState game) { + Card cardToUnattach = findCardToUnattach(source, (Player)ai); + if (cardToUnattach == null) { + // We really shouldn't be able to get here if there's nothing to unattach + return; + } + + Card equippingCard = cardToUnattach.getEquipping().get(0); + cardToUnattach.unEquipCard(equippingCard); + this.addToList(cardToUnattach); + } + + /* + * (non-Javadoc) + * + * @see + * forge.card.cost.CostPart#payHuman(forge.card.spellability.SpellAbility, + * forge.Card, forge.card.cost.Cost_Payment) + */ + @Override + public final boolean payHuman(final SpellAbility ability, final Card source, final CostPayment payment, final GameState game) { + this.resetList(); + Player activator = ability.getActivatingPlayer(); + Card cardToUnattach = findCardToUnattach(source, activator); + if (cardToUnattach != null && GuiDialog.confirm(source, String.format("Unattach %s?", cardToUnattach.toString()))) { + Card equippingCard = cardToUnattach.getEquipping().get(0); + cardToUnattach.unEquipCard(equippingCard); + this.addToList(cardToUnattach); + payment.setPaidManaPart(this); + } else { + payment.setCancel(true); + payment.getRequirements().finishPaying(); + return false; + } + + return true; + } + + private Card findCardToUnattach(final Card source, Player activator) { + if (getType().equals("CARDNAME")) { + if (source.isEquipping()) { + return source; + } + } else { + List attachees = CardLists.getValidCards(source.getEquippedBy(), this.getType(), activator, source); + if (attachees.size() > 0) { + // Just pick the first one, although maybe give a dialog + return attachees.get(0); + } + } + return null; + } + + /* + * (non-Javadoc) + * + * @see + * forge.card.cost.CostPart#decideAIPayment(forge.card.spellability.SpellAbility + * , forge.Card, forge.card.cost.Cost_Payment) + */ + @Override + public final boolean decideAIPayment(final AIPlayer ai, final SpellAbility ability, final Card source, final CostPayment payment) { + this.resetList(); + return true; + } +}