From 4837dbab301b452724ed997ae1a2473837d7c569 Mon Sep 17 00:00:00 2001 From: Sol Date: Mon, 3 Dec 2012 02:49:53 +0000 Subject: [PATCH] - Convert Gilder Bairn and Vampire Hexmage to script - Added support for Repeating over Counters --- res/cardsfolder/g/gilder_bairn.txt | 3 + res/cardsfolder/v/vampire_hexmage.txt | 5 +- .../card/abilityfactory/AbilityFactory.java | 21 +++ .../card/abilityfactory/ai/RepeatEachAi.java | 52 ++++++- .../effects/CountersPutEffect.java | 18 ++- .../effects/CountersRemoveEffect.java | 38 +++-- .../effects/RepeatEachEffect.java | 15 ++ .../cardfactory/CardFactoryCreatures.java | 142 +----------------- 8 files changed, 130 insertions(+), 164 deletions(-) diff --git a/res/cardsfolder/g/gilder_bairn.txt b/res/cardsfolder/g/gilder_bairn.txt index 2e05a4cf193..acfc39b65aa 100644 --- a/res/cardsfolder/g/gilder_bairn.txt +++ b/res/cardsfolder/g/gilder_bairn.txt @@ -3,6 +3,9 @@ ManaCost:1 GU GU Types:Creature Ouphe Text:no text PT:1/3 +A:AB$ RepeatEach | Cost$ 2 GU Untap | ValidTgts$ Permanent | RepeatCounters$ True | RepeatSubAbility$ DoubleCounters | SpellDescription$ For each counter on target permanent, put another of those counters on that permanent. | StackDescription$ SpellDescription | AILogic$ DoubleCounters | SubAbility$ DBCleanup +SVar:DoubleCounters:DB$ PutCounter | Defined$ Targeted | CounterType$ RepeatSVarCounter | CounterNum$ RepeatCounterAmount +SVar:DBCleanup:DB$ Cleanup | ClearRemembered$ True SVar:Rarity:Uncommon SVar:Picture:http://www.wizards.com/global/images/magic/general/gilder_bairn.jpg SetInfo:EVE|Uncommon|http://magiccards.info/scans/en/eve/152.jpg diff --git a/res/cardsfolder/v/vampire_hexmage.txt b/res/cardsfolder/v/vampire_hexmage.txt index 1850af2a5b0..833d043f5fe 100644 --- a/res/cardsfolder/v/vampire_hexmage.txt +++ b/res/cardsfolder/v/vampire_hexmage.txt @@ -1,9 +1,12 @@ Name:Vampire Hexmage ManaCost:B B Types:Creature Vampire Shaman -Text:Sacrifice Vampire Hexmage: Remove all counters from target permanent. +Text:no text PT:2/1 K:First Strike +A:AB$ RepeatEach | Cost$ Sac<1/CARDNAME> | ValidTgts$ Permanent | RepeatCounters$ True | RepeatSubAbility$ RemoveAllCounters | SpellDescription$ Remove all counters from target permanent. | StackDescription$ SpellDescription | AILogic$ RemoveAllCounters | SubAbility$ DBCleanup +SVar:RemoveAllCounters:DB$ RemoveCounter | Defined$ Targeted | CounterType$ RepeatSVarCounter | CounterNum$ RepeatCounterAmount +SVar:DBCleanup:DB$ Cleanup | ClearRemembered$ True SVar:RemAIDeck:True SVar:Rarity:Uncommon SVar:Picture:http://www.wizards.com/global/images/magic/general/vampire_hexmage.jpg diff --git a/src/main/java/forge/card/abilityfactory/AbilityFactory.java b/src/main/java/forge/card/abilityfactory/AbilityFactory.java index c964a9e90d4..b0fdeea7277 100644 --- a/src/main/java/forge/card/abilityfactory/AbilityFactory.java +++ b/src/main/java/forge/card/abilityfactory/AbilityFactory.java @@ -29,6 +29,7 @@ import forge.CardLists; import forge.CardUtil; import forge.Command; import forge.Constant; +import forge.CounterType; import forge.GameActionUtil; import forge.Singletons; import forge.card.cardfactory.CardFactoryUtil; @@ -1767,4 +1768,24 @@ public class AbilityFactory { } } + public static CounterType getCounterType(String name, SpellAbility sa) throws Exception { + CounterType counterType; + + try{ + counterType = CounterType.getType(name); + } catch(Exception e) { + String type = sa.getSVar(name); + if (type.equals("")) { + type = sa.getSourceCard().getSVar(name); + } + + if (type.equals("")) { + throw new Exception("Counter type doesn't match, nor does an SVar exist with the type name."); + } + counterType = CounterType.getType(type); + } + + return counterType; + } + } // end class AbilityFactory diff --git a/src/main/java/forge/card/abilityfactory/ai/RepeatEachAi.java b/src/main/java/forge/card/abilityfactory/ai/RepeatEachAi.java index bfa483afd94..8013d44eb2c 100644 --- a/src/main/java/forge/card/abilityfactory/ai/RepeatEachAi.java +++ b/src/main/java/forge/card/abilityfactory/ai/RepeatEachAi.java @@ -1,13 +1,19 @@ package forge.card.abilityfactory.ai; +import java.util.ArrayList; import java.util.List; +import com.google.common.base.Predicate; + import forge.Card; import forge.CardLists; +import forge.CounterType; import forge.CardPredicates.Presets; import forge.card.abilityfactory.SpellAiLogic; import forge.card.spellability.SpellAbility; +import forge.card.spellability.Target; import forge.game.player.Player; +import forge.game.zone.ZoneType; /** * TODO: Write javadoc for this type. @@ -34,11 +40,55 @@ public class RepeatEachAi extends SpellAiLogic { if (compTokenCreats.size() <= humTokenCreats.size()) { return false; } + } else if ("DoubleCounters".equals(logic)) { + // TODO Improve this logic, double Planeswalker counters first, then +1/+1 on Useful creatures + // Then Charge Counters, then -1/-1 on Opposing Creatures + List perms = new ArrayList(aiPlayer.getCardsIn(ZoneType.Battlefield)); + perms = CardLists.filter(CardLists.getTargetableCards(perms, sa), new Predicate() { + @Override + public boolean apply(final Card c) { + return (c.sumAllCounters() > 0); + } + }); + if (perms.isEmpty()) { + return false; + } + CardLists.shuffle(perms); + sa.setTargetCard(perms.get(0)); + } else if ("RemoveAllCounters".equals(logic)) { + // Break Dark Depths + Target tgt = sa.getTarget(); + List depthsList = aiPlayer.getCardsIn(ZoneType.Battlefield, "Dark Depths"); + depthsList = CardLists.filter(depthsList, new Predicate() { + @Override + public boolean apply(final Card crd) { + return crd.getCounters(CounterType.ICE) >= 3; + } + }); + + if (depthsList.size() > 0) { + tgt.addTarget(depthsList.get(0)); + return true; + } + + // Get rid of Planeswalkers: + List list = new ArrayList(aiPlayer.getOpponent().getCardsIn(ZoneType.Battlefield)); + list = CardLists.filter(list, new Predicate() { + @Override + public boolean apply(final Card crd) { + return crd.isPlaneswalker() && (crd.getCounters(CounterType.LOYALTY) >= 5); + } + }); + + if (list.isEmpty()) { + return false; + } + + tgt.addTarget(list.get(0)); } // TODO Add some normal AI variability here return true; } - } diff --git a/src/main/java/forge/card/abilityfactory/effects/CountersPutEffect.java b/src/main/java/forge/card/abilityfactory/effects/CountersPutEffect.java index 87ea1a6a24d..9b3aa30f8a4 100644 --- a/src/main/java/forge/card/abilityfactory/effects/CountersPutEffect.java +++ b/src/main/java/forge/card/abilityfactory/effects/CountersPutEffect.java @@ -21,7 +21,6 @@ public class CountersPutEffect extends SpellEffect { final StringBuilder sb = new StringBuilder(); final Card card = sa.getSourceCard(); - final CounterType cType = CounterType.valueOf(sa.getParam("CounterType")); final int amount = AbilityFactory.calculateAmount(card, sa.getParam("CounterNum"), sa); sb.append("Put "); @@ -57,7 +56,16 @@ public class CountersPutEffect extends SpellEffect { @Override public void resolve(SpellAbility sa) { final Card card = sa.getSourceCard(); - final String type = sa.getParam("CounterType"); + + CounterType counterType; + + try{ + counterType = AbilityFactory.getCounterType(sa.getParam("CounterType"), sa); + } catch(Exception e) { + System.out.println("Counter type doesn't match, nor does an SVar exist with the type name."); + return; + } + int counterAmount = AbilityFactory.calculateAmount(sa.getSourceCard(), sa.getParam("CounterNum"), sa); final int max = sa.hasParam("MaxFromEffect") ? Integer.parseInt(sa.getParam("MaxFromEffect")) : -1; @@ -86,16 +94,16 @@ public class CountersPutEffect extends SpellEffect { for (final Card tgtCard : tgtCards) { if ((tgt == null) || tgtCard.canBeTargetedBy(sa)) { if (max != -1) { - counterAmount = max - tgtCard.getCounters(CounterType.valueOf(type)); + counterAmount = max - tgtCard.getCounters(counterType); } final Zone zone = Singletons.getModel().getGame().getZoneOf(tgtCard); if (zone == null) { // Do nothing, token disappeared } else if (zone.is(ZoneType.Battlefield) || zone.is(ZoneType.Stack)) { - tgtCard.addCounter(CounterType.valueOf(type), counterAmount, true); + tgtCard.addCounter(counterType, counterAmount, true); } else { // adding counters to something like re-suspend cards - tgtCard.addCounter(CounterType.valueOf(type), counterAmount, false); + tgtCard.addCounter(counterType, counterAmount, false); } } } diff --git a/src/main/java/forge/card/abilityfactory/effects/CountersRemoveEffect.java b/src/main/java/forge/card/abilityfactory/effects/CountersRemoveEffect.java index 26bc637bbe1..92e2ae78fbc 100644 --- a/src/main/java/forge/card/abilityfactory/effects/CountersRemoveEffect.java +++ b/src/main/java/forge/card/abilityfactory/effects/CountersRemoveEffect.java @@ -31,12 +31,10 @@ public class CountersRemoveEffect extends SpellEffect { if ("Any".matches(counterName)) { if (amount == 1) { sb.append("a counter"); - } - else { + } else { sb.append(amount).append(" ").append(" counter"); } - } - else { + } else { sb.append(amount).append(" ").append(CounterType.valueOf(counterName).getName()).append(" counter"); } if (amount != 1) { @@ -63,6 +61,15 @@ public class CountersRemoveEffect extends SpellEffect { counterAmount = AbilityFactory.calculateAmount(sa.getSourceCard(), sa.getParam("CounterNum"), sa); } + CounterType counterType; + + try { + counterType = AbilityFactory.getCounterType(type, sa); + } catch (Exception e) { + System.out.println("Counter type doesn't match, nor does an SVar exist with the type name."); + return; + } + final Target tgt = sa.getTarget(); boolean rememberRemoved = false; @@ -73,7 +80,7 @@ public class CountersRemoveEffect extends SpellEffect { if ((tgt == null) || tgtCard.canBeTargetedBy(sa)) { final Zone zone = Singletons.getModel().getGame().getZoneOf(tgtCard); if (sa.getParam("CounterNum").equals("All")) { - counterAmount = tgtCard.getCounters(CounterType.valueOf(type)); + counterAmount = tgtCard.getCounters(counterType); } if (type.matches("Any")) { @@ -92,8 +99,7 @@ public class CountersRemoveEffect extends SpellEffect { if (typeChoices.size() > 1) { String prompt = "Select type counters to remove"; chosenType = GuiChoose.one(prompt, typeChoices); - } - else { + } else { chosenType = typeChoices.get(0); } chosenAmount = tgtCounters.get(chosenType); @@ -110,9 +116,10 @@ public class CountersRemoveEffect extends SpellEffect { String prompt = "Select the number of " + chosenType.getName() + " counters to remove"; chosenAmount = GuiChoose.one(prompt, choices); } - } - else { - // TODO: ArsenalNut (06 Feb 12) - computer needs better logic to pick a counter type and probably an initial target + } else { + // TODO: ArsenalNut (06 Feb 12)computer needs + // better logic to pick a counter type and probably + // an initial target // find first nonzero counter on target for (Object key : tgtCounters.keySet()) { if (tgtCounters.get(key) > 0) { @@ -134,8 +141,7 @@ public class CountersRemoveEffect extends SpellEffect { } counterAmount -= chosenAmount; } - } - else { + } else { if (zone.is(ZoneType.Battlefield) || zone.is(ZoneType.Exile)) { if (sa.hasParam("UpTo") && sa.getActivatingPlayer().isHuman()) { final ArrayList choices = new ArrayList(); @@ -148,14 +154,14 @@ public class CountersRemoveEffect extends SpellEffect { } } if (rememberRemoved) { - if (counterAmount > tgtCard.getCounters(CounterType.valueOf(type))) { - counterAmount = tgtCard.getCounters(CounterType.valueOf(type)); + if (counterAmount > tgtCard.getCounters(counterType)) { + counterAmount = tgtCard.getCounters(counterType); } for (int i = 0; i < counterAmount; i++) { - card.addRemembered(CounterType.valueOf(type)); + card.addRemembered(counterType); } } - tgtCard.subtractCounter(CounterType.valueOf(type), counterAmount); + tgtCard.subtractCounter(counterType, counterAmount); } } } diff --git a/src/main/java/forge/card/abilityfactory/effects/RepeatEachEffect.java b/src/main/java/forge/card/abilityfactory/effects/RepeatEachEffect.java index e6e59cc5b56..9951216dfbb 100644 --- a/src/main/java/forge/card/abilityfactory/effects/RepeatEachEffect.java +++ b/src/main/java/forge/card/abilityfactory/effects/RepeatEachEffect.java @@ -1,9 +1,12 @@ package forge.card.abilityfactory.effects; +import java.util.HashSet; import java.util.List; +import java.util.Set; import forge.Card; import forge.CardLists; +import forge.CounterType; import forge.Singletons; import forge.card.abilityfactory.AbilityFactory; import forge.card.abilityfactory.SpellEffect; @@ -74,5 +77,17 @@ public class RepeatEachEffect extends SpellEffect { source.removeRemembered(player); } } + + if (sa.hasParam("RepeatCounters")) { + Card target = sa.getTargetCard(); + Set types = new HashSet(target.getCounters().keySet()); + for (CounterType type : types) { + StringBuilder sb = new StringBuilder(); + sb.append("Number$").append(target.getCounters(type)); + source.setSVar("RepeatSVarCounter", type.getName().toUpperCase()); + source.setSVar("RepeatCounterAmount", sb.toString()); + AbilityFactory.resolve(repeat, false); + } + } } } diff --git a/src/main/java/forge/card/cardfactory/CardFactoryCreatures.java b/src/main/java/forge/card/cardfactory/CardFactoryCreatures.java index 4bbdc5a708c..85b8ffce519 100644 --- a/src/main/java/forge/card/cardfactory/CardFactoryCreatures.java +++ b/src/main/java/forge/card/cardfactory/CardFactoryCreatures.java @@ -76,70 +76,6 @@ import forge.util.Aggregates; * @version $Id$ */ public class CardFactoryCreatures { - - private static void getCard_GilderBairn(final Card card) { - final Cost abCost = new Cost(card, "2 GU Untap", true); - final Target tgt = new Target(card, "Select target permanent.", new String[] { "Permanent" }); - class GilderBairnAbility extends AbilityActivated { - public GilderBairnAbility(final Card ca, final Cost co, final Target t) { - super(ca, co, t); - } - - private static final long serialVersionUID = -1847685865277129366L; - - @Override - public void resolve() { - final Card c = this.getTargetCard(); - - if (c.sumAllCounters() == 0) { - return; - } else if (c.isInPlay() && c.canBeTargetedBy(this)) { - // zerker clean up: - for (final CounterType c1 : CounterType.values()) { - if (c.getCounters(c1) > 0) { - c.addCounter(c1, c.getCounters(c1), true); - } - } - } - } - - @Override - public AbilityActivated getCopy() { - return new GilderBairnAbility(getSourceCard(), getPayCosts(), new Target(getTarget())); - } - - @Override - public boolean canPlayAI() { - List perms = new ArrayList(getActivatingPlayer().getCardsIn(ZoneType.Battlefield)); - perms = CardLists.filter(CardLists.getTargetableCards(perms, this), new Predicate() { - @Override - public boolean apply(final Card c) { - //if (c.getCounters().isEmpty()) - return (c.sumAllCounters() > 0); - } - }); - if (perms.isEmpty()) { - return false; - } - CardLists.shuffle(perms); - this.setTargetCard(perms.get(0)); - return true; - } - - @Override - public String getDescription() { - final StringBuilder sb = new StringBuilder(); - sb.append(getPayCosts()); - sb.append("For each counter on target permanent, "); - sb.append("put another of those counters on that permanent."); - return sb.toString(); - } - } - final AbilityActivated a1 = new GilderBairnAbility(card, abCost, tgt); - - card.addSpellAbility(a1); - } - private static void getCard_PainterServant(final Card card) { final long[] timeStamp = new long[1]; final String[] color = new String[1]; @@ -551,78 +487,6 @@ public class CardFactoryCreatures { }; card.addComesIntoPlayCommand(comesIntoPlay); } - - private static void getCard_VampireHexmage(final Card card) { - /* - * Sacrifice Vampire Hexmage: Remove all counters from target - * permanent. - */ - - final Cost cost = new Cost(card, "Sac<1/CARDNAME>", true); - final Target tgt = new Target(card, "Select a permanent", "Permanent".split(",")); - class VampireHexmageAbility extends AbilityActivated { - public VampireHexmageAbility(final Card ca, final Cost co, final Target t) { - super(ca, co, t); - } - - @Override - public AbilityActivated getCopy() { - return new VampireHexmageAbility(getSourceCard(), - getPayCosts(), new Target(getTarget())); - } - - private static final long serialVersionUID = -5084369399105353155L; - - @Override - public boolean canPlayAI() { - - // Dark Depths: - final Player ai = getActivatingPlayer(); - List list = ai.getCardsIn(ZoneType.Battlefield, "Dark Depths"); - list = CardLists.filter(list, new Predicate() { - @Override - public boolean apply(final Card crd) { - return crd.getCounters(CounterType.ICE) >= 3; - } - }); - - if (list.size() > 0) { - tgt.addTarget(list.get(0)); - return true; - } - - // Get rid of Planeswalkers: - list = new ArrayList(ai.getOpponent().getCardsIn(ZoneType.Battlefield)); - list = CardLists.filter(list, new Predicate() { - @Override - public boolean apply(final Card crd) { - return crd.isPlaneswalker() && (crd.getCounters(CounterType.LOYALTY) >= 5); - } - }); - - if (list.size() > 0) { - tgt.addTarget(list.get(0)); - return true; - } - - return false; - } - - @Override - public void resolve() { - final Card c = this.getTargetCard(); - // need a copy to avoid exception caused by modification of Iterable being enumerated - Map copy = new HashMap(c.getCounters()); - for (final Entry counter : copy.entrySet()) { - c.subtractCounter(counter.getKey(), counter.getValue()); - } - } - } - final SpellAbility ability = new VampireHexmageAbility(card, cost, tgt); - - card.addSpellAbility(ability); - } - private static void getCard_SurturedGhoul(final Card card) { final int[] numCreatures = new int[1]; final int[] sumPower = new int[1]; @@ -1033,9 +897,7 @@ public class CardFactoryCreatures { public static void buildCard(final Card card, final String cardName) { - if (cardName.equals("Gilder Bairn")) { - getCard_GilderBairn(card); - } else if (cardName.equals("Painter's Servant")) { + if (cardName.equals("Painter's Servant")) { getCard_PainterServant(card); } else if (cardName.equals("Stangg")) { getCard_Stangg(card); @@ -1050,8 +912,6 @@ public class CardFactoryCreatures { } else if (cardName.equals("Gnarlid Pack") || cardName.equals("Apex Hawks") || cardName.equals("Enclave Elite") || cardName.equals("Quag Vampires") || cardName.equals("Skitter of Lizards") || cardName.equals("Joraga Warcaller")) { getCard_MultikickerP1P1(card, cardName); - } else if (cardName.equals("Vampire Hexmage")) { - getCard_VampireHexmage(card); } else if (cardName.equals("Sutured Ghoul")) { getCard_SurturedGhoul(card); } else if (cardName.equals("Yosei, the Morning Star")) {