It is currently 10 Sep 2025, 23:21
   
Text Size

Multizone Origin for ChangeZone

Post MTG Forge Related Programming Questions Here

Moderators: timmermac, Blacksmith, KrazyTheFox, Agetian, friarsol, CCGHQ Admins

Multizone Origin for ChangeZone

Postby moomarc » 16 Jul 2012, 17:44

I've made some changes to ChangeZone in my local copy that allows multizone Origin .Eg: Venser's Diffusion now uses this clean script:
Code: Select all
A:SP$ ChangeZone | Cost$ 2 U | ValidTgts$ Permanent.nonLand,Card.suspended | TgtPrompt$ Choose target nonland permanent or suspended card. | IsCurse$ True | Origin$ Exile,Battlefield | Destination$ Hand | SpellDescription$ Return target nonland permanent or suspended card to its owner's hand.
I need to test that I haven't messed up the AI though so can anyone recommend a quest deck where the AI uses a lot of bounce or tutoring (and preferably other ChangeZone types as well).

Otherwise here's a patch for ChangeZone.java if anyone wants to try it out:
MultiOriginPatch.txt
(59.48 KiB) Downloaded 269 times

Mostly it was just boxing the various blocks with
Code: Select all
for (ZoneType origin : originList) {
so should be fine, but I still want to test and make sure I didn't box anything incorrectly thanks to my inexperience.

Otherwise, what are some of the scenarios I should test?
-Marc
User avatar
moomarc
Pixel Commander
 
Posts: 2091
Joined: 04 Jun 2010, 15:22
Location: Johannesburg, South Africa
Has thanked: 371 times
Been thanked: 372 times

Re: Multizone Origin for ChangeZone

Postby moomarc » 16 Jul 2012, 21:31

Quick note that you need the change to Target selection I committed with Timebender for the multi origin to work for the human player. All it does is include valid targets from the battlefield in the list normally used for targeting in other zones if zones.size() >= 1.
-Marc
User avatar
moomarc
Pixel Commander
 
Posts: 2091
Joined: 04 Jun 2010, 15:22
Location: Johannesburg, South Africa
Has thanked: 371 times
Been thanked: 372 times

Re: Multizone Origin for ChangeZone

Postby friarsol » 16 Jul 2012, 22:56

moomarc wrote:Quick note that you need the change to Target selection I committed with Timebender for the multi origin to work for the human player. All it does is include valid targets from the battlefield in the list normally used for targeting in other zones if zones.size() >= 1.
Is there any way to differentiate where the card is coming from? Like how can I quickly tell if that's my card on the battlefield, or if that's my suspended card.
friarsol
Global Moderator
 
Posts: 7593
Joined: 15 May 2010, 04:20
Has thanked: 243 times
Been thanked: 965 times

Re: Multizone Origin for ChangeZone

Postby moomarc » 17 Jul 2012, 04:09

friarsol wrote:
moomarc wrote:Quick note that you need the change to Target selection I committed with Timebender for the multi origin to work for the human player. All it does is include valid targets from the battlefield in the list normally used for targeting in other zones if zones.size() >= 1.
Is there any way to differentiate where the card is coming from? Like how can I quickly tell if that's my card on the battlefield, or if that's my suspended card.
I'll have a look later but there should be a way to append the zone to each name in the choice list if there's more than one origin.
-Marc
User avatar
moomarc
Pixel Commander
 
Posts: 2091
Joined: 04 Jun 2010, 15:22
Location: Johannesburg, South Africa
Has thanked: 371 times
Been thanked: 372 times

Re: Multizone Origin for ChangeZone

Postby moomarc » 17 Jul 2012, 08:15

Haven't managed to append the card's zone yet, but I did realise that because of the way that Forge defines a Permanent, I had to add an extra restriction in IsValid for OnBattlefield (otherwise Venser's Diffusion, Timebender and the other cards from this block that I've been working on will allow you to target "Permanent cards" instead of Permanents). I'll apply the fix as soon as I've retested them all.
-Marc
User avatar
moomarc
Pixel Commander
 
Posts: 2091
Joined: 04 Jun 2010, 15:22
Location: Johannesburg, South Africa
Has thanked: 371 times
Been thanked: 372 times

Re: Multizone Origin for ChangeZone

Postby friarsol » 17 Jul 2012, 12:13

moomarc wrote:I'll have a look later but there should be a way to append the zone to each name in the choice list if there's more than one origin.
I'm not sure if we need to append the Zone to the card name (that might be too long anyway) but I wonder if the select box can have a descripter choice that isn't selectable that can list the start of a Zone. I don't know how (or if) this works in Java but in HTML it looks like this

http://www.w3schools.com/tags/tryit.asp ... l_optgroup
friarsol
Global Moderator
 
Posts: 7593
Joined: 15 May 2010, 04:20
Has thanked: 243 times
Been thanked: 965 times

Re: Multizone Origin for ChangeZone

Postby moomarc » 17 Jul 2012, 12:24

friarsol wrote:
moomarc wrote:I'll have a look later but there should be a way to append the zone to each name in the choice list if there's more than one origin.
I'm not sure if we need to append the Zone to the card name (that might be too long anyway) but I wonder if the select box can have a descripter choice that isn't selectable that can list the start of a Zone. I don't know how (or if) this works in Java but in HTML it looks like this

http://www.w3schools.com/tags/tryit.asp ... l_optgroup
I've been looking at the chooseOneOrNone GUI code (the whole GuiUtils class actually) and I'm stuggling to see how to work get anything extra in there. I think I might be able to work something out thanks to your suggestion though. Basically I need to break the arraylist passed to GuiUtils into smaller arrays per zone, then insert a dummy card in position 0, and feed those back into getChoices. Might be a bit beyond my skills but I'll give it a bash...
-Marc
User avatar
moomarc
Pixel Commander
 
Posts: 2091
Joined: 04 Jun 2010, 15:22
Location: Johannesburg, South Africa
Has thanked: 371 times
Been thanked: 372 times

Re: Multizone Origin for ChangeZone

Postby moomarc » 17 Jul 2012, 16:53

:cry: Looks like I'm not good enough for this. I tried setting it up in SpellAbility.TargetSelection and it work's for one valid target, but as soon as there's more than one valid target in a zone I get a ConcurrentModificationException error:
Code: Select all
java.util.ConcurrentModificationException
   at java.util.AbstractList$Itr.checkForComodification(Unknown Source)
   at java.util.AbstractList$Itr.next(Unknown Source)
   at forge.card.spellability.TargetSelection.chooseCardFromList(TargetSelection.java:444)
Here's the code (I've marked line 444 indicated by the error):
Code: Select all
    public final void chooseCardFromList(final CardList choices, final boolean targeted, final boolean mandatory) {
        // Send in a list of valid cards, and popup a choice box to target
        final Card dummy = new Card();
        dummy.setName("[FINISH TARGETING]");
        final SpellAbility sa = this.ability;
        final String message = this.target.getVTSelection();

        final Card divBattlefield = new Card();
        divBattlefield.setName("--CARDS ON BATTLEFIELD:--");
        final Card divExile = new Card();
        divExile.setName("--CARDS IN EXILE:--");
        final Card divGrave = new Card();
        divGrave.setName("--CARDS IN GRAVEYARD:--");
        final Card divLibrary = new Card();
        divLibrary.setName("--CARDS IN LIBRARY:--");
        final Card divStack = new Card();
        divStack.setName("--CARDS IN LIBRARY:--");

        CardList choicesZoneUnfiltered = choices;
        final CardList crdsBattle = new CardList();
        final CardList crdsExile = new CardList();
        final CardList crdsGrave = new CardList();
        final CardList crdsLibrary = new CardList();
        final CardList crdsStack = new CardList();
//ln444 for (final Card inZone : choicesZoneUnfiltered) {
            if (AllZoneUtil.getCardsIn(ZoneType.Battlefield).contains(inZone)) {
                crdsBattle.add(inZone);
                choicesZoneUnfiltered.remove(inZone);
            } else if (AllZoneUtil.getCardsIn(ZoneType.Exile).contains(inZone)) {
                crdsExile.add(inZone);
                choicesZoneUnfiltered.remove(inZone);
            } else if (AllZoneUtil.getCardsIn(ZoneType.Graveyard).contains(inZone)) {
                crdsGrave.add(inZone);
                choicesZoneUnfiltered.remove(inZone);
            } else if (AllZoneUtil.getCardsIn(ZoneType.Library).contains(inZone)) {
                crdsLibrary.add(inZone);
                choicesZoneUnfiltered.remove(inZone);
            } else if (AllZoneUtil.getCardsIn(ZoneType.Stack).contains(inZone)) {
                crdsStack.add(inZone);
                choicesZoneUnfiltered.remove(inZone);
            }
        }
        CardList choicesFiltered = new CardList();
        if (crdsBattle.size() >= 1) {
            choicesFiltered.add(divBattlefield);
            choicesFiltered.addAll(crdsBattle);
            crdsBattle.clear();
        }
        if (crdsExile.size() >= 1) {
            choicesFiltered.add(divExile);
            choicesFiltered.addAll(crdsExile);
            crdsExile.clear();
        }
        if (crdsGrave.size() >= 1) {
            choicesFiltered.add(divGrave);
            choicesFiltered.addAll(crdsGrave);
            crdsGrave.clear();
        }
        if (crdsLibrary.size() >= 1) {
            choicesFiltered.add(divLibrary);
            choicesFiltered.addAll(crdsLibrary);
            crdsLibrary.clear();
        }
        if (crdsStack.size() >= 1) {
            choicesFiltered.add(divStack);
            choicesFiltered.addAll(crdsStack);
            crdsStack.clear();
        }

        final Target tgt = this.getTgt();

        final CardList choicesWithDone = choicesFiltered;
        if (tgt.isMinTargetsChosen(sa.getSourceCard(), sa)) {
            // is there a more elegant way of doing this?
            choicesWithDone.add(dummy);
        }

        final Object check = GuiUtils.chooseOneOrNone(message, choicesWithDone.toArray());
        if (check != null) {
            final Card c = (Card) check;
            if (!c.equals(divBattlefield) && !c.equals(divExile) && !c.equals(divGrave)
                    && !c.equals(divLibrary) && !c.equals(divStack)) {
                if (c.equals(dummy)) {
                    this.setDoneTarget(true);
                } else {
                    tgt.addTarget(c);
                }
            }
        } else {
            this.setCancel(true);
        }

        this.chooseTargets();
    }
Sorry, that's the best I can manage. Hopefully one of you guys can see how to make it work. Aside from that, have the two people who downloaded the patch come across any other issues?
-Marc
User avatar
moomarc
Pixel Commander
 
Posts: 2091
Joined: 04 Jun 2010, 15:22
Location: Johannesburg, South Africa
Has thanked: 371 times
Been thanked: 372 times

Re: Multizone Origin for ChangeZone

Postby Hellfish » 17 Jul 2012, 17:13

The ConcurrentModificationException is thrown when you try to add or remove elements from a list inside of a loop that loops through the same list. Do you really need to remove the inZone card after it's been added to it's correct CardList? Or will cards occur multiple times in choicesZoneUnfiltered? If not, you'll only loop "past" each card once anyway.
So now you're
Screaming for the blood of the cookie monster
Evil puppet demon of obesity
Time to change the tune of his fearful ballad
C is for "Lettuce," that's good enough for me
User avatar
Hellfish
Programmer
 
Posts: 1297
Joined: 07 Jun 2009, 10:41
Location: South of the Pumphouse
Has thanked: 110 times
Been thanked: 169 times

Re: Multizone Origin for ChangeZone

Postby moomarc » 17 Jul 2012, 17:35

Hellfish wrote:The ConcurrentModificationException is thrown when you try to add or remove elements from a list inside of a loop that loops through the same list. Do you really need to remove the inZone card after it's been added to it's correct CardList? Or will cards occur multiple times in choicesZoneUnfiltered? If not, you'll only loop "past" each card once anyway.
I LOVE YOU! Thanks for that. Works like a dream! I'm going to commit this for now because it makes the Time Spiral cards I've added over the last day or so a bit easier to use. (Erm, apologies for the overreaction. I'm still just a designer with a newfound interest in hobby coding (thanks to Forge) so this was intense coding for me trying to track the right place to put it and work out the way to do it. So it was good to see it was just something small I missed).

Then, I'm starting another 3 week contract tomorrow so will probably have very little time for Forge. This means I won't be able to test whether the ChangeZone AI is broken anywhere because of the multi origin changes I made (the Time Spiral stuff is all just using the capabilities of TgtZone in AbilityFactory). So far I haven't come across anything strange, but I don't want to commit anything I won't be able to fix if anything comes up. Nothing has changed since I posted the ChangeZone patch in the first post, so if anyone feels it's worth adding use that patch. The only card I know of that actually uses a multizone origin is Venser's Diffusion, so here would be the updated script:
Venser's Diffusion | Open
Name:Venser's Diffusion
ManaCost:2 U
Types:Instant
Text:no text
A:SP$ ChangeZone | Cost$ 2 U | ValidTgts$ Permanent.nonLand+OnBattlefield,Card.suspended | TgtPrompt$ Choose target nonland permanent or suspended card. | IsCurse$ True | Origin$ Exile,Battlefield | Destination$ Hand | SpellDescription$ Return target nonland permanent or suspended card to its owner's hand.
SVar:Rarity:Common
SVar:Picture:http://www.wizards.com/global/images/magic/general/vensers_diffusion.jpg
SetInfo:FUT|Common|http://magiccards.info/scans/en/fut/47.jpg
Oracle:Return target nonland permanent or suspended card to its owner's hand.
End
-Marc
User avatar
moomarc
Pixel Commander
 
Posts: 2091
Joined: 04 Jun 2010, 15:22
Location: Johannesburg, South Africa
Has thanked: 371 times
Been thanked: 372 times


Return to Developer's Corner

Who is online

Users browsing this forum: No registered users and 50 guests

Main Menu

User Menu

Our Partners


Who is online

In total there are 50 users online :: 0 registered, 0 hidden and 50 guests (based on users active over the past 10 minutes)
Most users ever online was 7967 on 09 Sep 2025, 23:08

Users browsing this forum: No registered users and 50 guests

Login Form