It is currently 28 Oct 2025, 16:18
   
Text Size

Think Fast: Allowing the AI to Respond to the Stack

Post MTG Forge Related Programming Questions Here

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

Think Fast: Allowing the AI to Respond to the Stack

Postby lord of 13 » 04 Dec 2010, 17:21

So... this weekend was fairly quiet so I decided to try editing Forge's code again. I downloaded the latest SVN and Eclipse/Subclipse and starting coding.
I have two goals for this weekend:
1. Develop a primitive architecture to allow the AI to respond to spells/abilities on the stack successfully
2. Extend the scripting interface to support BooleanEnablers
a. Essentially, mechanics that are dependent on some sort of boolean conditional -> Think Metalcraft, Threshold, and the Zendikar Vampires mechanic as well as Landfall. Possibly can be extended to Kinship and "If you control another [cardType], [doStuff]" effects.
b. Syntax in the card files would be [Mox Opal]:
Code: Select all
K[Metalcraft]: tap: Add W
K[Metalcraft]: tap: Add U
K[Metalcraft]: tap: Add B
K[Metalcraft]: tap: Add R
K[Metalcraft]: tap: Add G
and such.
c. Compounding them would also be supported - simply use boolean operators and evaluate at runtime
Code: Select all
K[Metalcraft && Threshold]: tap: Add W
K[Metalcraft || Threshold]: tap: Add 1

//Searing Blaze
K[!Landfall]: spDamageTgtC:1:Drawback$DamageTgt/1:CARDNAME deals 1 damage to target creature and 1 damage to that creature's controller.
K[Landfall]: spDamageTgtC:3:Drawback$DamageTgt/3:CARDNAME deals 3 damage to target creature and 3 damage to that creature's controller.
But getting back to my first plan...
I have a question: how do you query a card to find out if it is a counterspell? getSpellAbilities()... and then what? Or if it has protection? Or should I merely search the card's text to see if it contains the word "Counter"?

My modifications are inside ComputerAI_General.java in the method stackResponse
The code I've written so far immediately precedes the final line of the method - AllZone.Phase.passPriority();
Code: Select all
//LordOf13: Following code can and should be encapsulated into its own method... later
       
       //LordOf13: Essentially, find out if the spell is helpful to the human
       //         or hurtful to the AI.
       //         It's assumed that targeting the appropriate player makes it helpful/hurtful.
       //         
       //         Then, identify if whose cards it targets - is it helpful
       //         or hurtful to permanents? Similar assumptions as above.
       //         For reference, the computer being targeted is more important than its cards
       //         being targeted
       Target targeted = sa.getTarget();
       ArrayList<Player> targetPlayer = targeted.getTargetPlayers();
       Card[] targetCard = new Card[targeted.getTargetCards().size()];
       targeted.getTargetCards().toArray(targetCard);
       boolean hurtful = targetPlayer.contains(AllZone.ComputerPlayer),
          helpful = targetPlayer.contains(AllZone.HumanPlayer);
       boolean creatureHurt = false, creatureHelp = false;
       for (int i = 0; i < targetCard.length; i++)
       {
          PlayerZone zone = AllZone.getZone(targetCard[i]);
          if (zone == null)//it's in a mysterious unrecognized zone
             continue;
          if (zone.getPlayer() == AllZone.ComputerPlayer)
             creatureHelp = true;
          if (zone.getPlayer() == AllZone.HumanPlayer)
             creatureHurt = true;
       }
       
       //disregard abilities for now and only consider cards in hand
       ArrayList<Card> castable = new ArrayList<Card>();
       Card[] hand = AllZone.Computer_Hand.getCards();
       for (int i = 0; i < hand.length; i++)
       {
          //TO DO: Check if you can generate enough mana to cast it
          if (hand[i].isInstant() || hand[i].hasKeyword("Flash"))
             castable.add(hand[i]);
       }
       
       //now... see which cards are useful
       Iterator<Card> castableIter = castable.iterator();
       Card card;
       while (castableIter.hasNext())
       {
          card = castableIter.next();
       }
><><><><><><><
Currently developing Mindgames, for playing a rules-enforced game of MtG.
RECENT PROJECTS
->XMLScript
->Zwiel Platformer
User avatar
lord of 13
DEVELOPER
 
Posts: 79
Joined: 06 Jan 2010, 01:36
Has thanked: 0 time
Been thanked: 0 time

Re: Think Fast: Allowing the AI to Respond to the Stack

Postby Rob Cashwalker » 04 Dec 2010, 18:12

The theory we're going with, is that the Ability object will have additional AI methods specific to each sort of point where the AI would want to check if it should play that ability.

So Giant Growth (AbilityFactory_Pump) would have implement two new methods - chkAI_DeclareAttack() and chkAI_DeclareBlock(). (theoretically, the original canPlayAI would be deprecated) Those methods would be called during the appropriate steps to evaluate the situation.

Other abilities would get chkAI_Upkeep or something, which would be checked in those appropriate steps.

Finally, adding a chkAI_SpellOnStack method would enable responding to spells on the stack. Most abilities may want to have this method and it may be very tricky... Giant Growth in response to damage or -1/-1 effects; Regeneration in response to destroy effects; counterspell in response to just about anything...
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: Think Fast: Allowing the AI to Respond to the Stack

Postby lord of 13 » 04 Dec 2010, 18:33

Hmm... alright.
So I should discard my current changes to that method and move on to the Boolean Qualifiers? Do you have plans for that?
><><><><><><><
Currently developing Mindgames, for playing a rules-enforced game of MtG.
RECENT PROJECTS
->XMLScript
->Zwiel Platformer
User avatar
lord of 13
DEVELOPER
 
Posts: 79
Joined: 06 Jan 2010, 01:36
Has thanked: 0 time
Been thanked: 0 time

Re: Think Fast: Allowing the AI to Respond to the Stack

Postby friarsol » 04 Dec 2010, 21:08

This functionality already exists in spell ability restrictions.

Take a look in there and there's a bunch of cards already using it but I'm not at my computer to give examples. Also look into lunge for how that card works in newer functionality
friarsol
Global Moderator
 
Posts: 7593
Joined: 15 May 2010, 04:20
Has thanked: 243 times
Been thanked: 965 times

Re: Think Fast: Allowing the AI to Respond to the Stack

Postby friarsol » 05 Dec 2010, 04:52

Ok here's more of an explanation about SA_Restrictions, since I was on my phone before:

They are automatically attached to AbilityFactory Architecture. They can handle many similar things to what you are referring to. We have a bunch of things already doing just that.

Example Vedalken Certarch for MetalCraft using IsPresent and PresentCompare:
Code: Select all
A:AB$Tap | Cost$ T | ValidTgts$ Artifact,Creature,Land | TgtPrompt$ Select target artifact, creature or land. | IsPresent$ Artifact | PresentCompare$ GE3 | PrecostDesc$ Metalcraft - | SpellDescription$ Tap target artifact, creature or land.
As far as AI response, this architecture is already in place similar to where you were looking. I added some more code in that spot, but I had some grander plans that I was going to start working on soon.

With the AbilityFactory system, I was going to attach the parsed AF to the SpellAbility to solve your question of "How do I know what a spell on the stack does?" this may not get us all of the cards, but it should give us a large majority. I just need to finish getting SubAbilities done before I can get that going.

I'm not sure if having separate functions for each Phase is really necessary for the AI. We could just use the current functions and return false for any phase that the spell wouldn't be cast in.

In Rob's example he talks about AF_Pump. So in Declare Attackers you would use Pump abilities that gave Evasion (either so your creature can block a different creature, or avoid other creatures). In Declare Blockers, you would protect your creatures from dying or kill opposing creatures (or deliver a death blow to the player). Before a Combat phase you might give a creature Haste. The only other case is responding to a non-Empty Stack. This situation is only for protecting your guy to a damage/pump curse.
friarsol
Global Moderator
 
Posts: 7593
Joined: 15 May 2010, 04:20
Has thanked: 243 times
Been thanked: 965 times


Return to Developer's Corner

Who is online

Users browsing this forum: No registered users and 23 guests

Main Menu

User Menu

Our Partners


Who is online

In total there are 23 users online :: 0 registered, 0 hidden and 23 guests (based on users active over the past 10 minutes)
Most users ever online was 9298 on 10 Oct 2025, 12:54

Users browsing this forum: No registered users and 23 guests

Login Form