It is currently 29 Aug 2025, 13:53
   
Text Size

spDiscard[Tgt|Opp]

Post MTG Forge Related Programming Questions Here

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

spDiscard[Tgt|Opp]

Postby Rob Cashwalker » 09 Jul 2010, 11:49

Finally assembled this keyword.. I had begun working on it a couple months ago.

Right now it only handles basic discards, where the targeted player or opponent chooses. The reveal and choose type are next, and will be part of the same keyword.

Syntax:
Code: Select all
spDiscard[Tgt|Opp]:[TgtChoose|OppChoose|AtRandom|Hand]:<numCards>:<Drawback:Spell Description:StackDescription>
When using "Hand" as the discard method, the number of cards may be 0 or any number... because it's ignored.
Code: Select all
        if (hasKeyword(card, "spDiscard") != -1)
        {
           int n = hasKeyword(card, "spDiscard");
           
           String parse = card.getKeyword().get(n).toString();
           card.removeIntrinsicKeyword(parse);
           
           String k[] = parse.split(":");
           final boolean Tgt = k[0].contains("Tgt");
           final boolean Opp = k[0].contains("Opp");
           
           final String DiscardMethod = k[1];
           
           final int NumCards[] = {-1138};
           final String NumCardsX[] = {"none"};
           final String UnlessType[] = {"none"};
           
           if (k[2].length() > 1)
           {
              String kk[] = k[2].split("/");
              if (kk[1].startsWith("UnlessDiscardType"))
              {
                 String jk[] = kk[1].split("\\.");
                 UnlessType[0] = jk[1];
              }
           }
           else if (k[2].matches("X"))
           {
             String xy = card.getSVar(k[2]);
             if (xy.startsWith("Count$"))
             {
                String kk[] = xy.split("\\$");
                NumCardsX[0] = kk[1];
             }
           }
           else if (k[2].matches("[0-9]"))
           {
              NumCards[0] = Integer.parseInt(k[2]);
           }
           
           
           final String Drawback[] = {"none"};
           final String spDesc[] = {"none"};
           final String stDesc[] = {"none"};
           
          if (k[3].contains("Drawback$"))
          {
             String kk[] = k[3].split("\\$");
             Drawback[0] = kk[1];
             if (k.length > 4) spDesc[0] = k[4];
             if (k.length > 5) stDesc[0] = k[5];
          }
          else
          {
             if (k.length > 3) spDesc[0] = k[3];
             if (k.length > 4) stDesc[0] = k[4];
          }
          
           SpellAbility spDiscard = new Spell(card)
           {
              private static final long serialVersionUID = 837472987492L;
              
                private int getNumCards() {
                    if(NumCards[0] != -1138) return NumCards[0];
                   
                    if(!NumCardsX[0].equals("none")) return CardFactoryUtil.xCount(card, NumCardsX[0]);
                   
                    return 0;
                }
               
                public boolean canPlayAI()
                {
                   int nCards = getNumCards();
                   
                   PlayerZone pzH = AllZone.getZone(Constant.Zone.Hand, Constant.Player.Human);
                   int numHHand = pzH.size();
                   
                   if (numHHand > (nCards - 1))
                      return true;
                      
                   return false;
                }
                public void resolve()
                {
                   int nCards = getNumCards();
                   
                   if (DiscardMethod.equals("OppChoose"))
                   {
                      String opp = AllZone.GameAction.getOpponent(card.getController());
                      
                      if (!UnlessType[0].equals("none"))
                         AllZone.GameAction.discardUnless(opp, nCards, UnlessType[0]);
                      else
                         AllZone.GameAction.discard(opp, nCards);
                   }
                   else if (DiscardMethod.equals("TgtChoose"))
                   {
                      if (!UnlessType[0].equals("none"))
                         AllZone.GameAction.discardUnless(getTargetPlayer(), nCards, UnlessType[0]);
                      else
                         AllZone.GameAction.discard(getTargetPlayer(), nCards);
                   }
                   else if (DiscardMethod.equals("AtRandom"))
                   {
                      AllZone.GameAction.discardRandom(getTargetPlayer(), nCards);
                   }
                   else if (DiscardMethod.equals("Hand"))
                   {
                      AllZone.GameAction.discardHand(getTargetPlayer());
                   }
                   
                   if (!Drawback[0].equals("none"))
                   {
                      CardFactoryUtil.doDrawBack(Drawback[0], 0, card.getController(), AllZone.GameAction.getOpponent(card.getController()), card.getController(), card, card);
                   }
                }
           };
           
           if (Tgt)
              spDiscard.setBeforePayMana(CardFactoryUtil.input_targetPlayer(spDiscard));
           else
              spDiscard.setTargetPlayer(AllZone.GameAction.getOpponent(card.getController()));
           
           spDiscard.setDescription(spDesc[0]);
           spDiscard.setStackDescription(stDesc[0]);
           
           card.clearSpellAbility();
           card.addSpellAbility(spDiscard);
           
            String bbCost = card.getSVar("Buyback");
            if (!bbCost.equals(""))
            {
               SpellAbility bbDiscardTgt = spDiscard.copy();
               bbDiscardTgt.setManaCost(CardUtil.addManaCosts(card.getManaCost(), bbCost));
               bbDiscardTgt.setDescription("Buyback " + bbCost + "(You may pay an additional " + bbCost + " as you cast this spell. If you do, put this card into your hand as it resolves.)");
               bbDiscardTgt.setIsBuyBackAbility(true);
               
               if (Tgt)
                  bbDiscardTgt.setBeforePayMana(CardFactoryUtil.input_targetPlayer(bbDiscardTgt));
               else
                  bbDiscardTgt.setTargetPlayer(AllZone.GameAction.getOpponent(card.getController()));
               
               card.addSpellAbility(bbDiscardTgt);
            }

        }//spDiscardTgt
Code: Select all
Unnerve
3 B
Sorcery
no text
spDiscardOpp:OppChoose:2:Each opponent discards two cards.:Unnerve - opponent discards cards

Wheel and Deal
3 U
Instant
no text
spDiscardOpp:Hand:0:Drawback$OppDraw/7:Any number of target opponents each discards his or her hand and draws seven cards.:Wheel and Deal - target player discards cards
Draw a card.

Stupor
2 B
Sorcery
no text
spDiscardOpp:AtRandom:1:Drawback$OppDiscard/1:Target opponent discards a card at random, then discards a card.:Stupor - opponent discards cards

Mind Knives
1 B
Sorcery
no text
spDiscardOpp:AtRandom:1:Target opponent discards a card at random.:Mind Knives - opponent discards cards

Deception
2 B
Sorcery
no text
spDiscardOpp:OppChoose:2:Target opponent discards two cards.:Deception - opponent discards cards

Wit's End
5 B B
Sorcery
no text
spDiscardTgt:Hand:0:Target player discards his or her hand.:Wit's End - target player discards cards

Waking Nightmare
2 B
Sorcery Arcane
no text
spDiscardTgt:TgtChoose:2:Target player discards two cards.:Waking Nightmare - target player discards cards

Voices from the Void
4 B
Sorcery
no text
spDiscardTgt:TgtChoose:X:Domain - Target player discards a card for each basic land type among lands you control.:Voices from the Void - target player discards cards

Unhinge
2 B
Sorcery
no text
spDiscardTgt:TgtChoose:1:Target player discards a card.:Unhinge - target player discards a card
Draw a card.

Unburden
1 B B
Sorcery
no text
spDiscardTgt:TgtChoose:2:Target player discards two cards.:Unburden - target player discards cards
Cycling:2

Three Tragedies
3 B B
Sorcery Arcane
no text
spDiscardTgt:TgtChoose:3:Target player discards three cards.:Three Tragedies - target player discards cards

Specter's Wail
1 B
Sorcery
no text
spDiscardTgt:AtRandom:1:Target player discards a card at random.:Specter's Wail - target player discards a card

Mind Twist
X B
Sorcery
no text
spDiscardTgt:AtRandom:X:Target player discards X cards at random.:Mind Twist - target player discards cards
SVar:X:Count$xPaid

Mind Sludge
4 B
Sorcery
no text
spDiscardTgt:TgtChoose:X:Target player discards a card for each Swamp you control.:Mind Sludge - target player discards cards
SVar:X:Count$TypeYouCtrl.Swamp

Mind Shatter
X B B
Sorcery
spDiscardTgt:AtRandom:X:Target player discards X cards at random.:Mind Shatter - target player discards cards
SVar:X:Count$xPaid

Mind Rot
2 B
Sorcery
no text
spDiscardTgt:TgtChoose:2:Target player discards two cards.:Mind Rot - target player discards cards

Mind Peel
B
Sorcery
no text
spDiscardTgt:1:Target player discards a card.:Mind Peel - target player discards a card
SVar:Buyback:2 B B

Mind Burst
1 B
Sorcery
no text
spDiscardTgt:TgtChoose:X:Target player discards X cards, where X is one plus the number of cards named Mind Burst in all graveyards.:Mind Burst - target player discards cards
SVar:X:Count$NamedInAllYards.Mind Burst/Plus.1

Hymn to Tourach
B B
Sorcery
no text
spDiscardTgt:AtRandom:2:Target player discards two cards at random.:Hymn to Tourach - target player discards cards

Haunting Hymn
4 B B
Instant
no text
spDiscardTgt:TgtChoose:X:Target player discards two cards. If you cast this spell during your main phase, that player discards four cards instead.:Haunting Hymn - target player discards cards
SVar:X:Count$IfMainPhase.4.2

Fugue
3 B B
Sorcery
no text
spDiscardTgt:TgtChoose:3:Target player discards three cards.:Fugue - target player discards cards

Forget
U U
Sorcery
no text
spDiscardTgt:TgtChoose:2:Drawback$TgtDraw/2:Target player discards two cards, then draws as many cards as he or she discarded this way.:Forget - target player discards cards

Fill with Fright
3 B
Sorcery
no text
spDiscardTgt:TgtChoose:2:Target player discards two cards.:Fill with Fright - target player discards cards
Scry 2

Wrench Mind
B B
Sorcery
no text
spDiscardTgt:TgtChoose:2/UnlessDiscardType.Artifact:Target player discards two cards unless he or she discards an artifact card.:Wrench Mind - target player discards cards

Surging Dementia
1 B
Sorcery
no text
spDiscardTgt:TgtChoose:1:Target player discards a card.:Surging Dementia - Target player discards a card.
Ripple:4
Surging Dementia was the only one already implemented. Someone got clever with the spDamage keyword, using it with 0 damage and a Drawback of Discard.
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: spDiscard[Tgt|Opp]

Postby Sloth » 09 Jul 2010, 13:10

You're version of Forget seems to allow a player to draw two cards if it is the last card in his hand. This should not be possible with the oracle wording.

Syphon Mind has the same problem.
User avatar
Sloth
Programmer
 
Posts: 3498
Joined: 23 Jun 2009, 19:40
Has thanked: 125 times
Been thanked: 507 times

Re: spDiscard[Tgt|Opp]

Postby Rob Cashwalker » 09 Jul 2010, 13:57

good catch. Forget about Forget.
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: spDiscard[Tgt|Opp]

Postby Chris H. » 09 Jul 2010, 14:24

I merged my local copy up to r1390 and noticed a warning in CardFactory.java. The local variable Opp is never read. This is line 468.

Code: Select all
        if (hasKeyword(card, "spDiscard") != -1)
        {
           int n = hasKeyword(card, "spDiscard");
           
           String parse = card.getKeyword().get(n).toString();
           card.removeIntrinsicKeyword(parse);
           
           String k[] = parse.split(":");
           final boolean Tgt = k[0].contains("Tgt");
           final boolean Opp = k[0].contains("Opp");
`
Some of the cards you list use the Opp rather than the Tgt in k[0] … so I wild hold off on adding new cards or converting over the existing cards for the moment.
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: spDiscard[Tgt|Opp]

Postby Rob Cashwalker » 09 Jul 2010, 15:25

No, go ahead with it. The "Opp" flag may become useful for the next stage.
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: spDiscard[Tgt|Opp]

Postby friarsol » 09 Jul 2010, 16:14

Could this keyword also work for "(You) Discard a card" as a cost? With Self as an option for the target. This could work great for spellshapers.

It may be easier for parsing to have the keyword just be spDiscard and let the first parameter be who is discarding.

Ex.
spDiscard:[Tgt|Opp|(Self)]:[TgtChoose|OppChoose|AtRandom|Hand]:<numCards>:<Drawback:Spell Description:StackDescription>

As for the second parameter, what is the difference betwen TgtChoose and OppChoose? It seems they might be "Discarding player chooses" and "Opponent of discarding player chooses". Maybe they can be clarified to OwnerChoose and OpponentChoose?

Although, I feel like that still may be confusing since the Opponent in the first parameter is different than the Opponent in the second parameter. Unless I'm confused myself.
friarsol
Global Moderator
 
Posts: 7593
Joined: 15 May 2010, 04:20
Has thanked: 243 times
Been thanked: 965 times

Re: spDiscard[Tgt|Opp]

Postby Rob Cashwalker » 09 Jul 2010, 16:27

No, discarding as a cost should be done as a cost. The AI for this assumes the intention is to make the player discard. Discarding as a cost should have AI that doesn't so much care about the discarding, more about the ultimate effect.
Same goes for how using "spDamageTgtP:0:Drawback$TgtDiscard:1" achieves the mechanical effect of "target player discards a card". However the AI for it assumes it's trying to deal damage to the player, so it would likely play the spell (if the AI calculation using zero damage even gets that far) even when the player had no cards in hand.

Tgt goes with TgtChoose and Opp goes with OppChoose. They're distinct effects - you could choose yourself if it's "target player" but not if it's "target opponent". However, we could probably drop the OppChoose, because the target player is set specifically to the opponent if not Tgt.
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: spDiscard[Tgt|Opp]

Postby Chris H. » 09 Jul 2010, 16:29

Rob Cashwalker wrote:No, go ahead with it. The "Opp" flag may become useful for the next stage.
`
OK, no prob. I will add the cards and pic urls. Several cards will need to be converted. While I am at it I will put in a suppress warning. :D
User avatar
Chris H.
Forge Moderator
 
Posts: 6320
Joined: 04 Nov 2008, 12:11
Location: Mac OS X Yosemite
Has thanked: 644 times
Been thanked: 643 times

Re: spDiscard[Tgt|Opp]

Postby friarsol » 09 Jul 2010, 16:34

Rob Cashwalker wrote:Tgt goes with TgtChoose and Opp goes with OppChoose. They're distinct effects - you could choose yourself if it's "target player" but not if it's "target opponent". However, we could probably drop the OppChoose, because the target player is set specifically to the opponent if not Tgt.
Ok, so this currently wouldn't handle a card like Coercion, because the Caster is the one who chooses (and not the target)?
friarsol
Global Moderator
 
Posts: 7593
Joined: 15 May 2010, 04:20
Has thanked: 243 times
Been thanked: 965 times

Re: spDiscard[Tgt|Opp]

Postby Rob Cashwalker » 09 Jul 2010, 16:48

Right... RevealYouChoose will be the next method implemented.
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: spDiscard[Tgt|Opp]

Postby Chris H. » 09 Jul 2010, 17:00

The cards.txt entries that use the spDiscardOpp form of the keyword are causing a null error.

Code: Select all
An error has occured. You can copy/paste this message or save it to a file.
Please report this, plus what you tried to do, to:
   http://www.slightlymagic.net/forum/viewforum.php?f=26
If you don't want to register an account, you can mail it directly to
   mtgerror@yahoo.com


null


Version:
Forge -- official beta: $Date: 2010-05-01 03:21:42 -0400 (Sat, 01 May 2010) $, SVN revision: $Revision: 916 $

OS: Mac OS X Version: 10.6.4 Architecture: x86_64

Java Version: 1.6.0_20 Vendor: Apple Inc.

Detailed error trace:
java.lang.NullPointerException
   at forge.CardFactory.getCard2(CardFactory.java:580)
   at forge.CardFactory.getCard(CardFactory.java:220)
   at forge.CardFactory.<init>(CardFactory.java:67)
   at forge.AllZone.<clinit>(AllZone.java:22)
   at forge.Gui_NewGame.main(Gui_NewGame.java:131)
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: spDiscard[Tgt|Opp]

Postby Rob Cashwalker » 09 Jul 2010, 19:05

Hmm...

When the card's being created it has no controller... duh.

fixed it in r.1393

Plus, I make use of Opp, so no more warning.
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: spDiscard[Tgt|Opp]

Postby Chris H. » 09 Jul 2010, 21:45

Thank you Rob.

I will merge in the new code and will then run a test to see if I am still having trouble adding Mind Peel. Mind Peel gave me an error in reference to the mana cost of the SVar Buyback:

Mind Peel
B
Sorcery
no text
spDiscardTgt:TgtChoose:1:Target player discards a card.:Mind Peel - target player discards a card
SVar:Buyback:2 B B

Code: Select all
An error has occured. You can copy/paste this message or save it to a file.
Please report this, plus what you tried to do, to:
   http://www.slightlymagic.net/forum/viewforum.php?f=26
If you don't want to register an account, you can mail it directly to
   mtgerror@yahoo.com


For input string: ""


Version:
Forge -- official beta: $Date: 2010-05-01 03:21:42 -0400 (Sat, 01 May 2010) $, SVN revision: $Revision: 916 $

OS: Mac OS X Version: 10.6.4 Architecture: x86_64

Java Version: 1.6.0_20 Vendor: Apple Inc.

Detailed error trace:
java.lang.NumberFormatException: For input string: ""
   at java.lang.NumberFormatException.forInputString(NumberFormatException.java:48)
   at java.lang.Integer.parseInt(Integer.java:470)
   at java.lang.Integer.valueOf(Integer.java:554)
   at forge.CardUtil.addManaCosts(CardUtil.java:244)
   at forge.CardFactory.getCard2(CardFactory.java:592)
   at forge.CardFactory.getCard(CardFactory.java:220)
   at forge.CardFactory.<init>(CardFactory.java:67)
   at forge.AllZone.<clinit>(AllZone.java:22)
   at forge.Gui_NewGame.main(Gui_NewGame.java:131)
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: spDiscard[Tgt|Opp]

Postby Chris H. » 10 Jul 2010, 12:01

I converted the 5 existing cards from code based to keyword-ed and they have been merged. All but 2 of the new cards have also been merged. So, all of the cards listed have been taken care of except for:

Forget
Mind Peel
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: spDiscard[Tgt|Opp]

Postby Rob Cashwalker » 10 Jul 2010, 16:44

I fixed the addManaCosts method to correctly handle adding a mana cost with no numeric component. Mind Peel costs B, so Integer.valueOf("") apparantly is the number format exception.... In VB Val("") is 0.
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

Next

Return to Developer's Corner

Who is online

Users browsing this forum: No registered users and 29 guests

Main Menu

User Menu

Our Partners


Who is online

In total there are 29 users online :: 0 registered, 0 hidden and 29 guests (based on users active over the past 10 minutes)
Most users ever online was 7303 on 15 Jul 2025, 20:46

Users browsing this forum: No registered users and 29 guests

Login Form