It is currently 12 Sep 2025, 12:22
   
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 Triadasoul » 29 Nov 2009, 10:30

Looking at Treetop village i decided to rewrite it's code for other living lands that aren't implemented yet.

1. Should i add "c.setManaCost("R")" string to give a colour to creatures ?
2. Should i change serialVersionUID?

If the code is right, i'll write it for other living lands.

Ghitu Encampment

Code: Select all
Cardfactory_Lands.java
  else if(cardName.equals("Ghitu Encampment"))
       {
         card.addComesIntoPlayCommand(new Command()
         {
         private static final long serialVersionUID = -2246560994818997231L;

         public void execute()
           {
             card.tap();
           }
         });

         final Command eot1 = new Command()
         {
         private static final long serialVersionUID = -8535770979347971863L;

         public void execute()
           {
             Card c = card;

             c.setBaseAttack(0);
             c.setBaseDefense(0);
             c.removeType("Creature");
             c.removeType("Warrior");
             c.removeIntrinsicKeyword("First Strike");
           }
         };

         final SpellAbility a1 = new Ability(card, "1 R")
         {
           public boolean canPlayAI()
           {
             return ! card.getType().contains("Creature");
           }
           public void resolve()
           {
             Card c = card;

             c.setBaseAttack(2);
             c.setBaseDefense(1);

             //to prevent like duplication like "Creature Creature"
             if(! c.getIntrinsicKeyword().contains("First Strike"))
             {
               c.addType("Creature");
               c.addType("Warrior");
               c.addIntrinsicKeyword("First Strike");
             }
             AllZone.EndOfTurn.addUntil(eot1);
           }
         };//SpellAbility

         card.clearSpellKeepManaAbility();
         card.addSpellAbility(a1);
         a1.setStackDescription(card +" becomes a 2/1 creature with first strike until EOT");

         Command paid1 = new Command() {
         private static final long serialVersionUID = -6800983290478844750L;

         public void execute() {AllZone.Stack.add(a1);}
        };

         a1.setBeforePayMana(new Input_PayManaCost_Ability(a1.getManaCost(), paid1));

================================================================================================
cards.txt:

Ghitu Encampment
R
Land
Ghitu Encampment comes into play tapped.  1R: Ghitu Encampment becomes a 2/1 red Warrior creature with first strike until end of turn. It's still a land.
tap: add R
=================================================================================================
cards_pictures.txt:

ghitu_encampment.jpg http://gatherer.wizards.com/Handlers/Image.ashx?multiverseid=106564
Triadasoul
 
Posts: 223
Joined: 21 Jun 2008, 20:17
Has thanked: 0 time
Been thanked: 4 times

Re: Programming a card

Postby zerker2000 » 30 Nov 2009, 03:46

1. No, you should add a "Ghitu Encampment is red." keyword.
2. Probably, just change a random digit or something.
Notes about code:
a) Comes into play tapped is a keyword, so there is no need to code it in CardFactory.
b) The duplication code should check for each of Creature, Warrior, and fStrike separately, as first strike can be lost as an effect of an ability. Also, I think addType checks for duplicity anyways, and if not that should probable be fixed in addType instead of in each card using it.
c)The whole paid1 mess is redundant, since if it is left out, you will still pay the mana and play the ability as usual.
Also, aren't gatherer pictures to be avoided due to quality concerns?
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 Triadasoul » 30 Nov 2009, 06:19

zerker2000 wrote:1. No, you should add a "Ghitu Encampment is red." keyword.
But it becomes red after activating the ability so i don't know how to use it as a keyword for now %)

zerker2000 wrote:Notes about code:
b) The duplication code should check for each of Creature, Warrior, and fStrike separately, as first strike can be lost as an effect of an ability. Also, I think addType checks for duplicity anyways, and if not that should probable be fixed in addType instead of in each card using it.
So should i use this code for that :
if(! c.getIntrinsicKeyword().contains("First Strike")) || ! c.gettype().contains("Warrior") || ! с.gettype().contains("Creature")) ?

zerker2000 wrote:c)The whole paid1 mess is redundant, since if it is left out, you will still pay the mana and play the ability as usual.
Also, aren't gatherer pictures to be avoided due to quality concerns?
I didn't understand about paid1, should i remove it at all ?
What picture database should i use then?

Thank you for your feedback. And what about previously posted Captain of the Watch?
Triadasoul
 
Posts: 223
Joined: 21 Jun 2008, 20:17
Has thanked: 0 time
Been thanked: 4 times

Re: Programming a card

Postby DennisBergkamp » 30 Nov 2009, 07:04

Actually, I think the first strike is fine, since it does addInstrinsicKeyword...
Captain of the Watch looks good, it *should* work, I'll add it into the code and test it...

Hi, i wanted to contribute, but i am a complete beginner in java, so i took some parts of the code and try to edit-compile them to suit Captain of the Watch needs :). I have several noob questions about this process:

1. How can i give this code a try in game?
2. What does serialVersionUID variable mean ?
3. In witch else files should i add code except Gameactionutil, StateBasedeffects.java, Cardfactory_creatures.java, Cards.txt, card-picture.txt in this case?
1. You'll have to install something like Eclipse, import the source, make the code changes and compile + run the whole thing (to get started using eclipse, check out this thread: viewtopic.php?f=52&t=1093 ).
2. Eclipse can generate these serialVersionUIDs automatically.
3. In the case of Captain of the Watch, these would be the only files that need changing.

EDIT: And hmm, unless I'm missing something here, using c.setManaCost("R"); should work alright too (then c.setManaCost(""); again), or Zerker's suggestion: c.addIntrinsicKeyword("Ghitu Encampment is red."); then c.removeIntrinsicKeyword("Ghitu Encampment is red."); when reset to a non-creature land again.
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 » 30 Nov 2009, 07:28

Triadasoul wrote:So should i use this code for that :
if(! c.getIntrinsicKeyword().contains("First Strike")) || ! c.gettype().contains("Warrior") || ! с.gettype().contains("Creature")) ?
What I meant is
Code: Select all
if(!c.getIntrinsicKeyword().contains("First Strike"))
  c.addIntrinsicKeyword("First Strike");
if(!с.getTypes().contains("Creature"))
  c.addType("Creature");
if(!c.getTypes().contains("Warrior"))
  c.addType("Warrior");
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 Triadasoul » 30 Nov 2009, 10:35

So i re-edited ghitu encampment. Added: colour, duplication code, "comes tapped" keyword. I didn't remove paid1 because i didn't know with what to replace it in Input_PayManaCost_Ability. I've tested it for a while, it works pretty fine except the dialog box for choosing manasource/ability is narrow for 2 of them.
Image

PS: how can i generate random serialVersionUID with eclipse? (didn't find it also)

Code: Select all
cards.txt
   //*************** START *********** START **************************
          else if(cardName.equals("Ghitu Encampment"))
          {
            final Command eot1 = new Command()
            {
            private static final long serialVersionUID = -8535770979347971863L;

            public void execute()
              {
                Card c = card;

                c.setBaseAttack(0);
                c.setBaseDefense(0);
                c.removeType("Creature");
                c.removeType("Warrior");
                c.removeIntrinsicKeyword("First Strike");
                c.setManaCost("");
                
              }
            };

            final SpellAbility a1 = new Ability(card, "1 R")
            {
              public boolean canPlayAI()
              {
                return ! card.getType().contains("Creature");
              }
              public void resolve()
              {
                Card c = card;

                c.setBaseAttack(2);
                c.setBaseDefense(1);
                c.setManaCost("R");

                //to prevent like duplication like "Creature Creature"
                if(!c.getIntrinsicKeyword().contains("First Strike"))
                    c.addIntrinsicKeyword("First Strike");
                  if(!c.getType().contains("Creature"))
                    c.addType("Creature");
                  if(!c.getType().contains("Warrior"))
                    c.addType("Warrior");
                AllZone.EndOfTurn.addUntil(eot1);
              }
            };//SpellAbility

            card.clearSpellKeepManaAbility();
            card.addSpellAbility(a1);
            a1.setStackDescription(card +" becomes a 2/1 creature with first strike until EOT");
            a1.setDescription("1 R: Ghitu Encampment becomes a 2/1 red Warrior creature with first strike until end of turn. It's still a land.");
            Command paid1 = new Command() {
            private static final long serialVersionUID = -6800983290478844750L;

            public void execute() {AllZone.Stack.add(a1);}
           };
            a1.setBeforePayMana(new Input_PayManaCost_Ability(a1.getManaCost(), paid1));
          }//*************** END ************ END **************************

================================================================================================
cards.txt:

Ghitu Encampment
no cost
Land
no text
Comes into play tapped.
tap: add R

====================================================================================================
card-pictures.txt:
http://www.wizards.com/global/images/magic/general/ghitu_encampment.jpg

PS: I've noticed that Forbidding Watchtower, Faerie Conclave, Treetop Village have manacost/and colour before the ability that isn't right. I can edit their code/cads.txt and post it here if needed.
Last edited by Triadasoul on 30 Nov 2009, 20:05, edited 2 times in total.
Triadasoul
 
Posts: 223
Joined: 21 Jun 2008, 20:17
Has thanked: 0 time
Been thanked: 4 times

Re: Programming a card

Postby Triadasoul » 30 Nov 2009, 12:27

Stalking Stones:

Code: Select all
cardfactory_lands.java:
   //*************** START *********** START **************************
          else if(cardName.equals("Stalking Stones"))
          {
          
            final SpellAbility a1 = new Ability(card, "6")
            {
              public boolean canPlayAI()
              {
                return ! card.getType().contains("Creature");
              }
              public void resolve()
              {
                Card c = card;

                c.setBaseAttack(3);
                c.setBaseDefense(3);
                c.setManaCost("");

                //to prevent like duplication like "Creature Creature"
                if(!c.getType().contains("Elemental"))
                    c.addType("Elemental");
                        if(!c.getType().contains("Artifact"))
                    c.addType("Artifact");
                   if(!c.getType().contains("Creature"))
                    c.addType("Creature");

                
              }
            };//SpellAbility

            card.clearSpellKeepManaAbility();
            card.addSpellAbility(a1);
            a1.setStackDescription(card +" becomes a 3/3 Elemental artifact creature that's still a land.");
                 a1.setDescription("6: Stalking Stones becomes a 3/3 Elemental artifact creature that's still a land. (This effect lasts indefinitely.)");
            Command paid1 = new Command() {
            private static final long serialVersionUID = -6800983290478844750L;

            public void execute() {AllZone.Stack.add(a1);}
           };
            a1.setBeforePayMana(new Input_PayManaCost_Ability(a1.getManaCost(), paid1));
          }//*************** END ************ END **************************
===============================================================================================================
cards.txt:

Stalking Stones
no cost
Land
no text
tap: add 1

==================================================================================================================
cards-pictures.txt
stalking_stones.jpg       http://www.wizards.com/global/images/magic/general/stalking_stones.jpg
Spawning Pool (regeneration doesn't work for now)

Code: Select all
cardfactory_lands.java:
  //*************** START *********** START **************************
          else if(cardName.equals("Spawning Pool"))
          {
            final Command eot1 = new Command()
            {
            private static final long serialVersionUID = -8535770979347971863L;

            public void execute()
              {
                Card c = card;

                c.setBaseAttack(0);
                c.setBaseDefense(0);
                c.removeType("Creature");
                c.removeType("Skeleton");
                c.removeIntrinsicKeyword("RegenerateMe:B");
                c.setManaCost("");
                
              }
            };

            final SpellAbility a1 = new Ability(card, "1 B")
            {
              public boolean canPlayAI()
              {
                return ! card.getType().contains("Creature");
              }
              public void resolve()
              {
                Card c = card;

                c.setBaseAttack(1);
                c.setBaseDefense(1);
                c.setManaCost("B");

                //to prevent like duplication like "Creature Creature"
                if(!c.getIntrinsicKeyword().contains("RegenerateMe:B"))
                    c.addIntrinsicKeyword("RegenerateMe:B");
                  if(!c.getType().contains("Creature"))
                    c.addType("Creature");
                  if(!c.getType().contains("Skeleton"))
                    c.addType("Skeleton");
                AllZone.EndOfTurn.addUntil(eot1);
              }
            };//SpellAbility

            card.clearSpellKeepManaAbility();
            card.addSpellAbility(a1);
            a1.setStackDescription(card +" becomes a 1/1 skeleton creature with B: regenerate this creature until EOT");

            Command paid1 = new Command() {
            private static final long serialVersionUID = -6800983290478844750L;

            public void execute() {AllZone.Stack.add(a1);}
           };
            a1.setBeforePayMana(new Input_PayManaCost_Ability(a1.getManaCost(), paid1));
          }//*************** END ************ END **************************
===============================================================================================================
cards.txt:
Spawning Pool
no cost
Land
no text
Comes into play tapped.
tap: add B
===============================================================================================================
Cards-pictures.txt
spawning_pool.jpg      http://www.wizards.com/global/images/magic/general/spawning_pool.jpg
I had the same problem with dialog boxes when trying to regenerate Spawning Pool, because its too narrow and i couldn't choose it.
Last edited by Triadasoul on 30 Nov 2009, 20:04, edited 1 time in total.
Triadasoul
 
Posts: 223
Joined: 21 Jun 2008, 20:17
Has thanked: 0 time
Been thanked: 4 times

Re: Programming a card

Postby DennisBergkamp » 30 Nov 2009, 17:58

What's happening here is that the ability gets added to the card, but the text of the ability is blank. So, taking the example of Stalking Stones:

Code: Select all
//your current code:
card.clearSpellKeepManaAbility();
card.addSpellAbility(a1);
a1.setStackDescription(card +" becomes a 3/3 Elemental Artifact Creature that's still a land.");
//Add this line:
a1.setDescription("6: Stalking Stones becomes a 3/3 Elemental artifact creature that's still a land.");
You'll need similar code for Ghitu Encampment:

Code: Select all
a1.setDescription("1 R: Ghitu Encampment becomes a 2/1 red Warrior creature with first strike until end of turn. It's still a land.");
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 Triadasoul » 30 Nov 2009, 20:17

I've edited abovementioned code of Ghitu Encampment and Stalking Stones + card.txt description. But i've some complexities with Spawning Pool cause adding/removing its regeneration via addIntrinsicKeyword("RegenerateMe:B") doesn't seem to work. There is no such a choice in a dialog box. I tried to add it via addSpellAbility, but i don't know how to remove it cause Clearspellability doesn't understand argument. Is there another way to add/remove this regeneration?
Triadasoul
 
Posts: 223
Joined: 21 Jun 2008, 20:17
Has thanked: 0 time
Been thanked: 4 times

Re: Programming a card

Postby DennisBergkamp » 30 Nov 2009, 21:15

Ah yes, the RegenerateMe keyword can't be added dynamically... But I think there's a removeSpellAbility(SpellAbility sa), zerker added this to support one of his cards, I can't remember which. But look at the code for Squirrel Nest (CardFactory_Auras), I'm pretty sure I used it there.
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 Triadasoul » 01 Dec 2009, 11:26

I've found it. What code should i take for duplicate prevenetion in this case ? Should i use getspellability for this and how? (for example regeneration is ability "a2")

And another existing card modification: Urza's Factory (copied from Vitu-Ghazi, the City-Tree)
Code: Select all
cardfactory_lands.java:
 //*************** START *********** START **************************
           else if(cardName.equals("Urza's Factory"))
           {
              final Ability_Tap ability = new Ability_Tap(card, "7")
              {
               private static final long serialVersionUID = 1781653158406511188L;

               public boolean canPlay()
                 {
                    if (AllZone.GameAction.isCardInPlay(card))
                       return true;
                    else
                       return false;
                 }
                
                 public void resolve()
                 {
                    String player = card.getController();
                   
                    PlayerZone play = AllZone.getZone(Constant.Zone.Play, player);

                      //make token
                      Card c = new Card();

                      c.setOwner(card.getController());
                      c.setController(card.getController());

                      c.setName("Assembly-Worker");
                      c.setImageName("c 2 2 Assembly-Worker");
                      c.setManaCost("");
                      c.setToken(true);
                     
                      c.addType("Artifact");
                      c.addType("Creature");
                      c.addType("Assembly-Worker");
                      c.setBaseAttack(2);
                      c.setBaseDefense(2);

                      play.add(c);
                 }
              };
             
              ability.setDescription("7, tap: Put a 2/2 colorless Assembly-Worker artifact creature token onto the battlefield.");
              ability.setStackDescription(card.getName() + " - Put a 2/2 colorless Assembly-Worker artifact creature token onto the battlefield.");
             
              card.addSpellAbility(ability);
             
              //not sure what's going on here, maybe because it's a land it doesn't add the ability to the text?
              //anyway, this does the trick:
              //card.removeIntrinsicKeyword("tap: add 1");
              card.setText(card.getSpellText() +  "\r\n  Put a 2/2 colorless Assembly-Worker artifact creature token onto the battlefield.");
              //card.addIntrinsicKeyword("tap: add 1");
             
           }//*************** END ************ END **************************
======================================================
cards.txt:
Urza's Factory
no cost
Land Urza's
no text
tap: add 1
======================================================
card-pictures.txt:
urzas_factory.jpg         http://www.wizards.com/global/images/magic/general/urzas_factory.jpg
And i've also added target Assembly Worker pumping to Mishra's Factory (copied from Blinkmoth Nexus)

Code: Select all
   //*************** START *********** START **************************
          else if(cardName.equals("Mishra's Factory"))
          {
            final Command eot1 = new Command()
            {
            private static final long serialVersionUID = -956566640027406078L;

            public void execute()
              {
                Card c = card;

                c.setBaseAttack(0);
                c.setBaseDefense(0);
                c.removeType("Artifact");
                c.removeType("Creature");
                c.removeType("Assembly-Worker");
              }
            };

            final SpellAbility a1 = new Ability(card, "1")
            {
              public boolean canPlayAI()
              {
                   return ! card.getType().contains("Creature");
                   //& ! card.isTapped() ;
                //it turns into a creature, but doesn't attack
//                return (! card.getKeyword().contains("Flying") &&
//                       (CardFactoryUtil.AI_getHumanCreature("Flying").isEmpty()));
              }
              public void resolve()
              {
                Card c = card;

                c.setBaseAttack(2);
                c.setBaseDefense(2);
                //to prevent like duplication like "Creature Creature"
                if(! c.getKeyword().contains("Creature"))
                {
                  c.addType("Artifact");
                  c.addType("Creature");
                  c.addType("Assembly-Worker");
                }
                AllZone.EndOfTurn.addUntil(eot1);
              }
            };//SpellAbility
            card.addSpellAbility(a1);
            a1.setDescription("1: Mishra's Factory becomes a 2/2 Assembly-Worker artifact creature until end of turn. It's still a land.");
            a1.setStackDescription(card +" - becomes a 2/2 creature until EOT");

            Command paid1 = new Command() {
            private static final long serialVersionUID = -6767109002136516590L;

            public void execute() {AllZone.Stack.add(a1);}
           };

            a1.setBeforePayMana(new Input_PayManaCost_Ability(a1.getManaCost(), paid1));
            final SpellAbility[] a2 = new SpellAbility[1];
            final Command eot2 = new Command()
              {
               private static final long serialVersionUID = 6180724472470740160L;

               public void execute()
                {
                  Card c = a2[0].getTargetCard();
                  if(AllZone.GameAction.isCardInPlay(c))
                  {
                    c.addTempAttackBoost(-1);
                    c.addTempDefenseBoost(-1);
                  }
                }
              };

            a2[0] = new Ability_Tap(card)
            {
            private static final long serialVersionUID = 3561450520225198222L;

            public boolean canPlayAI()
              {
                return getAttacker() != null;
              }
              public void chooseTargetAI()
              {
                setTargetCard(getAttacker());
              }
              public Card getAttacker()
              {
                //target creature that is going to attack
                Combat c = ComputerUtil.getAttackers();
                CardList att = new CardList(c.getAttackers());
                att.remove(card);
                att.shuffle();

                if(att.size() != 0)
                  return att.get(0);
                else
                  return null;
              }//getAttacker()

              public void resolve()
              {
                Card c = a2[0].getTargetCard();
                if(AllZone.GameAction.isCardInPlay(c) && CardFactoryUtil.canTarget(card,c) )
                {
                  c.addTempAttackBoost(1);
                  c.addTempDefenseBoost(1);

                  AllZone.EndOfTurn.addUntil(eot2);
                }
              }//resolve()
            };//SpellAbility
            card.addSpellAbility(a2[0]);
            a2[0].setDescription("tap: Target Assembly-Worker gets +1/+1 until end of turn.");


            @SuppressWarnings("unused") // target unused
         final Input target = new Input()
            {
             private static final long serialVersionUID = 8913477363141356082L;
            
             public void showMessage()
              {
                ButtonUtil.enableOnlyCancel();
                AllZone.Display.showMessage("Select Assembly-Worker to get +1/+1");
              }
              public void selectCard(Card c, PlayerZone zone)
              {
               if(!CardFactoryUtil.canTarget(card, c)){
                     AllZone.Display.showMessage("Cannot target this card (Shroud? Protection?).");
               }
               else if(c.isCreature() && c.getType().contains("Assembly-Worker"))
               {
                  card.tap();
                  AllZone.Human_Play.updateObservers();

                  a2[0].setTargetCard(c);//since setTargetCard() changes stack description
                  a2[0].setStackDescription(c +" gets +1/+1 until EOT");

                  AllZone.InputControl.resetInput();
                  AllZone.Stack.add(a2[0]);
                }
              }//selectCard()
              public void selectButtonCancel()
              {
                card.untap();
                stop();
              }
            };//Input target
            a2[0].setBeforePayMana(CardFactoryUtil.input_targetType(a2[0], "Assembly-Worker"));

          }//*************** END ************ END **************************
Goblin Burrows

Code: Select all
Cardfactory_lands:
//*************** START *********** START **************************
             else if(cardName.equals("Goblin Burrows"))
             {
               final SpellAbility[] a2 = new SpellAbility[1];
               final Command eot2 = new Command()
                 {
                  private static final long serialVersionUID = 6180724472470740160L;

                  public void execute()
                   {
                     Card c = a2[0].getTargetCard();
                     if(AllZone.GameAction.isCardInPlay(c))
                     {
                       c.addTempAttackBoost(-2);
                                            }
                   }
                 };

               a2[0] = new Ability_Tap(card, "1 R")
               {
               private static final long serialVersionUID = 3561450520225198222L;

               public boolean canPlayAI()
                 {
                   return getAttacker() != null;
                 }
                 public void chooseTargetAI()
                 {
                   setTargetCard(getAttacker());
                 }
                 public Card getAttacker()
                 {
                   //target creature that is going to attack
                   Combat c = ComputerUtil.getAttackers();
                   CardList att = new CardList(c.getAttackers());
                   att.remove(card);
                   att.shuffle();

                   if(att.size() != 0)
                     return att.get(0);
                   else
                     return null;
                 }//getAttacker()

                 public void resolve()
                 {
                   Card c = a2[0].getTargetCard();
                   if(AllZone.GameAction.isCardInPlay(c) && CardFactoryUtil.canTarget(card,c) )
                   {
                     c.addTempAttackBoost(2);
                    
                     AllZone.EndOfTurn.addUntil(eot2);
                   }
                 }//resolve()
               };//SpellAbility
               card.addSpellAbility(a2[0]);
               a2[0].setDescription("1 R, tap: Target Goblin gets +2/+0 until end of turn.");


               @SuppressWarnings("unused") // target unused
            final Input target = new Input()
               {
                private static final long serialVersionUID = 8913477363141356082L;
               
                public void showMessage()
                 {
                   ButtonUtil.enableOnlyCancel();
                   AllZone.Display.showMessage("Select Goblin to get +2/+0");
                 }
                 public void selectCard(Card c, PlayerZone zone)
                 {
                  if(!CardFactoryUtil.canTarget(card, c)){
                        AllZone.Display.showMessage("Cannot target this card (Shroud? Protection?).");
                  }
                  else if(c.isCreature() && c.getType().contains("Goblin"))
                  {
                     card.tap();
                     AllZone.Human_Play.updateObservers();

                     a2[0].setTargetCard(c);//since setTargetCard() changes stack description
                     a2[0].setStackDescription(c +" gets +2/+0 until EOT");

                     AllZone.InputControl.resetInput();
                     AllZone.Stack.add(a2[0]);
                   }
                 }//selectCard()
                 public void selectButtonCancel()
                 {
                   card.untap();
                   stop();
                 }
               };//Input target
               a2[0].setBeforePayMana(CardFactoryUtil.input_targetType(a2[0], "Goblin"));

             }//*************** END ************ END **************************
====================================================
cards.txt:
Goblin Burrows
no cost
Land
no text
tap: add 1
====================================================
card-pictures.txt:
goblin_burrows.jpg              http://www.wizards.com/global/images/magic/general/goblin_burrows.jpg

Skarrg, the Rage Pits

Code: Select all
cardfactory_lands:
//*************** START *********** START **************************
             else if(cardName.equals("Skarrg, the Rage Pits"))
             {
               final SpellAbility[] a2 = new SpellAbility[1];
               final Command eot2 = new Command()
                 {
                  private static final long serialVersionUID = 6180724472470740160L;

                  public void execute()
                   {
                     Card c = a2[0].getTargetCard();
                     if(AllZone.GameAction.isCardInPlay(c))
                     {
                       c.addTempAttackBoost(-1);
                       c.addTempDefenseBoost(-1);
                       c.removeIntrinsicKeyword("Trample");
                                            }
                   }
                 };

               a2[0] = new Ability_Tap(card, "G R")
               {
               private static final long serialVersionUID = 3561450520225198222L;

               public boolean canPlayAI()
                 {
                   return getAttacker() != null;
                 }
                 public void chooseTargetAI()
                 {
                   setTargetCard(getAttacker());
                 }
                 public Card getAttacker()
                 {
                   //target creature that is going to attack
                   Combat c = ComputerUtil.getAttackers();
                   CardList att = new CardList(c.getAttackers());
                   att.remove(card);
                   att.shuffle();

                   if(att.size() != 0)
                     return att.get(0);
                   else
                     return null;
                 }//getAttacker()

                 public void resolve()
                 {
                   Card c = a2[0].getTargetCard();
                   if(AllZone.GameAction.isCardInPlay(c) && CardFactoryUtil.canTarget(card,c) )
                   {
                     c.addTempAttackBoost(1);
                     c.addTempDefenseBoost(1);
                     c.addIntrinsicKeyword("Trample");
                     AllZone.EndOfTurn.addUntil(eot2);
                   }
                 }//resolve()
               };//SpellAbility
               card.addSpellAbility(a2[0]);
               a2[0].setDescription("G R, tap: Target creature gets +1/+1 and gains trample until end of turn.");


               @SuppressWarnings("unused") // target unused
            final Input target = new Input()
               {
                private static final long serialVersionUID = 8913477363141356082L;
               
                public void showMessage()
                 {
                   ButtonUtil.enableOnlyCancel();
                   AllZone.Display.showMessage("Select Creature to get +1/+1 and trample");
                 }
                 public void selectCard(Card c, PlayerZone zone)
                 {
                  if(!CardFactoryUtil.canTarget(card, c)){
                        AllZone.Display.showMessage("Cannot target this card (Shroud? Protection?).");
                  }
                  else if(c.isCreature())
                  {
                     card.tap();
                     AllZone.Human_Play.updateObservers();

                     a2[0].setTargetCard(c);//since setTargetCard() changes stack description
                     a2[0].setStackDescription(c +" gets +1/+1 and trample until EOT");

                     AllZone.InputControl.resetInput();
                     AllZone.Stack.add(a2[0]);
                   }
                 }//selectCard()
                 public void selectButtonCancel()
                 {
                   card.untap();
                   stop();
                 }
               };//Input target
               a2[0].setBeforePayMana(CardFactoryUtil.input_targetType(a2[0], "Creature"));

             }//*************** END ************ END **************************
          

====================================================
cards.txt
Skarrg, the Rage Pits
no cost
Land
no text
tap: add 1
====================================================
card-pictures.txt:
skarrg_the_rage_pits.jpg         http://www.wizards.com/global/images/magic/general/skarrg_the_rage_pits.jpg
Daru Encampment
Code: Select all
carfactory_lands:
 //*************** START *********** START **************************
             else if(cardName.equals("Daru Encampment"))
             {
               final SpellAbility[] a2 = new SpellAbility[1];
               final Command eot2 = new Command()
                 {
                  private static final long serialVersionUID = 6180724472470740160L;

                  public void execute()
                   {
                     Card c = a2[0].getTargetCard();
                     if(AllZone.GameAction.isCardInPlay(c))
                     {
                       c.addTempAttackBoost(-1);
                       c.addTempDefenseBoost(-1);
                                            }
                   }
                 };

               a2[0] = new Ability_Tap(card, "W")
               {
               private static final long serialVersionUID = 3561450520225198222L;

               public boolean canPlayAI()
                 {
                   return getAttacker() != null;
                 }
                 public void chooseTargetAI()
                 {
                   setTargetCard(getAttacker());
                 }
                 public Card getAttacker()
                 {
                   //target creature that is going to attack
                   Combat c = ComputerUtil.getAttackers();
                   CardList att = new CardList(c.getAttackers());
                   att.remove(card);
                   att.shuffle();

                   if(att.size() != 0)
                     return att.get(0);
                   else
                     return null;
                 }//getAttacker()

                 public void resolve()
                 {
                   Card c = a2[0].getTargetCard();
                   if(AllZone.GameAction.isCardInPlay(c) && CardFactoryUtil.canTarget(card,c) )
                   {
                     c.addTempAttackBoost(1);
                     c.addTempDefenseBoost(1);
                    
                     AllZone.EndOfTurn.addUntil(eot2);
                   }
                 }//resolve()
               };//SpellAbility
               card.addSpellAbility(a2[0]);
               a2[0].setDescription("W, tap: Target Soldier gets +1/+1 until end of turn.");


               @SuppressWarnings("unused") // target unused
            final Input target = new Input()
               {
                private static final long serialVersionUID = 8913477363141356082L;
               
                public void showMessage()
                 {
                   ButtonUtil.enableOnlyCancel();
                   AllZone.Display.showMessage("Select Soldier to get +1/+1");
                 }
                 public void selectCard(Card c, PlayerZone zone)
                 {
                  if(!CardFactoryUtil.canTarget(card, c)){
                        AllZone.Display.showMessage("Cannot target this card (Shroud? Protection?).");
                  }
                  else if(c.isCreature() && c.getType().contains("Soldier"))
                  {
                     card.tap();
                     AllZone.Human_Play.updateObservers();

                     a2[0].setTargetCard(c);//since setTargetCard() changes stack description
                     a2[0].setStackDescription(c +" gets +1/+1 until EOT");

                     AllZone.InputControl.resetInput();
                     AllZone.Stack.add(a2[0]);
                   }
                 }//selectCard()
                 public void selectButtonCancel()
                 {
                   card.untap();
                   stop();
                 }
               };//Input target
               a2[0].setBeforePayMana(CardFactoryUtil.input_targetType(a2[0], "Soldier"));

             }//*************** END ************ END **************************
====================================================
cards.txt:
Daru Encampment
no cost
Land
no text
tap: add 1
====================================================
card-pictures.txt:
Daru_Encampment.jpg        http://www.wizards.com/global/images/magic/general/Daru_Encampment.jpg
PS: I've noticed that AI taps living land creatures for mana instead of attacking with it, should this be covered in code or it'll be gone with AI improvement ?
Triadasoul
 
Posts: 223
Joined: 21 Jun 2008, 20:17
Has thanked: 0 time
Been thanked: 4 times

Re: Programming a card

Postby DennisBergkamp » 01 Dec 2009, 17:57

Cool! Thanks Triad, I'll add these :)

Yes, apparently the AI doesn't attack with living lands (canPlayAI returns false)... not sure if there's a good reason for this. It's possible originally the AI would tap its living lands creatures for mana to pay for their own abilities ;) This might still be the problem...
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 DennisBergkamp » 01 Dec 2009, 18:07

As for the duplicate detection, you probably have to do some hack like this:
Code: Select all
               boolean hasRegen = false;
               SpellAbility[] sas = card.getSpellAbility();
               for (SpellAbility sa : sas)
               {
                  if(sa.toString().equals("B: Regenerate this creature.")) //this is essentially ".getDescription()"
                     hasRegen = true;
               }
               if (!hasRegen){
                  //add regenAbility here, make sure you setDescription of the regenAbility to "B: Regenerate this creature."
               }
Hope that makes sense, basically just go through all of the Abilities of the card, and see if it has an ability with the regeneration text, if it doesn't, add the regeneration ability.
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 Rob Cashwalker » 01 Dec 2009, 18:09

DennisBergkamp wrote:Cool! Thanks Triad, I'll add these :)

Yes, apparently the AI doesn't attack with living lands (canPlayAI returns false)... not sure if there's a good reason for this. It's possible originally the AI would tap its living lands creatures for mana to pay for their own abilities ;) This might still be the problem...
How does the AI choose mana sources to pay for abilities? Somewhere there must be code that loops through a CardList of all possible mana sources. Sort the list such that man-lands are at the end. (assuming the AI keeps using list.get(0) for each needed mana)

The other issue will be that the AI would need to know if the man-land would be useful to attack with.... which normally is calculated in CardFactoryUtil.AI_doesCreatureAttack(card). But the man land isn't animated yet, therefore it will always return false.
The Force will be with you, Always.
User avatar
Rob Cashwalker
Programmer
 
Posts: 2167
Joined: 09 Sep 2008, 15:09
Location: New York
Has thanked: 5 times
Been thanked: 40 times

Re: Programming a card

Postby DennisBergkamp » 01 Dec 2009, 18:24

Well, it should actually disregard the man-land (what if it only has 1 or 2 manasources available?).

And yes, another possibility as you said, is the doesCreatureAttack() returning false. What we could do is add some method that predicts this (wouldCreatureAttack() :) ? )
User avatar
DennisBergkamp
AI Programmer
 
Posts: 2602
Joined: 09 Sep 2008, 15:46
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 46 guests

Main Menu

User Menu

Our Partners


Who is online

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

Login Form