It is currently 07 Sep 2025, 17:13
   
Text Size

spPumpTgt Revision

Post MTG Forge Related Programming Questions Here

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

Re: spPumpTgt Revision

Postby slapshot5 » 10 Apr 2010, 23:54

Is there a difference in syntax between spPumpTgt and enPump with respect to using "&" for multiple abilities?

Take for example, Wings of Aeshtir:

Code: Select all
Wings of Aesthir
W U
Enchantment Aura
Enchanted creature gets +1/+0 and has flying and first strike.
Enchant creature
enPump:+1/+0/Flying & First Strike
one could then reasonably assume that Daring Leap could be written as:

Code: Select all
Daring Leap
1 W U
Instant
no text
spPumpTgt:+1/+1/Flying & First Strike
But that does not work. It gives the creature +1/+1 correctly, but it gets "Flying & First Strike".

I admittedly haven't looked into this much, but perhaps parsing of "&" delimited strings isn't part of spPumpTgt?

-slapshot5
slapshot5
Programmer
 
Posts: 1391
Joined: 03 Jan 2010, 17:47
Location: Mac OS X
Has thanked: 25 times
Been thanked: 68 times

Re: spPumpTgt Revision

Postby Chris H. » 11 Apr 2010, 00:06

slapshot5 wrote:Is there a difference in syntax between spPumpTgt and enPump with respect to using "&" for multiple abilities?

Take for example, Wings of Aeshtir:

Code: Select all
Wings of Aesthir
W U
Enchantment Aura
Enchanted creature gets +1/+0 and has flying and first strike.
Enchant creature
enPump:+1/+0/Flying & First Strike
one could then reasonably assume that Daring Leap could be written as:

Code: Select all
Daring Leap
1 W U
Instant
no text
spPumpTgt:+1/+1/Flying & First Strike
But that does not work. It gives the creature +1/+1 correctly, but it gets "Flying & First Strike".

I admittedly haven't looked into this much, but perhaps parsing of "&" delimited strings isn't part of spPumpTgt?
`
Keywords are an ongoing and evolving sort of system. The "&" is a very recent addition and Rob is planning to add it to spPump[Tgt]. He mentioned recently that this would allow several more cards. :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: spPumpTgt Revision

Postby Rob Cashwalker » 29 Apr 2010, 02:32

OK, so Daring Leap is a go!

Had a few false starts, as I tried to figure out the best way to separately handle a list of keywords, versus a single keyword. Also looked into making the addExtrinsicKeyword handle the split, which would require almost no change to any type of pump code.

In the end, I found that it was easier to leave the "&" delimited string as-is as long as possible, until adding each ExtrinsicKeyword in the resolve method. To build the description, I used a secondary keyword string, which replaced the "&" with "," or "and" as necessary. ("Flying & First Strike" -> "Flying and First Strike" and "Fear & First Strike & Flying" -> "Fear, First Strike and Flying")

I just uploaded a few revisions to the SVN.

CardFactory.java
Code: Select all
        if(hasKeyword(card, "spPumpTgt") != -1) {
            int n = hasKeyword(card, "spPumpTgt");
           
            String parse = card.getKeyword().get(n).toString();
            card.removeIntrinsicKeyword(parse);
           
            String k[] = parse.split(":");
           
            final int NumAttack[] = {-1138};
            final String AttackX[] = {"none"};
            final int NumDefense[] = {-1138};
            final String DefenseX[] = {"none"};
            final String Keyword[] = {"none"};
           
            String ptk[] = k[1].split("/");
           
            if(ptk.length == 1) Keyword[0] = ptk[0];
           
            if(ptk.length >= 2) {
                if(ptk[0].matches("[\\+\\-][XY]")) {
                    String xy = card.getSVar(ptk[0].replaceAll("[\\+\\-]", ""));
                    if(xy.startsWith("Count$")) {
                        String kk[] = xy.split("\\$");
                        AttackX[0] = kk[1];
                       
                        if(ptk[0].contains("-")) if(AttackX[0].contains("/")) AttackX[0] = AttackX[0].replace("/",
                                "/Negative");
                        else AttackX[0] += "/Negative";
                    }
                } else if(ptk[0].matches("[\\+\\-][0-9]")) NumAttack[0] = Integer.parseInt(ptk[0].replace("+", ""));
               
                if(ptk[1].matches("[\\+\\-][XY]")) {
                    String xy = card.getSVar(ptk[1].replaceAll("[\\+\\-]", ""));
                    if(xy.startsWith("Count$")) {
                        String kk[] = xy.split("\\$");
                        DefenseX[0] = kk[1];
                       
                        if(ptk[1].contains("-")) if(DefenseX[0].contains("/")) DefenseX[0] = DefenseX[0].replace(
                                "/", "/Negative");
                        else DefenseX[0] += "/Negative";
                    }
                } else if(ptk[1].matches("[\\+\\-][0-9]")) NumDefense[0] = Integer.parseInt(ptk[1].replace("+", ""));
            }
           
            if(ptk.length == 3) Keyword[0] = ptk[2];
                       
            String dK = Keyword[0];
            if (Keyword[0].contains(" & "))
            {
               int amp = Keyword[0].lastIndexOf("&");
               StringBuffer sbk = new StringBuffer(Keyword[0]);
               sbk.replace(amp, amp + 1, "and");
               dK = sbk.toString();
               dK = dK.replace(" & ", ", ");
            }
           
            final String DrawBack[] = {"none"};
            final String spDesc[] = {"none"};
            final String stDesc[] = {"none"};
            //String d = new String("none");
            StringBuilder sb = new StringBuilder();
           
            if((AttackX[0].equals("none") && !(NumAttack[0] == -1138))
                    && (DefenseX[0].equals("none") && !(NumDefense[0] == -1138)) && Keyword[0].equals("none")) {
                // pt boost
                sb.append("Target creature gets ");
               
                if(NumAttack[0] > 0 || (NumAttack[0] == 0 && NumDefense[0] > 0)) // +0/+1
                sb.append("+");
                else if(NumAttack[0] < 0 || (NumAttack[0] == 0 && NumDefense[0] < 0)) // -0/-1
                sb.append("-");
               
                sb.append(Math.abs(NumAttack[0]) + "/");
               
                if(NumDefense[0] > 0 || (NumDefense[0] == 0 && NumAttack[0] > 0)) // +1/+0
                sb.append("+");
                else if(NumDefense[0] < 0 || (NumDefense[0] == 0 && NumAttack[0] < 0)) // -1/-0
                sb.append("-");
               
                sb.append(Math.abs(NumDefense[0]) + " until end of turn.");
            }
            if((AttackX[0].equals("none") && NumAttack[0] == -1138)
                    && (DefenseX[0].equals("none") && NumDefense[0] == -1138) && !Keyword[0].equals("none")) {
                // k boost
                sb.append("Target creature gains " + dK + " until end of turn.");
            }
            if((AttackX[0].equals("none") && !(NumAttack[0] == -1138))
                    && (DefenseX[0].equals("none") && !(NumDefense[0] == -1138)) && !Keyword[0].equals("none")) {
                // ptk boost
                sb.append("Target creature gets ");
               
                if(NumAttack[0] > 0 || (NumAttack[0] == 0 && NumDefense[0] > 0)) // +0/+1
                sb.append("+");
                else if(NumAttack[0] < 0 || (NumAttack[0] == 0 && NumDefense[0] < 0)) // -0/-1
                sb.append("-");
               
                sb.append(Math.abs(NumAttack[0]) + "/");
               
                if(NumDefense[0] > 0 || (NumDefense[0] == 0 && NumAttack[0] > 0)) // +1/+0
                sb.append("+");
                else if(NumDefense[0] < 0 || (NumDefense[0] == 0 && NumAttack[0] < 0)) // -1/-0
                sb.append("-");
               
                sb.append(Math.abs(NumDefense[0]));
               
                sb.append(" and gains " + dK + " until end of turn.");
            }
           
            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];
                }
            } else if(!sb.toString().equals("none")) {
                spDesc[0] = sb.toString();
                stDesc[0] = sb.toString();
            }
           

            SpellAbility spPump = new Spell(card) {
                private static final long serialVersionUID = 42244224L;
               
                private int getNumAttack() {
                    if(NumAttack[0] != -1138) return NumAttack[0];
                   
                    if(!AttackX[0].equals("none")) return CardFactoryUtil.xCount(card, AttackX[0]);
                   
                    return 0;
                }
               
                private int getNumDefense() {
                    if(NumDefense[0] != -1138) return NumDefense[0];
                   
                    if(!DefenseX[0].equals("none")) return CardFactoryUtil.xCount(card, DefenseX[0]);
                   
                    return 0;
                }
               
                @Override
                public boolean canPlayAI() {
                    int defense = getNumDefense();
                   
                    if(AllZone.Phase.getPhase().equals(Constant.Phase.Main2)) return false;
                   
                    CardList list = getCreatures();
                    if(!list.isEmpty()) {
                        boolean goodt = false;
                        Card t = new Card();
                        while(goodt == false && !list.isEmpty()) {
                            t = CardFactoryUtil.AI_getBestCreature(list);
                            if((t.getNetDefense() + defense) > 0) goodt = true;
                            else list.remove(t);
                        }
                        if(goodt == true) {
                            setTargetCard(t);
                            return true;
                        }
                    }
                   
                    return false;
                }
               
                CardList getCreatures() {
                    CardList list = new CardList(AllZone.Computer_Play.getCards());
                    list = list.filter(new CardListFilter() {
                        public boolean addCard(Card c) {
                            if(c.isCreature()) {
                                if(c.hasSickness() && Keyword[0].contains("Haste"))
                                   return CardFactoryUtil.canTarget(card, c);
                               
                                return (CardFactoryUtil.AI_doesCreatureAttack(c))
                                        && (CardFactoryUtil.canTarget(card, c))
                                        && (!Keyword[0].equals("none") && !c.hasAnyKeyword(Keyword[0].split(" & ")))
                                        && (!(!c.hasSickness()) && Keyword[0].contains("Haste"));
                               
                            }
                            return false;
                        }
                    });
                    return list;
                }
               
                @Override
                public void resolve() {
                    if(AllZone.GameAction.isCardInPlay(getTargetCard())
                            && CardFactoryUtil.canTarget(card, getTargetCard())) {
                        final Card[] creature = new Card[1];
                        creature[0] = getTargetCard();
                       
                        final int a = getNumAttack();
                        final int d = getNumDefense();
                       
                        final Command untilEOT = new Command() {
                            private static final long serialVersionUID = -42244224L;
                           
                            public void execute() {
                                if(AllZone.GameAction.isCardInPlay(creature[0])) {
                                    creature[0].addTempAttackBoost(-1 * a);
                                    creature[0].addTempDefenseBoost(-1 * d);
                                   
                                    if(!Keyword[0].equals("none"))
                                    {
                                       String[] kws = Keyword[0].split(" & ");
                                       for (int i=0; i<kws.length; i++)
                                          creature[0].removeExtrinsicKeyword(kws[i]);   
                                    }
                                       
                                }
                            }
                        };
                       
                        creature[0].addTempAttackBoost(a);
                        creature[0].addTempDefenseBoost(d);
                        if(!Keyword[0].equals("none"))
                        {
                           String[] kws = Keyword[0].split(" & ");
                           for (int i=0; i<kws.length; i++)
                              creature[0].addExtrinsicKeyword(kws[i]);
                        }
                       
                        AllZone.EndOfTurn.addUntil(untilEOT);
                       
                        if(!DrawBack[0].equals("none")) CardFactoryUtil.doDrawBack(DrawBack[0], 0,
                                card.getController(), AllZone.GameAction.getOpponent(card.getController()),
                                creature[0].getController(), card, creature[0]);
                    }
                }//resolve
            };//SpellAbility
           
            spPump.setBeforePayMana(CardFactoryUtil.input_targetCreature(spPump));
            spPump.setDescription(spDesc[0]);
            spPump.setStackDescription(stDesc[0]);
           
            card.clearSpellAbility();
            card.addSpellAbility(spPump);
        }
Card.java
Code: Select all
   public boolean hasKeyword(String keyword)
   {
      return getKeyword().contains(keyword);
   }
   
   public boolean hasAnyKeyword(String keywords[])
   {
      for (int i=0; i<keywords.length; i++)
         if (hasKeyword(keywords[i]))
            return true;
      
      return false;
   }
The Card.hasKeyword is distinctly different from the CardFactory.hasKeyword. And hasAnyKeyword is specifically useful for this situation, where the AI would play a multi keyword pump on a creature that has none of the keywords already.
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: spPumpTgt Revision

Postby Chris H. » 29 Apr 2010, 10:27

Thank you, Rob. I just updated the keyword listing with this newest rev. The keyword listing has gone through almost as many updates in the last several weeks as Forge itself.

Looks like the next release will have quite a few new keywords. :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: spPumpTgt Revision

Postby Sloth » 12 Sep 2010, 21:03

I just added the option Curse to this keyword (like enPumpCurse).

When the toughness gets lowered, the AI will only play the spell to kill a creature, otherwise it will always play the spell on the best human creature (not very efficient).

Sample:
Code: Select all
Disfigure
B
Instant
no text
spPumpTgtCurse:-2/-2
User avatar
Sloth
Programmer
 
Posts: 3498
Joined: 23 Jun 2009, 19:40
Has thanked: 125 times
Been thanked: 507 times

Re: spPumpTgt Revision

Postby Chris H. » 12 Sep 2010, 21:33

Sloth wrote:I just added the option Curse to this keyword (like enPumpCurse).

When the toughness gets lowered, the AI will only play the spell to kill a creature, otherwise it will always play the spell on the best human creature (not very efficient).
`
I seem to remember a card was recently added that used the spPumpTgt varient, can't remember the name off the top of my head. I just did a search and found Disorient in the cards.txt file. I guess that it should be changed to spPumpTgtCurse.
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

Previous

Return to Developer's Corner

Who is online

Users browsing this forum: No registered users and 37 guests

Main Menu

User Menu

Our Partners


Who is online

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

Login Form