It is currently 10 Sep 2025, 18:09
   
Text Size

generic code for aura?

Post MTG Forge Related Programming Questions Here

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

generic code for aura?

Postby slapshot5 » 03 May 2010, 17:11

Hi all,

I've dabbled in auras a bit, but not enough to have added one. Last night, I took a crack at Blight.

I thought this might be as easy as putting this in cards.txt:
Code: Select all
Blight
B B
Enchantment Aura
When enchanted land becomes tapped, destroy it.
Enchant land
then, adding a bit of code to handle the destroy in GameActionUtil.executeTapSideEffects()

But, alas, it was not. It just cast like a spell and did nothing. I can't see what this "Enchant land" keyword does. I thought (if I was lucky), that would be enough to handle basic targeting for the aura, and the drawing of the aura behind the land on the battlefield.

Is there a simple bit of code I need to add to make this work easily? Or, what, generally, would be required to add generic code to the aura system to handle this? I was going off Cursed Land for an example, since that works nicely. :)

-slapshot5
slapshot5
Programmer
 
Posts: 1391
Joined: 03 Jan 2010, 17:47
Location: Mac OS X
Has thanked: 25 times
Been thanked: 68 times

Re: generic code for aura?

Postby DennisBergkamp » 03 May 2010, 17:23

It really doesn't do anything. I can't remember the exact details, but I think the keyword "Enchant creature" does stuff, so I decided for "Enchant land" to just use the keyword spot as well. We could generalize it though, and create the necessary Input for anything that has "Enchant land"... there would also be the "Enchant land you control" case though.

Anyway, for Blight just add same Input that's used for Cursed Land (found in CardFactory_Auras.java), and of course the enchant and unEnchant Commands.
User avatar
DennisBergkamp
AI Programmer
 
Posts: 2602
Joined: 09 Sep 2008, 15:46
Has thanked: 0 time
Been thanked: 0 time

Re: generic code for aura?

Postby Chris H. » 03 May 2010, 17:52

DennisBergkamp wrote:Anyway, for Blight just add same Input that's used for Cursed Land (found in CardFactory_Auras.java), and of course the enchant and unEnchant Commands.
`
If you look in CardFactory_Auras.java you will find this code block for Cursed Land:

Code: Select all
        //*************** START *********** START **************************
        else if(cardName.equals("Cursed Land")) {
           
            final SpellAbility spell = new Spell(card) {
               
                private static final long serialVersionUID = 5394181222737344498L;
               
                @Override
                public boolean canPlayAI() {
                    CardList list = new CardList(AllZone.Human_Play.getCards());
                    list = list.getType("Land");
                   
                    if(list.isEmpty()) return false;
                   
                    setTargetCard(list.get(0));
                    return true;
                }//canPlayAI()
               
                @Override
                public void resolve() {
                    PlayerZone play = AllZone.getZone(Constant.Zone.Play, card.getController());
                    play.add(card);
                   
                    Card c = getTargetCard();
                   
                    if(AllZone.GameAction.isCardInPlay(c) && CardFactoryUtil.canTarget(card, c)) card.enchantCard(c);
                   
                }//resolve()
            };//SpellAbility
            card.clearSpellAbility();
            card.addSpellAbility(spell);
           
            Command onLeavesPlay = new Command() {
               
                private static final long serialVersionUID = 1395122135234314967L;
               
                public void execute() {
                    if(card.isEnchanting()) {
                        Card crd = card.getEnchanting().get(0);
                        card.unEnchantCard(crd);
                    }
                }
            };
            card.addLeavesPlayCommand(onLeavesPlay);
           
            Input runtime = new Input() {
               
                private static final long serialVersionUID = -6237279587146079880L;
               
                @Override
                public void showMessage() {
                    PlayerZone comp = AllZone.getZone(Constant.Zone.Play, Constant.Player.Computer);
                    PlayerZone hum = AllZone.getZone(Constant.Zone.Play, Constant.Player.Human);
                    CardList land = new CardList();
                    land.addAll(comp.getCards());
                    land.addAll(hum.getCards());
                    land = land.filter(new CardListFilter() {
                        public boolean addCard(Card c) {
                            return c.isLand();
                        }
                    });
                   
                    stopSetNext(CardFactoryUtil.input_targetSpecific(spell, land, "Select target land", true,
                            false));
                }
            };
            spell.setBeforePayMana(runtime);
        }//*************** END ************ END **************************
`
You can use this as a template and make a few adjustments to get it to work for your aura. :)
User avatar
Chris H.
Forge Moderator
 
Posts: 6320
Joined: 04 Nov 2008, 12:11
Location: Mac OS X Yosemite
Has thanked: 644 times
Been thanked: 643 times

Re: generic code for aura?

Postby DennisBergkamp » 03 May 2010, 18:15

Yep, exactly.
User avatar
DennisBergkamp
AI Programmer
 
Posts: 2602
Joined: 09 Sep 2008, 15:46
Has thanked: 0 time
Been thanked: 0 time

Re: generic code for aura?

Postby slapshot5 » 03 May 2010, 18:18

Yeah, I saw all that code for Cursed Land, but I was looking for an easier, softer way. :)

Maybe the plan for tonight is to look at the Enchant craeture stuff and see if I can come up with a basic framework for Enchant land.

Thanks guys.

-slapshot5
slapshot5
Programmer
 
Posts: 1391
Joined: 03 Jan 2010, 17:47
Location: Mac OS X
Has thanked: 25 times
Been thanked: 68 times

Re: generic code for aura?

Postby slapshot5 » 04 May 2010, 04:26

Ok, I've got generic code for auras working (I think.)

I'll post here for feedback rather than integrating at this point.

This code goes at the end of the if-else if block in CardFactory_Auras.java (but before the "Control Magic" code Chris<?> just added:

Code: Select all
///////////////////////////////////////////////////////////////////
        ////
        //// CAUTION: Keep this last in the if else if block for cardnames
        ////
        ///////////////////////////////////////////////////////////////////
       
        ////////////////////DRF test generic aura
        //*************** START *********** START **************************
        else if(isAuraType(card, "Land") || isAuraType(card, "Creature") ||
              isAuraType(card, "Artifact") || isAuraType(card, "Enchantment")) {
           
           System.out.println("In generic Aura code block");
           final String type = getAuraType(card);
           final boolean curse = isCurseAura(card);
           if("" == type) {
              System.out.println("Problem in generic Aura code - type is null");
           }
           final SpellAbility spell = new Spell(card) {
            private static final long serialVersionUID = 4191777361540717307L;

            @Override
              public boolean canPlayAI() {
               String player;
               if(curse) {
                  player = Constant.Player.Human;
               }
               else {
                  player = Constant.Player.Computer;
               }
                 CardList list = AllZoneUtil.getPlayerTypeInPlay(player, type);

                 if(list.isEmpty()) return false;
                 
                 //TODO - maybe do something intelligent here if it's not a curse, like
                 //checking the aura magnet list
                 setTargetCard(list.get(0));
                 return true;
              }//canPlayAI()

              @Override
              public void resolve() {
                 PlayerZone play = AllZone.getZone(Constant.Zone.Play, card.getController());
                    play.add(card);
                   
                    Card c = getTargetCard();
                    if(AllZone.GameAction.isCardInPlay(c) && CardFactoryUtil.canTarget(card, c)) card.enchantCard(c);                 
              }//resolve()
           };//SpellAbility
           card.clearSpellAbility();
           card.addSpellAbility(spell);
           card.addLeavesPlayCommand(unenchant);

           Input runtime = new Input() {
            private static final long serialVersionUID = -7100800261954421849L;

            @Override
              public void showMessage() {
                 CardList land = AllZoneUtil.getTypeInPlay(type);
                 stopSetNext(CardFactoryUtil.input_targetSpecific(spell, land,
                       "Select target "+type.toLowerCase(), true, false));
              }
           };
           spell.setBeforePayMana(runtime);
        }//*************** END ************ END **************************
       
        ///////////////////////////////////////////////////////////////////
        ////
        //// CAUTION: Keep the above code block last in the if else if block
        ////
        ///////////////////////////////////////////////////////////////////
        ////////////////////DRF test generic aura
It would need to stay at the end of that block if/when more auras are added.

It uses a couple of helper functions:

Code: Select all
private static boolean isAuraType(final Card aura, final String type) {
       System.out.println("isAuraType - checking - "+aura.getName());
       ArrayList<String> keywords = aura.getKeyword();
       for(String keyword:keywords) {
          System.out.println("Got keyword: "+keyword);
          if(keyword.startsWith("Enchant "+type)) {
             System.out.println("Ending isAuraType with true");
             return true;
          }
       }
       System.out.println("Ending isAuraType with false");
       return false;
    }
   
    private static String getAuraType(final Card aura) {
       ArrayList<String> keywords = aura.getKeyword();
       for(String keyword:keywords) {
          if(keyword.startsWith("Enchant ")) {
             StringTokenizer st = new StringTokenizer(keyword);
             st.nextToken(); //this should be "Enchant"
             return st.nextToken();  //should be "land", "artifact", etc
          }
       }
       return "";
    }
   
    private static boolean isCurseAura(final Card aura) {
       ArrayList<String> keywords = aura.getKeyword();
       for(String keyword:keywords) {
          if(keyword.startsWith("Enchant ")) {
             if(keyword.endsWith("Curse")) return true;
          }
       }
       return false;
    }
It will accept keywords of the form:
Code: Select all
Enchant <type> [Curse]
Enchant - all will have this
<type> - currently [Artifact, Creature, Land, Enchantment]
[Curse] - if this word is present, AI will target human's permanents.

This allows for Blight to be implemented as:

Code: Select all
Blight
B B
Enchantment Aura
When enchanted land becomes tapped, destroy it.
Enchant Land Curse
And all you have to do it add the appropriate resolution code to GameActionUtil.executeTapSideEffects():

Code: Select all
if(c.isEnchantedBy("Blight")) {
         final ArrayList<Card> blights = c.getEnchantedBy();
         final Card target = c;
         for(Card blight:blights) {
            if(blight.getName().equals("Blight")) {
               Ability ability = new Ability(blight, "0") {
                  @Override
                  public void resolve() {
                     AllZone.GameAction.destroy(target);
                  }
               };//Ability
               ability.setStackDescription(blight.getName()+" - Destroy enchanted land.");
               AllZone.Stack.add(ability);
            }
         }
      }//end Blight


Does this seem reasonable to people?

Since we just put out the third beta since the last release, I'm going to assume an upcoming release will happen soon. If so, I will hold off on integrating until after the release to allow for maximum testing.

A couple notes:
1) I did test Control Magic, and it still works after this change
2) I've partially gone through an alphabetical list of auras, and this should enable:

Code: Select all
Blight - Enchant Land Curse
Backfire - Enchant Creature Curse
Baneswap Affliction - Enchant Creature Curse
Binding Agony - Enchant Creature Curse
Contaminated Bond - Enchant Creature Curse
Curiosity - Enchant Creature
Curse Artifact - Enchant Artifact Curse
Curse of Chains - Enchant Creature Curse
Cursed Land - everything should be there already, just update cards.txt
Druid's Call
Emblem of the War-Mind
Extra Arms
Farmstead - Enchant Land
Fatal Mutation
Feedback - Enchant Enchantment Curse
...
to be implemented without having to worry about the specific aura code.

I can post a patch if code changes aren't clear.

-slapshot5

PS - Obviously this can be extended for YouControl vs. OpponentControls (Betrayal, et. al.), all permanents (Elemental Resonance, etc.), specific land types (Corrupted Roots, etc.), etc...
slapshot5
Programmer
 
Posts: 1391
Joined: 03 Jan 2010, 17:47
Location: Mac OS X
Has thanked: 25 times
Been thanked: 68 times

Re: generic code for aura?

Postby DennisBergkamp » 04 May 2010, 04:38

I think this looks good, and as long as it works and doesn't break anything else, why not ?
User avatar
DennisBergkamp
AI Programmer
 
Posts: 2602
Joined: 09 Sep 2008, 15:46
Has thanked: 0 time
Been thanked: 0 time

Re: generic code for aura?

Postby slapshot5 » 04 May 2010, 05:25

I had three different replies typed, but I'll go with this one:

I'll go ahead and commit this tomorrow. We can always back out, or comment out the one big if-else clause to disable the changes if they are too problematic for an impending release.

-slapshot5
slapshot5
Programmer
 
Posts: 1391
Joined: 03 Jan 2010, 17:47
Location: Mac OS X
Has thanked: 25 times
Been thanked: 68 times

Re: generic code for aura?

Postby DennisBergkamp » 04 May 2010, 06:15

Yes, exactly :)
User avatar
DennisBergkamp
AI Programmer
 
Posts: 2602
Joined: 09 Sep 2008, 15:46
Has thanked: 0 time
Been thanked: 0 time

Re: generic code for aura?

Postby Chris H. » 04 May 2010, 11:07

I just woke up and am on my first cup of coffee. This looks interesting. I agree with Dennis, might as well merge it and we will see how well it works out. :D
User avatar
Chris H.
Forge Moderator
 
Posts: 6320
Joined: 04 Nov 2008, 12:11
Location: Mac OS X Yosemite
Has thanked: 644 times
Been thanked: 643 times

Re: generic code for aura?

Postby slapshot5 » 04 May 2010, 13:03

Ok. I've committed this, and Blight, which is the only card that uses it right now. I have a couple more almost ready to go. I'll add a couple more throughout the day to execerise a bit more of this code.

Help regression testing other auras would be appreciated. :)

One drawback right now is the AI targeting code is dumb. Always targets list.get(0). Chris, I think you added better targeting code for the AI for auras somewhere, right? I just don't remember where. Feel free to add that targeting to the new code.

Let me know how it's working for you.

-slapshot5
slapshot5
Programmer
 
Posts: 1391
Joined: 03 Jan 2010, 17:47
Location: Mac OS X
Has thanked: 25 times
Been thanked: 68 times

Re: generic code for aura?

Postby Chris H. » 04 May 2010, 13:58

slapshot5 wrote:Ok. I've committed this, and Blight, which is the only card that uses it right now. I have a couple more almost ready to go. I'll add a couple more throughout the day to execerise a bit more of this code.

Help regression testing other auras would be appreciated. :)

One drawback right now is the AI targeting code is dumb. Always targets list.get(0). Chris, I think you added better targeting code for the AI for auras somewhere, right? I just don't remember where. Feel free to add that targeting to the new code.

Let me know how it's working for you.

-slapshot5
`
My memory is not what it used to be. :( But, yeah, I was designing an AI deck which uses Squirrel Nest and the AI was placing all of it's Squirrel Nest auras on the same land, via the "list.get(0)".

Here is the new and improved canPlayAI() from the above aura:

Code: Select all
                public boolean canPlayAI() {
                   
                   CardList list = new CardList(AllZone.Computer_Play.getCards());
                   list = list.filter(new CardListFilter() {
                       public boolean addCard(Card c) {
                           return c.isLand() && !c.isEnchanted() && CardFactoryUtil.canTarget(card, c);
                       }
                   });
                   
                    if (list.isEmpty()) return false;
                    else {
                       list.shuffle();
                        setTargetCard(list.get(0));
                        return true;
                    }
                }//canPlayAI()
`
This code makes a list of lands that do not yet have an aura attached and then sorts the land list. Feel free to use it, I'm glad that I could contribute something to help the code base.

We also need something similar for the AI to target it's own lands when it has a good aura. I have thought about this as the enManLand keyword would need a system where it would play the enchant on the last land in the list rather than the first. I assume that the computer when it spends mana is working through a list of lands. It starts with the first elements (lands that went into play) and then works it's way to the last lands to be played. :-k
User avatar
Chris H.
Forge Moderator
 
Posts: 6320
Joined: 04 Nov 2008, 12:11
Location: Mac OS X Yosemite
Has thanked: 644 times
Been thanked: 643 times

Re: generic code for aura?

Postby slapshot5 » 05 May 2010, 02:39

Well, this idea sure opened up a can of worms. The system works, but:

1) auras don't draw on Enchantments and Artifacts
1a) ok, that just requires some changes to GuiDisplayUtil.java

-artifacts
--what about Moxen?
--what about Equipment?

-enchantments
--no big deal, but!
--auras can also be the target of auras (think Feedback...)

So, if you have an artifact creature that is enchanted with an aura and equipped, and the equipment has an aura and the aura has an aura and the first aura has an aura...

This gets ugly in a hurry. The linking and effects all work from what I can tell, which is the important part, but the drawing goes south in a hurry.

Anyone familiar with this code want to take a crack? Someone good with recursion can probably do this in a few lines. :)

I'm inclined to just handle the basic cases for now.

-slapshot5
slapshot5
Programmer
 
Posts: 1391
Joined: 03 Jan 2010, 17:47
Location: Mac OS X
Has thanked: 25 times
Been thanked: 68 times

Re: generic code for aura?

Postby Chris H. » 05 May 2010, 03:16

slapshot5 wrote:Well, this idea sure opened up a can of worms. The system works, but:

1) auras don't draw on Enchantments and Artifacts
1a) ok, that just requires some changes to GuiDisplayUtil.java

-artifacts
--what about Moxen?
--what about Equipment?

-enchantments
--no big deal, but!
--auras can also be the target of auras (think Feedback...)

So, if you have an artifact creature that is enchanted with an aura and equipped, and the equipment has an aura and the aura has an aura and the first aura has an aura...

This gets ugly in a hurry. The linking and effects all work from what I can tell, which is the important part, but the drawing goes south in a hurry.

Anyone familiar with this code want to take a crack? Someone good with recursion can probably do this in a few lines. :)

I'm inclined to just handle the basic cases for now.

-slapshot5
`
Hmm, I just put together a test deck with several Animate Artifact auras and several artifacts including an equipment. I animated the equip and the other artifacts OK, bu when I then tried to equip the animated equipment onto another animated artifact ... Forge became confused.

At one point the equip had two separate images. :wink:
User avatar
Chris H.
Forge Moderator
 
Posts: 6320
Joined: 04 Nov 2008, 12:11
Location: Mac OS X Yosemite
Has thanked: 644 times
Been thanked: 643 times

Re: generic code for aura?

Postby MageKing17 » 05 May 2010, 04:15

Chris H. wrote:Hmm, I just put together a test deck with several Animate Artifact auras and several artifacts including an equipment. I animated the equip and the other artifacts OK, bu when I then tried to equip the animated equipment onto another animated artifact ... Forge became confused.

At one point the equip had two separate images. :wink:
Remember that rule 301.5c states, "An Equipment that's also a creature can't equip a creature."

Some time ago, we worked out a simple visual system for keeping what was attached to what straight in our heads. As far as I know, this was never actually added to the Incantus UI, but it's still on the to-do list.
Code: Select all
    +------+
    |Card C|
+------+   |
|Card ?|   |
| +------+ |
| |Card i|-+
| | +------+
+-| |Card B|
  | +------+
  +-|Card A|
    | +------+
    | |Card 1|
    | |      |
    +-|      |
      |      |
      +------+
Apologies for the bad ASCII art... hopefully you can see that cards A, B, and C are attacked to card 1, and card i is attached to card B, and card ? (I ran out of identification schemes) is attached to card i. Think of it as... indentation for attachment layers.
User avatar
MageKing17
Programmer
 
Posts: 473
Joined: 12 Jun 2008, 20:40
Has thanked: 5 times
Been thanked: 9 times

Next

Return to Developer's Corner

Who is online

Users browsing this forum: No registered users and 49 guests

Main Menu

User Menu

Our Partners


Who is online

In total there are 49 users online :: 0 registered, 0 hidden and 49 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 49 guests

Login Form