From 0a371d419549c041cb3f80ce90b946aadb418c20 Mon Sep 17 00:00:00 2001 From: jendave Date: Sat, 6 Aug 2011 05:34:29 +0000 Subject: [PATCH] - Added Sac- as a cost to abDamageTgt - Added Krovikan Horror, Fodder Cannon, Skull Catapult, Arms Dealer, Rath's Edge, Deadapult, Goblin Bombardment using new subkeyword - Added some missing Rarity values from the python script. --- res/card-pictures.txt | 7 + res/cards.txt | 45 ++++++ res/common.txt | 16 ++ res/quest/common.txt | 16 ++ res/quest/rare.txt | 7 + res/quest/uncommon.txt | 12 ++ res/rare.txt | 7 + res/uncommon.txt | 12 ++ src/forge/CardFactory.java | 265 ++++++++------------------------- src/forge/CardFactoryUtil.java | 48 +++++- src/forge/EndOfTurn.java | 1 + src/forge/GameActionUtil.java | 25 ++++ 12 files changed, 251 insertions(+), 210 deletions(-) diff --git a/res/card-pictures.txt b/res/card-pictures.txt index 4bb93f54001..3ecd9486eaf 100644 --- a/res/card-pictures.txt +++ b/res/card-pictures.txt @@ -3825,3 +3825,10 @@ rabid_wolverines.jpg http://www.wizards.com/global/images/magic/general/rabid_w citanul_druid.jpg http://www.wizards.com/global/images/magic/general/citanul_druid.jpg dwarven_berserker.jpg http://www.wizards.com/global/images/magic/general/dwarven_berserker.jpg battle_squadron.jpg http://www.wizards.com/global/images/magic/general/battle_squadron.jpg +deadapult.jpg http://www.wizards.com/global/images/magic/general/deadapult.jpg +raths_edge.jpg http://www.wizards.com/global/images/magic/general/raths_edge.jpg +arms_dealer.jpg http://www.wizards.com/global/images/magic/general/arms_dealer.jpg +skull_catapult.jpg http://www.wizards.com/global/images/magic/general/skull_catapult.jpg +fodder_cannon.jpg http://www.wizards.com/global/images/magic/general/fodder_cannon.jpg +krovikan_horror.jpg http://www.wizards.com/global/images/magic/general/krovikan_horror.jpg +goblin_bombardment.jpg http://www.wizards.com/global/images/magic/general/goblin_bombardment.jpg diff --git a/res/cards.txt b/res/cards.txt index 4023d7acf64..b1e5d38e25e 100644 --- a/res/cards.txt +++ b/res/cards.txt @@ -1,3 +1,48 @@ +Deadapult +2 R +Enchantment +no text +abDamageTgtCP R Sac-Zombie:2 + +Goblin Bombardment +1 R +Enchantment +no text +abDamageTgtCP 0 Sac-Creature:1 + +Rath's Edge +no cost +Legendary Land +no text +tap: add 1 +abDamageTgtCP 4 T Sac-Land:1 + +Arms Dealer +2 R +Creature Goblin +no text +1/1 +abDamageTgtC 1 R Sac-Goblin:4 + +Skull Catapult +4 +Artifact +no text +abDamageTgtCP 1 T Sac-Creature:2 + +Fodder Cannon +4 +Artifact +no text +abDamageTgtC 4 T Sac-Creature:4 + +Krovikan Horror +3 B +Creature Horror Spirit +no text +2/2 +abDamageTgtCP 1 Sac-Creature:1 + Aura Extraction 1 W Instant diff --git a/res/common.txt b/res/common.txt index 8835923a18e..0eb9f2688b6 100644 --- a/res/common.txt +++ b/res/common.txt @@ -1704,3 +1704,19 @@ Grizzled Wolverine Anaba Spirit Crafter Hissing Iguanar Sunken City +Disempower +Excommunicate +Uproot +Forced Retreat +Repel +Temporal Eddy +Time Ebb +Hoodwink +Disperse +Into Thin Air +Symbol of Unsummoning +Exiled Boggart +Glassdust Hulk +Deepwood Wolverine +Rabid Wolverines +Dwarven Berserker diff --git a/res/quest/common.txt b/res/quest/common.txt index 8835923a18e..0eb9f2688b6 100644 --- a/res/quest/common.txt +++ b/res/quest/common.txt @@ -1704,3 +1704,19 @@ Grizzled Wolverine Anaba Spirit Crafter Hissing Iguanar Sunken City +Disempower +Excommunicate +Uproot +Forced Retreat +Repel +Temporal Eddy +Time Ebb +Hoodwink +Disperse +Into Thin Air +Symbol of Unsummoning +Exiled Boggart +Glassdust Hulk +Deepwood Wolverine +Rabid Wolverines +Dwarven Berserker diff --git a/res/quest/rare.txt b/res/quest/rare.txt index 7cd46775feb..21a92446756 100644 --- a/res/quest/rare.txt +++ b/res/quest/rare.txt @@ -994,3 +994,10 @@ Taurean Mauler Kavu Monarch Sibilant Spirit Fountain Watch +Deadapult +Rath's Edge +Krovikan Horror +Archon of Redemption +Terra Eternal +Scion of the Wild +Battle Squadron diff --git a/res/quest/uncommon.txt b/res/quest/uncommon.txt index e1dcc809987..78aca2272ee 100644 --- a/res/quest/uncommon.txt +++ b/res/quest/uncommon.txt @@ -1049,3 +1049,15 @@ Flowstone Surge Insight Deepchannel Mentor Warmth +Arms Dealer +Skull Catapult +Fodder Cannon +Aura Extraction +Fallow Earth +Planar Void +Yawgmoth's Edict +Inspired Sprite +Harbor Guardian +Baloth Woodcrasher +Citanul Druid +Goblin Bombardment diff --git a/res/rare.txt b/res/rare.txt index 7cd46775feb..21a92446756 100644 --- a/res/rare.txt +++ b/res/rare.txt @@ -994,3 +994,10 @@ Taurean Mauler Kavu Monarch Sibilant Spirit Fountain Watch +Deadapult +Rath's Edge +Krovikan Horror +Archon of Redemption +Terra Eternal +Scion of the Wild +Battle Squadron diff --git a/res/uncommon.txt b/res/uncommon.txt index e1dcc809987..78aca2272ee 100644 --- a/res/uncommon.txt +++ b/res/uncommon.txt @@ -1049,3 +1049,15 @@ Flowstone Surge Insight Deepchannel Mentor Warmth +Arms Dealer +Skull Catapult +Fodder Cannon +Aura Extraction +Fallow Earth +Planar Void +Yawgmoth's Edict +Inspired Sprite +Harbor Guardian +Baloth Woodcrasher +Citanul Druid +Goblin Bombardment diff --git a/src/forge/CardFactory.java b/src/forge/CardFactory.java index efd9fd879f1..2f277c5a657 100644 --- a/src/forge/CardFactory.java +++ b/src/forge/CardFactory.java @@ -1686,19 +1686,32 @@ public class CardFactory implements NewConstants { tmpCost = k[0].substring(12); } + final boolean sacCost[] = {false}; + boolean sacFirstCost = false; + final String sacType[] = {""}; + + if(tmpCost.contains("Sac-")) { + sacCost[0] = true; + int sacPos = tmpCost.indexOf("Sac-"); + sacType[0] = tmpCost.substring(sacPos).replace("Sac-", "").trim(); + tmpCost = tmpCost.substring(0,sacPos-1).trim(); + sacFirstCost = (tmpCost.length() == 0); + } + boolean tapCost = false; - boolean tapOnlyCost = false; + boolean tapFirstCost = false; if(tmpCost.contains("T")) { tapCost = true; tmpCost = tmpCost.replace("T", ""); tmpCost = tmpCost.trim(); - if(tmpCost.length() == 0) tapOnlyCost = true; + tapFirstCost = (tmpCost.length() == 0); } + if (tmpCost == "") tmpCost = "0"; // this doesn't seem to do anything + final String manaCost = tmpCost; - final int NumDmg[] = {-1}; final String NumDmgX[] = {"none"}; @@ -1736,11 +1749,31 @@ public class CardFactory implements NewConstants { spDesc[0] = sb.toString(); stDesc[0] = card.getName() + " -" + sb.toString(); } - if(tapOnlyCost == true) spDesc[0] = "Tap: " + spDesc[0]; - else if(tapCost == true) spDesc[0] = manaCost + ", tap: " + spDesc[0]; - else spDesc[0] = manaCost + ": " + spDesc[0]; + StringBuilder abCost = new StringBuilder(); + abCost.append(manaCost); + if (tapCost){ + if (tapFirstCost) + abCost.append("T"); + else + abCost.append(", t"); + abCost.append("ap"); + } + if (sacCost[0]){ + if (sacFirstCost) + abCost.append("S"); + else + abCost.append(", s"); + abCost.append("acrifice a "); + abCost.append(sacType[0]); + } + abCost.append(": "); + + spDesc[0] = abCost + spDesc[0]; + + // Damage ability starts here if(!tapCost) { + // adDamage starts here final SpellAbility abDamage = new Ability_Activated(card, manaCost) { private static final long serialVersionUID = -7560349014757367722L; @@ -1759,10 +1792,10 @@ public class CardFactory implements NewConstants { CardList hand = new CardList(compHand.getCards()); if(hand.size() >= 7) // anti-discard-at-EOT - return true; + return true; - if(AllZone.Human_Life.getLife() < (10 - damage)) // if damage from this spell would drop the human to less than 10 life - return true; + if(AllZone.Human_Life.getLife() - damage < 10) // if damage from this spell would drop the human to less than 10 life + return true; return false; } @@ -1805,6 +1838,7 @@ public class CardFactory implements NewConstants { @Override public boolean canPlayAI() { + if (sacCost[0]) return false; damage = getNumDamage(); Random r = new Random(); // prevent run-away activations @@ -1869,15 +1903,20 @@ public class CardFactory implements NewConstants { abDamage.setDescription(spDesc[0]); abDamage.setStackDescription(stDesc[0]); - if(TgtCP[0] == true) abDamage.setBeforePayMana(CardFactoryUtil.input_targetCreaturePlayer( - abDamage, true, false)); + + if(TgtCP[0] == true) + abDamage.setBeforePayMana(CardFactoryUtil.input_targetCreaturePlayer(abDamage, true, sacFirstCost)); else if(TgtCreature[0] == true) abDamage.setBeforePayMana(CardFactoryUtil.input_targetCreature(abDamage)); else if(TgtPlayer[0] == true) abDamage.setBeforePayMana(CardFactoryUtil.input_targetPlayer(abDamage)); + if (sacCost[0]) + abDamage.setAfterPayMana(CardFactoryUtil.input_sacrificeType(abDamage, sacType[0], "Sacrifice a "+sacType[0])); + + card.addSpellAbility(abDamage); }//!tapCost - if(tapCost) { + else { //tapCost final SpellAbility abDamage = new Ability_Tap(card) { private static final long serialVersionUID = -7960649024757327722L; @@ -1896,10 +1935,10 @@ public class CardFactory implements NewConstants { CardList hand = new CardList(compHand.getCards()); if(hand.size() >= 7) // anti-discard-at-EOT - return true; + return true; - if(AllZone.Human_Life.getLife() < (10 - damage)) // if damage from this spell would drop the human to less than 10 life - return true; + if(AllZone.Human_Life.getLife() - damage < 10) // if damage from this spell would drop the human to less than 10 life + return true; return false; } @@ -1942,6 +1981,7 @@ public class CardFactory implements NewConstants { @Override public boolean canPlayAI() { + if (sacCost[0]) return false; damage = getNumDamage(); boolean na = false; @@ -2010,201 +2050,16 @@ public class CardFactory implements NewConstants { else if(TgtCreature[0] == true) abDamage.setBeforePayMana(CardFactoryUtil.input_targetCreature(abDamage)); else if(TgtPlayer[0] == true) abDamage.setBeforePayMana(CardFactoryUtil.input_targetPlayer(abDamage)); - if(!tapOnlyCost) abDamage.setManaCost(manaCost); + if (sacCost[0]) + abDamage.setAfterPayMana(CardFactoryUtil.input_sacrificeType(abDamage, sacType[0], "Sacrifice a "+sacType[0])); + + if(!tapFirstCost && !sacFirstCost) abDamage.setManaCost(manaCost); card.addSpellAbility(abDamage); }//tapCost } - } - - // TODO: remove abDamageCP in favor of abDamageTgt - if(hasKeyword(card, "abDamageCP") != -1) { - int n = hasKeyword(card, "abDamageCP"); - if(n != -1) { - String parse = card.getKeyword().get(n).toString(); - card.removeIntrinsicKeyword(parse); - - String k[] = parse.split(":"); - - String tmpCost = k[0].substring(11); - - final int dmg[] = new int[1]; - dmg[0] = Integer.parseInt(k[1]); - - boolean tapCost = false; - boolean tapOnlyCost = false; - - if(tmpCost.contains("T")) { - tapCost = true; - tmpCost = tmpCost.replace("T", ""); - tmpCost = tmpCost.trim(); - if(tmpCost.length() == 0) tapOnlyCost = true; - } - - final String manaCost = tmpCost; - - String tempDesc = ""; - tempDesc = cardName + " deals " + dmg[0] + " damage to target creature or player."; - final String Desc = tempDesc; - - if(!tapCost) { - final SpellAbility ability = new Ability_Activated(card, manaCost) { - private static final long serialVersionUID = -7560349014757367722L; - - @Override - public boolean canPlayAI() { - Random r = new Random(); - if(r.nextFloat() <= Math.pow(.6667, card.getAbilityUsed())) return true; - else return false; - } - - @Override - public void chooseTargetAI() { - CardList list = CardFactoryUtil.AI_getHumanCreature(dmg[0], card, true); - list.shuffle(); - - if(list.isEmpty() || AllZone.Human_Life.getLife() < 5 + dmg[0]) setTargetPlayer(Constant.Player.Human); - else setTargetCard(list.get(0)); - }//chooseTargetAI - - @Override - public void resolve() { - if(getTargetCard() != null) { - if(AllZone.GameAction.isCardInPlay(getTargetCard()) - && CardFactoryUtil.canTarget(card, getTargetCard())) { - if(card.getKeyword().contains("Wither")) getTargetCard().addCounter( - Counters.M1M1, dmg[0]); - else getTargetCard().addDamage(dmg[0], card); - if(card.getKeyword().contains("Lifelink")) GameActionUtil.executeLifeLinkEffects( - card, dmg[0]); - - CardList cl = CardFactoryUtil.getAurasEnchanting(card, "Guilty Conscience"); - for(Card c:cl) { - GameActionUtil.executeGuiltyConscienceEffects(card, c, dmg[0]); - } - } - } else { - AllZone.GameAction.getPlayerLife(getTargetPlayer()).subtractLife(dmg[0],card); - if(card.getKeyword().contains("Lifelink")) GameActionUtil.executeLifeLinkEffects( - card, dmg[0]); - - CardList cl = CardFactoryUtil.getAurasEnchanting(card, "Guilty Conscience"); - for(Card c:cl) { - GameActionUtil.executeGuiltyConscienceEffects(card, c, dmg[0]); - } - } - }//resolve() - };//Ability_Activated - - ability.setDescription(manaCost + ": " + Desc); - ability.setBeforePayMana(CardFactoryUtil.input_targetCreaturePlayer(ability, true, false)); - card.addSpellAbility(ability); - }//!tapCost - - if(tapOnlyCost == true) { - final Ability_Tap ability = new Ability_Tap(card) { - private static final long serialVersionUID = -7560349014757367722L; - - @Override - public void chooseTargetAI() { - CardList list = CardFactoryUtil.AI_getHumanCreature(1, card, true); - list.shuffle(); - - if(list.isEmpty() || AllZone.Human_Life.getLife() < 5 + dmg[0]) setTargetPlayer(Constant.Player.Human); - else setTargetCard(list.get(0)); - }//chooseTargetAI - - @Override - public void resolve() { - if(getTargetCard() != null) { - if(AllZone.GameAction.isCardInPlay(getTargetCard()) - && CardFactoryUtil.canTarget(card, getTargetCard())) { - if(card.getKeyword().contains("Wither")) getTargetCard().addCounter( - Counters.M1M1, dmg[0]); - else getTargetCard().addDamage(dmg[0], card); - if(card.getKeyword().contains("Lifelink")) GameActionUtil.executeLifeLinkEffects( - card, dmg[0]); - - CardList cl = CardFactoryUtil.getAurasEnchanting(card, "Guilty Conscience"); - for(Card c:cl) { - GameActionUtil.executeGuiltyConscienceEffects(card, c, dmg[0]); - } - - } - } else { - AllZone.GameAction.getPlayerLife(getTargetPlayer()).subtractLife(dmg[0],card); - if(card.getKeyword().contains("Lifelink")) GameActionUtil.executeLifeLinkEffects( - card, dmg[0]); - - CardList cl = CardFactoryUtil.getAurasEnchanting(card, "Guilty Conscience"); - for(Card c:cl) { - GameActionUtil.executeGuiltyConscienceEffects(card, c, dmg[0]); - } - - - card.setDealtDmgToOppThisTurn(true); - } - }//resolve() - };//Ability_Tap - - ability.setDescription("tap: " + Desc); - ability.setBeforePayMana(CardFactoryUtil.input_targetCreaturePlayer(ability, true, false)); - card.addSpellAbility(ability); - }//tapOnlyCost - - if(!tapOnlyCost && tapCost) { - final SpellAbility ability = new Ability_Tap(card, manaCost) { - private static final long serialVersionUID = -7560349014757367722L; - - @Override - public void chooseTargetAI() { - CardList list = CardFactoryUtil.AI_getHumanCreature(1, card, true); - list.shuffle(); - - if(list.isEmpty() || AllZone.Human_Life.getLife() < 5 + dmg[0]) setTargetPlayer(Constant.Player.Human); - else setTargetCard(list.get(0)); - }//chooseTargetAI - - @Override - public void resolve() { - if(getTargetCard() != null) { - if(AllZone.GameAction.isCardInPlay(getTargetCard()) - && CardFactoryUtil.canTarget(card, getTargetCard())) { - if(card.getKeyword().contains("Wither")) getTargetCard().addCounter( - Counters.M1M1, dmg[0]); - else getTargetCard().addDamage(dmg[0], card); - if(card.getKeyword().contains("Lifelink")) GameActionUtil.executeLifeLinkEffects( - card, dmg[0]); - - CardList cl = CardFactoryUtil.getAurasEnchanting(card, "Guilty Conscience"); - for(Card c:cl) { - GameActionUtil.executeGuiltyConscienceEffects(card, c, dmg[0]); - } - } - } else { - AllZone.GameAction.getPlayerLife(getTargetPlayer()).subtractLife(dmg[0],card); - if(card.getKeyword().contains("Lifelink")) GameActionUtil.executeLifeLinkEffects( - card, dmg[0]); - - - CardList cl = CardFactoryUtil.getAurasEnchanting(card, "Guilty Conscience"); - for(Card c:cl) { - GameActionUtil.executeGuiltyConscienceEffects(card, c, dmg[0]); - } - - card.setDealtDmgToOppThisTurn(true); - } - }//resolve() - };//Ability_Tap - - ability.setDescription(manaCost + ", tap: " + Desc); - ability.setBeforePayMana(CardFactoryUtil.input_targetCreaturePlayer(ability, true, false)); - card.addSpellAbility(ability); - }//!tapOnlyCost && tapCost - }//n - }//AbDamageCP - + }//abDamageTgt // Generic destroy target card if(hasKeyword(card, "spDestroyTgt") != -1) { diff --git a/src/forge/CardFactoryUtil.java b/src/forge/CardFactoryUtil.java index ce29e258bb9..8c8eb6169f6 100644 --- a/src/forge/CardFactoryUtil.java +++ b/src/forge/CardFactoryUtil.java @@ -354,12 +354,17 @@ public class CardFactoryUtil { void done() { paid.execute(); - if(spell instanceof Ability_Tap && spell.getManaCost().equals("0")) stopSetNext(new Input_NoCost_TapAbility( - (Ability_Tap) spell)); + if(spell instanceof Ability_Tap && spell.getManaCost().equals("0")) + stopSetNext(new Input_NoCost_TapAbility((Ability_Tap) spell)); else if(spell.getManaCost().equals("0") || this.isFree()) { - this.setFree(false); - AllZone.Stack.add(spell, spell.getSourceCard().getManaCost().contains("X")); - stop(); + if (spell.getAfterPayMana() == null){ + this.setFree(false); + AllZone.Stack.add(spell, spell.getSourceCard().getManaCost().contains("X")); + stop(); + } + else{ + stopSetNext(spell.getAfterPayMana()); + } } else stopSetNext(new Input_PayManaCost(spell)); } }; @@ -513,6 +518,39 @@ public class CardFactoryUtil { return target; }//input_sacrifice() + public static Input input_sacrificeType(final SpellAbility spell, final String type, final String message) { + // This input should be setAfterManaPaid so it can add the spell to the stack + Input target = new Input() { + private static final long serialVersionUID = 2685832214519141903L; + private CardList typeList; + + @Override + public void showMessage() { + PlayerZone play = AllZone.getZone(Constant.Zone.Play, spell.getSourceCard().getController()); + typeList = new CardList(play.getCards()); + typeList = typeList.getType(type); + AllZone.Display.showMessage(message); + ButtonUtil.enableOnlyCancel(); + } + + @Override + public void selectButtonCancel() { + stop(); + } + + @Override + public void selectCard(Card card, PlayerZone zone) { + if(typeList.contains(card)) { + AllZone.GameAction.sacrifice(card); + AllZone.Stack.add(spell); + stop(); + } + } + }; + return target; + }//input_sacrificeType() + + public static Input Wheneverinput_sacrifice(final SpellAbility spell, final CardList choices, final String message, final Command Paid) { Input target = new Input() { private static final long serialVersionUID = 2685832214519141903L; diff --git a/src/forge/EndOfTurn.java b/src/forge/EndOfTurn.java index 459b010e1ff..29b8c8e8693 100644 --- a/src/forge/EndOfTurn.java +++ b/src/forge/EndOfTurn.java @@ -41,6 +41,7 @@ public class EndOfTurn implements java.io.Serializable GameActionUtil.endOfTurn_Lighthouse_Chronologist(); GameActionUtil.endOfTurn_Thran_Quarry(); GameActionUtil.endOfTurn_Glimmervoid(); + GameActionUtil.endOfTurn_Krovikan_Horror(); //GameActionUtil.removeExaltedEffects(); GameActionUtil.removeAttackedBlockedThisTurn(); diff --git a/src/forge/GameActionUtil.java b/src/forge/GameActionUtil.java index bc3245ea1ad..64620f7459e 100644 --- a/src/forge/GameActionUtil.java +++ b/src/forge/GameActionUtil.java @@ -3702,6 +3702,31 @@ public class GameActionUtil { } } + public static void endOfTurn_Krovikan_Horror() + { + final String player = AllZone.Phase.getActivePlayer(); + final String opponent = AllZone.GameAction.getOpponent(player); + horrorReturn(player); + horrorReturn(opponent); + } + + public static void horrorReturn(String player) + { + // Find each Horror, peek at the card above it, if it's a creature return to hand + CardList grave = new CardList(AllZone.getZone(Constant.Zone.Graveyard, player).getCards()); + if (grave.getName("Krovikan Horror").size() == 0) return; + int i = 0; + while(i+1 < grave.size()){ + Card c = grave.get(i); + ArrayList types = grave.get(i+1).getType(); + if (c.getName().equals("Krovikan Horror") && types.contains("Creature")){ + AllZone.GameAction.moveToHand(c); + grave.remove(c); + } + else + i++; + } + } //END ENDOFTURN CARDS public static void removeAttackedBlockedThisTurn() {