Page 1 of 2

New keyword: spBounceTgt

PostPosted: 29 Jul 2010, 18:42
by Sloth
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?

Re: New keyword: spBounceTgt

PostPosted: 29 Jul 2010, 21:49
by Rob Cashwalker
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.

Re: New keyword: spBounceTgt

PostPosted: 30 Jul 2010, 00:16
by Chris H.
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

Re: New keyword: spBounceTgt

PostPosted: 30 Jul 2010, 06:21
by Sloth
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.

Re: New keyword: spBounceTgt

PostPosted: 30 Jul 2010, 11:50
by Rob Cashwalker
ShuffleIntoLibrary, I think is the only other form.

Re: New keyword: spBounceTgt

PostPosted: 30 Jul 2010, 12:15
by Sloth
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.

Re: New keyword: spBounceTgt

PostPosted: 30 Jul 2010, 13:59
by Rob Cashwalker
A likewise, good catch.

Re: New keyword: spBounceTgt

PostPosted: 02 Aug 2010, 15:00
by Chris H.
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();
}

Re: New keyword: spBounceTgt

PostPosted: 02 Aug 2010, 15:43
by DennisBergkamp
Definitely interesting, I guess the AI won't bounce stuff until after turn 3?

Re: New keyword: spBounceTgt

PostPosted: 02 Aug 2010, 16:04
by Sloth
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).

Re: New keyword: spBounceTgt

PostPosted: 02 Aug 2010, 21:48
by Chris H.
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);
        }
    });

Re: New keyword: spBounceTgt

PostPosted: 03 Aug 2010, 15:52
by friarsol
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.

Re: New keyword: spBounceTgt

PostPosted: 03 Aug 2010, 16:23
by Sloth
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.

Re: New keyword: spBounceTgt

PostPosted: 03 Aug 2010, 17:48
by Chris H.
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)

Re: New keyword: spBounceTgt

PostPosted: 03 Aug 2010, 18:46
by friarsol
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.