From a35bd26c4e19987b45f1aa2d7e522e254e0d67d1 Mon Sep 17 00:00:00 2001 From: jendave Date: Sat, 6 Aug 2011 13:31:49 +0000 Subject: [PATCH] - Initial code for AF_ChangeZone, a more generalized version of Bounce, Retrieve and Fetch. - Converted AEther Vial, Boomerang, Brainstorm, Buried Alive, Elvish Piper, Fertilid, Jester's Cap, Raise Dead to AF_ChangeZone --- .gitattributes | 1 + res/cardsfolder/aether_vial.txt | 2 + res/cardsfolder/boomerang.txt | 2 +- res/cardsfolder/brainstorm.txt | 3 +- res/cardsfolder/buried_alive.txt | 3 +- res/cardsfolder/elvish_piper.txt | 3 +- res/cardsfolder/fertilid.txt | 2 +- res/cardsfolder/jesters_cap.txt | 3 +- res/cardsfolder/raise_dead.txt | 2 +- src/forge/AbilityFactory.java | 26 +- src/forge/AbilityFactory_ChangeZone.java | 854 +++++++++++++++++++++++ src/forge/CardFactory.java | 42 +- src/forge/CardFactory_Creatures.java | 62 +- src/forge/CardFactory_Sorceries.java | 63 +- 14 files changed, 897 insertions(+), 171 deletions(-) create mode 100644 src/forge/AbilityFactory_ChangeZone.java diff --git a/.gitattributes b/.gitattributes index 41cdbb9ba51..94ac46a4d98 100644 --- a/.gitattributes +++ b/.gitattributes @@ -6033,6 +6033,7 @@ src/forge/Ability.java svneol=native#text/plain src/forge/AbilityFactory.java -text svneol=native#text/plain src/forge/AbilityFactory_AlterLife.java -text svneol=native#text/plain src/forge/AbilityFactory_Bounce.java -text svneol=native#text/plain +src/forge/AbilityFactory_ChangeZone.java -text svneol=native#text/plain src/forge/AbilityFactory_Combat.java -text svneol=native#text/plain src/forge/AbilityFactory_CounterMagic.java -text svneol=native#text/plain src/forge/AbilityFactory_Counters.java -text svneol=native#text/plain diff --git a/res/cardsfolder/aether_vial.txt b/res/cardsfolder/aether_vial.txt index 0b8f5776ec8..5029dc5c1e0 100644 --- a/res/cardsfolder/aether_vial.txt +++ b/res/cardsfolder/aether_vial.txt @@ -2,7 +2,9 @@ Name:AEther Vial ManaCost:1 Types:Artifact Text:no text +A:AB$ChangeZone | Cost$ T | Origin$ Hand | Destination$ Battlefield | ChangeType$ Creature.cmcEQX | ChangeNum$ 1 | SpellDescription$ You may put a creature card with converted mana cost equal to the number of charge counters on Ęther Vial from your hand onto the battlefield. K:WheneverKeyword:BeginningOfUpkeep:No_Initiator:Play:CustomCounter.CHARGE/1:Self:ASAP:Yes_No:ControllerUpkeep:At the beginning of your upkeep, you may put a charge counter on CARDNAME. +SVar:X:Count$CardCounters.CHARGE SVar:RemAIDeck:True SVar:Rarity:Uncommon SVar:Picture:http://www.wizards.com/global/images/magic/general/aether_vial.jpg diff --git a/res/cardsfolder/boomerang.txt b/res/cardsfolder/boomerang.txt index 01a9464c97c..5823b0beef5 100644 --- a/res/cardsfolder/boomerang.txt +++ b/res/cardsfolder/boomerang.txt @@ -2,7 +2,7 @@ Name:Boomerang ManaCost:U U Types:Instant Text:no text -A:SP$Bounce | Cost$ U U | ValidTgts$ Permanent | TgtPrompt$ Select target permanent | Destination$ Hand | SpellDescription$ Return target permanent to its owner's hand. +A:SP$ChangeZone | Cost$ U U | ValidTgts$ Permanent | TgtPrompt$ Select target permanent | Origin$ Battlefield | Destination$ Hand | SpellDescription$ Return target permanent to its owner's hand. SVar:Rarity:Common SVar:Picture:http://www.wizards.com/global/images/magic/general/boomerang.jpg SetInfo:8ED|Common|http://magiccards.info/scans/en/8e/63.jpg diff --git a/res/cardsfolder/brainstorm.txt b/res/cardsfolder/brainstorm.txt index 54e6b7d266d..c50b512f708 100644 --- a/res/cardsfolder/brainstorm.txt +++ b/res/cardsfolder/brainstorm.txt @@ -2,7 +2,8 @@ Name:Brainstorm ManaCost:U Types:Instant Text:no text -A:SP$Draw | Cost$ U | NumCards$ 3 | SpellDescription$ Draw three cards, then put two cards from your hand on top of your library in any order. | SubAbility$ YouHandToLibrary/2/Top +A:SP$Draw | Cost$ U | NumCards$ 3 | SpellDescription$ Draw three cards, then put two cards from your hand on top of your library in any order. | SubAbility$ SVar=ChangeZoneDB +SVar:ChangeZoneDB:DB$ChangeZone | Origin$ Hand | Destination$ Library | ChangeNum$ 2 SVar:Rarity:Common SVar:Picture:http://www.wizards.com/global/images/magic/general/brainstorm.jpg SetInfo:5ED|Common|http://magiccards.info/scans/en/5e/76.jpg diff --git a/res/cardsfolder/buried_alive.txt b/res/cardsfolder/buried_alive.txt index 5b93cf2b963..816ce4f3380 100644 --- a/res/cardsfolder/buried_alive.txt +++ b/res/cardsfolder/buried_alive.txt @@ -1,7 +1,8 @@ Name:Buried Alive ManaCost:2 B Types:Sorcery -Text:Search your library for up to three creature cards and put them into your graveyard. Then shuffle your library. +Text:no text +A:SP$ChangeZone | Cost$ 2 B | Origin$ Library | Destination$ Graveyard | ChangeType$ Creature | ChangeNum$ 3 | SpellDescription$ Search your library for up to three creature cards and put them into your graveyard. Then shuffle your library. SVar:Rarity:Uncommon SVar:Picture:http://www.wizards.com/global/images/magic/general/buried_alive.jpg SetInfo:WTH|Uncommon|http://magiccards.info/scans/en/wl/5.jpg diff --git a/res/cardsfolder/elvish_piper.txt b/res/cardsfolder/elvish_piper.txt index a9e7887b9df..ebd0ec2c34d 100644 --- a/res/cardsfolder/elvish_piper.txt +++ b/res/cardsfolder/elvish_piper.txt @@ -1,7 +1,8 @@ Name:Elvish Piper ManaCost:3 G Types:Creature Elf Shaman -Text:G, tap: You may put a creature card from your hand onto the battlefield. +Text:no text +A:AB$ChangeZone | Cost$ G T | Origin$ Hand | Destination$ Battlefield | ChangeType$ Creature | ChangeNum$ 1 | SpellDescription$ You may put a creature card from your hand onto the battlefield. PT:1/1 SVar:Rarity:Rare SVar:Picture:http://resources.wizards.com/magic/cards/9ed/en-us/card83072.jpg diff --git a/res/cardsfolder/fertilid.txt b/res/cardsfolder/fertilid.txt index 561ec43f469..e3d2880c68e 100644 --- a/res/cardsfolder/fertilid.txt +++ b/res/cardsfolder/fertilid.txt @@ -4,7 +4,7 @@ Types:Creature Elemental Text:no text PT:0/0 K:etbCounter:P1P1:2 -A:AB$Fetch | Cost$ 1 G SubCounter<1/P1P1> | ValidTgts$Player | Destination$ Battlefield | Tapped$ True | FetchType$ Land.Basic | FetchNum$ 1 | SpellDescription$ Target player searches his or her library for a basic land card and puts it onto the battlefield tapped. Then that player shuffles his or her library. +A:AB$ChangeZone | Cost$ 1 G SubCounter<1/P1P1> | ValidTgts$ Player | Defined$ Targeted | Origin$ Library | Destination$ Battlefield | Tapped$ True | ChangeType$ Land.Basic | ChangeNum$ 1 | SpellDescription$ Target player searches his or her library for a basic land card and puts it onto the battlefield tapped. Then that player shuffles his or her library. SVar:Rarity:Common SVar:Picture:http://www.wizards.com/global/images/magic/general/fertilid.jpg SetInfo:MOR|Common|http://magiccards.info/scans/en/mt/122.jpg diff --git a/res/cardsfolder/jesters_cap.txt b/res/cardsfolder/jesters_cap.txt index 34de1007414..1d0544a8920 100644 --- a/res/cardsfolder/jesters_cap.txt +++ b/res/cardsfolder/jesters_cap.txt @@ -1,7 +1,8 @@ Name:Jester's Cap ManaCost:4 Types:Artifact -Text:2, Tap, Sacrifice Jester's Cap: Search target player's library for three cards and exile them. Then that player shuffles his or her library. +Text:no text +A:AB$ChangeZone | Cost$ 2 T Sac<1/CARDNAME> | ValidTgts$ Player | Origin$ Library | Destination$ Exile | ChangeType$ Card | ChangeNum$ 3 | IsCurse$ True | SpellDescription$ Search target player's library for three cards and exile them. Then that player shuffles his or her library. SVar:RemAIDeck:True SVar:Rarity:Rare SVar:Picture:http://www.wizards.com/global/images/magic/general/jesters_cap.jpg diff --git a/res/cardsfolder/raise_dead.txt b/res/cardsfolder/raise_dead.txt index bfa3a37846b..b8ea43a5dac 100644 --- a/res/cardsfolder/raise_dead.txt +++ b/res/cardsfolder/raise_dead.txt @@ -2,7 +2,7 @@ Name:Raise Dead ManaCost:B Types:Sorcery Text:no text -A:SP$Retrieve | Cost$ B | Destination$ Hand | TgtPrompt$ Choose target creature card in your graveyard | ValidTgts$ Creature.YouCtrl | SpellDescription$ Return target creature card from your graveyard to your hand. +A:SP$ChangeZone | Cost$ B | Origin$ Graveyard | Destination$ Hand | TgtPrompt$ Choose target creature card in your graveyard | ValidTgts$ Creature.YouCtrl | SpellDescription$ Return target creature card from your graveyard to your hand. SVar:Rarity:Common SVar:Picture:http://resources.wizards.com/magic/cards/9ed/en-us/card83220.jpg SetInfo:8ED|Common|http://magiccards.info/scans/en/8e/157.jpg diff --git a/src/forge/AbilityFactory.java b/src/forge/AbilityFactory.java index 0b2d8d20b30..dc71a9ebb48 100644 --- a/src/forge/AbilityFactory.java +++ b/src/forge/AbilityFactory.java @@ -217,7 +217,17 @@ public class AbilityFactory { SA = AbilityFactory_Counters.createDrawbackProliferate(this); } - // do we want to merge Fetch, Retrieve and Bounce into ChangeZone? + + if (API.equals("ChangeZone")){ + if (isAb) + SA = AbilityFactory_ChangeZone.createAbilityChangeZone(this); + else if (isSp) + SA = AbilityFactory_ChangeZone.createSpellChangeZone(this); + else if (isDb) + SA = AbilityFactory_ChangeZone.createDrawbackChangeZone(this); + } + + // Fetch, Retrieve and Bounce should be converted ChangeZone if (API.equals("Fetch")){ if (isAb) SA = AbilityFactory_Fetch.createAbilityFetch(this); @@ -239,7 +249,7 @@ public class AbilityFactory { SA = AbilityFactory_Bounce.createSpellBounce(this); hostCard.setSVar("PlayMain1", "TRUE"); } - // Above to be merged? If so, merge then do SubAbility for each + // Convert above abilities to gain Drawback if (API.equals("Pump")) { @@ -607,6 +617,12 @@ public class AbilityFactory { players = new ArrayList(); if (defined.equals("Targeted")){ + Target tgt = sa.getTarget(); + if (tgt != null && tgt.getTargetPlayers().size() != 0){ + players.addAll(tgt.getTargetPlayers()); + return players; + } + SpellAbility parent; do{ parent = ((Ability_Sub)sa).getParent(); @@ -630,6 +646,12 @@ public class AbilityFactory { objects = new ArrayList(); if (defined.equals("Targeted")){ + Target tgt = sa.getTarget(); + if (tgt != null && tgt.getTargets().size() != 0){ + objects.addAll(tgt.getTargets()); + return objects; + } + SpellAbility parent; do{ parent = ((Ability_Sub)sa).getParent(); diff --git a/src/forge/AbilityFactory_ChangeZone.java b/src/forge/AbilityFactory_ChangeZone.java new file mode 100644 index 00000000000..f63bffe18bb --- /dev/null +++ b/src/forge/AbilityFactory_ChangeZone.java @@ -0,0 +1,854 @@ +package forge; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Random; + +public class AbilityFactory_ChangeZone { + + // Change Zone is going to work much differently than other AFs. + // *NOTE* Please do not use this as a base for copying and creating your own AF + + + public static SpellAbility createAbilityChangeZone(final AbilityFactory AF){ + final SpellAbility abChangeZone = new Ability_Activated(AF.getHostCard(), AF.getAbCost(), AF.getAbTgt()){ + private static final long serialVersionUID = 3728332812890211671L; + + public boolean canPlayAI(){ + return changeZoneCanPlayAI(AF, this); + } + + @Override + public void resolve() { + changeZoneResolve(AF, this); + } + + @Override + public String getStackDescription(){ + return changeZoneDescription(AF, this); + } + + }; + setMiscellaneous(AF, abChangeZone); + return abChangeZone; + } + + public static SpellAbility createSpellChangeZone(final AbilityFactory AF){ + final SpellAbility spChangeZone = new Spell(AF.getHostCard(), AF.getAbCost(), AF.getAbTgt()) { + private static final long serialVersionUID = 3270484211099902059L; + + public boolean canPlayAI(){ + return changeZoneCanPlayAI(AF, this); + } + + @Override + public void resolve() { + changeZoneResolve(AF, this); + } + + @Override + public String getStackDescription(){ + return changeZoneDescription(AF, this); + } + }; + setMiscellaneous(AF, spChangeZone); + return spChangeZone; + } + + public static SpellAbility createDrawbackChangeZone(final AbilityFactory AF){ + final SpellAbility dbChangeZone = new Ability_Sub(AF.getHostCard(), AF.getAbTgt()) { + private static final long serialVersionUID = 3270484211099902059L; + + @Override + public void resolve() { + changeZoneResolve(AF, this); + } + + @Override + public boolean chkAI_Drawback() { + return changeZonePlayDrawbackAI(AF, this); + } + + @Override + public String getStackDescription(){ + return changeZoneDescription(AF, this); + } + }; + setMiscellaneous(AF, dbChangeZone); + return dbChangeZone; + } + + private static void setMiscellaneous(AbilityFactory af, SpellAbility sa){ + // todo: if moving to or from Battlefield allow use in Main1? + HashMap params = af.getMapParams(); + if (af.getAbTgt() != null) + af.getAbTgt().setZone(params.get("Origin")); + + if (!(sa instanceof Ability_Sub)) + if (params.get("Origin").equals("Battlefield") || params.get("Destination").equals("Battlefield")) + af.getHostCard().setSVar("PlayMain1", "TRUE"); + } + + private static boolean changeZoneCanPlayAI(AbilityFactory af, SpellAbility sa){ + HashMap params = af.getMapParams(); + String origin = params.get("Origin"); + + if (origin.equals("Library") || origin.equals("Hand") || origin.equals("Sideboard")){ + return changeHiddenOriginCanPlayAI(af, sa); + } + else if (origin.equals("Graveyard") || origin.equals("Exile") || origin.equals("Battlefield")){ + return changeKnownOriginCanPlayAI(af, sa); + } + return false; + } + + private static boolean changeZonePlayDrawbackAI(AbilityFactory af, SpellAbility sa){ + HashMap params = af.getMapParams(); + String origin = params.get("Origin"); + + if (origin.equals("Library") || origin.equals("Hand") || origin.equals("Sideboard")){ + return changeHiddenOriginPlayDrawbackAI(af, sa); + } + else if (origin.equals("Graveyard") || origin.equals("Exile") || origin.equals("Battlefield")){ + return changeKnownOriginPlayDrawbackAI(af, sa); + } + return false; + } + + private static String changeZoneDescription(AbilityFactory af, SpellAbility sa){ + HashMap params = af.getMapParams(); + String origin = params.get("Origin"); + if (origin.equals("Library") || origin.equals("Hand") || origin.equals("Sideboard")){ + return changeHiddenOriginStackDescription(af, sa); + } + else if (origin.equals("Graveyard") || origin.equals("Exile") || origin.equals("Battlefield")){ + return changeKnownOriginStackDescription(af, sa); + } + + return ""; + } + + private static void changeZoneResolve(AbilityFactory af, SpellAbility sa){ + HashMap params = af.getMapParams(); + String origin = params.get("Origin"); + if (origin.equals("Library") || origin.equals("Hand") || origin.equals("Sideboard")){ + changeHiddenOriginResolve(af, sa); + } + else if (origin.equals("Graveyard") || origin.equals("Exile") || origin.equals("Battlefield")){ + changeKnownOriginResolve(af, sa); + } + } + + // ************************************************************************************* + // ************ Hidden Origin (Library/Hand/Sideboard) ********************************* + // ******* Hidden origin cards are chosen on the resolution of the spell *************** + // ************************************************************************************* + + private static boolean changeHiddenOriginCanPlayAI(AbilityFactory af, SpellAbility sa){ + // Fetching should occur fairly often as it helps cast more spells, and have access to more mana + Ability_Cost abCost = af.getAbCost(); + Card source = af.getHostCard(); + HashMap params = af.getMapParams(); + //String destination = params.get("Destination"); + String origin = params.get("Origin"); + + if (abCost != null){ + // AI currently disabled for these costs + if (abCost.getSacCost()){ + // Sac is ok in general, but should add some decision making based off what we Sacrifice and what we might get + } + if (abCost.getLifeCost()){ + if (AllZone.ComputerPlayer.getLife() - abCost.getLifeAmount() < 4) + return false; + } + if (abCost.getDiscardCost()) return false; + + if (abCost.getSubCounter()) return true; // only card that uses it is Fertilid + + } + + if (!ComputerUtil.canPayCost(sa)) + return false; + + Random r = new Random(); + // prevent run-away activations - first time will always return true + boolean chance = r.nextFloat() <= Math.pow(.6667, source.getAbilityUsed()); + + ArrayList pDefined; + Target tgt = af.getAbTgt(); + if(tgt != null && tgt.canTgtPlayer()) { + if (af.isCurse()) + tgt.addTarget(AllZone.HumanPlayer); + else + tgt.addTarget(AllZone.ComputerPlayer); + pDefined = tgt.getTargetPlayers(); + } + else{ + pDefined = AbilityFactory.getDefinedPlayers(sa.getSourceCard(), params.get("Defined"), sa); + } + + for(Player p : pDefined){ + if (origin.equals("Hand")){ + CardList hand = AllZoneUtil.getPlayerHand(p); + if (hand.size() == 0) + return false; + + if (p.isComputer()){ + if (params.containsKey("ChangeType")){ + hand = filterListByType(hand, params, "ChangeType", sa); + if (hand.size() == 0) + return false; + } + } + // TODO: add some more improvements based on Destination and Type + } + else if (origin.equals("Library")){ + CardList library = AllZoneUtil.getPlayerCardsInLibrary(p); + if (library.size() == 0) + return false; + + // TODO: add some more improvements based on Destination and Type + } + else if (origin.equals("Sideboard")){ + // todo: once sideboard is added + // canPlayAI for Wishes will go here + } + } + + Ability_Sub subAb = sa.getSubAbility(); + if (subAb != null) + chance &= subAb.chkAI_Drawback(); + + return ((r.nextFloat() < .8) && chance); + } + + private static boolean changeHiddenOriginPlayDrawbackAI(AbilityFactory af, SpellAbility sa){ + // if putting cards from hand to library and parent is drawing cards + // make sure this will actually do something: + + + return true; + } + + private static String changeHiddenOriginStackDescription(AbilityFactory af, SpellAbility sa){ + // TODO: build Stack Description will need expansion as more cards are added + HashMap params = af.getMapParams(); + + StringBuilder sb = new StringBuilder(); + Card host = af.getHostCard(); + + if (!(sa instanceof Ability_Sub)) + sb.append(host.getName()).append(" -"); + + sb.append(" "); + + String origin = params.get("Origin"); + String destination = params.get("Destination"); + + String type = params.containsKey("ChangeType") ? params.get("ChangeType") : ""; + + if (origin.equals("Library")){ + sb.append("Search your library for ").append(params.get("ChangeNum")).append(" ").append(type).append(" and "); + + sb.append("put that card "); + + if (destination.equals("Battlefield")){ + sb.append("onto the battlefield"); + if (params.containsKey("Tapped")) + sb.append(" tapped"); + + + sb.append("."); + + } + if (destination.equals("Hand")) + sb.append("into your hand."); + if (destination.equals("Graveyard")) + sb.append("into your graveyard."); + + sb.append("Then shuffle your library."); + } + else if (origin.equals("Hand")){ + + + sb.append("Put ").append(params.get("ChangeNum")).append(" ").append(type).append(" card(s) from your hand "); + + if (destination.equals("Battlefield")) + sb.append("onto the battlefield."); + if (destination.equals("Library")){ + int libraryPos = params.containsKey("LibraryPosition") ? Integer.parseInt(params.get("LibraryPosition")) : 0; + + if (libraryPos == 0) + sb.append("on top"); + if (libraryPos == -1) + sb.append("on bottom"); + + sb.append(" of your library."); + } + } + + Ability_Sub abSub = sa.getSubAbility(); + if (abSub != null) { + sb.append(abSub.getStackDescription()); + } + + return sb.toString(); + } + + private static void changeHiddenOriginResolve(AbilityFactory af, SpellAbility sa){ + HashMap params = af.getMapParams(); + + ArrayList fetchers = AbilityFactory.getDefinedPlayers(sa.getSourceCard(), params.get("Defined"), sa); + + for(Player player : fetchers){ + if (player.isComputer()){ + changeHiddenOriginResolveAI(af, sa); + } + else{ + changeHiddenOriginResolveHuman(af, sa); + } + } + } + + private static void changeHiddenOriginResolveHuman(AbilityFactory af, SpellAbility sa){ + HashMap params = af.getMapParams(); + Card card = af.getHostCard(); + Target tgt = af.getAbTgt(); + Player player; + if (tgt != null){ + player = tgt.getTargetPlayers().get(0); + if (!player.canTarget(sa.getSourceCard())) + return; + } + else{ + player = sa.getActivatingPlayer(); + } + + String origin = params.get("Origin"); + String destination = params.get("Destination"); + + CardList fetchList = AllZoneUtil.getCardsInZone(origin, player); + if (destination.equals("Library")) + AllZone.Display.getChoice(af.getHostCard().getName() + " - Looking at " + origin, fetchList.toArray()); + + fetchList = filterListByType(fetchList, params, "ChangeType", sa); + + PlayerZone origZone = AllZone.getZone(origin, player); + PlayerZone destZone = AllZone.getZone(destination, player); + + int changeNum = params.containsKey("ChangeNum") ? Integer.parseInt(params.get("ChangeNum")) : 1; + + for(int i=0; i < changeNum; i++){ + if(fetchList.size() == 0 || destination == null) + break; + + Object o = AllZone.Display.getChoiceOptional("Select a card", fetchList.toArray()); + + if(o != null) { + origZone.remove(o); + Card c = (Card) o; + fetchList.remove(c); + + if (destination.equals("Library")){ + // this needs to be zero indexed. Top = 0, Third = 2 + int libraryPos = params.containsKey("LibraryPosition") ? Integer.parseInt(params.get("LibraryPosition")) : 0; + destZone.add(c, libraryPos); + } + else{ + destZone.add(c); + if (destination.equals("Battlefield") && params.containsKey("Tapped")) + c.tap(); + } + } + } + player.shuffle(); + + String DrawBack = params.get("SubAbility"); + + if (af.hasSubAbility()){ + Ability_Sub abSub = sa.getSubAbility(); + if (abSub != null){ + abSub.resolve(); + } + else + CardFactoryUtil.doDrawBack(DrawBack, 0, card.getController(), card.getController().getOpponent(), card.getController(), card, null, sa); + } + } + + private static void changeHiddenOriginResolveAI(AbilityFactory af, SpellAbility sa){ + HashMap params = af.getMapParams(); + Target tgt = af.getAbTgt(); + Card card = af.getHostCard(); + + Player player; + if (tgt != null){ + player = tgt.getTargetPlayers().get(0); + if (!player.canTarget(sa.getSourceCard())) + return; + } + else{ + player = sa.getActivatingPlayer(); + } + + String origin = params.get("Origin"); + + CardList fetchList = AllZoneUtil.getCardsInZone(origin, player); + fetchList = filterListByType(fetchList, params, "ChangeType", sa); + + String destination = params.get("Destination"); + + PlayerZone origZone = AllZone.getZone(origin, player); + PlayerZone destZone = AllZone.getZone(destination, player); + + String type = params.get("ChangeType"); + + CardList fetched = new CardList(); + + int changeNum = params.containsKey("ChangeNum") ? Integer.parseInt(params.get("ChangeNum")) : 1; + + for(int i=0;i