It is currently 09 Sep 2025, 18:19
   
Text Size

New keyword: spBounceTgt

Post MTG Forge Related Programming Questions Here

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

New keyword: spBounceTgt

Postby Sloth » 29 Jul 2010, 18:42

I just made my first keyword: spBounceTgt

It is mostly just a copy of spDestroyTgt:

Code: Select all
// Generic bounce target card
        if(hasKeyword(card, "spBounceTgt") != -1) {
            int n = hasKeyword(card, "spBounceTgt");
           
            String parse = card.getKeyword().get(n).toString();
            card.removeIntrinsicKeyword(parse);
           
            String k[] = parse.split(":");
            String Targets = k[1]; // Artifact, Creature, Enchantment, Land, Permanent, White, Blue, Black, Red, Green, Colorless, MultiColor
            // non-Artifact, non-Creature, non-Enchantment, non-Land, non-Permanent,
            //non-White, non-Blue, non-Black, non-Red, non-Green, non-Colorless, non-MultiColor
            final String Tgts[] = Targets.split(",");
           
            String tmpDesc = card.getText().substring(15);
            int i = tmpDesc.indexOf(".");
            tmpDesc = tmpDesc.substring(0, i);
            final String Selec = "Select target " + tmpDesc + " to return to owners hand.";
                       
            card.clearSpellAbility();
           
            final SpellAbility spBnceTgt = new Spell(card) {
                private static final long serialVersionUID = 152897134770L;
               
                @Override
                public boolean canPlayAI() {
                    CardList results = new CardList();
                    CardList choices = getTargets();
                   
                    choices = choices.filter(new CardListFilter(){
                       public boolean addCard(Card c)
                       {
                          return !c.getKeyword().contains("Shroud");
                       }
                    });
                   
                   
                    if(choices.size() > 0) {
                        for(int i = 0; i < Tgts.length; i++) {
                            if(Tgts[i].equals("Artifact")) {
                                if(CardFactoryUtil.AI_getBestArtifact(choices) != null) results.add(CardFactoryUtil.AI_getBestArtifact(choices));
                            } else if(Tgts[i].equals("Creature")) {
                                if(CardFactoryUtil.AI_getBestCreature(choices) != null) results.add(CardFactoryUtil.AI_getBestCreature(choices));
                            } else if(Tgts[i].equals("Enchantment")) {
                                if(CardFactoryUtil.AI_getBestEnchantment(choices, card, true) != null) results.add(CardFactoryUtil.AI_getBestEnchantment(
                                        choices, card, true));
                            } else if(Tgts[i].equals("Land")) {
                                if(CardFactoryUtil.AI_getBestLand(choices) != null) results.add(CardFactoryUtil.AI_getBestLand(choices));
                            } else if(Tgts[i].equals("Permanent")) {
                                if(CardFactoryUtil.AI_getMostExpensivePermanent(choices, card, true) != null) results.add(CardFactoryUtil.AI_getMostExpensivePermanent(
                                        choices, card, true));
                            }
                        }
                    }
                   
                    if(results.size() > 0) {
                        results.shuffle();
                        setTargetCard(results.get(0));
                        return true;
                    }
                    return false;
                }
               
                CardList getTargets() {
                    CardList tmpList = new CardList();
                    tmpList.addAll(AllZone.Human_Play.getCards());
                    tmpList = tmpList.filter(new CardListFilter() {
                        public boolean addCard(Card c) {
                            return (CardFactoryUtil.canTarget(card, c));
                        }
                    });
                   
                    return tmpList.getValidCards(Tgts);
                }
               
                @Override
                public void resolve() {
                    if(AllZone.GameAction.isCardInPlay(getTargetCard())
                            && CardFactoryUtil.canTarget(card, getTargetCard())) {
                           if(getTargetCard().isToken()) AllZone.getZone(getTargetCard()).remove(getTargetCard());
                           else {
                                  PlayerZone hand = AllZone.getZone(Constant.Zone.Hand, getTargetCard().getOwner());
                                  AllZone.GameAction.moveTo(hand, getTargetCard());
            }
                        }

                   
                }
            }; //SpBnceTgt

      Input InGetTarget = CardFactoryUtil.input_targetValid(spBnceTgt, Tgts, Selec);
               /*new Input() {
                private static final long serialVersionUID = -152897134770L;
               
                @Override
                public void showMessage() {
                    CardList allCards = new CardList();
                    allCards.addAll(AllZone.Human_Play.getCards());
                    allCards.addAll(AllZone.Computer_Play.getCards());
                    / *allCards.filter(new CardListFilter() {
                        public boolean addCard(Card c) {
                            return (CardFactoryUtil.canTarget(card, c));
                        }
                    });* ///Input_targetSpecific already checks for this
                   
                    CardList choices = allCards.getValidCards(Tgts);
                    boolean free = false;
                    if(this.isFree()) free = true;
                    stopSetNext(CardFactoryUtil.input_targetSpecific(spBnceTgt, choices, Selec, true, free));
                }
            };*///InGetTarget
           
            //card.clearSpellAbility();
           
            card.setSVar("PlayMain1", "TRUE");
           
            spBnceTgt.setBeforePayMana(InGetTarget);
            spBnceTgt.setDescription(card.getText());
            card.setText("");
            card.addSpellAbility(spBnceTgt);
           
            String bbCost = card.getSVar("Buyback");
            if (!bbCost.equals(""))
            {
               SpellAbility bbBnceTgt = spBnceTgt.copy();
               bbBnceTgt.setManaCost(CardUtil.addManaCosts(card.getManaCost(), bbCost));
               bbBnceTgt.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.)");
               bbBnceTgt.setIsBuyBackAbility(true);
               
               bbBnceTgt.setBeforePayMana(CardFactoryUtil.input_targetValid(bbBnceTgt, Tgts, Selec));
               
               card.addSpellAbility(bbBnceTgt);
            }

        }//spBounceTgt
Do the more experienced coders have some suggestions how I should expand or improve the keyword?
User avatar
Sloth
Programmer
 
Posts: 3498
Joined: 23 Jun 2009, 19:40
Has thanked: 125 times
Been thanked: 507 times

Re: New keyword: spBounceTgt

Postby Rob Cashwalker » 29 Jul 2010, 21:49

Man.. I was gonna do that one....

I was going to revamp DestroyTgt, enabling Drawback$. Then when you copied it, it would already include it.

I would also include provision for different zones for the card to be bounced to.
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: New keyword: spBounceTgt

Postby Chris H. » 30 Jul 2010, 00:16

This line in the canPlayAI() method:

Code: Select all
return !c.getKeyword().contains("Shroud");
`
should be replaced with this line:

Code: Select all
return CardFactoryUtil.canTarget(card, c)
`
This way you are filtering out cards with both Shroud and Protection from {source card colors}.

I will remove the commented out cards from CardFactory tomorrow. We can then concentrate on converting the pre-existing bounce cards from implemented via code to keyword-ed. :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: New keyword: spBounceTgt

Postby Sloth » 30 Jul 2010, 06:21

Rob Cashwalker wrote:Man.. I was gonna do that one....
Sorry....

Rob Cashwalker wrote:I was going to revamp DestroyTgt, enabling Drawback$. Then when you copied it, it would already include it.
No problem, just do it. I'll try to update spBounceTgt or just copy the new version and start from that.

Rob Cashwalker wrote: I would also include provision for different zones for the card to be bounced to.
I added top of the library. I will try to add Exile. Are there any other zones?

Chris H. wrote:This line in the canPlayAI() method:

Code: Select all
return !c.getKeyword().contains("Shroud");
`
should be replaced with this line:

Code: Select all
return CardFactoryUtil.canTarget(card, c)
`
This way you are filtering out cards with both Shroud and Protection from {source card colors}.
Right I forgot about protection. I will replace the line.
User avatar
Sloth
Programmer
 
Posts: 3498
Joined: 23 Jun 2009, 19:40
Has thanked: 125 times
Been thanked: 507 times

Re: New keyword: spBounceTgt

Postby Rob Cashwalker » 30 Jul 2010, 11:50

ShuffleIntoLibrary, I think is the only other form.
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: New keyword: spBounceTgt

Postby Sloth » 30 Jul 2010, 12:15

Rob Cashwalker wrote:ShuffleIntoLibrary, I think is the only other form.
Good catch, this definitely belongs here. I will try to add this feature. Oblation needs to have Drawback$ though and Deglamer is the only other card I found. Did I miss any?

By the way Rob:
If you're working on the DestroyTgt keyword, wouldn't it be possible to exclude permanents with regeneration if the spell doesn't have NoRegen in canPlayAI here:

Code: Select all
choices = choices.filter(new CardListFilter(){
                       public boolean addCard(Card c)
                       {
                          return !c.getKeyword().contains("Indestructible");
                       }

True, the player doesn't always have the mana to activate regeneration, but a wasted spell weighs more I think.
User avatar
Sloth
Programmer
 
Posts: 3498
Joined: 23 Jun 2009, 19:40
Has thanked: 125 times
Been thanked: 507 times

Re: New keyword: spBounceTgt

Postby Rob Cashwalker » 30 Jul 2010, 13:59

A likewise, good catch.
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: New keyword: spBounceTgt

Postby Chris H. » 02 Aug 2010, 15:00

We have a few bounce spells that were originally coded without the use of this new keyword. I guess that we should convert them over to implemented via keyword.

I'm looking at the card object for:

Boomerang
Eye of Nowhere
Rescind
Surging AEther
Deny Reality

These original spells have an interesting if short canPlayAI method and I guess that I should add this to the new keyword.

Code: Select all
public boolean canPlayAI() {
    CardList human = CardFactoryUtil.AI_getHumanCreature(card, true);
    return 3 < AllZone.Phase.getTurn() && 0 < human.size();
}
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: New keyword: spBounceTgt

Postby DennisBergkamp » 02 Aug 2010, 15:43

Definitely interesting, I guess the AI won't bounce stuff until after turn 3?
User avatar
DennisBergkamp
AI Programmer
 
Posts: 2602
Joined: 09 Sep 2008, 15:46
Has thanked: 0 time
Been thanked: 0 time

Re: New keyword: spBounceTgt

Postby Sloth » 02 Aug 2010, 16:04

DennisBergkamp wrote:Definitely interesting, I guess the AI won't bounce stuff until after turn 3?
Doesn't make a big difference, but it would have a higher chance of hitting the player at a crucial point of his mana curve (i.e. a three mana permanent when he doesn't have a fourth land).
User avatar
Sloth
Programmer
 
Posts: 3498
Joined: 23 Jun 2009, 19:40
Has thanked: 125 times
Been thanked: 507 times

Re: New keyword: spBounceTgt

Postby Chris H. » 02 Aug 2010, 21:48

I made a minor adjustment to the spBounceTgt AI. I tried to keep it simple and we can always go back and change the number or remove the additional line of code. The start of the canPlayAI() method now looks like this:

Code: Select all
public boolean canPlayAI() {
    if (AllZone.Phase.getTurn() <= 3) return false;
   
    CardList results = new CardList();
    CardList choices = getTargets();
   
    choices = choices.filter(new CardListFilter(){
        public boolean addCard(Card c)
        {
            return CardFactoryUtil.canTarget(card, c);
        }
    });
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: New keyword: spBounceTgt

Postby friarsol » 03 Aug 2010, 15:52

I haven't looked into this keyword yet, but I figured I'd ask first. Is there a way to have multiple targets?

This would be needed for spells like Whiplash Trap or Plow Under.
friarsol
Global Moderator
 
Posts: 7593
Joined: 15 May 2010, 04:20
Has thanked: 243 times
Been thanked: 965 times

Re: New keyword: spBounceTgt

Postby Sloth » 03 Aug 2010, 16:23

friarisol wrote:I haven't looked into this keyword yet, but I figured I'd ask first. Is there a way to have multiple targets?

This would be needed for spells like Whiplash Trap or Plow Under.
There's always a way. But it has to be coded first.

I'm not planning to do this at the moment (I will be on vacation at least the next week). If someone wants to give it a try - Go for it.
User avatar
Sloth
Programmer
 
Posts: 3498
Joined: 23 Jun 2009, 19:40
Has thanked: 125 times
Been thanked: 507 times

Re: New keyword: spBounceTgt

Postby Chris H. » 03 Aug 2010, 17:48

Sloth wrote:I'm not planning to do this at the moment (I will be on vacation at least the next week). If someone wants to give it a try - Go for it.
`
You have committed an amazing amount of good work these last several weeks. 8) We wish you a pleasant and relaxing vacation. 8)
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: New keyword: spBounceTgt

Postby friarsol » 03 Aug 2010, 18:46

Sloth wrote:
friarisol wrote:I haven't looked into this keyword yet, but I figured I'd ask first. Is there a way to have multiple targets?

This would be needed for spells like Whiplash Trap or Plow Under.
There's always a way. But it has to be coded first.

I'm not planning to do this at the moment (I will be on vacation at least the next week). If someone wants to give it a try - Go for it.
Hah. I just meant was it available for use. I'm going on vacation soon myself, but figured I could get a few things done before that happens.
friarsol
Global Moderator
 
Posts: 7593
Joined: 15 May 2010, 04:20
Has thanked: 243 times
Been thanked: 965 times

Next

Return to Developer's Corner

Who is online

Users browsing this forum: No registered users and 41 guests

Main Menu

User Menu

Our Partners


Who is online

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

Login Form