Friday, November 16, 2007

Programming Magic Cards is Easy

I am currently slowly working on MTG Forge 2.0 and it is difficult of course. I want to be able to program cards that I currently cannot do. With version 2.0 I am rebuilding everything from scratch which means that the old card code won’t work with the new code. Also, my progress is slow because real life gets in the way.

The really hard part about version 2.0 isn’t really just the cards. It already has such great cards like Iridescent Angel, Dark Ritual, Hypnotic Specter, Loxodon Warhammer, and enchantments like Spirit Link. The hard part is all of the other stuff that supports the cards like the user interface, combat, reading and writing files for the deck builder, and handling mouse input.

When adding cards to version 1.0, I only have to think about the card functionality. Does the card have a target? Does the card do something weird? Does it have an effect that ends at end of turn? I can conveniently forget about all the other code except the 100 or so lines that make up a specific card.

After not looking at MTG Forge’s source code for a week or two it is hard to understand everything that is going on. For truly bad source code see InputControl’s getInput method. It is 120 lines long and is hard to read and understand. It selects the next phase like Declare Attackers or the first Main phase.

Thankfully most of my other code isn’t so bad, but it is still hard to for other people to understand. I tried very hard making the Java code for each card readable. The code below is the Mirrodin card Tanglebloom and it is taken from the current version of MTG Forge. You can compare and contrast this article with my previous essay “Programming Magic Cards is Hard.”



//taken from CardFactory.getCard()

//Tanglebloom is an artifact that costs 1 and has an ability “1, tap: You gain 1 life.”
if(cardName.equals("Tanglebloom"))
{
//1 is the mana cost for the ability
final SpellAbility sp = new Ability_Tap(card, "1")
{

//the computer will only play the ability during his second main phase
public boolean canPlayAI()
{
return AllZone.Phase.getPhase().equals(Constant.Phase.Main2);
}

public void resolve()
{
AllZone.GameAction.getPlayerLife(card.getController()).addLife(1);
}

};//SpellAbility

card.addSpellAbility(sp);

//the text that is on the card
sp.setDescription("1, tap: You gain 1 life.");

//the text that is shown when on the stack
sp.setStackDescription("Tanglebloom - " +card.getController() +" gains 1 life.");

//the Input class handles all input
//Input_PayManaCost extends Input and lets the user pay the mana cost
sp.setBeforePayMana(new Input_PayManaCost(sp));

3 comments:

Anonymous said...

Please consider making keyworded abilities true objects in your new version. I think that would make development of new cards much much easier for the people that want to program the cards.

Forge said...

I try to make some keyworded abilities just text that can be adding to the file "cards.txt" like flying and haste, in order to reduce the amount of code. Some keywords like cycling and evoke are implemented as objects since their effect varies from card to card.

Anonymous said...

Will this be compatible with Linux?
You should consider it. I've been trying to find a good MTG game for linux and the best one is Apprentice (actually a diff program called "mindless automation" but it's almost exactly the same).

Anyway, you'd get more people using it if it works with Linux. I could help you if you want, although I'm just a decent programmer. If I can't help you with code, I could help you test it, I have linux. Let me know what you think my email is jason5002@gmail.com