ChangeZone - changing spell on the stack
Post MTG Forge Related Programming Questions Here
Moderators: timmermac, Blacksmith, KrazyTheFox, Agetian, friarsol, CCGHQ Admins
4 posts
• Page 1 of 1
ChangeZone - changing spell on the stack
by moomarc » 18 Apr 2012, 00:39
I've just finished making it possible to use ChangeZone targeting spells on the stack.
Everything that was needed was almost there in CounterSpells, it just needed to be tweaked and ported. I've tested with Venser, Shaper Savant (as well as some other normal changeZone cards to make sure I didn't break it) and everything seems to work. At this stage its just for the human player, but I first wanted some experienced eyes checking what I've done so far to point out any errors and pitfalls. Here's a patch for AbilityFactoryChangeZone and the script for Venser:
). The script probably needs to be tweaked slightly too because you the can currently cancel out of the triggered ability. Probably just a mandatory true flag or two needed.
EDIT: Of course it could be completely wrong and painful to trained eyes in which case feel free to tell me to just scratch the idea.

- Patch | Open
- Code: Select all
### Eclipse Workspace Patch 1.0
#P Forge
Index: src/main/java/forge/card/abilityfactory/AbilityFactoryChangeZone.java
===================================================================
--- src/main/java/forge/card/abilityfactory/AbilityFactoryChangeZone.java (revision 15148)
+++ src/main/java/forge/card/abilityfactory/AbilityFactoryChangeZone.java (working copy)
@@ -1888,6 +1888,8 @@
*/
private static void changeKnownOriginResolve(final AbilityFactory af, final SpellAbility sa) {
ArrayList<Card> tgtCards;
+ ArrayList<SpellAbility> sas;
+
final HashMap<String, String> params = af.getMapParams();
final Target tgt = sa.getTarget();
final Player player = sa.getActivatingPlayer();
@@ -1905,6 +1907,28 @@
}
}
+ // changing zones for spells on the stack
+ if (tgt != null) {
+ sas = tgt.getTargetSAs();
+ } else {
+ sas = AbilityFactory.getDefinedSpellAbilities(sa.getSourceCard(), params.get("Defined"), sa);
+ }
+
+ for (final SpellAbility tgtSA : sas) {
+ final Card tgtSACard = tgtSA.getSourceCard();
+
+ if (tgtSA.isSpell() && !CardFactoryUtil.isCounterable(tgtSACard)) {
+ continue;
+ }
+
+ final SpellAbilityStackInstance si = AllZone.getStack().getInstanceFromSpellAbility(tgtSA);
+ if (si == null) {
+ continue;
+ }
+
+ removeFromStack(tgtSA, sa, si);
+ } // End of change from stack
+
final String remember = params.get("RememberChanged");
final String imprint = params.get("Imprint");
@@ -2043,6 +2067,54 @@
return ret;
}
+ /**
+ * <p>
+ * removeFromStack.
+ * </p>
+ *
+ * @param tgtSA
+ * a {@link forge.card.spellability.SpellAbility} object.
+ * @param srcSA
+ * a {@link forge.card.spellability.SpellAbility} object.
+ * @param si
+ * a {@link forge.card.spellability.SpellAbilityStackInstance}
+ * object.
+ */
+ private static void removeFromStack(final SpellAbility tgtSA, final SpellAbility srcSA, final SpellAbilityStackInstance si) {
+ AllZone.getStack().remove(si);
+
+ final AbilityFactory af = srcSA.getAbilityFactory();
+ final HashMap<String, String> params = af.getMapParams();
+
+ if (params.containsKey("Destination")) {
+ if (tgtSA.isAbility()) {
+ // Shouldn't be able to target Abilities on the stack
+ } else if (tgtSA.isFlashBackAbility()) {
+ Singletons.getModel().getGameAction().exile(tgtSA.getSourceCard());
+ } else if (params.get("Destination").equals("Graveyard")) {
+ Singletons.getModel().getGameAction().moveToGraveyard(tgtSA.getSourceCard());
+ } else if (params.get("Destination").equals("Exile")) {
+ Singletons.getModel().getGameAction().exile(tgtSA.getSourceCard());
+ } else if (params.get("Destination").equals("TopOfLibrary")) {
+ Singletons.getModel().getGameAction().moveToLibrary(tgtSA.getSourceCard());
+ } else if (params.get("Destination").equals("Hand")) {
+ Singletons.getModel().getGameAction().moveToHand(tgtSA.getSourceCard());
+ } else if (params.get("Destination").equals("BottomOfLibrary")) {
+ Singletons.getModel().getGameAction().moveToBottomOfLibrary(tgtSA.getSourceCard());
+ } else if (params.get("Destination").equals("ShuffleIntoLibrary")) {
+ Singletons.getModel().getGameAction().moveToBottomOfLibrary(tgtSA.getSourceCard());
+ tgtSA.getSourceCard().getController().shuffle();
+ } else {
+ throw new IllegalArgumentException("AbilityFactory_ChangeZone: Invalid Destination argument for card "
+ + srcSA.getSourceCard().getName());
+ }
+
+ if (!tgtSA.isAbility()) {
+ System.out.println("Moving spell to " + params.get("Destination"));
+ }
+ }
+ }
+
// *************************************************************************************
// ************************** ChangeZoneAll
// ********************************************
- Venser, Shaper Savant | Open
- Name:Venser, Shaper Savant
ManaCost:2 U U
Types:Legendary Creature Human Wizard
Text:no text
PT:2/2
K:Flash
T:Mode$ ChangesZone | Origin$ Any | Destination$ Battlefield | ValidCard$ Card.Self | Execute$ ChooseTgtMode | TriggerDescription$ When CARDNAME enters the battlefield, return target spell or permanent to its owner's hand.
SVar:ChooseTgtMode:AB$ Charm | Cost$ 0 | Defined$ You | Choices$ BounceSpell,BouncePermanent
SVar:BounceSpell:DB$ChangeZone | TargetType$ Spell | ValidTgts$ Card | TgtZone$ Stack | Origin$ Stack | Destination$ Hand | SpellDescription$ Return target spell to its owner's hand.
SVar:BouncePermanent:DB$ChangeZone | ValidTgts$ Permanent | TgtPrompt$ Select target permanent | Origin$ Battlefield | Destination$ Hand | SpellDescription$ Return target permanent to its owner's hand.
SVar:RemAIDeck:True
SVar:Rarity:Rare
SVar:Picture:http://www.wizards.com/global/images/magic/general/venser_shaper_savant.jpg
SetInfo:FUT|Rare|http://magiccards.info/scans/en/fut/46.jpg
Oracle:Flash (You may cast this spell any time you could cast an instant.)\nWhen Venser, Shaper Savant enters the battlefield, return target spell or permanent to its owner's hand.
End

EDIT: Of course it could be completely wrong and painful to trained eyes in which case feel free to tell me to just scratch the idea.
-Marc
-
moomarc - Pixel Commander
- Posts: 2091
- Joined: 04 Jun 2010, 15:22
- Location: Johannesburg, South Africa
- Has thanked: 371 times
- Been thanked: 372 times
Re: ChangeZone - changing spell on the stack
by Sloth » 18 Apr 2012, 05:31
No objections. And don't spend too much time on the AI, i don't think Venser will ever be played better than an overpriced Man-o'-War.
-
Sloth - Programmer
- Posts: 3498
- Joined: 23 Jun 2009, 19:40
- Has thanked: 125 times
- Been thanked: 507 times
Re: ChangeZone - changing spell on the stack
by moomarc » 18 Apr 2012, 08:56
Well it does that straight out the box without adding anything to AI (maybe its for that very reason). I haven't been able to make the AI even try target a spell on the stack so I guess its all fine then. Maybe just have a final look when I commit to see if there's something that needs to be there just in case.Sloth wrote:No objections. And don't spend too much time on the AI, i don't think Venser will ever be played better than an overpriced Man-o'-War.
I'm going to try Mindbreak Trap as well seeing as its the only other card so far that I can see needs this. Maybe that card will show up some shortfalls before I commit.
-Marc
-
moomarc - Pixel Commander
- Posts: 2091
- Joined: 04 Jun 2010, 15:22
- Location: Johannesburg, South Africa
- Has thanked: 371 times
- Been thanked: 372 times
Re: ChangeZone - changing spell on the stack
by moomarc » 18 Apr 2012, 11:02
I've just committed the stuff I've done for this. Sadly I couldn't add Mindbreak Trap because there seems to be a problem with TargetsMin and TargetsMax when targeting things on the stack. I first came across this when I tried to script Double Negative.
Venser is good to go though (and I decided he's not an overcosted Man-o'-War. You pay the extra 1 for targeting permanents instead of just creatures.
) You'll only be given the option of targeting a spell on the stack if there is actually one there. Unfortunately it can still be cancelled out of when targeting a spell on the stack because of the issue I mentioned above. I figured that if the player decides to use this exploit though, they just suck
)
Venser is good to go though (and I decided he's not an overcosted Man-o'-War. You pay the extra 1 for targeting permanents instead of just creatures.


-Marc
-
moomarc - Pixel Commander
- Posts: 2091
- Joined: 04 Jun 2010, 15:22
- Location: Johannesburg, South Africa
- Has thanked: 371 times
- Been thanked: 372 times
4 posts
• Page 1 of 1
Who is online
Users browsing this forum: No registered users and 39 guests