It is currently 11 Sep 2025, 17:17
   
Text Size

abDrawCards[Tgt]

Post MTG Forge Related Programming Questions Here

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

abDrawCards[Tgt]

Postby Rob Cashwalker » 20 Feb 2010, 05:07

This time around, a new ability, to go along with spDrawCards.

No crazy new syntax or anything. Just pretty much the same as spDrawCards. All drawbacks were already in place.

Unlike Pump and Damage, the Description parameters are very necessary, as I decided not to write code to translate 1 into "a card" and 2+ into "two cards"(etc).

Existing cards:
Code: Select all
Archivist
2 U U
Creature Human Wizard
no text
1/1
abDrawCards T:1:Draw a card.:Archivist - draw a card

Benalish Heralds
3 W
Creature Human Soldier
no text
2/4
abDrawCards 3 U T:1:Draw a card.:Benalish Heralds - draw a card

Bonded Fetch
2 U
Creature Homunculus
no text
0/2
Defender
Haste
abDrawCards T:1:Drawback$YouDiscard/1:Draw a card, then discard a card.:Bonded Fetch - draw a card and discard a card

Frontline Sage
2 U
Creature Human Wizard
no text
0/1
Exalted
abDrawCards U T:1:Drawback$YouDiscard/1:Draw a card, then discard a card.:Frontline Sage - draw a card then discard a card

Merfolk Looter
1 U
Creature Merfolk Rogue
no text
1/1
abDrawCards T:1:Drawback$YouDiscard/1:Draw a card, then discard a card.:Merfolk Looter - draw a card and discard a card

Mikokoro, Center of the Sea
no cost
Legendary Land
no text
tap: add 1
abDrawCards 2 T:1:Drawback$OppDraw/1:Each player draws a card.:Mikokoro, Center of the Sea - each player draws a card

Scepter of Insight
1 U U
Artifact
no text
abDrawCards 3 U T:1:Draw a card.:Scepter of Insight - draw a card

Thought Courier
1 U
Creature Human Wizard
no text
1/1
abDrawCards T:1:Drawback$YouDiscard/1:Draw a card, then discard a card.:Thought Courier - draw a card and discard a card

Xira Arien
B R G
Legendary Creature Insect Wizard
no text
1/2
Flying
abDrawCardsTgt B R G T:1:Target player draws a card.:Xira Arien - target player draws a card
New cards:
Code: Select all
Armistice
2 W
Enchantment
abDrawCards 3 W W:1:Drawback$OppGainLife/3:You draw a card and target opponent gains 3 life.:Armistice - draw a card and opponent gains life

Bazaar of Baghdad
no cost
Land
no text
abDrawCards T:2:Drawback$YouDiscard/3:Draw two cards, then discard three cards.:Bazaar of Baghdad - draw cards and discard cards

Cephalid Broker
3 U
Creature Cephalid
no text
2/2
abDrawCardsTgt T:2:Drawback$TgtDiscard/2:Target player draws two cards, then discards two cards.:Cephalid Broker - target player draws cards and discards cards

Cephalid Looter
2 U
Creature - Cephalid Rogue
no text
2/1
abDrawCardsTgt T:1:Drawback$TgtDiscard/1:Target player draws a card, then discards a card.:Cephalid Looter - target players draws a card and discards a card

Emmessi Tome
4
Artifact
no text
abDrawCards 5 T:2:Drawback$YouDiscard/1:Draw two cards, then discard a card.:Emmessi Tome - draw cards and discard a card

Grixis Battlemage
2 B
Creature Human Wizard
no text
2/2
abDrawCards U T:1:Drawback$YouDiscard/1:Draw a card, then discard a card.:Grixis Battlemage - draw a card and discard a card
abPumpTgt R T:This creature cannot block:Target creature can't block this turn.:Grixis Battlemage - target creature cannot block this turn

Jalum Tome
3
Artifact
no text
abDrawCards 2 T:1:Drawback$YouDiscard/1:Draw a card, then discard a card.:Jalum Tome - draw a card and discard a card

Jayemdae Tome
4
Artifact
no text
abDrawCards 4 T:1:Draw a card.:Jayemdae Tome - draw a card

Magus of the Bazaar
1 U
Creature Human Wizard
no text
0/1
abDrawCards T:2:Drawback$YouDiscard/3:Draw two cards, then discard three cards.:Magus of the Bazaar - draw cards and discard cards

Reckless Scholar
2 U
Creature Human Wizard
no text
2/1
abDrawCardsTgt T:1:Drawback$TgtDiscard/1:Target player draws a card, then discards a card.:Reckless Scholar - target player draws a card and discards a card

Riptide Director
2 U U
Creature Human Wizard
no text
2/3
abDrawCards 2 U U T:X:Draw a card for each Wizard you control.:Riptide Director - draw X cards
SVar:X:Count$TypeYouCtrl.Wizard

Sea Gate Loremaster
4 U
Creature Merfolk Wizard Ally
no text
1/3
abDrawCards T:X:Draw a card for each Ally you control.
SVar:X:Count$TypeYouCtrl.Ally

Tower of Fortunes
4
Artifact
no text
abDrawCards 8 T:4:Draw four cards.:Tower of Fortunes - draw cards

Treasure Trove
2 U U
Enchantment
no text
abDrawCards 2 U U:1:Draw a card.:Treasure Trove - draw a card
CardFactory:
Code: Select all
    while (hasKeyword(card, "abDrawCards") != -1)
    {
       int n = hasKeyword(card, "abDrawCards");
       String parse = card.getKeyword().get(n).toString();
       card.removeIntrinsicKeyword(parse);
       
       String k[] = parse.split(":");
       
       final boolean Tgt[] = {false};
       Tgt[0] = k[0].contains("Tgt");
       
        String tmpCost = new String("");
       
        if (Tgt[0])
           tmpCost = k[0].substring(14);
       
        else
              tmpCost = k[0].substring(11);
       
        boolean tapCost = false;
        boolean tapOnlyCost = false;
       
        if (tmpCost.contains("T"))
        {
           tapCost = true;
           tmpCost = tmpCost.replace("T", "");
           tmpCost = tmpCost.trim();
           if (tmpCost.length() == 0)
              tapOnlyCost = true;
        }
       
        final String manaCost = tmpCost;
       
       final int NumCards[] = {-1};
        final String NumCardsX[] = {"none"};

        if (k[1].matches("X"))
        {
           String x = card.getSVar(k[1]);
           if (x.startsWith("Count$"))
           {
              String kk[] = x.split("\\$");
              NumCardsX[0] = kk[1];
           }
        }
        else if (k[1].matches("[0-9][0-9]?"))
           NumCards[0] = Integer.parseInt(k[1]);
       
        // drawbacks and descriptions
        final String DrawBack[] = {"none"};
        final String spDesc[] = {"none"};
        final String stDesc[] = {"none"};
        if (k.length > 2)
        {
           if (k[2].contains("Drawback$"))
           {
              String kk[] = k[2].split("\\$");
              DrawBack[0] = kk[1];
              if (k.length > 3)
                 spDesc[0] = k[3];
              if (k.length > 4)
                 stDesc[0] = k[4];
           }
           else
           {
              if (k.length > 2)
                 spDesc[0] = k[2];
              if (k.length > 3)
                 stDesc[0] = k[3];
           }
        }
        if (tapOnlyCost == true)
            spDesc[0] = "Tap: " + spDesc[0];
         else if (tapCost == true)
            spDesc[0] = manaCost + ", tap: " + spDesc[0];
         else
            spDesc[0] = manaCost + ": " + spDesc[0];

       
        if (! tapCost)
        {
           final SpellAbility abDraw = new Ability_Activated(card, manaCost)
           {
                private static final long serialVersionUID = -206739246009089196L;

                private int ncards;
               
                public int getNumCards()
                {
                   if (NumCards[0] != -1)
                      return NumCards[0];

                   if (! NumCardsX[0].equals("none"))
                      return CardFactoryUtil.xCount(card, NumCardsX[0]);
                 
                   return 0;
                }

                public boolean canPlayAI()
                {
                   ncards = getNumCards();
                   int h = AllZone.getZone(Constant.Zone.Hand, Constant.Player.Computer).size();
                   int hl = AllZone.getZone(Constant.Zone.Library, Constant.Player.Human).size();
                   int cl = AllZone.getZone(Constant.Zone.Library, Constant.Player.Computer).size();
                   
                   Random r = new Random();
                   
                   // prevent run-away activations - first time will always return true
                   boolean rr = false;
                   if (r.nextFloat() <= Math.pow(.6667, card.getAbilityUsed()))
                      rr = true;


                   if (((hl - ncards) < 2) && Tgt[0])   // attempt to deck the human
                   {
                      setTargetPlayer(Constant.Player.Human);
                      return true && rr;
                   }
                 
                   if (((h + ncards) <= 7) && !((cl - ncards) < 1) && (r.nextInt(10) > 4))
                   {
                      setTargetPlayer(Constant.Player.Computer);
                      return true && rr;
                   }
                 
                   return false;
                }

                public void resolve()
                {
                   ncards = getNumCards();

                   String TgtPlayer = card.getController();
                   if (Tgt[0])
                      TgtPlayer = getTargetPlayer();

                   for (int i=0; i < ncards; i++)
                      AllZone.GameAction.drawCard(TgtPlayer);

                   if (! DrawBack[0].equals("none"))
                      CardFactoryUtil.doDrawBack(DrawBack[0], ncards, card.getController(), AllZone.GameAction.getOpponent(card.getController()), TgtPlayer, card, null);
                }
           };
           
           abDraw.setDescription(spDesc[0]);
           abDraw.setStackDescription(stDesc[0]);
           
           if (Tgt[0] == true)
              abDraw.setBeforePayMana(CardFactoryUtil.input_targetPlayer(abDraw));
              
           card.addSpellAbility(abDraw);
        }//!tapCost
       
        if (tapCost)
        {
           final SpellAbility abDraw = new Ability_Tap(card)
           {
                private static final long serialVersionUID = -2149577241283487990L;

                private int ncards;
               
                public int getNumCards()
                {
                   if (NumCards[0] != -1)
                      return NumCards[0];

                   if (! NumCardsX[0].equals("none"))
                      return CardFactoryUtil.xCount(card, NumCardsX[0]);
                 
                   return 0;
                }

                public boolean canPlayAI()
                {
                   ncards = getNumCards();
                   int h = AllZone.getZone(Constant.Zone.Hand, Constant.Player.Computer).size();
                   int hl = AllZone.getZone(Constant.Zone.Library, Constant.Player.Human).size();
                   int cl = AllZone.getZone(Constant.Zone.Library, Constant.Player.Computer).size();
                   
                   Random r = new Random();

                   if (((hl - ncards) < 2) && Tgt[0])   // attempt to deck the human if possible
                   {
                      setTargetPlayer(Constant.Player.Human);
                      return true;
                   }
                 
                   if (((h + ncards) <= 7) && !((cl - ncards) < 1) && (r.nextInt(10) > 4))
                   {
                      setTargetPlayer(Constant.Player.Computer);
                      return true;
                   }
                 
                   return false;
                }

                public void resolve()
                {
                   ncards = getNumCards();

                   String TgtPlayer = card.getController();
                   if (Tgt[0])
                      TgtPlayer = getTargetPlayer();

                   for (int i=0; i < ncards; i++)
                      AllZone.GameAction.drawCard(TgtPlayer);

                   if (! DrawBack[0].equals("none"))
                      CardFactoryUtil.doDrawBack(DrawBack[0], ncards, card.getController(), AllZone.GameAction.getOpponent(card.getController()), TgtPlayer, card, null);
                }
           };
           
           abDraw.setDescription(spDesc[0]);
           abDraw.setStackDescription(stDesc[0]);
           
           if (!tapOnlyCost)
              abDraw.setManaCost(manaCost);
           
           if (Tgt[0] == true)
              abDraw.setBeforePayMana(CardFactoryUtil.input_targetPlayer(abDraw));
              
           card.addSpellAbility(abDraw);
        }//tapCost
    }
Also, changed CardFacotryUtil.input_TargetPlayer sligtly:
Code: Select all
          this.setFree(false);
          AllZone.Stack.add(spell);
          if (spell.isTapAbility())
             spell.getSourceCard().tap();
          stop();
I added the check for isTapAbility, instead of adding a copy-paste job JUST for this variant. input_TargetCreature has a few forms, and I don't think they're all necessary.
I added this after finding that cephalid broker wasn't tapping when playing the ability, but non targeted a cards were tapping as expected. I didn't expect the input portion of code was responsible for tapping the card... I would've thought that it would be tapped by the code that actually selects and plays the ability....
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: abDrawCards[Tgt]

Postby Rob Cashwalker » 20 Feb 2010, 15:58

Nope.

I went through pretty much all of them, and only posted the ones that could be handled without some serious difficulty. I also don't include cards where timing restrictions would be impossible for the computer to play, like when an effect involves attacking (creatures) or blocking (creatures).

I also don't include cards that can't be implemented purely with existing keywords. When other keywords are created, then I'll be going through the same process, and the cards I skip now, might be included later.

The only ones that I'm on the fence about, are any abilities where sacrifice is a cost. I had a bit of an epiphany last night, where I realized there might be a simple way I could add sac costs to just about all of the abilities.
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: abDrawCards[Tgt]

Postby Marek14 » 20 Feb 2010, 16:27

Rob Cashwalker wrote:Nope.

I went through pretty much all of them, and only posted the ones that could be handled without some serious difficulty. I also don't include cards where timing restrictions would be impossible for the computer to play, like when an effect involves attacking (creatures) or blocking (creatures).

I also don't include cards that can't be implemented purely with existing keywords. When other keywords are created, then I'll be going through the same process, and the cards I skip now, might be included later.

The only ones that I'm on the fence about, are any abilities where sacrifice is a cost. I had a bit of an epiphany last night, where I realized there might be a simple way I could add sac costs to just about all of the abilities.
Not even Ocular Halo? That one just grants T: Draw a card, and has an activated ability to grant a keyword...
Marek14
Tester
 
Posts: 2773
Joined: 07 Jun 2008, 07:54
Has thanked: 0 time
Been thanked: 303 times

Re: abDrawCards[Tgt]

Postby DennisBergkamp » 20 Feb 2010, 18:57

I think that's a case that wouldn't work, some of the keywords you can't add in like that because they are not parsed dynamically (giving the regenerateMe:{cost} keyword to a creature in game wouldn't do anything either).
User avatar
DennisBergkamp
AI Programmer
 
Posts: 2602
Joined: 09 Sep 2008, 15:46
Has thanked: 0 time
Been thanked: 0 time

Re: abDrawCards[Tgt]

Postby Rob Cashwalker » 21 Feb 2010, 04:29

One of these days, we'll get around to completely reworking the keyword -> ability relationship by making an AbilityFactory. Then things like that will be easier to implement.
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


Return to Developer's Corner

Who is online

Users browsing this forum: No registered users and 38 guests

Main Menu

User Menu

Our Partners


Who is online

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

Login Form