From c7010f9197dbae8315e8e90536456c40eb799c62 Mon Sep 17 00:00:00 2001 From: jendave Date: Sat, 6 Aug 2011 05:26:27 +0000 Subject: [PATCH] - Added Volrath's Dungeon - AI currently won't activate Dungeon Bail cost. Related to ComputerUtil.playCards line that says "if(canPayCost(all[i]) && all[i].canPlay() && all[i].canPlayAI())" - Fix for AnyPlayer Abilities to checked for each ability, not just the card - Fix to add AnyPlayer abilities to Computer section that is actually used by the AI. - Fix AI_handToLibrary function that was discarding in certain circumstances --- res/card-pictures.txt | 1 + res/cards.txt | 5 ++ src/forge/CardFactory.java | 124 ++++++++++++++++++++++++++++++ src/forge/ComputerAI_General.java | 27 ++++++- src/forge/GameAction.java | 15 ++-- src/forge/Phase.java | 5 ++ 6 files changed, 170 insertions(+), 7 deletions(-) diff --git a/res/card-pictures.txt b/res/card-pictures.txt index 2589e8efbd6..806a13b8616 100644 --- a/res/card-pictures.txt +++ b/res/card-pictures.txt @@ -38,6 +38,7 @@ snow_covered_mountain.jpg http://www.wizards.com/global/images/magic/gene snow_covered_mountain1.jpg http://www.wizards.com/global/images/magic/general/snow_covered_mountain.jpg snow_covered_mountain2.jpg http://www.magickartenmarkt.de/img/cards/Ice_Age/snow_covered_mountain.jpg snow_covered_mountain3.jpg http://www.magickartenmarkt.de/img/cards/Ice_Age/snow_covered_mountain.jpg +volraths_dungeon.jpg http://www.wizards.com/global/images/magic/general/volraths_dungeon.jpg surveilling_sprite.jpg http://www.wizards.com/global/images/magic/general/surveilling_sprite.jpg merfolk_seer.jpg http://www.wizards.com/global/images/magic/general/merfolk_seer.jpg kingfisher.jpg http://www.wizards.com/global/images/magic/general/kingfisher.jpg diff --git a/res/cards.txt b/res/cards.txt index 711cc491821..bebf0b3d561 100644 --- a/res/cards.txt +++ b/res/cards.txt @@ -1,3 +1,8 @@ +Volrath's Dungeon +2 B B +Enchantment +no text + Sire of the Storm 4 U U Creature Spirit diff --git a/src/forge/CardFactory.java b/src/forge/CardFactory.java index e26eb1cf704..df4f1dbc874 100644 --- a/src/forge/CardFactory.java +++ b/src/forge/CardFactory.java @@ -15870,7 +15870,131 @@ public class CardFactory implements NewConstants { card.addSpellAbility(ability); }//*************** END ************ END ************************** + //*************** START *********** START ************************** + else if(cardName.equals("Volrath's Dungeon")) { + final SpellAbility dungeon = new Ability(card, "0") { + // todo(sol) discard really needs to happen as a cost but in resolution for now :( + + @Override + public void chooseTargetAI() { + setTargetPlayer(Constant.Player.Human); + } + + @Override + public boolean canPlay() { + return Phase.canCastSorcery(Constant.Player.Human) && AllZone.GameAction.isCardInPlay(card) && super.canPlay() && + AllZone.getZone(Constant.Zone.Hand, Constant.Player.Human).getCards().length > 0; + } + + @Override + public void resolve() { + String player = getActivatingPlayer(); + String target = getTargetPlayer(); + CardList playerHand = new CardList(AllZone.getZone(Constant.Zone.Hand, player).getCards()); + CardList targetHand = new CardList(AllZone.getZone(Constant.Zone.Hand, target).getCards()); + + if(playerHand.size() == 0) return; + + if (player == Constant.Player.Human){ + if (!humanDiscard(playerHand, false)) + return; + } + else if (player == Constant.Player.Computer){ + if (!computerDiscard(playerHand, false)) + return; + } + + if (targetHand.size() == 0) return; + + if (target == Constant.Player.Human){ + if (!humanDiscard(targetHand, true)) + return; + } + else if (target == Constant.Player.Computer){ + if (!computerDiscard(targetHand, true)) + return; + } + } + + public boolean humanDiscard(CardList hand, boolean toLibrary) + { + String destination = "discard"; + if (toLibrary) + destination = "place on top of library."; + Object discard = AllZone.Display.getChoiceOptional("Select Card to " + destination, + hand.toArray()); + if(discard == null) return false; + + Card card = (Card)discard; + + if (toLibrary) + AllZone.GameAction.moveToTopOfLibrary(card); + else + AllZone.GameAction.discard(card); + + return true; + } + + public boolean computerDiscard(CardList hand, boolean toLibrary) + { + if (toLibrary) + AllZone.GameAction.AI_handToLibrary("Top"); + else + AllZone.GameAction.AI_discard(); + + return true; + } + + @Override + public boolean canPlayAI() { + return (card.getController().equals(Constant.Player.Computer) && Phase.canCastSorcery(Constant.Player.Computer) + && AllZone.getZone(Constant.Zone.Hand, Constant.Player.Computer).getCards().length > 0 + && AllZone.getZone(Constant.Zone.Hand, getTargetPlayer()).getCards().length > 0); + } + };//SpellAbility dungeon + + final SpellAbility bail = new Ability(card, "0") { + // Life payment really should happen on activation, maybe can do with a popup? + @Override + public void resolve() { + String player = getActivatingPlayer(); + + if (AllZone.GameAction.payLife(player, 5, card)) + AllZone.GameAction.destroy(card); + } + + @Override + public boolean canPlay() { + if(AllZone.Human_Life.getLife() >= 5 && AllZone.GameAction.getLastPlayerToDraw().equals(Constant.Player.Human) && AllZone.GameAction.isCardInPlay(card) && super.canPlay()) + return true; + else return false; + } + + @Override + public boolean canPlayAI() { + if (card.getController().equals(Constant.Player.Human) && AllZone.Computer_Life.getLife() >= 9 && + AllZone.GameAction.getLastPlayerToDraw().equals(Constant.Player.Computer) && + AllZone.GameAction.isCardInPlay(card)) + return true; + else return false; + } + + };//SpellAbility pay bail + + dungeon.setBeforePayMana(CardFactoryUtil.input_targetPlayer(dungeon)); + dungeon.setChooseTargetAI(CardFactoryUtil.AI_targetHuman()); + dungeon.setDescription("Discard a card: Target player puts a card from his or her hand on top of his or her library. Activate this ability only any time you could cast a sorcery."); + dungeon.setStackDescription("CARDNAME - Target player chooses a card in hand and puts on top of library."); + + bail.setAnyPlayer(true); + bail.setDescription("Pay 5 Life: Destroy Volrath's Dungeon. Any player may activate this ability but only during his or her turn."); + bail.setStackDescription("Destroy CARDNAME."); + + card.addSpellAbility(dungeon); + card.addSpellAbility(bail); + }//*************** END ************ END ************************** + //*************** START *********** START ************************** else if(cardName.equals("Nameless Inversion")) { SpellAbility spell = new Spell(card) { diff --git a/src/forge/ComputerAI_General.java b/src/forge/ComputerAI_General.java index cb2f59c4700..02588704205 100644 --- a/src/forge/ComputerAI_General.java +++ b/src/forge/ComputerAI_General.java @@ -175,6 +175,18 @@ public class ComputerAI_General implements Computer { all.addAll(hand.toArray()); all.addAll(AllZone.Computer_Play.getCards()); + CardList humanPlayable = new CardList(); + humanPlayable.addAll(AllZone.Human_Play.getCards()); + humanPlayable = humanPlayable.filter(new CardListFilter() + { + public boolean addCard(Card c) + { + return (c.canAnyPlayerActivate()); + } + }); + + all.addAll(humanPlayable.toArray()); + return getPlayable(all); }//getMain1() @@ -192,6 +204,17 @@ public class ComputerAI_General implements Computer { } }); + CardList humanPlayable = new CardList(); + humanPlayable.addAll(AllZone.Human_Play.getCards()); + humanPlayable = humanPlayable.filter(new CardListFilter() + { + public boolean addCard(Card c) + { + return (c.canAnyPlayerActivate()); + } + }); + all.addAll(humanPlayable.toArray()); + return getPlayable(all); }//getMain2() @@ -204,7 +227,9 @@ public class ComputerAI_General implements Computer { for(SpellAbility sa:c.getSpellAbility()) //This try/catch should fix the "computer is thinking" bug try { - if(sa.canPlayAI() && ComputerUtil.canPayCost(sa)) spellAbility.add(sa); + if(sa.canPlayAI() && ComputerUtil.canPayCost(sa) && + (sa.isAnyPlayer() || sa.getSourceCard().getController().equals(Constant.Player.Computer))) + spellAbility.add(sa); } catch(Exception ex) { showError(ex, "There is an error in the card code for %s:%n", c.getName(), ex.getMessage()); } diff --git a/src/forge/GameAction.java b/src/forge/GameAction.java index 5bd6db70d07..e264348711b 100644 --- a/src/forge/GameAction.java +++ b/src/forge/GameAction.java @@ -248,17 +248,20 @@ public class GameAction { AllZone.Computer_Hand.remove(card); if(libPos.equals("top")) AllZone.Computer_Library.add(card, 0); else AllZone.Computer_Library.add(card); - return; } CardListUtil.sortAttackLowFirst(hand); CardListUtil.sortNonFlyingFirst(hand); - discard(hand.get(0)); + if(libPos.equals("top")) AllZone.Computer_Library.add(hand.get(0), 0); + else AllZone.Computer_Library.add(hand.get(0)); + AllZone.Computer_Hand.remove(hand.get(0)); return; } else { - CardListUtil.sortCMC(hand); - discard(hand.get(0)); + CardListUtil.sortCMC(hand); + if(libPos.equals("top")) AllZone.Computer_Library.add(hand.get(0), 0); + else AllZone.Computer_Library.add(hand.get(0)); + AllZone.Computer_Hand.remove(hand.get(0)); return; } } @@ -2825,7 +2828,6 @@ public class GameAction { } if(sa == null) return; - playSpellAbility(sa); } } @@ -3276,7 +3278,8 @@ public class GameAction { ArrayList list = new ArrayList(); for(int i = 0; i < sa.length; i++) - if(sa[i].canPlay()) list.add(sa[i]); + if(sa[i].canPlay() && (sa[i].getSourceCard().getController().equals(Constant.Player.Human) || sa[i].isAnyPlayer())) + list.add(sa[i]); SpellAbility[] array = new SpellAbility[list.size()]; list.toArray(array); diff --git a/src/forge/Phase.java b/src/forge/Phase.java index bac14b6519b..3d714e71fdd 100644 --- a/src/forge/Phase.java +++ b/src/forge/Phase.java @@ -402,4 +402,9 @@ public class Phase extends MyObservable return false; } + public static boolean canCastSorcery(String player) + { + return (AllZone.Phase.getPhase().equals(Constant.Phase.Main2) || (AllZone.Phase.getPhase().equals(Constant.Phase.Main1) + && AllZone.GameAction.getLastPlayerToDraw().equals(player)) && AllZone.Stack.size() == 0); + } }