From 3762b14ca092785d2902b03dae3592169d11797f Mon Sep 17 00:00:00 2001 From: jendave Date: Sat, 6 Aug 2011 03:03:43 +0000 Subject: [PATCH] - Phytohydra should be fixed. - Lands shouldn't be playable at opponent's EOT anymore. - Checking attack triggers should happen only once, after all attackers have been declared. - Added Goblin Piledriver, Flame Rift, Spectral Bears, Spectral Force, Pianna, Nomad Captain, Crypt Cobra, Swamp Mosquito, Suq'Ata Assassin. - Fixed a bunch of bugs with Mox Diamond. - Guiltfeeder should only trigger when it's unblocked (previously it would trigger when trampling over also). - Fixed Elvish Piper (not sure how it broke?). - Added Poison Counters. - AI shouldn't play Cognivore, Terravore, Cantivore, Magnivore, Mortivore anymore if there are no cards in any graveyard keeping them alive. --- .gitattributes | 1 + res/card-pictures.txt | 8 ++ res/cards.txt | 53 ++++++- src/forge/AllZone.java | 3 + src/forge/CardFactory.java | 37 ++++- src/forge/CardFactoryUtil.java | 4 +- src/forge/CardFactory_Creatures.java | 178 +++++++++++++++++++++-- src/forge/CardUtil.java | 34 +++++ src/forge/CombatUtil.java | 187 +++++++++++++++++++++++-- src/forge/GameAction.java | 9 +- src/forge/GameActionUtil.java | 8 +- src/forge/GuiDisplay3.java | 33 ++++- src/forge/InputControl.java | 72 +++++++--- src/forge/Input_CombatDamage.java | 3 +- src/forge/Input_FirstStrikeDamage.java | 3 +- src/forge/PlayerLife.java | 20 ++- src/forge/PlayerPoisonCounter.java | 26 ++++ 17 files changed, 600 insertions(+), 79 deletions(-) create mode 100644 src/forge/PlayerPoisonCounter.java diff --git a/.gitattributes b/.gitattributes index aeb078b14de..455a34a2b14 100644 --- a/.gitattributes +++ b/.gitattributes @@ -210,6 +210,7 @@ src/forge/PhaseObserver.java svneol=native#text/plain src/forge/PicturePanel.java svneol=native#text/plain src/forge/PicturePanelResize.java -text svneol=native#text/plain src/forge/PlayerLife.java svneol=native#text/plain +src/forge/PlayerPoisonCounter.java -text svneol=native#text/plain src/forge/PlayerZone.java svneol=native#text/plain src/forge/PlayerZoneUtil.java svneol=native#text/plain src/forge/PlayerZone_ComesIntoPlay.java svneol=native#text/plain diff --git a/res/card-pictures.txt b/res/card-pictures.txt index 13dc7bd035a..e236ab85054 100644 --- a/res/card-pictures.txt +++ b/res/card-pictures.txt @@ -18,6 +18,14 @@ forest.jpg http://resources.wizards.com/magic/cards/unh/en-us/card73946.jpg forest1.jpg http://gatherer.wizards.com/handlers/image.ashx?type=card&multiverseid=2748 forest2.jpg http://gatherer.wizards.com/handlers/image.ashx?type=card&multiverseid=587 forest3.jpg http://gatherer.wizards.com/handlers/image.ashx?type=card&multiverseid=586 +swamp_mosquito.jpg http://www.wizards.com/global/images/magic/general/swamp_mosquito.jpg +suqata_assassin.jpg http://www.wizards.com/global/images/magic/general/suqata_assassin.jpg +crypt_cobra.jpg http://www.wizards.com/global/images/magic/general/crypt_cobra.jpg +pianna_nomad_captain.jpg http://www.wizards.com/global/images/magic/general/pianna_nomad_captain.jpg +spectral_force.jpg http://www.wizards.com/global/images/magic/general/spectral_force.jpg +spectral_bears.jpg http://www.wizards.com/global/images/magic/general/spectral_bears.jpg +goblin_piledriver.jpg http://www.wizards.com/global/images/magic/general/goblin_piledriver.jpg +flame_rift.jpg http://www.wizards.com/global/images/magic/general/flame_rift.jpg prowess_of_the_fair.jpg http://www.wizards.com/global/images/magic/general/prowess_of_the_fair.jpg abomination.jpg http://www.wizards.com/global/images/magic/general/abomination.jpg time_warp.jpg http://www.wizards.com/global/images/magic/general/time_warp.jpg diff --git a/res/cards.txt b/res/cards.txt index 61835872829..d6cd3f932da 100644 --- a/res/cards.txt +++ b/res/cards.txt @@ -1,3 +1,54 @@ +Swamp Mosquito +1 B +Creature Insect +Whenever Swamp Mosquito attacks and isn't blocked, defending player gets a poison counter. (A player with ten or more poison counters loses the game.) +0/1 +Flying + +Suq'Ata Assassin +1 B B +Creature Human Assassin +Whenever Suq'Ata Assassin attacks and isn't blocked, defending player gets a poison counter. (A player with ten or more poison counters loses the game.) +1/1 +Fear + +Crypt Cobra +3 B +Creature Snake +Whenever Crypt Cobra attacks and isn't blocked, defending player gets a poison counter. (A player with ten or more poison counters loses the game.) +3/3 + +Pianna, Nomad Captain +1 W W +Legendary Creature Human Nomad +Whenever Pianna, Nomad Captain attacks, attacking creatures get +1/+1 until end of turn. +2/2 + +Spectral Force +3 G G +Creature Elemental Spirit +Whenever Spectral Force attacks, if defending player controls no black permanents, it doesn't untap during your next untap step. +8/8 +Trample + +Spectral Bears +1 G +Creature Bear Spirit +Whenever Spectral Bears attacks, if defending player controls no black nontoken permanents, it doesn't untap during your next untap step. +3/3 + +Goblin Piledriver +1 R +Creature Goblin Warrior +Whenever Goblin Piledriver attacks, it gets +2/+0 until end of turn for each other attacking Goblin. +1/2 +Protection from blue + +Flame Rift +1 R +Sorcery +Flame Rift deals 4 damage to each player. + Prowess of the Fair 1 B Tribal Enchantment Elf @@ -503,7 +554,7 @@ RegenerateMe:B Headhunter 1 B Creature Human Cleric -Whenever Headhunter deals combat damage to a player, that player discards a card +Whenever Headhunter deals combat damage to a player, that player discards a card. 1/1 Morph:B diff --git a/src/forge/AllZone.java b/src/forge/AllZone.java index 061791497d7..1ce5ea76117 100644 --- a/src/forge/AllZone.java +++ b/src/forge/AllZone.java @@ -37,6 +37,9 @@ public class AllZone implements NewConstants { public static PlayerLife Human_Life = new PlayerLife(); public static PlayerLife Computer_Life = new PlayerLife(); + + public static PlayerPoisonCounter Human_PoisonCounter = new PlayerPoisonCounter(); + public static PlayerPoisonCounter Computer_PoisonCounter = new PlayerPoisonCounter(); //Human_Play, Computer_Play is different because Card.comesIntoPlay() is called when a card is added by PlayerZone.add(Card) public final static PlayerZone Human_Play = new PlayerZone_ComesIntoPlay(Constant.Zone.Play, Constant.Player.Human); diff --git a/src/forge/CardFactory.java b/src/forge/CardFactory.java index 19ba385061a..78edc9cbc53 100644 --- a/src/forge/CardFactory.java +++ b/src/forge/CardFactory.java @@ -15418,16 +15418,19 @@ return land.size() > 1 && CardFactoryUtil.AI_isMainPhase(); private static final long serialVersionUID = -1319202902385425204L; public void showMessage() { - AllZone.Display.showMessage("Discard from your hand a land card"); + AllZone.Display.showMessage("Discard a land card (or select Mox Diamond to sacrifice it)"); ButtonUtil.enableOnlyCancel(); } public void selectCard(Card c, PlayerZone zone) { - if(zone.is(Constant.Zone.Hand)) + if(zone.is(Constant.Zone.Hand) && c.isLand()) { AllZone.GameAction.discard(c); - if(!c.isLand()) - AllZone.GameAction.sacrifice(card); + stop(); + } + else if (c.equals(card)) + { + AllZone.GameAction.sacrifice(card); stop(); } } @@ -15488,7 +15491,7 @@ return land.size() > 1 && CardFactoryUtil.AI_isMainPhase(); return (c.isLand()); } }); - return list.size() != 0; + return list.size() != 0 && super.canPlay(); }//canPlay() }; card.addComesIntoPlayCommand(intoPlay); @@ -17355,6 +17358,8 @@ return land.size() > 1 && CardFactoryUtil.AI_isMainPhase(); card.addSpellAbility(ab1); }//*************** END ************ END ************************** + + //*************** START *********** START ************************** else if(cardName.equals("Path to Exile")) @@ -17763,6 +17768,28 @@ return land.size() > 1 && CardFactoryUtil.AI_isMainPhase(); card.clearSpellAbility(); card.addSpellAbility(spell); }//*************** END ************ END ************************** + + //*************** START *********** START ************************** + if (cardName.equals("Flame Rift")) + { + final SpellAbility spell = new Spell(card) + { + private static final long serialVersionUID = -6008296722680155321L; + + public void resolve() + { + AllZone.Human_Life.subtractLife(4); + AllZone.Computer_Life.subtractLife(4); + } + + public boolean canPlayAI() + { + return AllZone.Computer_Life.getLife() > 7 && AllZone.Human_Life.getLife() < 7; + } + }; + card.clearSpellAbility(); + card.addSpellAbility(spell); + } // Cards with Cycling abilities diff --git a/src/forge/CardFactoryUtil.java b/src/forge/CardFactoryUtil.java index 121cd4a1fb2..498c32575cd 100644 --- a/src/forge/CardFactoryUtil.java +++ b/src/forge/CardFactoryUtil.java @@ -2951,8 +2951,8 @@ public class CardFactoryUtil //do card1 and card2 share any colors? public static boolean sharesColorWith(Card card1, Card card2) { - ArrayList card1Colors = CardUtil.getColors(card1); - ArrayList card2Colors = CardUtil.getColors(card2); + ArrayList card1Colors = CardUtil.getOnlyColors(card1); + ArrayList card2Colors = CardUtil.getOnlyColors(card2); for (String color : card1Colors) { diff --git a/src/forge/CardFactory_Creatures.java b/src/forge/CardFactory_Creatures.java index 7edb6e3d969..48bb16459d4 100644 --- a/src/forge/CardFactory_Creatures.java +++ b/src/forge/CardFactory_Creatures.java @@ -1665,7 +1665,6 @@ public class CardFactory_Creatures { - //*************** START *********** START ************************** else if(cardName.equals("Filigree Angel")) @@ -6096,6 +6095,63 @@ public class CardFactory_Creatures { }//*************** END ************ END ************************** + //*************** START *********** START ************************** + else if (cardName.equals("Elvish Piper")) + { + final SpellAbility ability = new Ability_Tap(card, "G") + { + private static final long serialVersionUID = 4414609319033894302L; + public boolean canPlayAI() {return getCreature().size() != 0;} + public void chooseTargetAI() + { + card.tap(); + Card target = CardFactoryUtil.AI_getBestCreature(getCreature()); + setTargetCard(target); + } + CardList getCreature() + { + CardList list = new CardList(AllZone.Computer_Hand.getCards()); + list = list.getType("Creature"); + return list; + } + public void resolve() + { + Card c = getTargetCard(); + PlayerZone hand = AllZone.getZone(Constant.Zone.Hand, card.getController()); + PlayerZone play = AllZone.getZone(Constant.Zone.Play, card.getController()); + + if(AllZone.GameAction.isCardInZone(c, hand)) + { + hand.remove(c); + play.add(c); + } + } + }; + + ability.setBeforePayMana(new Input() + { + private static final long serialVersionUID = -1647181037510967127L; + + public void showMessage() + { + String controller = card.getController(); + CardList creats = new CardList(AllZone.getZone(Constant.Zone.Hand, controller).getCards()); + creats = creats.filter(new CardListFilter() + { + public boolean addCard(Card c) + { + PlayerZone zone = AllZone.getZone(c); + return c.isCreature() && zone.is(Constant.Zone.Hand); + } + + }); + stopSetNext(CardFactoryUtil.input_targetSpecific(ability, creats, "Select a creature", false)); + } + }); + card.addSpellAbility(ability); + }//*************** END ************ END ************************** + + /* //*************** START *********** START ************************** else if(cardName.equals("Elvish Piper")) { @@ -6181,7 +6237,7 @@ public class CardFactory_Creatures { ability.setBeforePayMana(target); }//*************** END ************ END ************************** - + */ //*************** START *********** START ************************** else if(cardName.equals("Weathered Wayfarer")) @@ -12335,9 +12391,8 @@ public class CardFactory_Creatures { }//*************** END ************ END ************************** - - //*************** START *********** START ************************** + //*************** START *********** START ************************** else if (cardName.equals("Oros, the Avenger")) { final Ability ability2 = new Ability(card, "2 W") @@ -15879,7 +15934,7 @@ public class CardFactory_Creatures { { CardList list = new CardList(AllZone.getZone(Constant.Zone.Play, Constant.Player.Computer).getCards()); list = list.getType("Artifact"); - return super.canPlay() && list.size() > 0; + return super.canPlayAI() && list.size() > 0; } }; card.clearSpellAbility(); @@ -15898,7 +15953,7 @@ public class CardFactory_Creatures { { CardList list = new CardList(AllZone.getZone(Constant.Zone.Play, Constant.Player.Computer).getCards()); list = list.getType("Enchantment"); - return super.canPlay() && list.size() > 0; + return super.canPlayAI() && list.size() > 0; } }; card.clearSpellAbility(); @@ -15906,6 +15961,107 @@ public class CardFactory_Creatures { } //*************** END ************ END ************************** + //*************** START *********** START ************************** + else if(cardName.equals("Cantivore")) + { + SpellAbility spell = new Spell_Permanent(card) + { + private static final long serialVersionUID = 7254358703158629514L; + + public boolean canPlayAI() + { + CardList list = new CardList(AllZone.getZone(Constant.Zone.Graveyard, Constant.Player.Computer).getCards()); + list.addAll(AllZone.getZone(Constant.Zone.Graveyard, Constant.Player.Human).getCards()); + list = list.getType("Enchantment"); + return super.canPlayAI() && list.size() > 0; + } + }; + card.clearSpellAbility(); + card.addSpellAbility(spell); + } + //*************** END ************ END ************************** + + //*************** START *********** START ************************** + else if(cardName.equals("Terravore")) + { + SpellAbility spell = new Spell_Permanent(card) + { + private static final long serialVersionUID = 7316190829288665283L; + + public boolean canPlayAI() + { + CardList list = new CardList(AllZone.getZone(Constant.Zone.Graveyard, Constant.Player.Computer).getCards()); + list.addAll(AllZone.getZone(Constant.Zone.Graveyard, Constant.Player.Human).getCards()); + list = list.getType("Land"); + return super.canPlayAI() && list.size() > 0; + } + }; + card.clearSpellAbility(); + card.addSpellAbility(spell); + } + //*************** END ************ END ************************** + + //*************** START *********** START ************************** + else if(cardName.equals("Mortivore")) + { + SpellAbility spell = new Spell_Permanent(card) + { + private static final long serialVersionUID = -7118801410173525870L; + + public boolean canPlayAI() + { + CardList list = new CardList(AllZone.getZone(Constant.Zone.Graveyard, Constant.Player.Computer).getCards()); + list.addAll(AllZone.getZone(Constant.Zone.Graveyard, Constant.Player.Human).getCards()); + list = list.getType("Creature"); + return super.canPlayAI() && list.size() > 0; + } + }; + card.clearSpellAbility(); + card.addSpellAbility(spell); + } + //*************** END ************ END ************************** + + //*************** START *********** START ************************** + else if(cardName.equals("Cognivore")) + { + SpellAbility spell = new Spell_Permanent(card) + { + private static final long serialVersionUID = -2216181341715046786L; + + public boolean canPlayAI() + { + CardList list = new CardList(AllZone.getZone(Constant.Zone.Graveyard, Constant.Player.Computer).getCards()); + list.addAll(AllZone.getZone(Constant.Zone.Graveyard, Constant.Player.Human).getCards()); + list = list.getType("Instant"); + return super.canPlayAI() && list.size() > 0; + } + }; + card.clearSpellAbility(); + card.addSpellAbility(spell); + } + //*************** END ************ END ************************** + + //*************** START *********** START ************************** + else if(cardName.equals("Magnivore")) + { + SpellAbility spell = new Spell_Permanent(card) + { + private static final long serialVersionUID = -2252263708643462897L; + + public boolean canPlayAI() + { + CardList list = new CardList(AllZone.getZone(Constant.Zone.Graveyard, Constant.Player.Computer).getCards()); + list.addAll(AllZone.getZone(Constant.Zone.Graveyard, Constant.Player.Human).getCards()); + list = list.getType("Sorcery"); + return super.canPlayAI() && list.size() > 0; + } + }; + card.clearSpellAbility(); + card.addSpellAbility(spell); + } + //*************** END ************ END ************************** + + //*************** START *********** START ************************** if(cardName.equals("Magus of the Library")) { @@ -18667,15 +18823,7 @@ public class CardFactory_Creatures { { public void addDamage(final int n, final Card source) { - final Ability ability = new Ability(card, "0") - { - public void resolve(){ - for (int i=0;i(colors); } + public static ArrayList getOnlyColors(Card c) { + String m = c.getManaCost(); + Set colors = new HashSet(); + + for(int i = 0; i < m.length(); i++) { + switch(m.charAt(i)) { + case ' ': + break; + case 'G': + colors.add(Constant.Color.Green); + break; + case 'W': + colors.add(Constant.Color.White); + break; + case 'B': + colors.add(Constant.Color.Black); + break; + case 'U': + colors.add(Constant.Color.Blue); + break; + case 'R': + colors.add(Constant.Color.Red); + break; + } + } + for(String kw : c.getKeyword()) + if(kw.startsWith(c.getName()+" is ")) + for(String color : Constant.Color.Colors) + if(kw.endsWith(color+".")) + colors.add(color); + return new ArrayList(colors); + } + + public static boolean hasCardName(String cardName, ArrayList list) { Card c; boolean b = false; diff --git a/src/forge/CombatUtil.java b/src/forge/CombatUtil.java index 44edbe3d3d2..9e298e78e20 100644 --- a/src/forge/CombatUtil.java +++ b/src/forge/CombatUtil.java @@ -509,7 +509,7 @@ public class CombatUtil for(int i = 0; i < attack.length; i++) { GameActionUtil.executeExaltedEffects2(attack[i], AllZone.Combat); - checkDeclareAttackers(attack[i]); + //checkDeclareAttackers(attack[i]); attackerName = attack[i].getName(); if (attack[i].isFaceDown()) attackerName = "Morph"; @@ -547,7 +547,7 @@ public class CombatUtil for(int i = 0; i < attack.length; i++) { GameActionUtil.executeExaltedEffects2(attack[i], AllZone.pwCombat); - checkDeclareAttackers(attack[i]); + //checkDeclareAttackers(attack[i]); attackerName = attack[i].getName(); if (attack[i].isFaceDown()) attackerName = "Morph"; @@ -658,9 +658,11 @@ public class CombatUtil return false; } - private static void checkDeclareAttackers(Card c) //this method checks triggered effects of attacking creatures, right before defending player declares blockers + public static void checkDeclareAttackers(Card c) //this method checks triggered effects of attacking creatures, right before defending player declares blockers { - if (AllZone.Phase.getPhase().equals("Declare Attackers")) + //human does not have an "attackers_instantAbility" phase during his turn (yet), so triggers will happen at the beginning of declare blockers + if (AllZone.Phase.getPhase().equals("Declare Blockers") || + AllZone.Phase.getPhase().equals(Constant.Phase.Combat_Declare_Attackers_InstantAbility)) { //Beastmaster Ascension @@ -878,6 +880,48 @@ public class CombatUtil AllZone.Stack.add(ability2); }//Goblin General + if (c.getName().equals("Pianna, Nomad Captain") && !c.getCreatureAttackedThisTurn()) + { + + //final Card crd = c; + Ability ability2 = new Ability(c,"0") + { + public void resolve() + { + CardList cl = new CardList(AllZone.Combat.getAttackers()); + final CardList creatures = cl; + + final Command untilEOT = new Command() + { + private static final long serialVersionUID = -7050310805245783042L; + + public void execute() + { + for (Card creat:creatures){ + if(AllZone.GameAction.isCardInPlay(creat)) + { + creat.addTempAttackBoost(-1); + creat.addTempDefenseBoost(-1); + } + } + } + };//Command + + for (Card creat:creatures){ + if(AllZone.GameAction.isCardInPlay(creat) ) + { + creat.addTempAttackBoost(1); + creat.addTempDefenseBoost(1); + } + } + AllZone.EndOfTurn.addUntil(untilEOT); + } + }; + + ability2.setStackDescription(c.getName() + " - attacking creatures get +1/+1 until end of turn."); + AllZone.Stack.add(ability2); + }//Goblin General + if(c.getName().equals("Zur the Enchanter") && !c.getCreatureAttackedThisTurn()) { PlayerZone library = AllZone.getZone(Constant.Zone.Library, c.getController()); @@ -1124,7 +1168,6 @@ public class CombatUtil } };//Command - if(AllZone.GameAction.isCardInPlay(charger)) { charger.addTempAttackBoost(k); @@ -1141,6 +1184,50 @@ public class CombatUtil }//Knotvine Paladin + + + else if(c.getName().equals("Goblin Piledriver") && !c.getCreatureAttackedThisTurn()) + { + final Card piledriver = c; + Ability ability2 = new Ability(c,"0") + { + public void resolve() + { + CardList list = new CardList(); + list.addAll(AllZone.Combat.getAttackers()); + list = list.filter(new CardListFilter(){ + public boolean addCard(Card card) { + return (!card.equals(piledriver) && card.isCreature() && (card.getType().contains("Goblin") || card.getKeyword().contains("Changeling"))); + } + }); + final int otherGoblins = list.size(); + + final Command untilEOT = new Command() + { + private static final long serialVersionUID = -4154121199693045635L; + + public void execute() + { + if(AllZone.GameAction.isCardInPlay(piledriver)) + { + piledriver.addTempAttackBoost(-2*otherGoblins); + } + } + };//Command + + if(AllZone.GameAction.isCardInPlay(piledriver)) + { + piledriver.addTempAttackBoost(2*otherGoblins); + AllZone.EndOfTurn.addUntil(untilEOT); + } + }//resolve + + };//ability + + ability2.setStackDescription(c.getName() + " - gets +2/+0 until end of turn for each other attacking Goblin."); + AllZone.Stack.add(ability2); + + }//Goblin Piledriver else if((c.getName().equals("Charging Bandits") || c.getName().equals("Wei Ambush Force") || c.getName().equals("Ravenous Skirge") || c.getName().equals("Vicious Kavu") @@ -1184,6 +1271,42 @@ public class CombatUtil }//+2+0 Chargers + else if (c.getName().equals("Spectral Bears")) + { + String opp = AllZone.GameAction.getOpponent(c.getController()); + PlayerZone play = AllZone.getZone(Constant.Zone.Play, opp); + CardList list = new CardList(play.getCards()); + list = list.filter(new CardListFilter() + { + public boolean addCard(Card crd) + { + return CardUtil.getColors(crd).contains(Constant.Color.Black) && !crd.isToken(); + } + }); + if (list.size() == 0) + { + c.addExtrinsicKeyword("This card doesn't untap during your next untap step."); + } + } + + else if (c.getName().equals("Spectral Force")) + { + String opp = AllZone.GameAction.getOpponent(c.getController()); + PlayerZone play = AllZone.getZone(Constant.Zone.Play, opp); + CardList list = new CardList(play.getCards()); + list = list.filter(new CardListFilter() + { + public boolean addCard(Card crd) + { + return CardUtil.getColors(crd).contains(Constant.Color.Black); + } + }); + if (list.size() == 0) + { + c.addExtrinsicKeyword("This card doesn't untap during your next untap step."); + } + } + else if(c.getName().equals("Witch-Maw Nephilim") && !c.getCreatureAttackedThisTurn() && c.getNetAttack() >= 10) { final Card charger = c; @@ -1216,7 +1339,7 @@ public class CombatUtil };//ability - ability2.setStackDescription(c.getName() + " - gains trample until end of turn if its power is 10 or greater."); + ability2.setStackDescription(c.getName() + " - gains trample until end of turn if its power is 10 or greater."); AllZone.Stack.add(ability2); @@ -1332,7 +1455,6 @@ public class CombatUtil { String player = c.getController(); - PlayerZone lib = AllZone.getZone(Constant.Zone.Library, player); PlayerZone hand = AllZone.getZone(Constant.Zone.Hand, player); if (lib.size() > 0 ) { @@ -1342,12 +1464,12 @@ public class CombatUtil }; Card top = lib.get(0); if (top.getType().contains("Creature")) - { + { AllZone.GameAction.getPlayerLife(player).addLife(top.getBaseDefense()); AllZone.GameAction.getPlayerLife(player).subtractLife(top.getBaseAttack()); hand.add(top); lib.remove(top); - }; + }; }//Sapling of Colfenor @@ -1355,6 +1477,49 @@ public class CombatUtil }//if Phase = declare attackers }//checkDeclareAttackers + + public static void checkUnblockedAttackers(Card c) + { + if (c.getName().equals("Guiltfeeder")) + { + final String player = c.getController(); + final String opponent = AllZone.GameAction.getOpponent(player); + + Ability ability2 = new Ability(c, "0") + { + public void resolve() + { + + PlayerZone graveyard = AllZone.getZone(Constant.Zone.Graveyard, + opponent); + CardList cardsInGrave = new CardList(graveyard.getCards()); + PlayerLife life = AllZone.GameAction.getPlayerLife(opponent); + + life.subtractLife(cardsInGrave.size()); + + } + };// ability2 + + ability2.setStackDescription(c.getName() + " - " + opponent + + " loses life equal to cards in graveyard."); + AllZone.Stack.add(ability2); + + } + else if (c.getName().equals("Crypt Cobra") || c.getName().equals("Suq'Ata Assassin") || + c.getName().equals("Swamp Mosquito")) + { + String controller = c.getController(); + String opp = AllZone.GameAction.getOpponent(controller); + + if (opp.equals(Constant.Player.Human)) + AllZone.Human_PoisonCounter.addPoisonCounters(1); + else + AllZone.Computer_PoisonCounter.addPoisonCounters(1); + } + + + } + private static void checkDeclareBlockers(Card c) { if (AllZone.Phase.getPhase().equals("Declare Blockers")) @@ -1647,9 +1812,7 @@ public class CombatUtil AllZone.EndOfCombat.addAt(atEOC); } - - - + a.setCreatureGotBlockedThisTurn(true); } }//Class CombatUtil \ No newline at end of file diff --git a/src/forge/GameAction.java b/src/forge/GameAction.java index f6a2c8aed77..5810e286963 100644 --- a/src/forge/GameAction.java +++ b/src/forge/GameAction.java @@ -317,12 +317,14 @@ private Card getCurrentCard(int ID) boolean stop = false; - if(AllZone.Computer_Life.getLife() <= 0) + if(AllZone.Computer_Life.getLife() <= 0 + || AllZone.Computer_PoisonCounter.getPoisonCounters() >= 10 ) { Constant.Runtime.WinLose.addWin(); stop = true; } - if(AllZone.Human_Life.getLife() <= 0) + if(AllZone.Human_Life.getLife() <= 0 + || AllZone.Human_PoisonCounter.getPoisonCounters() >= 10) { Constant.Runtime.WinLose.addLose(); stop = true; @@ -1146,7 +1148,8 @@ private int getDifferentLand(CardList list, String land) ArrayList choices = new ArrayList(); - if (Input_Main.canPlayNumberOfLands > 0) + if (Input_Main.canPlayNumberOfLands > 0 && + (AllZone.Phase.getPhase().equals(Constant.Phase.Main1) || AllZone.Phase.getPhase().equals(Constant.Phase.Main2)) ) choices.add("Play land"); for (SpellAbility sa: sas) diff --git a/src/forge/GameActionUtil.java b/src/forge/GameActionUtil.java index a7f98e5d738..b57b3999edf 100644 --- a/src/forge/GameActionUtil.java +++ b/src/forge/GameActionUtil.java @@ -3596,8 +3596,6 @@ public class GameActionUtil playerCombatDamage_Augury_Adept(c); else if (c.getName().equals("Warren Instigator")) playerCombatDamage_Warren_Instigator(c); - else if (c.getName().equals("Guiltfeeder")) - playerCombatDamage_Guiltfeeder(c); else if (c.getName().equals("Spawnwrithe")) playerCombatDamage_Spawnwrithe(c); else if (c.getName().equals("Glint-Eye Nephilim") || c.getName().equals("Cold-Eyed Selkie") ) @@ -3665,13 +3663,11 @@ public class GameActionUtil */ private static void playerCombatDamage_Oros(Card c) { - System.out.println("Oros swung unblocked."); SpellAbility[] sa = c.getSpellAbility(); if (c.getController().equals(Constant.Player.Human)) AllZone.GameAction.playSpellAbility(sa[1]); else ComputerUtil.playNoStack(sa[1]); - } private static void playerCombatDamage_Dimir_Cutpurse(Card c) @@ -4110,6 +4106,7 @@ public class GameActionUtil AllZone.Stack.add(ability2); } + /* private static void playerCombatDamage_Guiltfeeder(Card c) { final String player = c.getController(); @@ -4133,8 +4130,8 @@ public class GameActionUtil ability2.setStackDescription(c.getName() + " - " + opponent + " loses life equal to cards in graveyard."); AllZone.Stack.add(ability2); - } + */ private static void playerCombatDamage_Goblin_Lackey(Card c) { @@ -4237,7 +4234,6 @@ public class GameActionUtil }//warren instigator - private static void playerCombatDamage_Shadowmage_Infiltrator(Card c) { diff --git a/src/forge/GuiDisplay3.java b/src/forge/GuiDisplay3.java index 26103dd12dc..88c6e7c6f20 100644 --- a/src/forge/GuiDisplay3.java +++ b/src/forge/GuiDisplay3.java @@ -85,6 +85,7 @@ public class GuiDisplay3 extends JFrame implements Display, NewConstants, NewCon public static Color c1 = new Color(204, 204, 204); public static Color c2 = new Color(204, 204, 204); + public static Color c3 = new Color(0, 164, 0); private Action HUMAN_GRAVEYARD_ACTION; private Action HUMAN_REMOVED_ACTION; @@ -583,6 +584,15 @@ public class GuiDisplay3 extends JFrame implements Display, NewConstants, NewCon }); AllZone.Computer_Life.updateObservers(); + oppPCLabel.setText("Poison Counters: " + AllZone.Computer_PoisonCounter.getPoisonCounters()); + AllZone.Computer_PoisonCounter.addObserver(new Observer() { + public void update(Observable a, Object b) { + int pcs = AllZone.Computer_PoisonCounter.getPoisonCounters(); + oppPCLabel.setText("Poison Counters: " + pcs); + } + }); + AllZone.Computer_PoisonCounter.updateObservers(); + //player life playerLifeLabel.setText("" + AllZone.Human_Life.getLife()); AllZone.Human_Life.addObserver(new Observer() { @@ -593,6 +603,15 @@ public class GuiDisplay3 extends JFrame implements Display, NewConstants, NewCon }); AllZone.Human_Life.updateObservers(); + playerPCLabel.setText("Poison Counters: " + AllZone.Human_PoisonCounter.getPoisonCounters()); + AllZone.Human_PoisonCounter.addObserver(new Observer() { + public void update(Observable a, Object b) { + int pcs = AllZone.Human_PoisonCounter.getPoisonCounters(); + playerPCLabel.setText("Poison Counters: " + pcs); + } + }); + AllZone.Human_PoisonCounter.updateObservers(); + //stack AllZone.Stack.addObserver(new Observer() { public void update(Observable a, Object b) { @@ -849,7 +868,11 @@ public class GuiDisplay3 extends JFrame implements Display, NewConstants, NewCon private void initOpp(JPanel pane) { oppLifeLabel.setFont(lifeFont); - oppLifeLabel.setHorizontalAlignment(SwingConstants.CENTER); + //oppLifeLabel.setHorizontalAlignment(SwingConstants.CENTER); + + oppPCLabel.setFont(statFont); + //oppPCLabel.setHorizontalAlignment(SwingConstants.TOP); + oppPCLabel.setForeground(c3); JLabel oppLibraryLabel = new JLabel(ForgeProps.getLocalized(COMPUTER_LIBRARY.TITLE), SwingConstants.TRAILING); @@ -905,6 +928,7 @@ public class GuiDisplay3 extends JFrame implements Display, NewConstants, NewCon oppPanel.setLayout(new BorderLayout()); oppPanel.add(oppNumbersPanel, BorderLayout.WEST); oppPanel.add(oppLifeLabel, BorderLayout.EAST); + oppPanel.add(oppPCLabel, BorderLayout.AFTER_LAST_LINE); pane.add(new ExternalPanel(oppPanel), "compy"); } @@ -932,7 +956,9 @@ public class GuiDisplay3 extends JFrame implements Display, NewConstants, NewCon playerLifeLabel.setFont(lifeFont); playerLifeLabel.setHorizontalAlignment(SwingConstants.CENTER); - + playerPCLabel.setFont(statFont); + playerPCLabel.setForeground(c3); + JLabel playerLibraryLabel = new JLabel(ForgeProps.getLocalized(HUMAN_LIBRARY.TITLE), SwingConstants.TRAILING); playerLibraryLabel.setFont(statFont); @@ -1002,6 +1028,7 @@ public class GuiDisplay3 extends JFrame implements Display, NewConstants, NewCon playerPanel.setLayout(new BorderLayout()); playerPanel.add(playerNumbersPanel, BorderLayout.WEST); playerPanel.add(playerLifeLabel, BorderLayout.EAST); + playerPanel.add(playerPCLabel, BorderLayout.AFTER_LAST_LINE); pane.add(new ExternalPanel(playerPanel), "human"); } @@ -1117,6 +1144,8 @@ public class GuiDisplay3 extends JFrame implements Display, NewConstants, NewCon public JPanel picturePanel = new JPanel(); JLabel oppLifeLabel = new JLabel(); JLabel playerLifeLabel = new JLabel(); + JLabel oppPCLabel = new JLabel(); + JLabel playerPCLabel = new JLabel(); JLabel cdLabel1 = new JLabel(); JLabel cdLabel2 = new JLabel(); JLabel cdLabel3 = new JLabel(); diff --git a/src/forge/InputControl.java b/src/forge/InputControl.java index 08ad2ec9751..7305df8f0ed 100644 --- a/src/forge/InputControl.java +++ b/src/forge/InputControl.java @@ -46,9 +46,9 @@ package forge; { if(phase.equals(Constant.Phase.Untap)) { - AllZone.Combat.reset(); - AllZone.Combat.setAttackingPlayer(Constant.Player.Human); - AllZone.Combat.setDefendingPlayer(Constant.Player.Computer); + AllZone.Combat.reset(); + AllZone.Combat.setAttackingPlayer(Constant.Player.Human); + AllZone.Combat.setDefendingPlayer(Constant.Player.Computer); AllZone.pwCombat.reset(); AllZone.pwCombat.setAttackingPlayer(Constant.Player.Human); @@ -83,8 +83,18 @@ package forge; else if (phase.equals(Constant.Phase.Combat_Declare_Attackers_InstantAbility)) { - if (! skipPhase()) + if (! skipPhase()) + { + CardList list = new CardList(); + list.addAll(AllZone.Combat.getAttackers()); + list.addAll(AllZone.pwCombat.getAttackers()); + for (Card c : list) + { + CombatUtil.checkDeclareAttackers(c); + } + return new Input_Attack_Instant(); + } else { AllZone.Phase.setNeedToNextPhase(true); @@ -201,8 +211,19 @@ package forge; //takes place during the computer's turn, like blocking etc... else if(phase.equals(Constant.Phase.Combat_Declare_Blockers)) { - if(! skipPhase()) - return new Input_Block(); + if(! skipPhase()) + { + /* + CardList list = new CardList(); + list.addAll(AllZone.Combat.getAttackers()); + list.addAll(AllZone.pwCombat.getAttackers()); + for (Card c : list) + { + CombatUtil.checkDeclareAttackers(c); + } + */ + return new Input_Block(); + } else { //AllZone.Phase.nextPhase(); @@ -221,25 +242,36 @@ package forge; { //computer if(phase.equals(Constant.Phase.Untap)) { - AllZone.Combat.reset(); - AllZone.Combat.setAttackingPlayer(Constant.Player.Computer); - AllZone.Combat.setDefendingPlayer(Constant.Player.Human); - - AllZone.pwCombat.reset(); - AllZone.pwCombat.setAttackingPlayer(Constant.Player.Computer); - AllZone.pwCombat.setDefendingPlayer(Constant.Player.Human); - - return new Input_Untap(); - } + AllZone.Combat.reset(); + AllZone.Combat.setAttackingPlayer(Constant.Player.Computer); + AllZone.Combat.setDefendingPlayer(Constant.Player.Human); + + AllZone.pwCombat.reset(); + AllZone.pwCombat.setAttackingPlayer(Constant.Player.Computer); + AllZone.pwCombat.setDefendingPlayer(Constant.Player.Human); + + return new Input_Untap(); + } else if(phase.equals(Constant.Phase.Draw)) - return new Computer_Draw(); + return new Computer_Draw(); else if(phase.equals(Constant.Phase.Cleanup)) - { + { return new Computer_Cleanup(); - } + } + else if (phase.equals(Constant.Phase.Combat_Declare_Blockers)) + { + CardList list = new CardList(); + list.addAll(AllZone.Combat.getAttackers()); + list.addAll(AllZone.pwCombat.getAttackers()); + for (Card c : list) + { + CombatUtil.checkDeclareAttackers(c); + } + return AllZone.Computer; + } else - return AllZone.Computer; + return AllZone.Computer; }//Computer return new Input() diff --git a/src/forge/Input_CombatDamage.java b/src/forge/Input_CombatDamage.java index 162df985591..a171082d1c8 100644 --- a/src/forge/Input_CombatDamage.java +++ b/src/forge/Input_CombatDamage.java @@ -72,7 +72,8 @@ private void playerDamage(PlayerLife p) //if (unblocked.getCard(j).hasSecondStrike()) { if (!unblocked.getCard(j).hasFirstStrike() || (unblocked.getCard(j).hasFirstStrike() && unblocked.getCard(j).hasDoubleStrike())) { - GameActionUtil.executePlayerCombatDamageEffects(unblocked.get(j)); + GameActionUtil.executePlayerCombatDamageEffects(unblocked.get(j)); + CombatUtil.checkUnblockedAttackers(unblocked.get(j)); } } diff --git a/src/forge/Input_FirstStrikeDamage.java b/src/forge/Input_FirstStrikeDamage.java index 4f2f128b112..e62b03c64c9 100644 --- a/src/forge/Input_FirstStrikeDamage.java +++ b/src/forge/Input_FirstStrikeDamage.java @@ -72,7 +72,8 @@ private void playerDamage(PlayerLife p) for(int j = 0; j < unblocked.size(); j++) { //System.out.println("Unblocked Creature: " +unblocked.get(j).getName()); - GameActionUtil.executePlayerCombatDamageEffects(unblocked.get(j)); + GameActionUtil.executePlayerCombatDamageEffects(unblocked.get(j)); + CombatUtil.checkUnblockedAttackers(unblocked.get(j)); /*if (unblocked.get(j).getKeyword().contains("Lifelink")) { diff --git a/src/forge/PlayerLife.java b/src/forge/PlayerLife.java index cdcf88f09de..3641e9cb2ab 100644 --- a/src/forge/PlayerLife.java +++ b/src/forge/PlayerLife.java @@ -6,28 +6,26 @@ public class PlayerLife extends MyObservable implements java.io.Serializable private int life; private int assignedDamage;//from combat - public void setAssignedDamage(int n) - {assignedDamage = n;} - public int getAssignedDamage() - {return assignedDamage;} + public void setAssignedDamage(int n) {assignedDamage = n;} + public int getAssignedDamage() {return assignedDamage;} public int getLife() { - return life; + return life; } public void setLife(int life2) { - life = life2; - this.updateObservers(); + life = life2; + this.updateObservers(); } public void addLife(int life2) { - life += life2; - this.updateObservers(); + life += life2; + this.updateObservers(); } public void subtractLife(int life2) { - life -= life2; - this.updateObservers(); + life -= life2; + this.updateObservers(); } } \ No newline at end of file diff --git a/src/forge/PlayerPoisonCounter.java b/src/forge/PlayerPoisonCounter.java new file mode 100644 index 00000000000..2978cd5d972 --- /dev/null +++ b/src/forge/PlayerPoisonCounter.java @@ -0,0 +1,26 @@ +package forge; +public class PlayerPoisonCounter extends MyObservable implements java.io.Serializable +{ + private static final long serialVersionUID = 7559655609258111697L; + private int poisonCounters; + + public int getPoisonCounters() + { + return poisonCounters; + } + public void setLife(int poisonCounters2) + { + poisonCounters = poisonCounters2; + this.updateObservers(); + } + public void addPoisonCounters(int poisonCounters2) + { + poisonCounters += poisonCounters2; + this.updateObservers(); + } + public void subtractLife(int poisonCounters2) + { + poisonCounters -= poisonCounters2; + this.updateObservers(); + } +} \ No newline at end of file