It is currently 14 Sep 2025, 17:26
   
Text Size

Programming a card

Post MTG Forge Related Programming Questions Here

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

Re: Programming a card

Postby cyclope » 05 Oct 2009, 16:07

Thanks Zerker2000 for your help...
But is there an easiest way...
There are already cards like this in MTg : King Goblin , Champion Elf and i don't see that sort of code ...
Can anybody explain it to me ?
cyclope
 
Posts: 69
Joined: 28 Sep 2009, 18:08
Has thanked: 0 time
Been thanked: 0 time

Re: Programming a card

Postby DennisBergkamp » 05 Oct 2009, 16:51

cyclope wrote:Thanks Zerker2000 for your help...
But is there an easiest way...
There are already cards like this in MTg : King Goblin , Champion Elf and i don't see that sort of code ...
Can anybody explain it to me ?
Ahh, these cards are trickier, because they are state based effects.
They can be found in GameActionUtil.java (and stateBasedEffects.java). The way these cards are written is currently pretty ugly, but they seem to work.
GameActionUtil.java also includes cards that have upkeep effects (Howling Mine, Bitterblossom, ... ).
User avatar
DennisBergkamp
AI Programmer
 
Posts: 2602
Joined: 09 Sep 2008, 15:46
Has thanked: 0 time
Been thanked: 0 time

Re: Programming a card

Postby zerker2000 » 05 Oct 2009, 23:29

cyclope wrote:Thanks Zerker2000 for your help...
But is there an easiest way...
There are already cards like this in MTg : King Goblin , Champion Elf and i don't see that sort of code ...
Can anybody explain it to me ?
No offence intended, but:
Easier way?! I just handed the code to you in a generic form on a silver platter!
O forest, hold thy wand'ring son
Though fears assail the door.
O foliage, cloak thy ravaged one
In vestments cut for war.


--Eladamri, the Seed of Freyalise
zerker2000
Programmer
 
Posts: 569
Joined: 09 May 2009, 21:40
Location: South Pasadena, CA
Has thanked: 0 time
Been thanked: 0 time

Re: Programming a card

Postby cyclope » 06 Oct 2009, 17:17

I see no offence Zerker2000 but as i can't find the code in cardfactory.java , i thought it had an easier way ...
I was wrong and thank you all for your help you give to a guy who isn't a programmer but just a "copy and paste" coder...
cyclope
 
Posts: 69
Joined: 28 Sep 2009, 18:08
Has thanked: 0 time
Been thanked: 0 time

Re: Programming a card

Postby Chris H. » 06 Oct 2009, 17:41

cyclope wrote:I see no offence Zerker2000 but as i can't find the code in cardfactory.java , i thought it had an easier way ...
I was wrong and thank you all for your help you give to a guy who isn't a programmer but just a "copy and paste" coder...
`
I am in a similar position. I downloaded Eclipse and learned how to build the the source code. The Eclipse site has a nice tutorial that will teach you how to use the application.

The Sun site has a nice Java tutorial ... reading the tutorial is helping me to learn Java. "Copy and paste" coding and making minor modifications to the existing code helps with the learning process. 8)
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: Programming a card

Postby zerker2000 » 07 Oct 2009, 03:05

Chris H. wrote:"Copy and paste" coding and making minor modifications to the existing code helps with the learning process. 8)
Helps start the learning process more than anything :). Anyways, if you understand how inputs and stuff work in forge, and are able to distinguish between things that are coded differently (e.g. static ability "elves get +1/+1" and spell "elves get +1/+1 until EOT"") you rarely go beyond ""Copy and paste" coding and making minor modifications". Seriously, all the basics have been done already: targeting at cards and players, Activated/static/triggered abilities, any effect in magic you can think of ... it usually Is a matter of finding a card that has an effect in the right situation, copying in the code of a card(or cards) that do the right thing, and then tweaking values to squash bugs and ensure proper amounts of effect.
O forest, hold thy wand'ring son
Though fears assail the door.
O foliage, cloak thy ravaged one
In vestments cut for war.


--Eladamri, the Seed of Freyalise
zerker2000
Programmer
 
Posts: 569
Joined: 09 May 2009, 21:40
Location: South Pasadena, CA
Has thanked: 0 time
Been thanked: 0 time

Re: Programming a card

Postby cyclope » 07 Oct 2009, 16:24

In the GameAtionUtil.java , i see some code relative to the "echo" capacity...
Code: Select all
if (c.getIntrinsicKeyword().contains("Echo") && .....
Is "Echo" a keyword ? or can we programm with this code cards with "echo" ?
cyclope
 
Posts: 69
Joined: 28 Sep 2009, 18:08
Has thanked: 0 time
Been thanked: 0 time

Re: Programming a card

Postby DennisBergkamp » 07 Oct 2009, 16:26

Ah no, it's something I was experimenting with, it wouldn't do anything.
User avatar
DennisBergkamp
AI Programmer
 
Posts: 2602
Joined: 09 Sep 2008, 15:46
Has thanked: 0 time
Been thanked: 0 time

Re: Programming a card

Postby Chris H. » 07 Oct 2009, 17:37

zerker2000 wrote:Seriously, all the basics have been done already: targeting at cards and players, Activated/static/triggered abilities, any effect in magic you can think of ... it usually Is a matter of finding a card that has an effect in the right situation, copying in the code of a card(or cards) that do the right thing, and then tweaking values to squash bugs and ensure proper amounts of effect.
`
I think that Rares did a wonderful job getting the project as far along as he did with little help from other people initially. And Rob's and Dennis' additions to the project have moved us forward.

cyclope has added several cards and I am awed by what he has been able to accomplish.

I hope that he will try Eclipse and I am sure that we can answer any more questions he may have about the Eclipse application. :D
Last edited by Chris H. on 07 Oct 2009, 18:41, edited 1 time in total.
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: Programming a card

Postby cyclope » 07 Oct 2009, 18:08

Thanks Dennis but I don't know if I'm very helpfull...
I will code simple cards that aren't in cards.tx and that are similar to other existing...
here there is an another enchant: Zephid's Embrace...
I hope my code is correct:
Code: Select all
//*************** START *********** START **************************
if(cardName.equals("Zephid's Embrace"))
{
  final SpellAbility spell = new Spell(card)
  {

   public boolean canPlayAI()
    {
      CardList list = new CardList(AllZone.Computer_Play.getCards());
      list = list.getType("Creature");

      if(list.isEmpty())
       return false;

      //else
      CardListUtil.sortAttack(list);
      CardListUtil.sortFlying(list);

      for (int i=0;i<list.size();i++) {
         if (CardFactoryUtil.canTarget(card, list.get(i)))
         {
            setTargetCard(list.get(i));
            return true;
         }
      }
      return false;
    }//canPlayAI()
    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);
         System.out.println("Enchanted: " +getTargetCard());
      }
    }//resolve()
  };//SpellAbility
  card.clearSpellAbility();
  card.addSpellAbility(spell);

  Command onEnchant = new Command()
  {   

   public void execute()
      {
         if (card.isEnchanting())
         {
            Card crd = card.getEnchanting().get(0);
      crd.addSemiPermanentAttackBoost(2);
            crd.addSemiPermanentDefenseBoost(2);
            crd.addExtrinsicKeyword("Shroud");
      crd.addExtrinsicKeyword("Flying");
         }
      }//execute()
  };//Command


  Command onUnEnchant = new Command()
  {   

   public void execute()
      {
         if (card.isEnchanting())
         {
            Card crd = card.getEnchanting().get(0);
        crd.addSemiPermanentAttackBoost(-2);
            crd.addSemiPermanentDefenseBoost(-2);
            crd.removeExtrinsicKeyword("Shroud");
       crd.removeExtrinsicKeyword("Flying");
         }
     
      }//execute()
   };//Command
   
   Command onLeavesPlay = new Command()
   {


   public void execute()
      {
         if (card.isEnchanting())
         {
            Card crd = card.getEnchanting().get(0);
            card.unEnchantCard(crd);
         }
      }
   };

  card.setEnchant(onEnchant);
  card.setUnEnchant(onUnEnchant);
  card.setLeavesPlay(onLeavesPlay);

  spell.setBeforePayMana(CardFactoryUtil.input_targetCreature(spell));
}//*************** END ************ END **************************

I see many lines like
Code: Select all
 private static final long serialVersionUID = 447190529377334168L;
in cardfactory.java and in other files...
Can anybody explain me how I can generate this serialVersion UID for a card ?
cyclope
 
Posts: 69
Joined: 28 Sep 2009, 18:08
Has thanked: 0 time
Been thanked: 0 time

Re: Programming a card

Postby cyclope » 07 Oct 2009, 18:44

I try to code Silent Attendant :
Code: Select all
//*************** START *********** START **************************
    if(cardName.equals("Silent Attendant"))
    {
      final Ability_Tap ability = new Ability_Tap(card)
      {
      public void resolve()
        {
         
          AllZone.GameAction.getPlayerLife(card.getController()).addLife(1);
        }
        public boolean canPlayAI()
        {
          //computer should play ability if this creature doesn't attack
          Combat c = ComputerUtil.getAttackers();
          CardList list = new CardList(c.getAttackers());

          //could this creature attack?, if attacks, do not use ability
          return (! list.contains(card));
        }
      };//SpellAbility
      card.addSpellAbility(ability);
      ability.setDescription("tap: You gain 1 life.");
      ability.setStackDescription(card.getName() + " -  you gain 1 life.");
      ability.setBeforePayMana(new Input_NoCost_TapAbility(ability));
    }//*************** END ************ END **************************
And the enchant Hero's Resolve:
Code: Select all
//*************** START *********** START **************************
if(cardName.equals("Hero's Resolve"))
{
  final SpellAbility spell = new Spell(card)
  {

   public boolean canPlayAI()
    {
      CardList list = new CardList(AllZone.Computer_Play.getCards());
      list = list.getType("Creature");

      if(list.isEmpty())
       return false;

      //else
      CardListUtil.sortAttack(list);
      CardListUtil.sortFlying(list);

      for (int i=0;i<list.size();i++) {
         if (CardFactoryUtil.canTarget(card, list.get(i)))
         {
            setTargetCard(list.get(i));
            return true;
         }
      }
      return false;
    }//canPlayAI()
    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);
         System.out.println("Enchanted: " +getTargetCard());
      }
    }//resolve()
  };//SpellAbility
  card.clearSpellAbility();
  card.addSpellAbility(spell);

  Command onEnchant = new Command()
  {   

   public void execute()
      {
         if (card.isEnchanting())
         {
            Card crd = card.getEnchanting().get(0);
      crd.addSemiPermanentAttackBoost(1);
            crd.addSemiPermanentDefenseBoost(5);
           
         }
      }//execute()
  };//Command


  Command onUnEnchant = new Command()
  {   

   public void execute()
      {
         if (card.isEnchanting())
         {
            Card crd = card.getEnchanting().get(0);
        crd.addSemiPermanentAttackBoost(-1);
            crd.addSemiPermanentDefenseBoost(-5);
           
         }
     
      }//execute()
   };//Command
   
   Command onLeavesPlay = new Command()
   {


   public void execute()
      {
         if (card.isEnchanting())
         {
            Card crd = card.getEnchanting().get(0);
            card.unEnchantCard(crd);
         }
      }
   };

  card.setEnchant(onEnchant);
  card.setUnEnchant(onUnEnchant);
  card.setLeavesPlay(onLeavesPlay);

  spell.setBeforePayMana(CardFactoryUtil.input_targetCreature(spell));
}//*************** END ************ END **************************
If you see errors , rep me...
Last edited by cyclope on 07 Oct 2009, 19:10, edited 2 times in total.
cyclope
 
Posts: 69
Joined: 28 Sep 2009, 18:08
Has thanked: 0 time
Been thanked: 0 time

Re: Programming a card

Postby Chris H. » 07 Oct 2009, 18:49

cyclope wrote:I see many lines like
Code: Select all
 private static final long serialVersionUID = 447190529377334168L;
in cardfactory.java and in other files...
Can anybody explain me how I can generate this serialVersion UID for a card ?
`
The serialVersion UID for a card are created in Eclipse. Dennis can have his copy of Eclipse create the serialVersion UID for a card when he adds your code submissions.

If and when you become familiar with the Eclipse package we can teach you how to create them from within Eclipse. :)
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: Programming a card

Postby cyclope » 07 Oct 2009, 19:07

Thanks Chris...

I wonder if this code for Whispersilk Cloak is good:
Code: Select all
//*************** START *********** START **************************
    if (cardName.equals("Whispersilk Cloak"))
    {
       final Ability equip = new Ability(card, "2")
       {
          public void resolve()
          {
             if (AllZone.GameAction.isCardInPlay(getTargetCard()) && CardFactoryUtil.canTarget(card, getTargetCard()) )
             {
                if (card.isEquipping())
                {
                   Card crd = card.getEquipping().get(0);
                   if (crd.equals(getTargetCard()) )
                      return;
                   
                   card.unEquipCard(crd);
                }   
                card.equipCard(getTargetCard());
             }
          }
          
          public boolean canPlay()
          {
             return AllZone.getZone(card).is(Constant.Zone.Play) &&           
                      AllZone.Phase.getActivePlayer().equals(card.getController()) &&
                      (AllZone.Phase.getPhase().equals("Main1") || AllZone.Phase.getPhase().equals("Main2") );
          }
          
          public boolean canPlayAI()
            {
              return getCreature().size() != 0 && !card.isEquipping();
            }
         
          
          public void chooseTargetAI()
            {
              Card target = CardFactoryUtil.AI_getBestCreature(getCreature());
              setTargetCard(target);
            }
            CardList getCreature()
            {
              CardList list = new CardList(AllZone.Computer_Play.getCards());
              list = list.filter(new CardListFilter()
              {
                public boolean addCard(Card c)
                {
                  return c.isCreature() && (!CardFactoryUtil.AI_doesCreatureAttack(c)) && CardFactoryUtil.canTarget(card, c) &&
                         (! c.getKeyword().contains("Defender"));
                }
              });
              // list.remove(card);      // if mana-only cost, allow self-target
              return list;
            }//getCreature()
          
       };//equip ability
       

       Command onEquip = new Command()
       {   

         

         public void execute()
           {
            if (card.isEquipping())
             {
                Card crd = card.getEquipping().get(0);
                crd.addExtrinsicKeyword("Unblockable");
                crd.addExtrinsicKeyword("Shroud");
                
             } 
           }//execute()
       };//Command
      

       Command onUnEquip = new Command()
       {   

         

         public void execute()
           {
            if (card.isEquipping())
             {
                Card crd = card.getEquipping().get(0);
                crd.removeExtrinsicKeyword("Unblockable");
                crd.removeExtrinsicKeyword("Shroud");
                
                   
             }
            
           }//execute()
       };//Command
      
       
       Input runtime = new Input()
       {
         

         public void showMessage()
             {
               //get all creatures you control
               CardList list = new CardList();
               list.addAll(AllZone.Human_Play.getCards());
               list = list.getType("Creature");
              
               stopSetNext(CardFactoryUtil.input_targetSpecific(equip, list, "Select target creature to equip", true));
             }
        };//Input
      
       equip.setBeforePayMana(runtime);
       
       equip.setDescription("Equip: 2");
       card.addSpellAbility(equip);
       
       card.setEquip(onEquip);
       card.setUnEquip(onUnEquip);

    } //*************** END ************ END **************************
cyclope
 
Posts: 69
Joined: 28 Sep 2009, 18:08
Has thanked: 0 time
Been thanked: 0 time

Re: Programming a card

Postby DennisBergkamp » 07 Oct 2009, 19:07

Thanks Dennis but I don't know if I'm very helpfull...
I will code simple cards that aren't in cards.tx and that are similar to other existing...
here there is an another enchant: Zephid's Embrace...
I hope my code is correct:
You're definitely being helpful! Every card (however simple) is a welcome addition.
Especially the Auras you've been posting, we don't have that many of them in the game (yet), because it's something that was added fairly recently.

And yes exactly, those serialVersionIDs get generated by Eclipse.
User avatar
DennisBergkamp
AI Programmer
 
Posts: 2602
Joined: 09 Sep 2008, 15:46
Has thanked: 0 time
Been thanked: 0 time

Re: Programming a card

Postby cyclope » 09 Oct 2009, 15:50

Thanks Dennis...
Here is a Zendikar aura Nimbus Wings:
Code: Select all
//*************** START *********** START **************************
if(cardName.equals("Nimbus Wings"))
{
  final SpellAbility spell = new Spell(card)
  {

   public boolean canPlayAI()
    {
      CardList list = new CardList(AllZone.Computer_Play.getCards());
      list = list.getType("Creature");

      if(list.isEmpty())
       return false;

      //else
      CardListUtil.sortAttack(list);
      CardListUtil.sortFlying(list);

      for (int i=0;i<list.size();i++) {
         if (CardFactoryUtil.canTarget(card, list.get(i)))
         {
            setTargetCard(list.get(i));
            return true;
         }
      }
      return false;
    }//canPlayAI()
    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);
         System.out.println("Enchanted: " +getTargetCard());
      }
    }//resolve()
  };//SpellAbility
  card.clearSpellAbility();
  card.addSpellAbility(spell);

  Command onEnchant = new Command()
  {   

   public void execute()
      {
         if (card.isEnchanting())
         {
            Card crd = card.getEnchanting().get(0);
      crd.addSemiPermanentAttackBoost(1);
            crd.addSemiPermanentDefenseBoost(2);
           
      crd.addExtrinsicKeyword("Flying");
         }
      }//execute()
  };//Command


  Command onUnEnchant = new Command()
  {   

   public void execute()
      {
         if (card.isEnchanting())
         {
            Card crd = card.getEnchanting().get(0);
        crd.addSemiPermanentAttackBoost(-1);
            crd.addSemiPermanentDefenseBoost(-2);
           
       crd.removeExtrinsicKeyword("Flying");
         }
     
      }//execute()
   };//Command
   
   Command onLeavesPlay = new Command()
   {


   public void execute()
      {
         if (card.isEnchanting())
         {
            Card crd = card.getEnchanting().get(0);
            card.unEnchantCard(crd);
         }
      }
   };

  card.setEnchant(onEnchant);
  card.setUnEnchant(onUnEnchant);
  card.setLeavesPlay(onLeavesPlay);

  spell.setBeforePayMana(CardFactoryUtil.input_targetCreature(spell));
}//*************** END ************ END **************************
and i'm wondering if this should work for Paralysing Grasp:
Code: Select all
//*************** START *********** START **************************
if(cardName.equals("Paralysing Grasp"))
{
  final SpellAbility spell = new Spell(card)
  {

   public boolean canPlayAI()
    {
      CardList list = new CardList(AllZone.Computer_Play.getCards());
      list = list.getType("Creature");

      if(list.isEmpty())
       return false;

      //else
      CardListUtil.sortAttack(list);
      CardListUtil.sortFlying(list);

      for (int i=0;i<list.size();i++) {
         if (CardFactoryUtil.canTarget(card, list.get(i)))
         {
            setTargetCard(list.get(i));
            return true;
         }
      }
      return false;
    }//canPlayAI()
    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);
         System.out.println("Enchanted: " +getTargetCard());
      }
    }//resolve()
  };//SpellAbility
  card.clearSpellAbility();
  card.addSpellAbility(spell);

  Command onEnchant = new Command()
  {   

   public void execute()
      {
         if (card.isEnchanting())
         {
            Card crd = card.getEnchanting().get(0);
         crd.addExtrinsicKeyword("This card does not untap during your untap phase");
         }
      }//execute()
  };//Command


  Command onUnEnchant = new Command()
  {   

   public void execute()
      {
         if (card.isEnchanting())
         {
            Card crd = card.getEnchanting().get(0);
                   
       crd.removeExtrinsicKeyword("This card does not untap during your untap phase");
         }
     
      }//execute()
   };//Command
   
   Command onLeavesPlay = new Command()
   {


   public void execute()
      {
         if (card.isEnchanting())
         {
            Card crd = card.getEnchanting().get(0);
            card.unEnchantCard(crd);
         }
      }
   };

  card.setEnchant(onEnchant);
  card.setUnEnchant(onUnEnchant);
  card.setLeavesPlay(onLeavesPlay);

  spell.setBeforePayMana(CardFactoryUtil.input_targetCreature(spell));
}//*************** END ************ END **************************

cyclope
 
Posts: 69
Joined: 28 Sep 2009, 18:08
Has thanked: 0 time
Been thanked: 0 time

PreviousNext

Return to Developer's Corner

Who is online

Users browsing this forum: No registered users and 91 guests

Main Menu

User Menu

Our Partners


Who is online

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

Login Form