Page 1 of 2

New keyword: spDestroyAll

PostPosted: 15 Aug 2010, 17:24
by Sloth
I've added a new keyword: spDestroyAll

spDestroyAll:<AffectedType>:<Options>

<AffectedType>: takes all the restrictions of spDestroyTgt.

<Options>: Only NoRegen is supported at the moment.

The AI will use these spells if at least 2 more human permanents will be destroyed. That means that some spells like Armageddon should not be converted, but most of the other spells have the same restrictions (Wrath of God) or none at all (Purify).

Here is the code:
Code: Select all
        // Generic destroy all card
        if(hasKeyword(card, "spDestroyAll") != -1) {
            int n = hasKeyword(card, "spDestroyAll");
           
            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(",");
           
            final boolean NoRegen = (k.length == 3);
           
            card.clearSpellAbility();
           
            final SpellAbility spDstryAll = new Spell(card) {
                private static final long serialVersionUID = 132554543614L;
               
                @Override
                public boolean canPlayAI() {
                    CardList human = new CardList(AllZone.Human_Play.getCards());
                    CardList computer = new CardList(AllZone.Computer_Play.getCards());
                   
                    human = human.getValidCards(Tgts);
                    human = human.getNotKeyword("Indestructible");
                    computer = computer.getValidCards(Tgts);
                    computer = computer.getNotKeyword("Indestructible");
                   
                    // the computer will at least destroy 2 more human permanents
                    return  AllZone.Phase.getPhase().equals(Constant.Phase.Main2) &&
                          (computer.size() < human.size() - 1);
                }

                @Override
                public void resolve() {
                    CardList all = new CardList();
                    all.addAll(AllZone.Human_Play.getCards());
                    all.addAll(AllZone.Computer_Play.getCards());
                    all = all.getValidCards(Tgts);
                   
                    CardListUtil.sortByIndestructible(all);
                    CardListUtil.sortByDestroyEffect(all);
                   
                    for(int i = 0; i < all.size(); i++) {
                        Card c = all.get(i);
                        if(NoRegen) AllZone.GameAction.destroyNoRegeneration(c); else AllZone.GameAction.destroy(c);
                    }
                }// resolve()

            }; //SpDstryAll
           
           
            card.setSVar("PlayMain1", "TRUE");
            card.addSpellAbility(spDstryAll);           

        }//spDestroyAll

Re: New keyword: spDestroyAll

PostPosted: 16 Aug 2010, 00:18
by Rob Cashwalker
Nice work.

I would suggest changing
final boolean NoRegen = (k.length == 3);
to actually check for "NoRegen" so other options can be added without changing much code.

Edit - For example, add Drawback as an option.

Re: New keyword: spDestroyAll

PostPosted: 17 Aug 2010, 20:14
by Chris H.
Sloth wrote:I've added a new keyword: spDestroyAll

spDestroyAll:<AffectedType>:<Options>

<AffectedType>: takes all the restrictions of spDestroyTgt.

<Options>: Only NoRegen is supported at the moment.

The AI will use these spells if at least 2 more human permanents will be destroyed. That means that some spells like Armageddon should not be converted, but most of the other spells have the same restrictions (Wrath of God) or none at all (Purify).
`
I converted 4 spells to the spDestroyAll keyword.

Acid Rain
Boil
Boiling Seas
Flashfires

These spells use a different AI test. It only checks to see if the human has > 3 of the affected land type in play. I thought about it and decided that we humans are likely to play multi-color decks more often than single color decks. And these four cards will not appear in a randomly generated deck.

So, the spDestroyAll AI test may be enough. What do other people think?

Re: New keyword: spDestroyAll

PostPosted: 17 Aug 2010, 23:39
by Chris H.
We have a code block with a number of spells:

Akroma's Vengeance
Devastation
Jokulhaups
Purify
Shatterstorm
Obliterate

I commented out the code block and tried to convert Akroma's Vengeance. The card now looks like this:

Akroma's Vengeance
4 W W
Sorcery
Destroy all artifacts, creatures, and enchantments.
spDestroyAll:Artifact,Creature,Enchantment
Cycling:3
SVar:Rarity:Rare
SVar:Picture:http://www.wizards.com/global/images/magic/general/akromas_vengeance.jpg
`
It worked in a test game, except for one thing. When this spell is cast, it brings up a choose window where we get to select the spDestroyAll or the Cycling SpellAbility. Having the spell description on the fourth line, well, the spDestroyAll spell description will not appear in the choose window. In the original code block there is a test for this card and it sets the spell description via:

Code: Select all
spell.setDescription("Destroy all artifacts, creatures, and enchantments.");

Re: New keyword: spDestroyAll

PostPosted: 18 Aug 2010, 00:21
by Rob Cashwalker
The original spDestroyTgt that Sloth has based these keywords on, assumed very simple spells using just the normal card text.

I am revising spDestroyTgt right now to support Drawback. I will also look into making sure these spells set their descriptions.

Re: New keyword: spDestroyAll

PostPosted: 18 Aug 2010, 07:54
by Sloth
Rob Cashwalker wrote:I am revising spDestroyTgt right now to support Drawback. I will also look into making sure these spells set their descriptions.
Thanks Rob!

I just converted Rebuild to keyword and the Cycling choice works fine.

I will now start to improve canPlayAI for spDestroyAll.

My first draft is:

X = number of permanents + total CMC + number of lands (human)

and if the computers life is below 7 add the total power of the human creatures (which should make a huge difference).

Y = number of permanents + total CMC + number of lands (computer)

canPlayAI returns true if Y < X - 3.

Re: New keyword: spDestroyAll

PostPosted: 18 Aug 2010, 13:11
by Chris H.
Rob Cashwalker wrote:The original spDestroyTgt that Sloth has based these keywords on, assumed very simple spells using just the normal card text.

I am revising spDestroyTgt right now to support Drawback. I will also look into making sure these spells set their descriptions.
`
I merged Rob's work into my local copy and was able to convert over a few more spells.

However, Obliterate does not display it's "CARDNAME can't be countered." keyword. We had in the past several other keywords that failed to show up in the text panel. I should be able to add this additional keyword to the proper section in card.getText(), or at least I think that I can fix it this way. We will see. :D

Re: New keyword: spDestroyAll

PostPosted: 18 Aug 2010, 13:32
by Rob Cashwalker
I originally assigned card.getText to the spell description, then card.setText("").
Now, I noticed that there's card.getSpellText, which seems like it should return the "printed" text, as opposed to the parsed, generated text.

Re: New keyword: spDestroyAll

PostPosted: 18 Aug 2010, 16:38
by Chris H.
Rob Cashwalker wrote:I originally assigned card.getText to the spell description, then card.setText("").
Now, I noticed that there's card.getSpellText, which seems like it should return the "printed" text, as opposed to the parsed, generated text.
`
That might solve the problem. We should check into this and see if it makes a difference at some point.

Re: New keyword: spDestroyAll

PostPosted: 18 Aug 2010, 17:28
by Rob Cashwalker
The code I submitted last night uses it. So if it's not working now, then I don't know what it should do.

The DestroyTgt and BounceTgt code relies on the wording "Destroy/Return target ____" being at the beginning of the printed text. The "____" is inserted into the input prompt.
Without using the card text (relying on the description coming from the keyword line itself, then I would need another parameter of SVar to provide the "____".
After using the card.getSpellText for the spellDescription, it uses card.setText("") to clear it. (so it doesn't appear twice from card.getText() - once from the printed text and then from the SpellAbility)

The DestroyAll and BounceAll code just sucks up the card.getSpellText, and then clears it. It doesn't need the printed text for anything else.

Re: New keyword: spDestroyAll

PostPosted: 19 Aug 2010, 00:46
by Chris H.
I had problems converting Guan Yu's 1,000-Li March to keyword. It would not display the spell text. The card worked and would kill tapped creatures. I looked at your message and realized that I would have to change the cards.txt entry to this:

Guan Yu's 1,000-Li March
4 W W
Sorcery
Destroy all creatures that are tapped.
spDestroyAll:Creature.tapped
SVar:Rarity:Rare
SVar:Picture:http://www.wizards.com/global/images/magic/general/guan_yus_1000_li_march.jpg

Re: New keyword: spDestroyAll

PostPosted: 21 Aug 2010, 03:31
by Rob Cashwalker
I just added drawback handling to spDestroyAll.

This was my test card:
Code: Select all
Hellfire
2 B B B
Sorcery
Destroy all nonblack creatures. Hellfire deals X plus 3 damage to you, where X is the number of creatures put into all graveyards this way.
spDestroyAll:Creature.nonBlack:Drawback$DamageYou/X.Plus.3
SVar:Rarity:Rare
There are a handful of cards with drawbacks we can handle. I think all or almost all of them involve the number of cards the spell actually destroyed, so that is the number being passed as "X".

To actually count some other criteria, use "dX" and an SVar to define the Count$.

Doing this card also revealed some bugs in the doDrawback math handling code, so I had to debug those before proving the actual functionality.

Re: New keyword: spDestroyAll

PostPosted: 07 Sep 2010, 19:20
by Chris H.
Rob Cashwalker wrote:I just added drawback handling to spDestroyAll.

This was my test card:
Code: Select all
Hellfire
2 B B B
Sorcery
Destroy all nonblack creatures. Hellfire deals X plus 3 damage to you, where X is the number of creatures put into all graveyards this way.
spDestroyAll:Creature.nonBlack:Drawback$DamageYou/X.Plus.3
SVar:Rarity:Rare
There are a handful of cards with drawbacks we can handle. I think all or almost all of them involve the number of cards the spell actually destroyed, so that is the number being passed as "X".

To actually count some other criteria, use "dX" and an SVar to define the Count$.

Doing this card also revealed some bugs in the doDrawback math handling code, so I had to debug those before proving the actual functionality.
`
I spent some time trying to figure out the SVar for Hellfire. I assume that this would do it:

SVar:X:Count$TypeOnBattlefield.Creature.nonBlack

Re: New keyword: spDestroyAll

PostPosted: 07 Sep 2010, 19:30
by friarsol
Chris H. wrote:I spent some time trying to figure out the SVar for Hellfire. I assume that this would do it:

SVar:X:Count$TypeOnBattlefield.Creature.nonBlack
That doesn't account for Indestructible creatures or creatures that regenerated from the Hellfire (and possibly others).

Re: New keyword: spDestroyAll

PostPosted: 07 Sep 2010, 20:03
by Chris H.
friarisol wrote:That doesn't account for Indestructible creatures or creatures that regenerated from the Hellfire (and possibly others).
`
I had considered:

SVar:X:Count$TypeInAllYards.Creature.nonBlack

but this version also has problems determining the correct number of X. And I am not sure when X is calculated, although I assume that it is equal to the number of cards in the list of valid targets.