Monday, July 2, 2007

Static Abilities

Today, I’m going to talk about the hardest cards to program. Cards like Glorious Anthem caused me a lot of headaches.

This is a definition of static abilities from the rules manual.

You don’t play and resolve static abilities like the other two ability types. When a permanent with a static ability comes into play, the ability’s effect simply “turns on.” It stays on as long as the permanent stays in play. (Static abilities create continuous effects.) Most enchantments have static abilities. For example, Telepathy reads, “Your opponents play with their hands revealed.” Once Telepathy is in play, you don’t have to pay a cost to have your opponent reveal his or her hand. Your opponent’s hand is just kept face up on the table until Telepathy leaves play.

I call static ability, state abilities since they depend on the current “state” or condition of the game. State abilities include Glorious Anthem, Levitation, Soul Warden, and Castle Raptors. Glorious Anthem gives your creatures +1/+1, so it changes the state of the game. Castle Raptors gets a bonus if it is untapped.

In MTG Forge static effects are processed after you play a land, the computer plays a land, or a spell/ability is resolved. The code for Glorious Anthem is a little messy since it keeps track of old creatures that were already in play. Glorious Anthem first takes away the +1/+1 from all old cards and then gives the bonus for each copy of Glorious Anthem in play. The code loops through all copies of Glorious Anthem in case you and your opponent both have it in play. This code also works correctly if you have multiple Anthems in play.

The code below was taken from the class GameActionUtil. It has a method called executeCardStateEffects that executes all of the effects. Doing state effects this way has the drawback of separating code from the Card and SpellAbility classes which I would prefer not to. Platinum Angel has a very cool and hard to program state effect that denies your opponent from winning the game. Check it out in the upcoming 10th edition core set.

GameAction also implements some state effects in the method checkStateEffects. Other MTG Forge state effects include sending a creature to the graveyard if it has sufficient damage. Destroying legendary creatures if two are into play and checking to see if any player’s life is 0. The cards that have a state effect in MTG Forge are Baru, Fist of Krosa, Soul Warden, Essence Warden, Nightmare, Korlash, Heir to Blackblade, Glorious Anthem, Gaea's Anthem, Wonder, Anger, Valor, Veteran Armorer, Radiant, Archangel, and Castle Raptors.


static Command Glorious_Anthem = new Command()
{
CardList gloriousAnthemList = new CardList();
public void execute()
{
CardList list = gloriousAnthemList;
Card c;
//reset all cards in list - aka "old" cards
for(int i = 0; i < list.size(); i++)
{
c = list.get(i);
c.setAttack(c.getAttack() - 1);
c.setDefense(c.getDefense() - 1);
}

//add +1/+1 to cards
list.clear();
PlayerZone[] zone = getZone("Glorious Anthem");

//for each zone found add +1/+1 to each card
for(int outer = 0; outer < zone.length; outer++)
{
CardList creature = new CardList(zone[outer].getCards());
creature = creature.getType("Creature");

for(int i = 0; i < creature.size(); i++)
{
c = creature.get(i);
c.setAttack(c.getAttack() + 1);
c.setDefense(c.getDefense() + 1);

gloriousAnthemList.add(c);
}//for inner
}//for outer
}//execute()
};//Glorious Anthem

//returns all PlayerZones that has at least 1 Glorious Anthem
//if Computer has 2 Glorious Anthems, AllZone.Computer_Play will be returned twice
PlayerZone[] getZone(String cardName)
//method body removed on purpose

2 comments:

clemens said...

Hi!

I know this is an older post of you, and maybe you have got a better solution already. I also want to make a magic computer game, partly for playing, but mostly for the challenge.

my attemp on glorious anthem and so on would be to modify how p/t is determined. the p/t that is "printet" isn't modified. just when the opponent, the view or a state-based effect wants to know its power, all cards are asked if the want to modify the returned value

Zeigfreid said...

Hi

This is something I am totally having trouble with. State-based effects, such as creatures being destroyed when they have 0 toughness, are all meant to be checked any time the stack is empty. But effects from cards like Glorious Anthem, they are continuous. I can't think of a good time to update their effect, except after any event.

For spells and abilities I will use method calls; for triggered abilities I will use something like a mouseMotionListener, but for magicEvents; but for static abilities? I just don't know yet. I hope I can figure out a good way...

z.