From 71e2aac3cc7646cebaecbd09c36dc72ab4928aba Mon Sep 17 00:00:00 2001 From: jendave Date: Sat, 6 Aug 2011 05:20:04 +0000 Subject: [PATCH] Expanded the Whenever Keyword (More support for combat). Converted Rogue Kavu and Alley Grifters to keyword. Added Battle Strain, Abyssal Nightstalker and Fledgling Griffin --- res/card-pictures.txt | 3 + res/cards.txt | 35 +++++++-- src/forge/CombatUtil.java | 28 ++----- src/forge/GameAction.java | 144 +++++++++++++++++++++++++++--------- src/forge/InputControl.java | 3 + 5 files changed, 153 insertions(+), 60 deletions(-) diff --git a/res/card-pictures.txt b/res/card-pictures.txt index 18dbcdc7119..d20622364a0 100644 --- a/res/card-pictures.txt +++ b/res/card-pictures.txt @@ -38,6 +38,9 @@ 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 +battle_strain.jpg http://www.wizards.com/global/images/magic/general/battle_strain.jpg +abyssal_nightstalker.jpg http://serv4.tcgimages.eu/img/cards/Portal_Second_Age/abyssal_nightstalker.jpg +fledgling_griffin.jpg http://www.wizards.com/global/images/magic/general/fledgling_griffin.jpg rogue_kavu.jpg http://www.wizards.com/global/images/magic/general/rogue_kavu.jpg matca_rioters.jpg http://www.wizards.com/global/images/magic/general/matca_rioters.jpg psychatog.jpg http://www.wizards.com/global/images/magic/general/psychatog.jpg diff --git a/res/cards.txt b/res/cards.txt index e35b7fa8758..f3db4731600 100644 --- a/res/cards.txt +++ b/res/cards.txt @@ -1,9 +1,36 @@ +Battle Strain +1 R +Enchantment +no text +WheneverKeyword:Blocks:No_Initiator:Play:Damage/1:ControllingPlayer_Initiator:ASAP:No_Condition:No Special Condition:Whenever a creature blocks, Battle Strain deals 1 damage to that creature's controller. + +Alley Grifters +1 B B +Creature Human Mercenary +no text +2/2 +WheneverKeyword:BecomesBlocked:Self:Play:DiscardCards/1:ControllingPlayer_Opponent:ASAP:No_Condition:No Special Condition:Whenever Alley Grifters becomes blocked, defending player discards a card. + +Abyssal Nightstalker +3 B +Creature Nightstalker +no text +2/2 +WheneverKeyword:isUnblocked:Self:Play:DiscardCards/1:ControllingPlayer_Opponent:ASAP:No_Condition:No Special Condition:Whenever Abyssal Nightstalker attacks and isn't blocked, defending player discards a card. + +Fledgling Griffin +1 W +Creature Griffin +no text +2/2 +WheneverKeyword:EntersBattleField:Type/Land:Play:KeywordPumpEOT/Flying:Self:ASAP:No_Condition:Initiator - OwnedByController:Landfall — Whenever a land enters the battlefield under your control, Fledgling Griffin gains flying until end of turn. + Rogue Kavu 1 R Creature Kavu no text 1/1 -Whenever CARDNAME attacks alone, it gets +2/+0 until end of turn. +WheneverKeyword:Attack - Alone:Self:Play:StatsPumpEOT/2/0:Self:ASAP:No_Condition:No Special Condition:Whenever Rogue Kavu attacks alone, it gets +2/+0 until end of turn. Niv-Mizzet, the Firemind 2 U U R R @@ -15795,12 +15822,6 @@ Creature Fish Whenever Quagmire Lamprey becomes blocked by a creature, put a -1/-1 counter on that creature. 1/1 -Alley Grifters -1 B B -Creature Human Mercenary -Whenever Alley Grifters becomes blocked, defending player discards a card. -2/2 - Sylvan Basilisk 3 G G Creature Basilisk diff --git a/src/forge/CombatUtil.java b/src/forge/CombatUtil.java index 070d8725615..46e90c1bf32 100644 --- a/src/forge/CombatUtil.java +++ b/src/forge/CombatUtil.java @@ -1964,6 +1964,9 @@ public class CombatUtil { }//checkDeclareAttackers public static void checkUnblockedAttackers(Card c) { + + AllZone.GameAction.CheckWheneverKeyword(c,"isUnblocked",null); + if(c.getName().equals("Guiltfeeder")) { final String player = c.getController(); final String opponent = AllZone.GameAction.getOpponent(player); @@ -2004,6 +2007,8 @@ public class CombatUtil { for (Card c:cl) { + AllZone.GameAction.CheckWheneverKeyword(c,"Blocks",null); + if (!c.getCreatureBlockedThisCombat()) { for(Ability ab:CardFactoryUtil.getBushidoEffects(c)) { AllZone.Stack.add(ab); @@ -2088,6 +2093,8 @@ public class CombatUtil { public static void checkBlockedAttackers(Card a, Card b) { //System.out.println(a.getName() + " got blocked by " + b.getName()); + AllZone.GameAction.CheckWheneverKeyword(a,"BecomesBlocked",null); + if(!a.getCreatureGotBlockedThisCombat()) { for(Ability ab:CardFactoryUtil.getBushidoEffects(a)) AllZone.Stack.add(ab); @@ -2181,26 +2188,7 @@ public class CombatUtil { } else if(a.getName().equals("Sylvan Basilisk")) { AllZone.GameAction.destroy(b); System.out.println("destroyed blocker " + b.getName()); - } else if(a.getName().equals("Alley Grifters") && !a.getCreatureGotBlockedThisCombat()) { - String player = a.getController(); - String opp = b.getController(); - - if(player.equals(Constant.Player.Computer)) { - PlayerZone hand = AllZone.getZone(Constant.Zone.Hand, opp); - CardList list = new CardList(hand.getCards()); - - Object o = AllZone.Display.getChoiceOptional("Select card to discard", list.toArray()); - if(o == null) AllZone.GameAction.discardRandom(opp); - else { - Card c = (Card) o; - AllZone.GameAction.discard(c); - } - } else //computer just discards at random - { - AllZone.GameAction.discardRandom(opp); - } - }//Alley Grifters - else if(a.getName().equals("Quagmire Lamprey")) { + } else if(a.getName().equals("Quagmire Lamprey")) { b.addCounter(Counters.M1M1, 1); } else if(a.getName().equals("Elven Warhounds")) { PlayerZone play = AllZone.getZone(Constant.Zone.Play, b.getController()); diff --git a/src/forge/GameAction.java b/src/forge/GameAction.java index f5af5514277..48e5380e22d 100644 --- a/src/forge/GameAction.java +++ b/src/forge/GameAction.java @@ -925,17 +925,17 @@ public class GameAction { for(int y = 0; y < Effects; y++) { // Variables - String AmountParse = Effect[y]; - int I_Amount = 0; - String S_Amount = ""; + String AmountParse = Effect[y]; + String[] S_Amount = AmountParse.split("/"); + int[] I_Amount = new int[S_Amount.length - 1]; + int Multiple_Targets = 1; - if((AmountParse.split("/")).length > 1) { - S_Amount = AmountParse.split("/")[1]; + for(int b = 0; b < S_Amount.length - 1; b++) { - if(S_Amount.equals("Toughness")) I_Amount = F_TriggeringCard.getNetDefense(); - else if(S_Amount.equals("Power")) I_Amount = F_TriggeringCard.getNetAttack(); - else if(S_Amount.equals("Life_Gained")) I_Amount = ((Integer)Custom_Parameters[0]); - else if(S_Amount.contains("ControlledAmountType")) { + if(S_Amount[b+1].equals("Toughness")) I_Amount[b] = F_TriggeringCard.getNetDefense(); + else if(S_Amount[b+1].equals("Power")) I_Amount[b] = F_TriggeringCard.getNetAttack(); + else if(S_Amount[b+1].equals("Life_Gained")) I_Amount[b] = ((Integer)Custom_Parameters[0]); + else if(S_Amount[b+1].contains("ControlledAmountType")) { final String[] TypeSplit = AmountParse.split("/"); CardList Cards_WithAllTypes = new CardList(); Cards_WithAllTypes.add(new CardList(AllZone.getZone(Constant.Zone.Play, card.getController()).getCards())); @@ -946,19 +946,23 @@ public class GameAction { return false; } }); - I_Amount = Cards_WithAllTypes.size(); + I_Amount[b] = Cards_WithAllTypes.size(); } - else I_Amount = Integer.valueOf(S_Amount); - } - int Multiple_Targets = 1; + else if(!S_Amount[0].equals("KeywordPumpEOT")) I_Amount[b] = Integer.valueOf(S_Amount[b+1]); + + // NOTE: Multiple Targets and Groups of Integers is not supported + if(k[8].contains("MultipleTargets")) { - Multiple_Targets = I_Amount; - I_Amount = 1; + Multiple_Targets = I_Amount[0]; + I_Amount[0] = 1; } + } // For + final int F_Multiple_Targets = Multiple_Targets; final Object[] Targets_Multi = new Object[Multiple_Targets]; final int[] index = new int[1]; - final int F_Amount = I_Amount; + final int[] F_Amount = I_Amount; + final String[] F_S_Amount = S_Amount; final int F_Target = Effects_Count[0]; @@ -968,7 +972,7 @@ public class GameAction { public void execute() { MultiTarget_Cancelled = false; for(int i = 0; i < F_Multiple_Targets; i++) { - AllZone.InputControl.setInput(CardFactoryUtil.input_MultitargetCreatureOrPlayer(ability , i , F_Amount*F_Multiple_Targets,new Command() { + AllZone.InputControl.setInput(CardFactoryUtil.input_MultitargetCreatureOrPlayer(ability , i , F_Amount[0]*F_Multiple_Targets,new Command() { private static final long serialVersionUID = -328305150127775L; @@ -985,7 +989,12 @@ public class GameAction { }; if(k[8].contains("MultipleTargets")) CommandExecute[0] = MultiTargetsCommand; else if(k[8].contains("SingleTarget")) CommandExecute[0] = MultiTargetsCommand; - else CommandExecute[0] = Command.Blank; + else { + if(F_TargetPlayer[y] != null) Targets_Multi[index[0]] = F_TargetPlayer[y]; + if(F_TargetCard[y] != null) Targets_Multi[index[0]] = F_TargetCard[y]; + index[0]++; + CommandExecute[0] = Command.Blank; + } // Null if(Effect[y].equals("Null")) { @@ -999,12 +1008,80 @@ public class GameAction { private static final long serialVersionUID = 151367344511590317L; public void execute() { - if(Whenever_Go(F_card,F_k) == true) if(AllZone.GameAction.isCardInZone(F_TargetCard[F_Target],Required_Zone)) F_TargetCard[F_Target].addCounter(Counters.P1P1, F_Amount); + if(Whenever_Go(F_card,F_k) == true) if(AllZone.GameAction.isCardInZone(F_TargetCard[F_Target],Required_Zone)) F_TargetCard[F_Target].addCounter(Counters.P1P1, F_Amount[0]); }; }; Command_Effects[F_Target] = Proper_resolve; - StackDescription = StackDescription + F_TargetCard[y] + " gets " + F_Amount + " +1/+1 counters"; + StackDescription = StackDescription + F_TargetCard[y] + " gets " + F_Amount[0] + " +1/+1 counters"; } + // StatsPumpEOT/Power/Toughness + if(Effect[y].contains("StatsPumpEOT")) { + + Command Proper_resolve = new Command() { + private static final long serialVersionUID = 151367344511590317L; + + public void execute() { + if(Whenever_Go(F_card,F_k) == true) if(AllZone.GameAction.isCardInZone(F_TargetCard[F_Target],Required_Zone)) { + final Command untilEOT = new Command() { + private static final long serialVersionUID = 1497565871061029469L; + + public void execute() { + if(AllZone.GameAction.isCardInPlay(F_card)) { + F_card.addTempAttackBoost(- F_Amount[0]); + F_card.addTempDefenseBoost(- F_Amount[1]); + } + } + };//Command + + + F_card.addTempAttackBoost(F_Amount[0]); + F_card.addTempDefenseBoost(F_Amount[1]); + + AllZone.EndOfTurn.addUntil(untilEOT); + } + }; + }; + Command_Effects[F_Target] = Proper_resolve; + StackDescription = StackDescription + F_TargetCard[y] + " gets " + ((F_Amount[0] > -1)? "+" :"") + F_Amount[0] + + "/" + ((F_Amount[1] > -1)? "+" :"") + F_Amount[1] + " until End of Turn"; + } + + // KeywordPumpEOT/Keyword(s) + if(Effect[y].contains("KeywordPumpEOT")) { + + Command Proper_resolve = new Command() { + private static final long serialVersionUID = 151367344511590317L; + + public void execute() { + if(Whenever_Go(F_card,F_k) == true) if(AllZone.GameAction.isCardInZone(F_TargetCard[F_Target],Required_Zone)) { + final Command untilEOT = new Command() { + private static final long serialVersionUID = 1497565871061029469L; + + public void execute() { + if(AllZone.GameAction.isCardInPlay(F_card)) { + for(int i =0; i < F_S_Amount.length - 1; i++) { + F_card.removeIntrinsicKeyword(F_S_Amount[i + 1]); + } + } + } + };//Command + + for(int i =0; i < F_S_Amount.length - 1; i++) { + F_card.addIntrinsicKeyword(F_S_Amount[i + 1]); + } + AllZone.EndOfTurn.addUntil(untilEOT); + } + }; + }; + String Desc = ""; + for(int KW =0; KW < F_S_Amount.length - 1; KW++) { + Desc = Desc + F_S_Amount[KW + 1]; + if(KW < F_S_Amount.length - 2) Desc = Desc + ", "; + } + Command_Effects[F_Target] = Proper_resolve; + StackDescription = StackDescription + F_TargetCard[y] + " gets " + Desc + " until End of Turn"; + } + // Gain Life if(Effect[y].contains("ModifyLife")) { Command Proper_resolve = new Command() { @@ -1013,14 +1090,14 @@ public class GameAction { public void execute() { if(Whenever_Go(F_card,F_k) == true) if(AllZone.GameAction.isCardInZone(F_card,Required_Zone)) { PlayerLife life = AllZone.GameAction.getPlayerLife(F_TargetPlayer[F_Target]); - if(F_Amount > -1) life.addLife(F_Amount); - else life.subtractLife(F_Amount * -1,F_card); + if(F_Amount[0] > -1) life.addLife(F_Amount[0]); + else life.subtractLife(F_Amount[0] * -1,F_card); } } }; Command_Effects[F_Target] = Proper_resolve; - StackDescription = StackDescription + F_TargetPlayer[F_Target] + ((F_Amount > -1)? " gains " + F_Amount:"") + ((F_Amount <= -1)? " loses " + F_Amount * -1:"") + " life"; + StackDescription = StackDescription + F_TargetPlayer[F_Target] + ((F_Amount[0] > -1)? " gains " + F_Amount[0]:"") + ((F_Amount[0] <= -1)? " loses " + F_Amount[0] * -1:"") + " life"; } // Draw Cards @@ -1036,7 +1113,7 @@ public class GameAction { } }; Command_Effects[F_Target] = Proper_resolve; - StackDescription = StackDescription + F_TargetPlayer[F_Target] + " draws " + F_Amount + " card(s)"; + StackDescription = StackDescription + F_TargetPlayer[F_Target] + " draws " + F_Amount[0] + " card(s)"; } // Discard Cards @@ -1046,13 +1123,13 @@ public class GameAction { public void execute() { if(Whenever_Go(F_card,F_k) == true) if(AllZone.GameAction.isCardInZone(F_card,Required_Zone)) { - AllZone.GameAction.discard(F_TargetPlayer[F_Target],F_Amount); + AllZone.GameAction.discard(F_TargetPlayer[F_Target],F_Amount[0]); } } }; Command_Effects[F_Target] = Proper_resolve; - StackDescription = StackDescription + F_TargetPlayer[F_Target] + " discards " + F_Amount + " card(s)"; + StackDescription = StackDescription + F_TargetPlayer[F_Target] + " discards " + F_Amount[0] + " card(s)"; } // Make Token-Type-color-Power-Toughness-Keywords---Amount @@ -1081,7 +1158,7 @@ public class GameAction { if(Whenever_Go(F_card,F_k) == true) if(AllZone.GameAction.isCardInZone(F_card,Required_Zone)) { String Color = F_TokenConditions[2]; if(F_TokenConditions[2].equals("c")) Color = "1"; - for(int z = 0; z < F_Amount; z++) + for(int z = 0; z < F_Amount[0]; z++) CardFactoryUtil.makeToken( F_TokenConditions[1] + " Token", F_TokenConditions[2]+ " " + Integer.valueOf(F_TokenConditions[3])+ " " + Integer.valueOf(F_TokenConditions[4]) + " " + F_TokenConditions[1], F_card, Color, new String[] { @@ -1092,7 +1169,7 @@ public class GameAction { } }; Command_Effects[F_Target] = Proper_resolve; - StackDescription = StackDescription + F_TargetPlayer[F_Target] + " puts " + F_Amount + " " + F_TokenConditions[3] + + StackDescription = StackDescription + F_TargetPlayer[F_Target] + " puts " + F_Amount[0] + " " + F_TokenConditions[3] + "/" + F_TokenConditions[4] + " " + F_Color + " " + F_TokenConditions[1] + " creature token(s) onto the battlefield"; } @@ -1173,22 +1250,23 @@ public class GameAction { if(AllZone.GameAction.isCardInPlay((Card) Targets_Multi[z]) && CardFactoryUtil.canTarget(F_card, (Card) Targets_Multi[z])) { Card c = (Card) Targets_Multi[z]; - AllZone.GameAction.addDamage(c, F_card, F_Amount); + AllZone.GameAction.addDamage(c, F_card, F_Amount[0]); } } else { - AllZone.GameAction.addDamage( (String) Targets_Multi[z], F_Amount,F_card); + AllZone.GameAction.addDamage( (String) Targets_Multi[z], F_Amount[0],F_card); } } } - if(F_card.getController().equals(Constant.Player.Computer)) AllZone.GameAction.addDamage(Constant.Player.Human, F_Amount*F_Multiple_Targets,F_card); + if(F_card.getController().equals(Constant.Player.Computer)) AllZone.GameAction.addDamage(Constant.Player.Human, F_Amount[0]*F_Multiple_Targets,F_card); } }; }; Command_Effects[F_Target] = Proper_resolve; - if(F_Multiple_Targets != 1) StackDescription = StackDescription + "deals " + F_Amount*F_Multiple_Targets + " damage" + " divided among up to " + Multiple_Targets + " target creatures and/or players"; + if(F_Multiple_Targets != 1) StackDescription = StackDescription + "deals " + F_Amount[0]*F_Multiple_Targets + " damage" + " divided among up to " + Multiple_Targets + " target creatures and/or players"; else if(F_card.getController().equals(Constant.Player.Computer)) StackDescription = StackDescription + "targeting Human "; - else StackDescription = StackDescription + "targeting ?"; + else StackDescription = StackDescription + "targeting " + ((F_TargetCard[y] != null)? F_TargetCard[y]:"") + + ((F_TargetPlayer[y] != null)? F_TargetPlayer[y]:""); } Effects_Count[0]++; diff --git a/src/forge/InputControl.java b/src/forge/InputControl.java index 0695094a794..60249279ba3 100644 --- a/src/forge/InputControl.java +++ b/src/forge/InputControl.java @@ -81,6 +81,9 @@ public class InputControl extends MyObservable implements java.io.Serializable { //check for exalted: if ((AllZone.Combat.getDeclaredAttackers() + AllZone.pwCombat.getDeclaredAttackers() == 1) && !appliedExaltedEffects) { + + AllZone.GameAction.CheckWheneverKeyword(list.get(0), "Attack - Alone", null); + // if (list.size()==1) { String attackingPlayer = AllZone.Combat.getAttackingPlayer(); PlayerZone play = AllZone.getZone(Constant.Zone.Play, attackingPlayer);