It is currently 30 Oct 2025, 17:46
   
Text Size

Adding similar cards

Post MTG Forge Related Programming Questions Here

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

Adding similar cards

Postby Chris H. » 15 Sep 2009, 18:07

I have a new card to submit. It may be too late to get it in for the next release, we can always add it to the following release.

Add this to cards.txt:

Code: Select all
Last Caress
2 B
Sorcery
Target player loses 1 life and you gain 1 life. Draw a card.
Cantrip
.
The following replaces the code for Soul Feast (I am combining Soul Feast with the new spell Last Caress):

Code: Select all
    ////////////////////////////////////////////////////////////
    if (cardName.equals("Soul Feast") || cardName.equals("Last Caress"))
    {
      final SpellAbility spell = new Spell(card)
      {
      private static final long serialVersionUID = -8277174319360648715L;

      public void resolve()
        {
          int n = 4;
         
          if (cardName.equals("Last Caress"))
             n = 1;

          AllZone.GameAction.getPlayerLife(getTargetPlayer()).subtractLife(n);
          PlayerLife life = AllZone.GameAction.getPlayerLife(card.getController());
          life.addLife(n);
        }//resolve()
      };//SpellAbility

      spell.setChooseTargetAI(CardFactoryUtil.AI_targetHuman());
      spell.setBeforePayMana(CardFactoryUtil.input_targetPlayer(spell));

      card.clearSpellAbility();
      card.addSpellAbility(spell);

      return card;
    }
    //////////////////////////////////////////////////////////
.
Add this to cards-pictures.txt:
.
Attachments
Last Caress pic url.zip
(661 Bytes) Downloaded 363 times
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: Adding similar cards

Postby mtgrares » 15 Sep 2009, 18:11

It looks good. I'm sure you were very happy when you got to use the card that YOU programmed. Its a great feeling.

And by the way, I just use the lines ////////////////////////////////////////////////// to make SURE that I notice that I'm starting or ending a specific card, because it is really easy to make mistakes when a card is longer than a screen and I accidentally hit pageUp or pageDown and end up messing up a different card.
mtgrares
DEVELOPER
 
Posts: 1352
Joined: 08 Sep 2008, 22:10
Has thanked: 3 times
Been thanked: 12 times

Re: Adding similar cards

Postby Rob Cashwalker » 15 Sep 2009, 19:34

This mechanic is begging for a keyword.
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: Adding similar cards

Postby DennisBergkamp » 15 Sep 2009, 20:02

Nice. No it's not too late for the next release, in fact I'm still in the process of adding some new cards (from the latest set).
User avatar
DennisBergkamp
AI Programmer
 
Posts: 2602
Joined: 09 Sep 2008, 15:46
Has thanked: 0 time
Been thanked: 0 time

Re: Adding similar cards

Postby silly freak » 15 Sep 2009, 20:37

i personally don't think it is a good idea to release new cards before wizards does. but i don't fear we are faster anyways ^^

for the keyword: i don't know for life drain, but with damage, there is "equal to the ammount of damage dealt this way" which is slightly different from "deal X, gain X". if possible, maybe there should be two versions for this difference?
___

where's the "trust me, that will work!" switch for the compiler?
Laterna Magica - blog, forum, project, 2010/09/06 release!
silly freak
DEVELOPER
 
Posts: 598
Joined: 26 Mar 2009, 07:18
Location: Vienna, Austria
Has thanked: 93 times
Been thanked: 25 times

Re: Adding similar cards

Postby Chris H. » 15 Sep 2009, 21:37

I hope to get my level of training and understanding to a point where I can make a contribution by making a keyword. I feel like I am trying to graduate from first grade and make it to second grade. :roll:

They should change my status from tester to Jr. Wannabee Code-Hacker Trainee.

There are several cards that use this mechanic, all but Soul Feast and Last Caress have other abilities like the Morsel Theft spell. At least the Last Caress spell makes good use of Rob' cantrip keyword.



I noticed that Dennis had created a second method for Goldmeadow Harrier rather than combining it with Squall Drifter. So I went and did some research and came up with a long list of creatures that are very similar. Talk about begging for a keyword.

There is no AI for this type of card at this time … it has got me to thinking …

Check to see if the computer has the Royal Assassin Combo in play?

How about tapping the Human's biggest creatures so they can't block for an up-coming attack?


Unfortunately, the computer can't use this before the human attacks.
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: Adding similar cards

Postby Chris H. » 16 Sep 2009, 01:24

Let there be tokens, tokens and more tokens. The spell Dragon Fodder uses the Raise the Alarm spell as a template. I decided to keep these two spells separate since there is enough important data in the method that we do not want to become confused.

Add this to cards.txt:

Code: Select all
Dragon Fodder
1 R
Sorcery
Put two 1/1 red Goblin creature tokens onto the battlefield.
.
Add this code to CardFactory.java (below the Raise the Alarm method?) :

Code: Select all
    //*************** START *********** START **************************
    if(cardName.equals("Dragon Fodder"))
    {
      SpellAbility spell = new Spell(card)
      {
      private static final long serialVersionUID = -6704097906643840324L;

      public void resolve()
        {
          PlayerZone play = AllZone.getZone(Constant.Zone.Play, card.getController());
          for (int i = 0; i < 2; i++)
          {
            Card c = new Card();

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

            c.setName("R 1 1 Goblin");
            c.setManaCost("R");
            c.setToken(true);

            c.addType("Creature");
            c.addType("Goblin");
            c.setBaseAttack(1);
            c.setBaseDefense(1);

            play.add(c);
          }//for
        }//resolve()
      };
      card.clearSpellAbility();
      card.addSpellAbility(spell);
    }//*************** END ************ END **************************
.
This spell creates r_1_1_goblin creature tokens and we already have a jpg for these Goblins.





EDIT:

I see that I forgot to include the jpg url for the Dragon Fodder spell:


.
Attachments
Dragon Fodder pic url.zip
(671 Bytes) Downloaded 353 times
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: Adding similar cards

Postby Rob Cashwalker » 16 Sep 2009, 03:40

I'd have to think lose life/gain life spells are common enough to warrant a keyword. And honestly at this stage, we should refrain from adding card code which isn't at least 75% unique from any other card. Soul Feast is one that is so simple that I've put it off for a while.
Just make up the shouldLoseLife() function, and copy the DamageCP parser for the damage, then add the spellability from soul feast, substituting the explicit number for a variable.
I'll come along later sometime to dress it up with extra abilities

Deal damage/gain life is different, and I'm including it in an enhanced damage spell keyword handler.

Token generation is another ability I want to keyword. The only difference between many token generating spells is the number of tokens, the type and p/t and sometimes the name. All stuff that's easy to parse.
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: Adding similar cards

Postby Chris H. » 18 Sep 2009, 12:28

Rob Cashwalker wrote:Just make up the shouldLoseLife() function, and copy the DamageCP parser for the damage, then add the spellability from soul feast, substituting the explicit number for a variable.
OK, I have found the DamageCP parser and I modified a copy to become the parser for a keyword that we can call spLoseLifeGainLife. The parser looks like this and I think it is OK:

Code: Select all
   private final int shouldSpLoseLifeGainLife(Card c){
          ArrayList<String> a = c.getKeyword();
          for (int i = 0; i < a.size(); i++)
             if (a.get(i).toString().startsWith("spLoseLifeGainLife"))
                return i;
          
          return -1;
   }
.
Farther down I have the following unfinished code:

Code: Select all
    //Spell gain life lose life cards (like Soul Feast)
    if (shouldSpLoseLifeGainLife(card)  != -1)
    {
       int n = shouldSpLoseLifeGainLife(card);
       if (n != -1)
       {
           String parse = card.getKeyword().get(n).toString();
          card.removeIntrinsicKeyword(parse);
         
          card.clearSpellAbility();
         
          String k[] = parse.split(":");
          final String life = k[1];
         
          // need to add Soul Feast code here or access code from CardFactoryUtil
         
       }
    }// spLoseLifeGainLife
.
Note the comment "// need to add Soul Feast code here or access code from CardFactoryUtil".

I tried to add the Soul Feast code here and I had problems in reference to something related to a class and I could not get rid of the errors.

Looking at the code for spDamageCP, it looks like I need to have a statement:

Code: Select all
card.addSpellAbility(CardFactoryUtil.spellability_spLoseLifeGainLife(card, life));
.
which would pass some parameters to some new code that I would have to add to CardFactoryUtil.

I am somewhat confused. I think that I should be able to add the Soul Feast code here and not have to access CardFactoryUtil. :?
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: Adding similar cards

Postby Rob Cashwalker » 18 Sep 2009, 15:23

In Soul Feast, there is a SpellAbility defined. Copy that ability into your parser after the part which extracts the number. Modify the spell Ability resolve() method, such that the number of life lost/gained is the variable that contains the extracted number.

Set the descriptions of the SpellAbility (assembled on the fly, like this: "string" + numLife + "string") and then use the addSpellAbility() method to add the SpellAbility object to the card.
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: Adding similar cards

Postby frwololo » 28 Sep 2009, 03:34

Rob Cashwalker wrote:Token generation is another ability I want to keyword. The only difference between many token generating spells is the number of tokens, the type and p/t and sometimes the name. All stuff that's easy to parse.
I dream of the day we can have compatibility for keywords between Forge and Wagic :lol:
Here's how we write tokens in Wagic:

[card]
text=Kicker {6} (You may pay an additional {6} as you cast this spell.) Put six 1/1 white Kor Soldier creature tokens onto the battlefield. If Conqueror's Pledge was kicked, put twelve of those tokens onto the battlefield instead.
id=195626
name=Conqueror's Pledge
mana={2}{W}{W}{W}
kicker={6}
auto=token(Kor Soldier,Creature Kor Soldier,1/1,white)*6
auto=kicker token(Kor Soldier,Creature Kor Soldier,1/1,white)*6
type=Sorcery
rarity=R
[/card]

first is the name, then type and subtypes, P/T, last one is colors and abilities (flying and stuff like this...). *n is optional and indicates the number of tokens
frwololo
DEVELOPER
 
Posts: 265
Joined: 21 Jun 2008, 04:33
Has thanked: 0 time
Been thanked: 3 times

Re: Adding similar cards

Postby mtgrares » 30 Sep 2009, 19:25

I dream of the day we can have compatibility for keywords between Forge and Wagic.
Well MTG Forge supports more keywords and scripting than I ever thought it would. Scripting is nice since it saves on coding if you don't mind working on just individual "script words" that can be combined in a large variety of ways.

I dream of scripting all of MTG Forge's cards

Code: Select all
Shock.txt
Shock
R
Instant

Spell
Text: Shock deals 2 damage to target creature or player.
Target: creature or player
Resolve: damage target creature or player, 2
Code: Select all
Prodigal_Pyromancer.txt
Prodigal Pyromancer
2 R
Creature Human Wizard
1/1

Activated Ability
Text: tap: Prodigal Pyromancer deals 1 damage to target creature or player.
Target: creature or player
Cost: tap
Resolve: damage target creature or player, 1
The idea is to divide cards into targets, costs, and resolves that can be reused and separated. That way Shock and Prodigal Pyromancer could share the same targeting and resolve code. What a wonderful dream. (I really need to sit my butt down and try to just code these two cards like this.)
mtgrares
DEVELOPER
 
Posts: 1352
Joined: 08 Sep 2008, 22:10
Has thanked: 3 times
Been thanked: 12 times

Re: Adding similar cards

Postby Marek14 » 30 Sep 2009, 19:48

mtgrares wrote:
I dream of the day we can have compatibility for keywords between Forge and Wagic.
Well MTG Forge supports more keywords and scripting than I ever thought it would. Scripting is nice since it saves on coding if you don't mind working on just individual "script words" that can be combined in a large variety of ways.

I dream of scripting all of MTG Forge's cards

Code: Select all
Shock.txt
Shock
R
Instant

Spell
Text: Shock deals 2 damage to target creature or player.
Target: creature or player
Resolve: damage target creature or player, 2
Code: Select all
Prodigal_Pyromancer.txt
Prodigal Pyromancer
2 R
Creature Human Wizard
1/1

Activated Ability
Text: tap: Prodigal Pyromancer deals 1 damage to target creature or player.
Target: creature or player
Cost: tap
Resolve: damage target creature or player, 1
The idea is to divide cards into targets, costs, and resolves that can be reused and separated. That way Shock and Prodigal Pyromancer could share the same targeting and resolve code. What a wonderful dream. (I really need to sit my butt down and try to just code these two cards like this.)
You know, you don't really need the "damage target creature or player" in resolve... why not simply "damage target"?

Then, Lava Spike would be

Code: Select all
Lava Spike.txt
Lava Spike
R
Sorcery

Spell
Text: Lava Spike deals 3 damage to target player.
Target: player
Resolve: damage target, 3
Marek14
Tester
 
Posts: 2774
Joined: 07 Jun 2008, 07:54
Has thanked: 0 time
Been thanked: 303 times

Re: Adding similar cards

Postby mtgrares » 30 Sep 2009, 20:07

You know, you don't really need the "damage target creature or player" in resolve... why not simply "damage target"?
Both strings can mean the same thing. I tend to be a little too wordy or verbose when I'm not sure what I'm doing.
mtgrares
DEVELOPER
 
Posts: 1352
Joined: 08 Sep 2008, 22:10
Has thanked: 3 times
Been thanked: 12 times

Re: Adding similar cards

Postby Chris H. » 18 Oct 2009, 01:47

A new spell:

(NOTE: In my tests I could not get the computer to cast this spell even though it was attacking with four 1/1 creatures. I copied the AI code from the block of code which covers most of these cards. I modified the code from Titanic Ultimatum for the rest of this spell. I also tried the test with Glorious Charge and the computer once again failed to cast this spell even though it was attacking with four creatures.)

Code: Select all
Marshaling Cry
1 W W
Sorcery
Creatures you control get +1/+1 and gain vigilance until end of turn.
Cycling:2
`
Code: Select all
   //*************** START *********** START **************************
   if (cardName.equals("Marshaling Cry"))
   {
      SpellAbility spell = new Spell(card)
      {

         private static final long serialVersionUID = -8141210741282528210L;

         public boolean canPlayAI()
         {
            return getAttacker() != null;
         }
         public Card getAttacker()
         {
            //target creature that is going to attack
            Combat c = ComputerUtil.getAttackers();
            Card[] att = c.getAttackers();
            if (att.length > 1)   // Effect best used on at least a couple creatures
               return att[0];
            else
               return null;
         }//getAttacker()

         public void resolve()
         {
            PlayerZone play = AllZone.getZone(Constant.Zone.Play, card.getController());
            CardList list = new CardList(play.getCards());
            @SuppressWarnings("unused") // c
            Card c;

            for (int i = 0; i < list.size(); i++)
            {
               final Card[] target = new Card[1];
               target[0] = list.get(i);

               final Command untilEOT = new Command()
               {
                  
                  private static final long serialVersionUID = 6075570541463641361L;

                  public void execute()
                  {
                     if (AllZone.GameAction.isCardInPlay(target[0]))
                     {
                        target[0].addTempAttackBoost(-1);
                        target[0].addTempDefenseBoost(-1);

                        target[0].removeExtrinsicKeyword("Vigilance");
                     }
                  }
               };//Command

               if (AllZone.GameAction.isCardInPlay(target[0]))
               {
                  target[0].addTempAttackBoost(1);
                  target[0].addTempDefenseBoost(1);

                  target[0].addExtrinsicKeyword("Vigilance");

                  AllZone.EndOfTurn.addUntil(untilEOT);
               }//if
            }//for
         }//resolve()
      };
      spell.setStackDescription(card.getController() + " creatures get +1/+1 and gain vigilance until end of turn.");
      card.setFlashback(true);
      card.clearSpellAbility();
      card.addSpellAbility(spell);
      spell.setDescription("Creatures you control get +1/+1 and gain vigilance until end of turn.");
      card.addSpellAbility(CardFactoryUtil.ability_Flashback(card, "3 W", "0"));
   }//*************** END ************ END **************************
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

Next

Return to Developer's Corner

Who is online

Users browsing this forum: No registered users and 40 guests

Main Menu

User Menu

Our Partners


Who is online

In total there are 40 users online :: 0 registered, 0 hidden and 40 guests (based on users active over the past 10 minutes)
Most users ever online was 9298 on 10 Oct 2025, 12:54

Users browsing this forum: No registered users and 40 guests

Login Form