Monday, June 25, 2007

MTG Forge Overview

Trying to understand a whole programming project is difficult and almost impossible without copious amounts of documentation. I’m going to try to summarize the major classes MTG Forge uses. The Card class mimics the functions of a real card, and the Card class exists in your hand, in play, in the graveyard, and removed from the game. A Card can hold any number of SpellAbility objects. Each Card has at least one SpellAbility and if the Card has an ability like Elvish Piper, the Card will have two SpellAbilities added. One SpellAbility is the default summon creature spell and the other SpellAbility is the activated ability that lets you put a creature from your hand into play.

Every SpellAbility can have an optional mana cost, the only SpellAbilities that don’t have a mana cost are creatures that have tap abilities. Instants and Sorceries also use the SpellAbility class. SpellAbility has a resolve method that is called after it is popped off the stack. The CardFactory class makes new cards and copies existing ones. CardFactory also adds the SpellAbility objects to the Cards, and implements SpellAbility’s resolve method. The resolve method for Wrath of God would destroy everything.

The file “cards.txt” holds simple cards as well as all the text for Instants and Sorceries. This file saved time because I didn’t have to program simple creatures like Glory Seeker. This file also let me specify mana abilities, so creatures like Bird of Paradise are only implemented in cards.txt, no other code is needed. Flying, haste, fear, and vigilance are also supported by cards.txt Some users have added their own cards, which surprised me.

The class that runs everything is Gui_NewGame. It starts up the user interface and initializes everything. Every screen is a separate class and JFrame. These display classes all start with the abbreviation Gui and are only loosely tied together, they all read from Constant.Runtime in order to read which deck you and the computer are using.

I hate not throwing some code at you. J The code below constructs Serra Avenger. AllZone holds all of the zones, in play, graveyard, etc… and can be globally accessed. Global variables are generally bad, but they really helped get MTG Forge working. The computer can play regular creature cards like Serra Avenger using the code below, since it just pays the mana cost and the resolve method works the same for both the human and computer player.

The computer checks the canPlay and canPlayAI methods in SpellAbility to see if it is allowed to play that card. This specific card does not have a canPlayAI method, a card like Hex does, because it targets 6 creatures. The card below belongs in the human player’s deck, since he both controls and owns the card. If this card was going into the computer’s library, the computer would be listed as the owner and controller.


final Card card = new Card();
card.setName("Serra Avenger");
card.setManaCost("W W");

card.setAttack(3);
card.setDefense(3);

card.addKeyword("Flying");
card.addKeyword("Vigilance");

card.setOwner("Human");
card.setController("Human");

SpellAbility spell = new SpellAbility(SpellAbility.Spell, card)
{
public void resolve()
{
PlayerZone play = AllZone.getZone(Constant.Zone.Play, card.getController());
play.add(card);
}
public boolean canPlay()
{
//Serra Avenger cannot be played for the first three turns of the game
return 3 < AllZone.Phase.getTurn();
}
};
card.addSpellAbility(spell);

2 comments:

clacker said...

I've found that using the javadoc program can be helpful in documenting and also for looking over someone else's code. It creates a series of web pages with cross links to other pages for all of the classes. For example, you can see that SpellAbility has the subclasses:

SpellAbility
    Ability
    Ability_Activated
    Ability_Hand
    Ability_Tap
    Spell

You can also see what the fields, methods, and constructors are.

Forge said...

Thats true, even though my code doesn't have any comments JavaDoc does show inheritance and all public methods. I tried to make all the class and method names readable, but the overall archetecture I'm a little confusing.